[gnutls-devel] X.509 "Key Identifiers" in GnuTLS

Peter Williams home_pw at msn.com
Tue Mar 5 19:40:10 CET 2013


Think of it as vendor-value add - where no one will agree on its value. Often patent or “other” reasons are behind such inability to agree.

 

For example, a hash value in the serial number of certs saved VeriSign from the md5 compromise, since it made it SO Much harder to predict a plaintext AND find a collision. To me it was elementary cryptanalysis; but try convincing generalists of it. Specialists in the know would accept the argument, but there would always be “specious” reasons why not to make it a standardized element. We all know what lay behind those specious reasons, now.


From: Daniel Kahn Gillmor
Sent: ‎March‎ ‎5‎, ‎2013 ‎1‎:‎05‎ ‎AM
To: GnuTLS development list
Subject: [gnutls-devel] X.509 "Key Identifiers" in GnuTLS



I'm trying to understand the specification of X.509 Key Identifiers
(e.g. subjectKeyIdentifier and issuerKeyIdentifier).  It looks to me
like GnuTLS diverges from the "common method" for generating these
identifiers, but i don't see any documentation that explains the
divergence.

I understand that there is no official requirement that these strings
are formed in any specific way.  However, the canonical RFC for PKIX

 https://tools.ietf.org/html/rfc5280#section-4.2.1.2

suggests that the "common method" involves an SHA-1 digest of the
contents of the BIT STRING subjectPublicKey field.

However, GnuTLS appears to calculate the SHA-1 digest over the entire
DER-encoded subjectPublicKeyInfo object (that is, over the sequence of
the algorithmIdentifier and subjectPublicKey together).

0 dkg at alice:~$ certtool --generate-privkey --bits=1024 > x.key
** Note: Please use the --sec-param instead of --bits
Generating a 1024 bit RSA private key...
0 dkg at alice:~$ certtool --key-info < x.key | grep 'Public Key ID:'
Public Key ID: 46:F6:84:5B:9E:25:69:0C:85:17:32:F7:08:9A:F0:EF:D3:61:76:94
0 dkg at alice:~$ certtool --pubkey-info --outder --load-privkey x.key  | sha1sum
46f6845b9e25690c851732f7089af0efd3617694  -
0 dkg at alice:~$ certtool --pubkey-info --outder --load-privkey x.key  | dumpasn1 -a -
Warning: Input is non-seekable, some functionality has been disabled.
  0 159: SEQUENCE {
  3  13:   SEQUENCE {
  5   9:     OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1)
 16   0:     NULL
       :     }
 18 141:   BIT STRING
       :     30 81 89 02 81 81 00 B9 1D 5D 74 11 FE 2B 99 F2
       :     10 AF BC E7 E9 D4 8D 2E 84 30 15 FD AF 68 F9 34
       :     1B 11 3F 9F 7B 6D 81 5F B2 AD FD 12 35 57 E6 12
       :     7D 77 28 64 61 2F 02 AB DD 23 57 23 69 65 0E CC
       :     D4 5C 51 39 57 01 F8 E4 DD 2E 77 94 D3 51 76 74
       :     37 8C 5E F7 5C EE CC 4D 86 06 F4 CB 5D 2B 8B 6F
       :     C5 FA 2E 10 B1 15 E7 48 63 A8 D5 C2 B2 48 F1 99
       :     93 48 6B E6 FD 0E 8C E9 03 7C 24 76 04 56 AC 0F
       :     23 8A 35 26 19 92 7B 02 03 01 00 01
       :   }

0 warnings, 0 errors.
0 dkg at alice:~$ 

Here's a hacky implementation using the RFC's suggested common approach,
followed by a demonstration that OpenSSL uses the "common method" when
it generates certificates, while GnuTLS's certtool uses the whole
subjectPublicKeyInfo:

0 dkg at alice:~$ certtool --pubkey-info --outder --load-privkey x.key  | dumpasn1 -a - 2>/dev/null | grep '^\s*:\s*[0-9A-F ]*$' | tr -d ':\ \n' | perl -MDigest::SHA  -e 'undef $/; my $x = <STDIN>; printf("%s\n", Digest::SHA::sha1_hex(pack("H*", $x)));'
2750d2f7899c2f8e18be77af5d1d3522b7ada279
0 dkg at alice:~$ openssl req -nodes -text -new -key x.key -keyform PEM -subj '/CN=test.example.org/' -x509 | grep -A1 Identifier
            X509v3 Subject Key Identifier: 
                27:50:D2:F7:89:9C:2F:8E:18:BE:77:AF:5D:1D:35:22:B7:AD:A2:79
            X509v3 Authority Key Identifier: 
                keyid:27:50:D2:F7:89:9C:2F:8E:18:BE:77:AF:5D:1D:35:22:B7:AD:A2:79
0 dkg at alice:~$ echo cn=test.example.org > template.txt
0 dkg at alice:~$ certtool -s  --load-privkey x.key --template template.txt 2>&1  | grep -A1 'Key Identifier'
                Subject Key Identifier (not critical):
                        46f6845b9e25690c851732f7089af0efd3617694
0 dkg at alice:~$ 


It appears that we could align GnuTLS with the "common method" PKIX
keyID generation with the following change:

diff --git a/lib/x509/x509.c b/lib/x509/x509.c
index 57f540a..009f053 100644
--- a/lib/x509/x509.c
+++ b/lib/x509/x509.c
@@ -2667,7 +2667,7 @@ _gnutls_get_key_id (gnutls_pk_algorithm_t pk, gnutls_pk_params_st * params,
       return GNUTLS_E_SHORT_MEMORY_BUFFER;
     }
 
-  ret = _gnutls_x509_encode_PKI_params(&der, pk, params);
+  ret = _gnutls_x509_write_pubkey (pk, params, &der);
   if (ret < 0)
     return gnutls_assert_val(ret);
 

(the tests would also need to be updated because the key ID changes as
does the "Random Art", since that is based on the key ID)

The advantage of making this change would be increased interoperability
in the future with other TLS implementations and X.509 search tools, and
closer alignment to the documented "common method".

A disadvantage, of course, is that older versions of GnuTLS and newer
versions of GnuTLS will not produce the same Key IDs for any given key :/

I can see an argument for including the algorithm identifier in the
material digested for the key ID: for DSA and ECC, the parameters for
the specific algorithm are only stored in the algorithmIdentifier, not
the subjectPublicKey.  It seems possible that the same subjectPublicKey
data could be used in two (or more) different parameterized algorithms,
and the RFC 5280 suggestion wouldn't capture the distinction.  the
current GnuTLS implementation would capture the distinction in the
digest.

And i note that GnuTLS's choice of key ID seems to map precisely to the
proposal outlined in the (not yet finalized) websec internet draft about
key pinning:

  https://tools.ietf.org/html/draft-ietf-websec-key-pinning-04#section-2.4

The TACK proposal also looks at a digest of the whole
subjectPublicKeyInfo, not just the subjectPublicKey:

  https://tools.ietf.org/html/draft-perrin-tls-tack-02#section-3.2.1

So that suggests that other people who are actively thinking about
concisely identifying public keys have made the same tradeoff as GnuTLS
currently makes.

So i think my questions are:

 0) do we want GnuTLS to use the RFC 5280 "common method" suggestion, or
 are we fine with the current implementation?

 1) if we stay with the current implementation, can we improve the
 documentation explaining why we have chosen this mechanism instead of
 the "common method"?  I'd be happy to try to write some documentation
 once i understand the background better.

 2) if we stay with the current implementation, should we reach out to
 other free X.509 certificate generation tools (notably OpenSSL) and
 suggest that they reconsider?

Any thoughts?

    --dkg
-------------- next part --------------
An HTML attachment was scrubbed...
URL: </pipermail/attachments/20130305/e3469e75/attachment-0001.htm>


More information about the Gnutls-devel mailing list