M2Crypto: How to generate subjectKeyIdentifier /authorityKeyIdentifier

  • Thread starter Matthias Güntert
  • Start date
M

Matthias Güntert

Hello

I am trying to add the extensions "subjectKeyIdentifier" and
"authorityKeyIdentifier" to a x509v3 certificate.

Regarding rfc5280, section 4.2.1.2 the key identifier is composed of the
160-bit SHA-1 hash of the BIT STRING subjectPublicKey

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

I don't know how or which function to use from EVP.PKey() to compose a
fingerprint from the public key, as you can see below I was playing
around with some functions, which simply returned nonsense (at least for
me)

I would be happy if someone could provide some example code on how to
generate a fingerprint from the public key.

"print keyp.final()" nor "print keyp.sign_final() on the last line does
return anything...
--------------------------------------------------------
from M2Crypto import X509, m2, RSA, EVP
from config import *

import os.path

class Keypair(object):
def __init__(self):
self.config = Config()
self.keypair = EVP.PKey()

def create_keypair(self, key_size=1024):
# generate an RSA key pair
# OpenSSL book page 232
# second argument should be a constant RSA_F4 or RSA_3
rsa_key_pair = RSA.gen_key(key_size, m2.RSA_F4)

# check if RSA key pair is usable
# OpenSSL book page 232
if rsa_key_pair.check_key() != 1:
print 'error while generating key!'
sys.exit()

# EVP object which can hold either a DSA or an RSA object
# OpenSSL book page 236
evp_key_container = EVP.PKey()
evp_key_container.assign_rsa(rsa_key_pair)

self.keypair = evp_key_container

def save_keypair(self, filename):
if not os.path.exists(filename):
self.keypair.save_key(filename, None)
else:
print "error in save_keypair(): cannot save key, it already
exists"

def load_keypair(self, filename):
try:
self.keypair = EVP.load_key(filename)
except TypeError:
print "error in load_keypair(): maybe file does not exist?"

def get_keypair(self):
return self.keypair

def get_public_key(self):
return self.keypair.pkey

def print_keypair(self):
print self.keypair.as_pem(None)

if __name__ == "__main__":
keypair = Keypair()
keypair.create_keypair()
# keypair.save_keypair("test.keys")
keyp = keypair.get_keypair()

print keyp.final()
print keyp.sign_final()
---------------------------------------------------------

And this maybe some OT question but how can I use OpenSSL to generate
some fingerprint for testing and comparison purpose?

For example I have got a certificate client.crt and the keys client.key

$ openssl x509 -noout -text -in client.crt
[...]
X509v3 Subject Key Identifier:
D2:C0:39:37:45:F6:A3:BF:D8:91:A2:F5:C7:43:42:80:6A:3C:38:AF
X509v3 Authority Key Identifier:
A7:E2:2E:59:F8:53:1F:68:F2:59:34:32:42:F6:21:20:C0:D1:3A:89
[...]

But openssl provides me different fingerprint... so whats wrong here?

$ openssl rsa -pubout -in client_1.key | openssl sha1 -c
writing RSA key
cc:d2:ab:16:1f:a1:23:3e:fe:45:03:ab:4f:86:57:65:52:16:b2:1a
 
M

Matthias Güntert

M2Crypto has a couple of bugs open related that, with potential
workarounds that I haven't yet deemed polished enough to checkin, but
which might help you out:

https://bugzilla.osafoundation.org/show_bug.cgi?id=7530
https://bugzilla.osafoundation.org/show_bug.cgi?id=12151

Thanks, that helped me a lot. Generating the 'subjectKeyIdentifier' now
works for me using the following procedure:

----------------------------------------------------------
import hashlib

def get_public_key_fingerprint(self):
h = hashlib.new('sha1')
h.update(self.keypair.as_der())
client_serial = h.hexdigest().upper()
client_serial_hex = ''

for byte in xrange(20):
client_serial_hex += client_serial[byte*2] + client_serial[byte*2
+1]
if byte < 19:
client_serial_hex += ':'

return client_serial_hex

[...]
cert_extension_4 = X509.new_extension("subjectKeyIdentifier",
keys_ca.get_public_key_fingerprint())
----------------------------------------------------------

However I don't understand the way the hash gets build. Comparing the
output from a given keypair and certificate build via OpenVPNs easy-rsa
scripts shows different subjectKeyIdentifiers. As stated out by rfc5280
there is no right or wrong way in creating the unique hash, so this
should be fine.

But setting the 'authorityKeyIdentifier' extension gives me some
headache here. The following code snippet produces a segmentation fault
on my python interpreter (version 2.6)

----------------------------------------------------------
cert_extension = X509.new_extension("authorityKeyIdentifier",
keys_ca.get_public_key_fingerprint())

cert_extension_stack.push(cert_extension)
----------------------------------------------------------

Same on this:
----------------------------------------------------------
cert_extension =

X509.new_extension("authorityKeyIdentifier",
"keyid:1C:88:E1:8E:F1:5F:9D:1C:2B:6C:41:D4:3D:BB:79:0D:33:4A:E3:9A,
DirName:/C=US/ST=CA/L=SanFrancisco/O=Fort-Funston/CN=Fort-Funston
CA/[email protected], serial:B1:82:B1:E4:23:78:F1:12")

cert_extension_stack.push(cert_extension)
----------------------------------------------------------

So the question is: Is there another workaround to set this extension?
How can I provide more information to get this fixed? Working with the
latest SVN version is no option for me at the moment.

Thanks in advance,
Matthias
 
M

Matthias Güntert

Hello once again

Now I have the extension-patch [0] applied to the M2Crypto SVN branch
(revision 704). Creating a root and an subRoot CA certificate now works
great including the SKID/AKID extensions.

I am also able to verify those created certificates using:

$ openssl verify -CAfile rootCA.crt rootCA.crt
rootCA.crt: OK

$ openssl verify -CAfile rootCA.crt subRootCA.crt
subRootCA.crt: OK

But having a closer look onto the generated key ID's shows that there is
either something wrong in the way I am adding the subjectKeyIdentifier
extension or the way the hash gets calculated in the background.

This are the hashes:

__rootCA__
SKID F4:EF:64:5F:7A:A2:2A:14:14:F9:AE:6E:DB:04:78:0A:8C:6E:02:9F -: A
--> OKAY
AKID F4:EF:64:5F:7A:A2:2A:14:14:F9:AE:6E:DB:04:78:0A:8C:6E:02:9F -: A
--> OKAY

__subRootCA (signed by rootCA)__
SKID DA:39:A3:EE:5E:6B:4B:0D:32:55:BF:EF:95:60:18:90:AF:D8:07:09 -: B
--> OKAY
AKID F4:EF:64:5F:7A:A2:2A:14:14:F9:AE:6E:DB:04:78:0A:8C:6E:02:9F -: A
--> OKAY

__client (signed by rootCA)__
SKID DA:39:A3:EE:5E:6B:4B:0D:32:55:BF:EF:95:60:18:90:AF:D8:07:09 -: B
--> NOT OKAY, should be different from RootCA
AKID F4:EF:64:5F:7A:A2:2A:14:14:F9:AE:6E:DB:04:78:0A:8C:6E:02:9F -: A
--> OKAY

__client (signed by subRootCA)__
SKID DA:39:A3:EE:5E:6B:4B:0D:32:55:BF:EF:95:60:18:90:AF:D8:07:09 -: B
--> NOT OKAY, should be different from subRootCA
AKID DA:39:A3:EE:5E:6B:4B:0D:32:55:BF:EF:95:60:18:90:AF:D8:07:09 -: B
--> OKAY

I really would be happy if someone could have a look at my code [1] as
this extensions are important for verifying the trust chain. Please let
me know if there is anything I can do with my limited knowledge about
OpenSSL to get this working...

Regards, Matthias

[0] https://bugzilla.osafoundation.org/attachment.cgi?id=5106
[1] http://code.google.com/p/webca/source/browse/trunk/src/ca.py
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top