[openssl-dev] Retrieving DSA public key (Y) in ASN.1 format

Dave Thompson dthompson at prinpay.com
Tue Dec 16 22:34:07 UTC 2014


> From: openssl-dev On Behalf Of Douglas E Engert
> Sent: Tuesday, December 16, 2014 11:40

> On 12/16/2014 12:18 AM, Philip Prindeville wrote:
> > Is there an easy way to get at the parameter 'y' (DSA->pub_key, which is
a
> BIGNUM *) in ASN.1 format?  (See (2) below.)
> > Better yet, how to take that and pass it to ASN_item_digest()?
> >
> > Also, there's some confusion (at least for me) about what constitutes
> DSAPublicKey.  According to RFC-5912 you have: <snip>
> >     DSA-Params ::= <snip: p,q,g>
> >     DSAPublicKey ::= INTEGER --  public key, y
> > so I'd assume that i2d_DSAPublicKey() would generate a DER string
> containing the serialization of a single ASN.1 object, i.e. the INTEGER
> containing 'y' or dsa->pub_key as the serialized ASN representation of
that
> BIGNUM.
> >
> > Alas, it doesn't.
> 
> I would assume it would do what you say.  People confuse what is in a
> SubjectPublicKeyInfo
> which includes an algorithm oid, parameters and the public key.
> 
> The same type of confusion can occur with ECC.
> 
The OpenSSL implementation of DSAPublicKey has some arcana in it 
that I haven't seen elsewhere. I suspect this may be because DSA was 
the first parameterized (PK?) cipher and broke new territory. See below.

> PKCS#15 has ASN.1 definitions that might help, and it referes to ANSI X9
> documents. <snip>

> > If I run test/dsatest for instance and I write out the generated DSA
key,
> then parse it, I get <snip>

Note dsatest's main function is to test that the *parameter* generation 
algorithm, specified by FIPS 186 to be reproducible and thus (provably?) 
nothing-up-my-sleeve, works. For testing keys it would be simpler to just
use 
some fixed (but valid) params.  But anyway:

> > $ openssl asn1parse -in dsa.der -inform DER -i
> >      0:d=0  hl=3 l= 222 cons: SEQUENCE
> >      3:d=1  hl=2 l=  64 prim:  INTEGER
> :18CF7F66E23221AEA14DB900DA06BE46A91DF113D490C3C6A0C57EEAEE56
> DF1E9059A541445CFCBE1B63E8197199C0C9FD25A7CCE3354CC1077D577C3
> 112A6CA
> >     69:d=1  hl=2 l=  65 prim:  INTEGER
> :8DF2A494492276AA3D25759BB06869CBEAC0D83AFB8D0CF7CBB8324F0D7
> 882E5D0762FC5B7210EAFC2E9ADAC32AB7AAC49693DFBF83724C2EC0736E
> E31C80291
> >    136:d=1  hl=2 l=  21 prim:  INTEGER
> :C773218C737EC8EE993B4F2DED30F48EDACE915F
> >    159:d=1  hl=2 l=  64 prim:  INTEGER
> :626D027839EA0A13413163A55B4CB500299D5522956CEFCB3BFF10F399CE
> 2C2E71CB9DE5FA24BABF58E5B79521925C9CC42E9F6F464B088CC572AF53E
> 6D78802
> > $
> 
> It is not clear to me where the above is defined.
> 
> > is the result of calling i2d_DSAPublicKey() and writing that to a file.

HERE'S THE TRICKY BIT:

It's defined where you would expect, in dsa/dsa_asn1.c .
But it's defined as a "choice" that does either the standard INTEGER 
(from internal BIGNUM) *OR* the above SEQUENCE which is named 
'dsa_pub_internal' suggesting that it should be internal to OpenSSL 
i.e. not interoperable or standard, but not explained that I can find.

Anyway, to get the standard form apparently you need to set 
dsa->write_params to 0 (false) which is done *for the SPKI form* 
in dsa_ameth.c dsa_pub_encode.

> > Calling i2d_DSA_PUBKEY_fp() results in something else: <snip>
> That appears to be a SubjectPublicKeyInfo (SPKI) , with algorithm ID,
> parameters, and the public key in the bit string.

Yes. PUBKEY is effectively the OpenSSL name for SPKI. There are also
RSA_PUBKEY,
EC_PUBKEY, and generic PUBKEY routines.

> But as you say below, the bit string looks like a SPKI!

No he doesn't and it doesn't. 

> > Using dumpasn1 I find out that the BIT STRING at the end is actually:
> >
> > $ dumpasn1 -a -d -z -h -l dsa5.der
> >      <30 81 F0>
> >    0 240: SEQUENCE {
> >      <30 81 A8>
> >    3 168: . SEQUENCE {
> >      <06 07>
> >    6   7: . . OBJECT IDENTIFIER dsa (1 2 840 10040 4 1)
> >         : . . . (ANSI X9.57 algorithm)
> >      <30 81 9C>
> >   15 156: . . SEQUENCE {
> >      <02 41>
> >   18  65: . . . INTEGER
> >         : . . . . 00 8D F2 A4 94 49 22 76 AA 3D 25 75 9B B0 68 69
> >         : . . . . CB EA C0 D8 3A FB 8D 0C F7 CB B8 32 4F 0D 78 82
> >         : . . . . E5 D0 76 2F C5 B7 21 0E AF C2 E9 AD AC 32 AB 7A
> >         : . . . . AC 49 69 3D FB F8 37 24 C2 EC 07 36 EE 31 C8 02
> >         : . . . . 91
> >      <02 15>
> >   85  21: . . . INTEGER
> >         : . . . . 00 C7 73 21 8C 73 7E C8 EE 99 3B 4F 2D ED 30 F4
> >         : . . . . 8E DA CE 91 5F
> >      <02 40>
> > 108  64: . . . INTEGER
> >         : . . . . 62 6D 02 78 39 EA 0A 13 41 31 63 A5 5B 4C B5 00
> >         : . . . . 29 9D 55 22 95 6C EF CB 3B FF 10 F3 99 CE 2C 2E
> >         : . . . . 71 CB 9D E5 FA 24 BA BF 58 E5 B7 95 21 92 5C 9C
> >         : . . . . C4 2E 9F 6F 46 4B 08 8C C5 72 AF 53 E6 D7 88 02
> >         : . . . }
> >         : . . }
> >      <03 43>
> > 174  67: . BIT STRING, encapsulates {
> >      <02 40>
> > 177  64: . . INTEGER
> >         : . . . 18 CF 7F 66 E2 32 21 AE A1 4D B9 00 DA 06 BE 46
> >         : . . . A9 1D F1 13 D4 90 C3 C6 A0 C5 7E EA EE 56 DF 1E
> >         : . . . 90 59 A5 41 44 5C FC BE 1B 63 E8 19 71 99 C0 C9
> >         : . . . FD 25 A7 CC E3 35 4C C1 07 7D 57 7C 31 12 A6 CA
> >         : . . }
> >         : . }

See? Starting at 174 BITSTRING containing DER/BER for INTEGER.

> > Oddly, though, if I define:
> >
> > int i2d_DSAPublicKey_fp(FILE *fp, DSA *dsa)
> >         {
> >         return ASN1_i2d_fp_of_const(DSA,i2d_DSAPublicKey,fp,dsa);
> >         }
> >
> > and call that, it correctly writes out 'y' (dsa->pub_key) as: <snip
INTEGER>
> > which I'm happy about, but don't quite understand.
> >
For me that code writes the 'internal' SEQUENCE, consistent with others,
UNLESS I previously within the same program call i2d_DSA_PUBKEY 
(perhaps indirectly such as PEM_write_PUBKEY) or clear write_params.
Did you maybe do the former of these?

> > So, a few questions:
> >
> > (1) what's the quick way to, given a DSA *, compute a hash (given an
> EVP_MD *) over dsa->pub_key as an ASN.1 primitive?  I tried:
> >
> > ASN1_item_digest(ASN1_ITEM_ref(BIGNUM), mdtype, dsa->pub_key, md,
> mdlen);
> >
> > but it's giving me highly dubious results.
> >
I wouldn't poke around in internals like that, I would just i2d to a buffer 
and hash the buffer. 32 bytes of memory costs about $.000001 .
I'm not sure even bitcoin divides small enough to make that detectable.

(Alternatively one could get a cert for the key from a CA that uses SKId 
which is conventionally the hash of the "raw" pubkey. <G><G><G>)

> > (2) where is the ASN.1 module definition which corresponds to the format
> used by i2d_DSA_PUBKEY_fp()?
> >
If you mean the ASN.1 source, RFC 5280 augmented by IIRC 3279,
which got them from (CCITT) X.509 and (ANSI) X9.something,
in addition to Douglas's answer of PKCS#15.

If you mean the data the OpenSSL code uses to do ASN.1,
generic PUBKEY=X509_PUBKEY=SPKI is in asn1/x_pubkey.c, 
and the DSA-specific part is in dsa/dsa_asn1.c .

> > (3) is there a way to generate a pk-dsa serialization in the library or
do I
> have to muster this by hand?
> >
> > (4) why does i2d_DSAPublicKey() give you its current results and not the
> DER representation of 'y' (dsa->pub_key)?
> >
See above.




More information about the openssl-dev mailing list