i2d_ASN1_INTEGER zero pad

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

i2d_ASN1_INTEGER zero pad

William Roberts
Hi,
I occasionally get spurious errors in my ECDSA signatures, and it
appears that when the top byte is over 0x80 of either the R or S
component, that I get a zero pad. I noticed all this when reading
through the source, their was some comments (see below). I noticed a
d2i_ASN1_UINTEGER, but I can't find a coresponding i2d_ version to
create it. The zero pad seems to be the correct behavior, but it seems
to be breaking things.

I understand the ECDSA signature to be a der encoded:
0x30 (ASN1 sequence>
0x<len> (byte len of sequence)
0x20 <ASN1 int header>
0x <int len>
<R>
0x20 <ASN1 int header>
0x <int len>
<S>

Below we can see the zero pad on R where the first byte is 0xB2.
pSignature is what's in question:

26: C_Sign
2019-08-06 02:51:15.252
[in] hSession = 0x100000000000000
[in] pData[ulDataLen] 00007ffe2dcc7520 / 32
    00000000  A7 84 A1 44 7F 22 B3 52 98 D8 02 30 E3 7D 21 BD  ...D^?".R...0.}!.
    00000010  C9 78 3E 3B 9C 1B 53 BA FD 95 B7 93 A6 64 E5 4E  .x>;..S......d.N
[out] pSignature[*pulSignatureLen] 0000558c88c9b640 / 71
    00000000  30 45 02 21 00 B2 F0 60 57 11 B3 63 83 94 FB 15  0E.!...`W..c....
    00000010  74 DC 8C DF A8 2E D9 29 35 89 F7 15 74 70 11 9D  t......)5...tp..
    00000020  3A E1 3A BE 10 02 20 42 4A 99 54 2E 0D D5 32 92  :.:... BJ.T...2.
    00000030  3B 7B 96 E9 2F B8 8B 24 77 38 2F 37 FD 13 98 35  ;{../..$w8/7...5
    00000040  4E FC C1 D2 80 6E 46                             N....nF
Returned:  0 CKR_OK


-- details and links --
This is the link to the issue request I got filed for more details:
https://github.com/tpm2-software/tpm2-pkcs11/issues/277

https://docs.huihoo.com/doxygen/openssl/1.0.1c/a__int_8c_source.html

  95  * Positive integers are no problem: they are almost the same as the DER
   96  * encoding, except if the first byte is >= 0x80 we need to add
a zero pad.

  266 /* This is a version of d2i_ASN1_INTEGER that ignores the sign bit of
  267  * ASN1 integers: some broken software can encode a positive INTEGER
  268  * with its MSB set as negative (it doesn't add a padding zero).
  269  */
  270
  271 ASN1_INTEGER *d2i_ASN1_UINTEGER(ASN1_INTEGER **a, const unsigned
char **pp,
  272          long length)
  273     {


https://www.openssl.org/docs/man1.1.0/man3/d2i_ASN1_UINTEGER.html
Reply | Threaded
Open this post in threaded view
|

Re: i2d_ASN1_INTEGER zero pad

Matt Caswell-2


On 06/08/2019 16:34, William Roberts wrote:
> Hi,
> I occasionally get spurious errors in my ECDSA signatures, and it
> appears that when the top byte is over 0x80 of either the R or S
> component, that I get a zero pad. I noticed all this when reading
> through the source, their was some comments (see below). I noticed a
> d2i_ASN1_UINTEGER, but I can't find a coresponding i2d_ version to
> create it. The zero pad seems to be the correct behavior, but it seems
> to be breaking things.

As you note the zero pad is the correct behaviour.


> This is the link to the issue request I got filed for more details:
> https://github.com/tpm2-software/tpm2-pkcs11/issues/277

This seems to be a problem in tmp2-pkcs11 and not OpenSSL. So its not clear to
me what your question to openssl-users is?

Matt
Reply | Threaded
Open this post in threaded view
|

Re: i2d_ASN1_INTEGER zero pad

William Roberts
On Tue, Aug 6, 2019 at 10:56 AM Matt Caswell <[hidden email]> wrote:

>
>
>
> On 06/08/2019 16:34, William Roberts wrote:
> > Hi,
> > I occasionally get spurious errors in my ECDSA signatures, and it
> > appears that when the top byte is over 0x80 of either the R or S
> > component, that I get a zero pad. I noticed all this when reading
> > through the source, their was some comments (see below). I noticed a
> > d2i_ASN1_UINTEGER, but I can't find a coresponding i2d_ version to
> > create it. The zero pad seems to be the correct behavior, but it seems
> > to be breaking things.
>
> As you note the zero pad is the correct behaviour.
>
>
> > This is the link to the issue request I got filed for more details:
> > https://github.com/tpm2-software/tpm2-pkcs11/issues/277
>
> This seems to be a problem in tmp2-pkcs11 and not OpenSSL. So its not clear to
> me what your question to openssl-users is?

The questions is their is a d2i_ASN1_UINTEGER exists for that zero pad
issue, is their a i2d version, I couldn't find one.

I guess a second question is, is their a better way to build an ECDSA
signature from the R and S components, the code
for ASNI sequence is something I never figured out, is their an
example in ossl somewhere?

>
> Matt
Reply | Threaded
Open this post in threaded view
|

Re: i2d_ASN1_INTEGER zero pad

Matt Caswell-2


On 06/08/2019 17:00, William Roberts wrote:

> On Tue, Aug 6, 2019 at 10:56 AM Matt Caswell <[hidden email]> wrote:
>>
>>
>>
>> On 06/08/2019 16:34, William Roberts wrote:
>>> Hi,
>>> I occasionally get spurious errors in my ECDSA signatures, and it
>>> appears that when the top byte is over 0x80 of either the R or S
>>> component, that I get a zero pad. I noticed all this when reading
>>> through the source, their was some comments (see below). I noticed a
>>> d2i_ASN1_UINTEGER, but I can't find a coresponding i2d_ version to
>>> create it. The zero pad seems to be the correct behavior, but it seems
>>> to be breaking things.
>>
>> As you note the zero pad is the correct behaviour.
>>
>>
>>> This is the link to the issue request I got filed for more details:
>>> https://github.com/tpm2-software/tpm2-pkcs11/issues/277
>>
>> This seems to be a problem in tmp2-pkcs11 and not OpenSSL. So its not clear to
>> me what your question to openssl-users is?
>
> The questions is their is a d2i_ASN1_UINTEGER exists for that zero pad
> issue, is their a i2d version, I couldn't find one.

No, an i2d version does not exists. d2i_ASN1_UINTEGER exists only for
interoperability with broken software. From the code (crypto/asn1/a_int.c):

/*
 * This is a version of d2i_ASN1_INTEGER that ignores the sign bit of ASN1
 * integers: some broken software can encode a positive INTEGER with its MSB
 * set as negative (it doesn't add a padding zero).
 */

ASN1_INTEGER *d2i_ASN1_UINTEGER(ASN1_INTEGER **a, const unsigned char **pp,
                                long length)

Sine we don't want to *create* knowingly broken DER we don't provide the
equivalent function.


>
> I guess a second question is, is their a better way to build an ECDSA
> signature from the R and S components, the code
> for ASNI sequence is something I never figured out, is their an
> example in ossl somewhere?

If you have the r and s components in raw "binary" format then something like
this should create an OpenSSL ECDSA_SIG object (totally untested):

ECDSA_SIG *create_ecdsa_sig(unsigned char *r, size_t rlen, unsigned char *s,
size_t slen)
{
    ECDSA_SIG *sig = ECDSA_SIG_new();

    if (sig == NULL)
        return NULL;

    sig->r = BN_bin2bn(r, rlen, NULL);
    sig->s = BN_bin2bn(s, slen, NULL);

    if (sig->r == NULL || sig->s == NULL) {
        ECDSA_SIG_free(sig);
        return NULL;
    }

    return sig;
}

Once you have the ECDSA_SIG structure then encoding it as DER is simply a call
to i2d_ECDSA_SIG:

https://www.openssl.org/docs/manmaster/man3/i2d_ECDSA_SIG.html


Matt






Reply | Threaded
Open this post in threaded view
|

Re: i2d_ASN1_INTEGER zero pad

William Roberts
On Tue, Aug 6, 2019 at 11:16 AM Matt Caswell <[hidden email]> wrote:

>
>
>
> On 06/08/2019 17:00, William Roberts wrote:
> > On Tue, Aug 6, 2019 at 10:56 AM Matt Caswell <[hidden email]> wrote:
> >>
> >>
> >>
> >> On 06/08/2019 16:34, William Roberts wrote:
> >>> Hi,
> >>> I occasionally get spurious errors in my ECDSA signatures, and it
> >>> appears that when the top byte is over 0x80 of either the R or S
> >>> component, that I get a zero pad. I noticed all this when reading
> >>> through the source, their was some comments (see below). I noticed a
> >>> d2i_ASN1_UINTEGER, but I can't find a coresponding i2d_ version to
> >>> create it. The zero pad seems to be the correct behavior, but it seems
> >>> to be breaking things.
> >>
> >> As you note the zero pad is the correct behaviour.
> >>
> >>
> >>> This is the link to the issue request I got filed for more details:
> >>> https://github.com/tpm2-software/tpm2-pkcs11/issues/277
> >>
> >> This seems to be a problem in tmp2-pkcs11 and not OpenSSL. So its not clear to
> >> me what your question to openssl-users is?
> >
> > The questions is their is a d2i_ASN1_UINTEGER exists for that zero pad
> > issue, is their a i2d version, I couldn't find one.
>
> No, an i2d version does not exists. d2i_ASN1_UINTEGER exists only for
> interoperability with broken software. From the code (crypto/asn1/a_int.c):
>
> /*
>  * This is a version of d2i_ASN1_INTEGER that ignores the sign bit of ASN1
>  * integers: some broken software can encode a positive INTEGER with its MSB
>  * set as negative (it doesn't add a padding zero).
>  */
>
> ASN1_INTEGER *d2i_ASN1_UINTEGER(ASN1_INTEGER **a, const unsigned char **pp,
>                                 long length)
>
> Sine we don't want to *create* knowingly broken DER we don't provide the
> equivalent function.
>

That's what I figured.

>
> >
> > I guess a second question is, is their a better way to build an ECDSA
> > signature from the R and S components, the code
> > for ASNI sequence is something I never figured out, is their an
> > example in ossl somewhere?
>
> If you have the r and s components in raw "binary" format then something like
> this should create an OpenSSL ECDSA_SIG object (totally untested):
>
> ECDSA_SIG *create_ecdsa_sig(unsigned char *r, size_t rlen, unsigned char *s,
> size_t slen)
> {
>     ECDSA_SIG *sig = ECDSA_SIG_new();
>
>     if (sig == NULL)
>         return NULL;
>
>     sig->r = BN_bin2bn(r, rlen, NULL);
>     sig->s = BN_bin2bn(s, slen, NULL);
>
>     if (sig->r == NULL || sig->s == NULL) {
>         ECDSA_SIG_free(sig);
>         return NULL;
>     }
>
>     return sig;
> }
>
> Once you have the ECDSA_SIG structure then encoding it as DER is simply a call
> to i2d_ECDSA_SIG:
>
> https://www.openssl.org/docs/manmaster/man3/i2d_ECDSA_SIG.html
>

That's what I am looking for, thanks!

>
> Matt
>
>
>
>
>
>
Reply | Threaded
Open this post in threaded view
|

Re: i2d_ASN1_INTEGER zero pad

William Roberts
On Tue, Aug 6, 2019 at 11:18 AM William Roberts
<[hidden email]> wrote:

>
> On Tue, Aug 6, 2019 at 11:16 AM Matt Caswell <[hidden email]> wrote:
> >
> >
> >
> > On 06/08/2019 17:00, William Roberts wrote:
> > > On Tue, Aug 6, 2019 at 10:56 AM Matt Caswell <[hidden email]> wrote:
> > >>
> > >>
> > >>
> > >> On 06/08/2019 16:34, William Roberts wrote:
> > >>> Hi,
> > >>> I occasionally get spurious errors in my ECDSA signatures, and it
> > >>> appears that when the top byte is over 0x80 of either the R or S
> > >>> component, that I get a zero pad. I noticed all this when reading
> > >>> through the source, their was some comments (see below). I noticed a
> > >>> d2i_ASN1_UINTEGER, but I can't find a coresponding i2d_ version to
> > >>> create it. The zero pad seems to be the correct behavior, but it seems
> > >>> to be breaking things.
> > >>
> > >> As you note the zero pad is the correct behaviour.
> > >>
> > >>
> > >>> This is the link to the issue request I got filed for more details:
> > >>> https://github.com/tpm2-software/tpm2-pkcs11/issues/277
> > >>
> > >> This seems to be a problem in tmp2-pkcs11 and not OpenSSL. So its not clear to
> > >> me what your question to openssl-users is?
> > >
> > > The questions is their is a d2i_ASN1_UINTEGER exists for that zero pad
> > > issue, is their a i2d version, I couldn't find one.
> >
> > No, an i2d version does not exists. d2i_ASN1_UINTEGER exists only for
> > interoperability with broken software. From the code (crypto/asn1/a_int.c):
> >
> > /*
> >  * This is a version of d2i_ASN1_INTEGER that ignores the sign bit of ASN1
> >  * integers: some broken software can encode a positive INTEGER with its MSB
> >  * set as negative (it doesn't add a padding zero).
> >  */
> >
> > ASN1_INTEGER *d2i_ASN1_UINTEGER(ASN1_INTEGER **a, const unsigned char **pp,
> >                                 long length)
> >
> > Sine we don't want to *create* knowingly broken DER we don't provide the
> > equivalent function.
> >
>
> That's what I figured.
>
> >
> > >
> > > I guess a second question is, is their a better way to build an ECDSA
> > > signature from the R and S components, the code
> > > for ASNI sequence is something I never figured out, is their an
> > > example in ossl somewhere?
> >
> > If you have the r and s components in raw "binary" format then something like
> > this should create an OpenSSL ECDSA_SIG object (totally untested):
> >
> > ECDSA_SIG *create_ecdsa_sig(unsigned char *r, size_t rlen, unsigned char *s,
> > size_t slen)
> > {
> >     ECDSA_SIG *sig = ECDSA_SIG_new();
> >
> >     if (sig == NULL)
> >         return NULL;
> >
> >     sig->r = BN_bin2bn(r, rlen, NULL);
> >     sig->s = BN_bin2bn(s, slen, NULL);
> >
> >     if (sig->r == NULL || sig->s == NULL) {
> >         ECDSA_SIG_free(sig);
> >         return NULL;
> >     }
> >
> >     return sig;
> > }
> >
> > Once you have the ECDSA_SIG structure then encoding it as DER is simply a call
> > to i2d_ECDSA_SIG:
> >
> > https://www.openssl.org/docs/manmaster/man3/i2d_ECDSA_SIG.html
> >
>
> That's what I am looking for, thanks!
>

For completeness encase anyone else stumbles into this bit of lore, is
that pkcs11 doesn't use
the IETF ASN1 encoded scheme. While our code did occasionally suffer
from this "UNINTEGER" issue,
It actually uses a straight R + S concatenation.

However, this code will fix our tpm2-tools code.

> >
> > Matt
> >
> >
> >
> >
> >
> >
Reply | Threaded
Open this post in threaded view
|

Re: i2d_ASN1_INTEGER zero pad

Matt Caswell-2
In reply to this post by Matt Caswell-2


On 06/08/2019 17:16, Matt Caswell wrote:
>     sig->r = BN_bin2bn(r, rlen, NULL);
>     sig->s = BN_bin2bn(s, slen, NULL);

As a slight amendment to my earlier answer - a better way to do the above two
lines would be to use the ECDSA_SIG_set0() function to set the r and s
components rather than diving into the internals of the ECDSA_SIG structure.

Matt