使用openssl验证ECDSA签名类型时,ASN1编码例程错误 [英] ASN1 encoding routines errors when verifying ECDSA signature type with openssl

查看:1699
本文介绍了使用openssl验证ECDSA签名类型时,ASN1编码例程错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试验证外部方提供给我们的SHA256 ECDSA数字签名。他们已经在内部验证了其签名过程,但我们的尝试并未成功。在openssl验证期间,我们反复收到 asn1编码例程错误,但是我看不到签名或我们的过程出了什么问题。



这里是测试设置...
公钥(pubkey.pem):

 - --- BEGIN PUBLIC KEY ----- 
MFkwEwYHKoZIzj0CAQYIKoZIzjz0DAQcDQgAEOorVp0M8xien / r1 / 1Ln7TkSpzzcX
BL / MGRz66J1HSlEgBD5FwwpO1vo6D9b

正在签名的消息是纯文本字符串:

  HELLO 

数字签名(signature.sig) :

  JJhwReHev8cxOsNKCR5t / Ee3WU9c7tkf9RuGNamXdpXQu9OL8ZKnsrblCO7vEmOXGKGrk6NsgA5JZpQhXO $ A $$$$


$ b

我们采用的一般方法是:

 #创建消息文件
回声 HELLO hello.txt

#VERIFY
openssl dgst -sha256 -verify pubkey.pem -signature signature.sig hello.txt

并且响应为

 验证数据错误
4655195756:错误:0DFFF09B:asn1编码例程:CRYPTO_internal:太长:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.260.1/libressl-2.6/crypto/asn1/asn1/asn1_lib.c:143:
4655195756:错误:0DFFF066:asn1编码例程:CRYPTO_internal:坏对象标头:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.260.1/libressl-2.6/crypto/asn1 /tasn_dec.c:1113:
4655195756:错误:0DFFF03A:asn1编码例程:CRYPTO_internal:嵌套的asn1错误:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.260.1/ libressl-2.6 / crypto / asn1 / tasn_dec.c:306:Type = ECDSA_SIG

或者,我们对base64编码签名 base64 -D signature.sig> signature.bin ,但得到相同的错误响应。我也尝试过使用 openssl pkeyutl ,但这也会导致 asn1编码例程错误。使用ans1parse解析签名产生率:

  openssl asn1parse -in signature.bin 
错误:偏移量太大

很明显,数字签名采用的格式我不处理,但是我看不到问题所在

解决方案

您的signature.sig文件似乎是base64编码的。像这样解码:

  $ base64 -d signature.sig> signature.bin 

让我们看看我们拥有什么:

  $ hexdump -C signature.bin 
00000000 24 98 70 45 e1 de bf c7 31 3a c3 4a 09 1e 6d fc | $ .pE .... 1:.J..m。|
00000010 47 b7 59 4f 5c ee d9 1f f5 1b 86 35 a9 97 76 95 | G.YO\ ...... 5..v。|
00000020 d0 bb d3 8b f1 92 a7 b2 b6 e5 08 ee ef 12 63 97 | ........ c。|
00000030 18 a1 ab 93 a3 6c 80 0e 49 66 94 21 5c ed c0 d5 | ..... l..If。!\ ... |
00000040

出于比较目的,我根据相同的曲线创建了一个新的ECDSA私钥,公钥正在使用(P-256):

  $ openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out key .pem 

然后使用它签名一些数据:

  $ echo HELLO> hello.txt 
$ openssl dgst -sha256 -sign key.pem -out hello.sig hello.txt
$ openssl asn1parse -in hello.sig -inform DER
0:d = 0 hl = 2 l = 68缺点:SEQUENCE
2:d = 1 hl = 2 l = 32 prim:整数:2C1599C7765B047A2E98E2265CF6DB91232200559909D7F97CA3E859A39AC02C
36:d = 1 hl = 2 l = 32 prime:INTEGER:14EDF7A76A68A76A68A4984B $ b

所以您会注意到这里有两个整数,每个整数恰好是32个字节长。这对应于ECDSA_SIG ASN.1定义:

  ECDSA-Sig-Value :: =序列{r INTEGER,s INTEGER} 

原始ECDSA签名由两个整数 r和 s组成。 OpenSSL希望将它们包装在DER编码表示中。但是,由于您已经发现签名所拥有的内容不是有效的DER。但是 恰好是64个字节长-这表明它由2个32个字节的整数串联在一起组成。



对于本练习,我们可以使用十六进制编辑器将原始r和s值转换为DER格式。让我们看一下我之前创建的hello.sig文件的十六进制转储:

  $ hexdump -C hello.sig 
00000000 30 44 02 20 2c 15 99 c7 76 5b 04 7a 2e 98 e2 26 | 0D。 ,... v [.z ...& |
00000010 5c f6 db 91 23 22 00 55 99 09 d7 f9 7c a3 e8 59 | \ ...#。U .... | ..Y |
00000020 a3 9a c0 2c 02 20 14 e7 48 df 69 2a 8a 7a 2e 41 | ...,.. Hi * .zA |
00000030 f9 84 49 77 82 ff 03 f9 70 dd b6 59 1c cc 68 c7 | ..Iw。 ... p..Y..h。|
00000040 17 04 b9 59 a4 80 | ... Y .. |
00000046

我们从 30 开始,它告诉我们我们有一个序列,下一个字节是 44 是剩余数据的长度,接下来是 02 是整数的标记,后跟 20 (十进制等于32),它是整数的长度,接下来的32个字节是整数( r 值)。然后我们还有另一个 02 字节(整数)和 20 (长度为32),后跟 s 值。



因此,如果我们添加字节 30 44 02 20 到二进制签名数据的前面,然后是fi第一个32个字节的数据,然后是 02 20 ,然后是下一个32个字节,我们应该得到我们想要的...



...不幸的是,它不是那么简单。您的 s 值比较复杂。您会注意到它以字节 d0 开头。该字节具有其最高有效位集-在整数的DER编码中表示该整数值为负。那不是我们想要的。为了解决这个问题,我们必须在 s 值的前面添加一个额外的 00 字节。



这样做会改变总长度,因此我们现在必须将这些字节添加到开头的 30 45 02 20 之后,再加上前32个签名数据的字节数,然后是 02 21 00 ,然后是签名数据的后32个字节。我在十六进制编辑器中完成了此操作,并提出了以下内容:

  $ hexdump -C signature2.bin 
00000000 30 45 02 20 24 98 70 45 e1 de bf c7 31 3a c3 4a | 0E。 $ .pE .... 1:.J |
00000010 09 1e 6d fc 47 b7 59 4f 5c ee d9 1f f5 1b 86 35 | ..m.G.YO\ ...... 5 |
00000020 a9 97 76 95 02 21 00 d0 bb d3 8b f1 92 a7 b2 b6 | ..v ..!..... |
00000030 e5 08 ee ef 12 63 97 18 a1 ab 93 a3 6c 80 0e 49 | ..... c ...... l..I |
00000040 66 94 21 5c ed c0 d5 | f。!\ ... |
00000047

让我们检查一下看起来是否理智:

  $ openssl asn1parse -in signature2.bin -inform DER 
0:d = 0 hl = 2 l = 69 cons:SEQUENCE
2: d = 1 hl = 2 l = 32素数:INTEGER:24987045E1DEBFC7313AC34A091E6DFC47B7594F5CEED91FF51B8635A9977695
36:d = 1 hl = 2 l = 33素数:INTEGER:D0BBD38BF192A7B2B6E508EEEF $ 12 $ b93e0CE $ CE $ 694b93E0CE $ CE $ CE $ 694b93E0CE $ CE $ CE $ 694b93C0CE p>

现在让我们尝试验证签名:

  $ openssl dgst -sha256 -verify pubkey.pem -signature signature2.bin hello.txt 
验证失败

Darn。如此近而又远。但是至少我们摆脱了ASN.1错误。那为什么不起作用呢?凭直觉我做到了:

  echo -n HELLO> hello2.txt 

回显的 -n arg抑制输出中的换行符。也许不应将换行符包含在要进行签名摘要的数据中。因此,尝试一下:

  $ openssl dgst -sha256 -verify pubkey.pem -signature signature2.bin hello2.txt 
验证成功

成功!


I'm trying to verify a SHA256 ECDSA digital signature provided to us by an external party. They have verified their signing process in-house, but we've been unsuccessful in our attempts. We repeatedly get asn1 encoding routines errors during openssl verify, but I'm unable to see what's wrong with the signature or our process.

Here's out test setup... Public key (pubkey.pem):

-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEOorVp0M8xien/r1/1Ln7TkSpzzcX
BL/MGRz66J1HSlEgBD5FwwpO1vo6jf/9azcrrrDdCi2NH9/cSDfv5D8gTA==
-----END PUBLIC KEY-----

The message being signed is the plaintext string:

HELLO

The digital signature (signature.sig):

JJhwReHev8cxOsNKCR5t/Ee3WU9c7tkf9RuGNamXdpXQu9OL8ZKnsrblCO7vEmOXGKGrk6NsgA5JZpQhXO3A1Q==

The general approach we've taken is:

# create message file
echo "HELLO" > hello.txt

#VERIFY
openssl dgst -sha256 -verify pubkey.pem -signature signature.sig hello.txt

and the response is

Error Verifying Data
4655195756:error:0DFFF09B:asn1 encoding routines:CRYPTO_internal:too long:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.260.1/libressl-2.6/crypto/asn1/asn1_lib.c:143:
4655195756:error:0DFFF066:asn1 encoding routines:CRYPTO_internal:bad object header:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.260.1/libressl-2.6/crypto/asn1/tasn_dec.c:1113:
4655195756:error:0DFFF03A:asn1 encoding routines:CRYPTO_internal:nested asn1 error:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.260.1/libressl-2.6/crypto/asn1/tasn_dec.c:306:Type=ECDSA_SIG

Alternatively, we've base64 encoding the signature base64 -D signature.sig > signature.bin but get the same error responses. I've tried to use openssl pkeyutl as well, but that results in asn1 encoding routines errors as well. Using ans1parse to parse the signature yields:

openssl asn1parse -in signature.bin
Error: offset too large

Clearly the digital signature is in a format I'm not handling, but I'm unable to see the problem.

解决方案

Your signature.sig file appears to be base64 encoded. Decode it like this:

$ base64 -d signature.sig >signature.bin

Let's see what we have:

$ hexdump -C signature.bin
00000000  24 98 70 45 e1 de bf c7  31 3a c3 4a 09 1e 6d fc  |$.pE....1:.J..m.|
00000010  47 b7 59 4f 5c ee d9 1f  f5 1b 86 35 a9 97 76 95  |G.YO\......5..v.|
00000020  d0 bb d3 8b f1 92 a7 b2  b6 e5 08 ee ef 12 63 97  |..............c.|
00000030  18 a1 ab 93 a3 6c 80 0e  49 66 94 21 5c ed c0 d5  |.....l..If.!\...|
00000040

For comparison purposes I created a new ECDSA private key based on the same curve your public key is using (P-256):

$ openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out key.pem

And then signed some data using it:

$ echo "HELLO" > hello.txt
$ openssl dgst -sha256 -sign key.pem -out hello.sig hello.txt
$ openssl asn1parse -in hello.sig -inform DER
    0:d=0  hl=2 l=  68 cons: SEQUENCE          
    2:d=1  hl=2 l=  32 prim: INTEGER           :2C1599C7765B047A2E98E2265CF6DB91232200559909D7F97CA3E859A39AC02C
   36:d=1  hl=2 l=  32 prim: INTEGER           :14E748DF692A8A7A2E41F984497782FF03F970DDB6591CCC68C71704B959A480

So you'll note that what we have here is two integers in a sequence where each integer is exactly 32 bytes long. This corresponds to the ECDSA_SIG ASN.1 definition:

ECDSA-Sig-Value ::= SEQUENCE { r INTEGER, s INTEGER }

A raw ECDSA signature is comprised of two integers "r" and "s". OpenSSL expects them to be wrapped up inside a DER encoded representation. However, as you've already discovered what you have for the signature is not valid DER. It is however exactly 64 bytes long - which suggests it is comprised of 2 32 byte integers concatenated together.

For the purposes of this exercise we can use a hex editor to convert the raw r and s values into a DER format. Lets looks at a hexdump of the hello.sig file I created earlier:

$ hexdump -C hello.sig
00000000  30 44 02 20 2c 15 99 c7  76 5b 04 7a 2e 98 e2 26  |0D. ,...v[.z...&|
00000010  5c f6 db 91 23 22 00 55  99 09 d7 f9 7c a3 e8 59  |\...#".U....|..Y|
00000020  a3 9a c0 2c 02 20 14 e7  48 df 69 2a 8a 7a 2e 41  |...,. ..H.i*.z.A|
00000030  f9 84 49 77 82 ff 03 f9  70 dd b6 59 1c cc 68 c7  |..Iw....p..Y..h.|
00000040  17 04 b9 59 a4 80                                 |...Y..|
00000046

We start off with 30 which tell us we have a sequence. The next byte is 44 which is the length of the remaining data. Next is 02 which is the tag for an integer, followed by 20 (which equals 32 in decimal), which is the length of the integer. The next 32 bytes is the integer (the r value). Then we have another 02 byte (integer) and 20 (length of 32) followed by the 32 bytes of the s value.

So if we add the bytes 30 44 02 20 to the front of your binary signature data, followed by the first 32 bytes of data, followed by 02 20 followed by the next 32 byes we should get what we want...

...except unfortunately its not quite that simple. There is a complication in your s value. You will note that it starts with the byte d0. This byte has its most significat bit set - which in DER encoding of an integer indicates that the integer value is negative. That's not what we want. To get around this we have to add an extra 00 byte onto the front of the s value.

Doing that changes the overall length so we now have to add these bytes to the begining 30 45 02 20 followed by the first 32 bytes from the signature data, followed by 02 21 00 followed by the next 32 bytes of the signature data. I did this in a hex editor and came up with the following:

$ hexdump -C signature2.bin
00000000  30 45 02 20 24 98 70 45  e1 de bf c7 31 3a c3 4a  |0E. $.pE....1:.J|
00000010  09 1e 6d fc 47 b7 59 4f  5c ee d9 1f f5 1b 86 35  |..m.G.YO\......5|
00000020  a9 97 76 95 02 21 00 d0  bb d3 8b f1 92 a7 b2 b6  |..v..!..........|
00000030  e5 08 ee ef 12 63 97 18  a1 ab 93 a3 6c 80 0e 49  |.....c......l..I|
00000040  66 94 21 5c ed c0 d5                              |f.!\...|
00000047

Lets check that this looks sane:

$ openssl asn1parse -in signature2.bin -inform DER
    0:d=0  hl=2 l=  69 cons: SEQUENCE          
    2:d=1  hl=2 l=  32 prim: INTEGER           :24987045E1DEBFC7313AC34A091E6DFC47B7594F5CEED91FF51B8635A9977695
   36:d=1  hl=2 l=  33 prim: INTEGER           :D0BBD38BF192A7B2B6E508EEEF12639718A1AB93A36C800E496694215CEDC0D5

Now lets try and verify the signature:

$ openssl dgst -sha256 -verify pubkey.pem -signature signature2.bin hello.txt
Verification Failure

Darn. So near and yet so far. But at least we got rid of the ASN.1 errors. So why isn't it working? On a hunch I did this:

echo -n "HELLO" > hello2.txt

The "-n" arg to echo suppresses newlines from the output. Perhaps the newline shouldn't be included in the data to be digested for the signature. So, trying that out:

$ openssl dgst -sha256 -verify pubkey.pem -signature signature2.bin hello2.txt
Verified OK

Success!

这篇关于使用openssl验证ECDSA签名类型时,ASN1编码例程错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆