0

I have a small JSON file which contains an EC signature generated by SubtleCrypto.sign() ECDSA algorithm and SHA512 digest. Now I manually generate the signature, but I would like to automate it. I have a restriction to use the nginx:alpine base image to do that. So I have installed OpenSSL, but it turns out, SubbtleCrypto.verify() needs the signature in IEEE P1363 format, but OpenSSL uses the ASN1 format. Is there a way to use the signature generated by openssl in the browser?

Note:

I created the EC key pair in the browser and it is working fine when the signature is generated with SubtleCrypto.sign().

Then I have exported the private key in PKCS#8 format, and saved it as a PEM file to be used as an input for OpenSSL.

-----BEGIN EC PRIVATE KEY-----
<Base64 encoded content here...>
-----END EC PRIVATE KEY-----

and use the following to generate the signature in Base64 for {} (data.json)

$ openssl dgst -sha512 -sign private.pem data.json | base64
MIGHAkEZ0YthoqLqCW1ll0MvPEYdhoz+p1zxQnLt0sl0rSvD8eI0BdAeQUqS1fUlNi8O39ClI6OI
JDZJqJ3OkTFkMyqzaAJCAT8koJnhqv2PUHla7EWV/qVIBb9LtPovQODl0+CsBQlkGO+TKkX3X57+
rpOZMqYv1tIOAz1m5ry0sOo0hGSe4c8X

then I used this website (the link contains the signature as well in Base64 encoded ASN1 format): asn1 decoder to get the r and s decimal values, and then followed this SO answer:

r = 346169932049245619871744113024266741326899713498883047336224784039276978051811648336988371154157537871201508197563500632048282301939214838670217488915673960
s = 4279009059525041370739088323750483074176965727856497966083564113228214038964554024207556176396942898795827323835166902701178318351093672293528073206493204247

hex_val = 19D18B61A2A2EA096D6597432F3C461D868CFEA75CF14272EDD2C974AD2BC3F1E23405D01E414A92D5F525362F0EDFD0A523A388243649A89DCE913164332AB368013F24A099E1AAFD8F50795AEC4595FEA54805BF4BB4FA2F40E0E5D3E0AC05096418EF932A45F75F9EFEAE939932A62FD6D20E033D66E6BCB4B0EA3484649EE1CF17

and the resulting base64 signature is

GdGLYaKi6gltZZdDLzxGHYaM/qdc8UJy7dLJdK0rw/HiNAXQHkFKktX1JTYvDt/QpSOjiCQ2SaidzpExZDMqs2gBPySgmeGq/Y9QeVrsRZX+pUgFv0u0+i9A4OXT4KwFCWQY75MqRfdfnv6uk5kypi/W0g4DPWbmvLSw6jSEZJ7hzxc=

and that fails to verify in the browser.

Edit:

I have created an example with the calculations I have made here. I generated the signature with the above openssl command with the key file given and a json file containing {} only.

Hodossy Szabolcs
  • 1,598
  • 3
  • 18
  • 34
  • *...Is there a way to use the signature generated by openssl in the browser?...* You need to convert the signature, either with a third-party library or by yourself. The former is more convenient with regard to implementation, but creates a dependency. So it is up to your requirements. – Topaco Nov 30 '22 at 16:34
  • Yeah, I have tried that to no avail. I am not sure thought what is the input of the digest algorithm or if I have correctly converted the signature. – Hodossy Szabolcs Dec 01 '22 at 08:05
  • You should post a sample ASN.1/DER encoded signature and how you converted it to P1363. – Topaco Dec 01 '22 at 08:09
  • I used this website (the link contains the signature as well in Base64 encoded ASN1 format): [asn1 decoder](https://lapo.it/asn1js/#MIGIAkIAzjZXUyv5EcPyLh3R7SP7pz2Kte44X7bIucOMJ2L5JEPtS1MRfnOs5aebiajNb6kD2qna3OvcIUoxaTEHuuccHn8CQgCo8EuPy5I3KsPU2DR2Fgw7ZMrkoH7U3JMDX1hTKkPGIyvfQnioksny9CmfRnBHpQDvI3oMASHhRxUKG7yapgZJmA) to get the `r` and `s` decimal values, and then followed [this SO answer](https://stackoverflow.com/a/47946906) – Hodossy Szabolcs Dec 01 '22 at 14:10
  • From this description it is not possible to verify if you are doing it correctly. Post either the code with the implementation or an example with an ASN.1/DER encoded signature and the derived P1363 signature. – Topaco Dec 01 '22 at 14:29
  • I did it manually, not coded it yet, although it would have been easier at this point.... I added the example I have worked with. – Hodossy Szabolcs Dec 01 '22 at 14:55
  • You have not specified the curve, perhaps secp521r1, for which the order of the base point is 521 bits large, rounded up to full octets 528 bits = 66 bytes, which thus corresponds to the size of r and s respectively. If r is smaller, it is padded from the front with 0x00 values, the same is true for s. In your case the r value is smaller (65 bytes) and gets a leading 0x00, i.e. the P1363 signature is hex encoded 0019...6801...17. – Topaco Dec 01 '22 at 16:02
  • Unfortunatelly I don't have information about the curve, but it is a very good point. I will try with proper padding, thanks! – Hodossy Szabolcs Dec 01 '22 at 19:04
  • I have created a new key pair and implemented the whole calculation available [here](https://github.com/hodossy/sign-with-openssl-verify-with-subtle-crypto/blob/main/index.html) – Hodossy Szabolcs Dec 02 '22 at 11:37
  • I cannot successfully verify the OpenSSL signature from the link in your last comment, *even with OpenSSL*. However, the OpenSSL signatures I created can be successfully verified with the JavaScript code. This means that the JavaScript code works, and that the posted data is the problem (check signature creation and data consistency). – Topaco Dec 02 '22 at 23:27
  • Thanks for verifying my code! It is embarrassing, but I still struggle to achieve a verifiable signature. I use the `echo {} | openssl -sha512 -sign private.pem | base64` command to generate the signature. What command did you use? – Hodossy Szabolcs Dec 08 '22 at 09:42
  • And I just found out the importance of the `-n` flag for echo. I managed to verify a signature generated with `echo -n {} | openssl -sha512 -sign private.pem | base64` – Hodossy Szabolcs Dec 08 '22 at 10:06

0 Answers0