# Temporary sandbox for Python PKCS #8 hacks, probably integrate into # test scripts, libhal.py, etc once have figured this out. # # Both PyCrpto and the Python ecdsa package have their own ASN.1, so # why are we using yet another package? Because it's easier to # understand, that's why. Perhaps once we've debugged this we'll # recode it using one of the other packages to reduce external # dependencies, but for now, pyasn1 wins on ease of debugging. # # Also see the "native" encode and decode routines in pyasn1, which # supposedly encode and decode to built-in Python data types instead # of the fancy types from the pyasn1 library. Might be simpler, but # whole new mess so defer for now. # RFC 5208: PKCS #8 # RFC 2313: PKCS #1.5 [rsa.c] # RFC 5915: EC keys [ecdsa.c] from pyasn1.type.univ import Sequence, SetOf, Integer, OctetString, ObjectIdentifier, BitString, Any from pyasn1.type.namedtype import NamedTypes, NamedType, OptionalNamedType from pyasn1.type.namedval import NamedValues from pyasn1.type.tag import Tag, tagClassContext, tagFormatSimple, tagFormatConstructed from pyasn1.type.constraint import SingleValueConstraint from pyasn1.codec.der.encoder import encode as DER_Encode from pyasn1.codec.der.decoder import decode as DER_Decode from ecdsa import der as ECDSA_DER from ecdsa.util import oid_ecPublicKey, encoded_oid_ecPublicKey from ecdsa.keys import SigningKey from ecdsa.curves import find_curve class AlgorithmIdentifier(Sequence): componentType = NamedTypes( NamedType( "algorithm", ObjectIdentifier()), OptionalNamedType( "parameters", Any())) class AttributeTypeAndValue(Sequence): componentType = NamedTypes( NamedType( "type", ObjectIdentifier()), NamedType( "value", Any())) class Attribute(Sequence): componentType = NamedTypes( NamedType( "type", ObjectIdentifier()), NamedType( "vals", SetOf(componentType = Any()))) # RFC 5208 class PrivateKeyInfo(Sequence): componentType = NamedTypes( NamedType( "version", Integer(namedValues = NamedValues(("v1", 0))) .subtype(subtypeSpec = Integer.subtypeSpec + SingleValueConstraint(0))), NamedType( "privateKeyAlgorithm", AlgorithmIdentifier()), NamedType( "privateKey", OctetString()), OptionalNamedType( "attributes", SetOf(componentType = Attribute()) .subtype(implicitTag = Tag(tagClassContext, tagFormatConstructed, 0)))) class EncryptedPrivateKeyInfo(Sequence): componentType = NamedTypes( NamedType( "encryptionAlgorithm", AlgorithmIdentifier()), NamedType( "encryptedData", OctetString())) # RFC 2313 class RSAPrivateKey(Sequence): componentType = NamedTypes( NamedType( "version", Integer() .subtype(subtypeSpec = Integer.subtypeSpec + SingleValueConstraint(0))), NamedType( "n", Integer()), NamedType( "e", Integer()), NamedType( "d", Integer()), NamedType( "p", Integer()), NamedType( "q", Integer()), NamedType( "dP", Integer()), NamedType( "dQ", Integer()), NamedType( "u", Integer())) # RFC 5915 class ECPrivateKey(Sequence): componentType = NamedTypes( NamedType( "version", Integer(namedValues = NamedValues(("ecPrivkeyVer1", 1))) .subtype(subtypeSpec = Integer.subtypeSpec + SingleValueConstraint(1))), NamedType( "privateKey", OctetString()), OptionalNamedType( "parameters", ObjectIdentifier() .subtype(explicitTag = Tag(tagClassContext, tagFormatSimple, 0))), OptionalNamedType( "publicKey", BitString() .subtype(explicitTag = Tag(tagClassContext, tagFormatSimple, 1)))) # Test data, generated by OpenSSL der_test_keys = dict( ec_rfc5915 = ''' MHcCAQEEIFWaZOsQxLwZmIK4YAuf1d8S9Pnznvzcl9TjiMpvXkCYoAoGCCqGSM49 AwEHoUQDQgAEC/8vH5bL+3KNNF/NL+VmUKZQtjA59UsGtKP6FP4ZqFc3Y7Gie77/ lG1/L+s/6ircB1JkI8zaE3KYd7s+7IYIEQ== '''.decode("base64"), ec_pkcs8 = ''' MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgVZpk6xDEvBmYgrhg C5/V3xL0+fOe/NyX1OOIym9eQJihRANCAAQL/y8flsv7co00X80v5WZQplC2MDn1 Swa0o/oU/hmoVzdjsaJ7vv+UbX8v6z/qKtwHUmQjzNoTcph3uz7shggR '''.decode("base64"), rsa_rfc2313 = ''' MIIEpAIBAAKCAQEAx/N9ee3u6Z6qjw5waPhuUBYy7m6+kRfNYB8KSERGd5K2xD96 IeyvEv+xMDA2BQ3xOummL2yAjtMZ2N7Le37nfpvtzwVWqrOHzq7OWaw/pPl1N9Lq VSQLPoxHw3TVe69QNPVu5SeumaOGXmzTIs1pr2yVBZD/i2KYiif3BO2SgoDx7g4s cFdg/6YiDpKYbY/yx4YN6KJxDGMM6DE0Ih8hE68flJMSIbUWIaJZo0b7XPeE9zYU zf93VLvuYIqWYMuwTw5TSUnzeRq6ALJpf90nObduJsYEPu/i4RFlxdm5WsmOb2Tu F7JFesEdGeT9lCxxd3CI5YTItQIBWsx0AzCS/QIDAQABAoIBAQCmC7Zvwv9cUr8g /cSr52L0bvrstlra8wFCiYRobwp10gilAHHUKlFZXa0vb1ns6J8jZVT0nQ5FjVkx mBMzAzgLFEJwYOaP63ckVFZYcYqI3gBR0312JvCPiL8vuZ5vkC7zS75D3qhIPlwf ng/YHu1dGLbIYJlWjxJN6NJh7Uh1xlZcm0WAJYhJpmMIZJv2abTS4GXw4SVOyMnd tPEgEfrK/y2PsNUPwnby6LR1cE2rxOQtb6gNCov0AAiE0BsJeE7jXa2IEl6lKoBR ChDMAeU53pJPlcYt7ZmAgyezuEfnr4kY5Rk/nTcwTxTpzQi7Dcth8QCRqfu4wXXj QEN7b9cBAoGBAPNjRPc/Z89jYp1IDR+R5oi7YTsLzNAIlS/t9wgrujnVdsm00xos dd+NwvjTi7wE0fV+7u5/W9ni3077JaBGBa9+nD0iB0PgAJW+tb8HUJXABQKoTA4m yyiAHNHgarwc1uwr+yAYqvSj7aAvIcZeXgi3qxDXEOSKuk8n57/TpPMVAoGBANJP /9/6zxd3PdogiP0nC+piJHstexk+l4WRqGWWuRG0VTIEfBk4dQfj/UwfmTcCQxAe D0e9EoHeVOfsv4nfOfDhGC7jHLkLpNJbc5ttgr2sZ6qIouBJ8suMDte/zZze27aU 7epFqw0w9Y58fwRyP2u5ILYFcm+cWeplg9lY4rpJAoGBALzLs1Krn4YzDOr+Whe0 IITN/XVFCQIStk8wo2B2MwXrvTJoDx0Ngf4AxE4qIwmdH5T0erkMmB5jK1/j12MF DiH874tIWyRenXWLMwZU0UDoa7qM/Do6A3uOLUzsbT8wi9M1pp5WJD6S7qBED0oG
[submodule "libhal"]
	path = libraries/libhal
	url = git@git.cryptech.is:sw/libhal.git
	branch = rpc
[submodule "thirdparty/libtfm"]
	path = libraries/thirdparty/libtfm
	url = git@git.cryptech.is:sw/thirdparty/libtfm.git
"][0] print "privateKey:" print " version:", rsa_pkcs8_privateKey["version"] print " n:", rsa_pkcs8_privateKey["n"] print " e:", rsa_pkcs8_privateKey["e"] print " d:", rsa_pkcs8_privateKey["d"] print " p:", rsa_pkcs8_privateKey["p"] print " q:", rsa_pkcs8_privateKey["q"] print " dP:", rsa_pkcs8_privateKey["dP"] print " dQ:", rsa_pkcs8_privateKey["dQ"] print " u:", rsa_pkcs8_privateKey["u"] # Generate PKCS #8 from ECPrivateKey and check against static data p8 = PrivateKeyInfo() ec = ECPrivateKey() ec["version"] = ec_rfc5915["version"] ec["privateKey"] = ec_rfc5915["privateKey"] ec["publicKey"] = ec_rfc5915["publicKey"] p8["version"] = 0 p8["privateKeyAlgorithm"] = AlgorithmIdentifier() p8["privateKeyAlgorithm"]["algorithm"] = "1.2.840.10045.2.1" p8["privateKeyAlgorithm"]["parameters"] = ObjectIdentifier(ec_rfc5915["parameters"]) p8["privateKey"] = DER_Encode(ec) der = DER_Encode(p8) #print; dumpasn1(der) #print; dumpasn1(der_test_keys["ec_pkcs8"]) print; print "Reencoded PKCS #8 {} static data".format("matches" if der == der_test_keys["ec_pkcs8"] else "doesn't match") # Try doing same thing with ecdsa package ASN.1 utilities. sk = SigningKey.from_der(der_test_keys["ec_rfc5915"]) vk = ECDSA_DER.encode_bitstring("\x00\x04" + sk.get_verifying_key().to_string()) ec = ECDSA_DER.encode_sequence(ECDSA_DER.encode_integer(1), ECDSA_DER.encode_octet_string(sk.to_string()), ECDSA_DER.encode_constructed(1, vk)) p8 = ECDSA_DER.encode_sequence(ECDSA_DER.encode_integer(0), ECDSA_DER.encode_sequence(encoded_oid_ecPublicKey, sk.curve.encoded_oid), ECDSA_DER.encode_octet_string(ec)) print; print "ECDSA-library PKCS #8 encoding {} pyasn1 PKCS #8 encoding".format("matches" if p8 == der_test_keys["ec_pkcs8"] else "doesn't match") # Generate ECPrivateKey from PKCS #8 and check against static data ec = ECPrivateKey() ec["version"] = ec_pkcs8_privateKey["version"] ec["privateKey"] = ec_pkcs8_privateKey["privateKey"] ec["parameters"] = str(DER_Decode(ec_pkcs8["privateKeyAlgorithm"]["parameters"])[0]) ec["publicKey"] = ec_pkcs8_privateKey["publicKey"] der = DER_Encode(ec) #print; dumpasn1(der) #print; dumpasn1(der_test_keys["ec_rfc5915"]) print; print "Reencoded PKCS #8 {} static data".format("matches" if der == der_test_keys["ec_rfc5915"] else "doesn't match") # Paranoia: Make sure we really can load the RFC 5915 we just generated. sk = SigningKey.from_der(der) print; print "ECDSA Python library parse of reencoded PKCS #8 data: {!r}".format(sk) # Same thing with ecdsa package ASN.1 utilities. car, cdr = ECDSA_DER.remove_sequence(der_test_keys["ec_pkcs8"]) assert cdr == "" version, cdr = ECDSA_DER.remove_integer(car) assert version == 0 car, ec = ECDSA_DER.remove_sequence(cdr) oid, cdr = ECDSA_DER.remove_object(car) assert oid == oid_ecPublicKey oid, cdr = ECDSA_DER.remove_object(cdr) curve = find_curve(oid) assert cdr == "" car, cdr = ECDSA_DER.remove_octet_string(ec) assert cdr == "" car, cdr = ECDSA_DER.remove_sequence(car) assert cdr == "" version, cdr = ECDSA_DER.remove_integer(car) assert version == 1 privkey, cdr = ECDSA_DER.remove_octet_string(cdr) tag, car, cdr = ECDSA_DER.remove_constructed(cdr) assert tag == 1 assert cdr == "" pubkey, cdr = ECDSA_DER.remove_bitstring(car) assert cdr == "" assert pubkey[:2] == "\x00\x04" sk = SigningKey.from_string(privkey, curve) print; print "ECDSA-library PKCS #8 decoding {} pyasn1 PKCS #8 decoding".format( "matches" if der == sk.to_der() else "doesn't match")