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

Daniel Kahn Gillmor dkg at fifthhorseman.net
Tue Mar 5 10:04:04 CET 2013

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

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


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

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)));'
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: 
            X509v3 Authority Key Identifier: 
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):
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,
-  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

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:


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


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?

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 965 bytes
Desc: not available
URL: </pipermail/attachments/20130305/10456331/attachment.pgp>

More information about the Gnutls-devel mailing list