def generate_csr(self, private_key, subject_name, extensions=None): common_name = subject_name.get_attributes_for_oid( NameOID.COMMON_NAME)[0].value info = CertificationRequestInfo({ 'version': 0, 'subject': Name.build({ 'country_name': 'US', 'state_or_province_name': 'North Carolina', 'organization_name': 'Hyperledger', 'organizational_unit_name': 'Fabric', 'common_name': common_name }), 'subject_pk_info': PublicKeyInfo.load(encode_ec_public_key(private_key.public_key)), 'attributes': CRIAttributes([]) }) hash = hashlib.sha256(info.dump()).digest() signature = private_key.private_key.sign(hash, mechanism=Mechanism.ECDSA) csr = CertificationRequest({ 'certification_request_info': info, 'signature_algorithm': { 'algorithm': 'sha256_ecdsa', 'parameters': None }, 'signature': encode_ecdsa_signature(signature) }) der = csr.dump() result = x509.load_der_x509_csr(der, default_backend()) return result
def _address_from_pub(pubkey: bytes): public_der = encode_ec_public_key(pubkey) # public key in der encoding is 32 bytes of header stuff, then 65 bytes of the uncompressed public key # so we start from the 33rd byte pub_uncompressed = public_der[24:].hex() return pubkey_to_addr(pub_uncompressed)
def pkcs11_to_crypto_key(self, pkcs11_public_key: pkcs11.KeyType) -> PublicKey: """ Convert a `pkcs11` public key to a `cryptography` public key. :param pkcs11.KeyType pkcs11_public_key: A `pkcs11` format public key. :return: A `cryptography` format public key. :rtype: :class:`PublicKey` """ if self.pkcs11_key_type == pkcs11.KeyType.RSA: der_public_key = encode_rsa_public_key(pkcs11_public_key) elif self.pkcs11_key_type == pkcs11.KeyType.DSA: y = int.from_bytes(pkcs11_public_key[pkcs11.Attribute.VALUE], byteorder="big") g = int.from_bytes(pkcs11_public_key[pkcs11.Attribute.BASE], byteorder="big") p = int.from_bytes(pkcs11_public_key[pkcs11.Attribute.PRIME], byteorder="big") q = int.from_bytes(pkcs11_public_key[pkcs11.Attribute.SUBPRIME], byteorder="big") der_public_key = DSA.construct( (y, g, p, q)).export_key(format="DER") elif self.pkcs11_key_type == pkcs11.KeyType.EC: der_public_key = encode_ec_public_key(pkcs11_public_key) else: raise TypeError(f"Key type for {pkcs11_public_key} not supported") return load_der_public_key(der_public_key)
def _load_key(self): with self.token.open(user_pin=self.user_pin) as session: keys = session.get_objects( {pkcs11.Attribute.CLASS: pkcs11.ObjectClass.PUBLIC_KEY}) for key in keys: if key.label == self.label: self.public_key = encode_ec_public_key(key)[24:] self._address = self._address_from_pub(key)
def test_ecdh(self): # A key we generated earlier self.session.create_domain_parameters(KeyType.EC, { Attribute.EC_PARAMS: encode_named_curve_parameters('secp256r1'), }, local=True)\ .generate_keypair() # Retrieve our keypair, with our public key encoded for interchange alice_priv = self.session.get_key(key_type=KeyType.EC, object_class=ObjectClass.PRIVATE_KEY) alice_pub = self.session.get_key(key_type=KeyType.EC, object_class=ObjectClass.PUBLIC_KEY) alice_pub = encode_ec_public_key(alice_pub) from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives.serialization import \ Encoding, PublicFormat, load_der_public_key # Bob generates a keypair, with their public key encoded for # interchange bob_priv = ec.generate_private_key(ec.SECP256R1, default_backend()) bob_pub = bob_priv.public_key().public_bytes( Encoding.DER, PublicFormat.SubjectPublicKeyInfo, ) # Bob converts Alice's key to internal format and generates their # shared key bob_shared_key = bob_priv.exchange( ec.ECDH(), load_der_public_key(alice_pub, default_backend()), ) key = alice_priv.derive_key( KeyType.GENERIC_SECRET, 256, mechanism_param=( KDF.NULL, None, # N.B. it seems like SoftHSMv2 requires an EC_POINT to be # DER-encoded, which is not what the spec says decode_ec_public_key(bob_pub, encode_ec_point=Is.softhsm2) [Attribute.EC_POINT], ), template={ Attribute.SENSITIVE: False, Attribute.EXTRACTABLE: True, }, ) alice_shared_key = key[Attribute.VALUE] # We should have the same shared key self.assertEqual(bob_shared_key, alice_shared_key)
def generate(self): if not self._address: # if we got here, we didn't succeed in loading during _load_key, so we can just generate a new one without # being afraid of multiple objects # todo: handle multiple objects a little more gracefully? We'll see how other HSMs handle this shit... with self.token.open(rw=True, user_pin=self.user_pin) as session: ecparams = session.create_domain_parameters( pkcs11.KeyType.EC, { pkcs11.Attribute.EC_PARAMS: ec.encode_named_curve_parameters('secp256k1'), }, local=True) pub, _ = ecparams.generate_keypair(label=self.label, store=True) self._address = self._address_from_pub(pub) self.public_key = encode_ec_public_key(pub)[24:] return self.label
def __init__(self, key_name): # load pkcs11 lib self.lib = pkcs11.lib(os.environ['PKCS11_LIB']) self.user_pin = os.environ['USER_PIN'] self.token = next(self.lib.get_tokens()) # get any token self.key_name = key_name # initiate session via pkcs11 start = time.time() self.session = self.token.open(user_pin=self.user_pin) print("time (connect) {}s".format(time.time() - start)) start = time.time() # get key returns >1 key for some reason # key = session.get_key(object_class=ObjectClass.PRIVATE_KEY, # key_type=KeyType.EC, # label=self.key_name) # get key by iterating through all session objects instead iterator = self.session.get_objects({ Attribute.KEY_TYPE: KeyType.EC, Attribute.CLASS: ObjectClass.PRIVATE_KEY, Attribute.LABEL: self.key_name }) self.key = next(iterator) print(self.key) print("time (get private key) {}s".format(time.time() - start)) start = time.time() _ = next(iterator) # test get_objects() still returns > 1 iterator._finalize() iterator = self.session.get_objects({ Attribute.KEY_TYPE: KeyType.EC, Attribute.CLASS: ObjectClass.PUBLIC_KEY, Attribute.LABEL: self.key_name }) pub = next(iterator) print(pub) pubder = ec.encode_ec_public_key(pub) self.pubcrypto = serialization.load_der_public_key( pubder, default_backend()) print("time (get public key) {}s".format(time.time() - start)) _ = next(iterator) # test get_objects() still returns > 1 iterator._finalize()
def test_ecdsa(self): # A key we generated earlier self.session.create_domain_parameters(KeyType.EC, { Attribute.EC_PARAMS: encode_named_curve_parameters('secp256r1'), }, local=True)\ .generate_keypair() priv = self.session.get_key(key_type=KeyType.EC, object_class=ObjectClass.PRIVATE_KEY) signature = priv.sign(b'Data to sign', mechanism=Mechanism.ECDSA_SHA1) # Encode as ASN.1 for OpenSSL signature = encode_ecdsa_signature(signature) from oscrypto.asymmetric import load_public_key, ecdsa_verify pub = self.session.get_key(key_type=KeyType.EC, object_class=ObjectClass.PUBLIC_KEY) pub = load_public_key(encode_ec_public_key(pub)) ecdsa_verify(pub, signature, b'Data to sign', 'sha1')
def test_import_key_params(self): der = base64.b64decode(""" MIICXDCCAc8GByqGSM49AgEwggHCAgEBME0GByqGSM49AQECQgH///////////// //////////////////////////////////////////////////////////////// /////////zCBngRCAf////////////////////////////////////////////// ///////////////////////////////////////8BEFRlT65YY4cmh+SmiGgtoVA 7qLacluZsxXzuLSJkY7xCeFWGTlR7H6TexZSwL07sb8HNXPfiD0sNPHvRR/Ua1A/ AAMVANCeiAApHLhTlsxnFzkyhKqg2mS6BIGFBADGhY4GtwQE6c2ePstmI5W0Qpxk gTkFP7Uh+CivYGtNPbqhS1537+dZKP4dwSei/6jeM0izwYVqQpv5fn4xwuW9ZgEY OSlqeJo7wARcil+0LH0b2Zj1RElXm0RoF6+9Fyc+ZiyX7nKZXvQmQMVQuQE/rQdh NTxwhqJywkCIvpR2n9FmUAJCAf////////////////////////////////////// ////+lGGh4O/L5Zrf8wBSPcJpdA7tcm4iZxHrrtvtx6ROGQJAgEBA4GGAAQBMLgt gTFBGr0f7YrWwZsCPpLxaUQvUKvz2C6ghiFmxc2EzBgxDY+ywnmG4T++EVZhJHTP eIOnVRcHXXivkRe+YMQBbH/fZyqfCe41vIl39bwhqli839AAj/WoxXZuilpKaXBp vGbx2380UIhrec1jFjItOOg/Xp9dOecjQZK7Z0wVq1U= """) key = self.session.create_object(decode_ec_public_key(der)) self.assertIsInstance(key, pkcs11.PublicKey) # We should get back to identity self.assertEqual(encode_ec_public_key(key), der)
def test_import_key_named_curve(self): der = base64.b64decode(""" MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEa6Q5Hs+j71J1lc+VziafH+uL6603 R8gTAphQD0iLG9Q9RgAvDQdFFpzkvXI+mEGVNRMmT/BA1OtficHcAXTdXA== """) key = self.session.create_object(decode_ec_public_key(der)) self.assertIsInstance(key, pkcs11.PublicKey) # Something signed with OpenSSL signature = base64.b64decode(""" MEYCIQD1nDlli+uLuGX3eobKJe7PsRYkYJ4F15bjqbbB+MHewwIhAPGFRwyuFOvH zuj+sxXwk1CsDWN7AXbmHufOlOarXpiq """) signature = decode_ecdsa_signature(signature) self.assertTrue( key.verify(b'Data to sign', signature, mechanism=Mechanism.ECDSA_SHA1)) # We should get back to identity self.assertEqual(encode_ec_public_key(key), der)
pub, priv = ecparams.generate_keypair(store=True, label="{}".format( os.environ['KEY_LABEL'])) except Exception as e: print("key already exists") for obj in session.get_objects({ Attribute.KEY_TYPE: KeyType.EC, Attribute.LABEL: "{}".format(os.environ['KEY_LABEL']) }): if obj.object_class == ObjectClass.PUBLIC_KEY: pub = obj print("{}".format(pub)) pubder = ec.encode_ec_public_key(pub) pubcrypto = serialization.load_der_public_key(pubder, default_backend()) print( pubcrypto.public_bytes( serialization.Encoding.X962, serialization.PublicFormat.CompressedPoint).hex()) # # do uncompressed -> compressed manually # # similar result as above # point = pub[Attribute.EC_POINT] # if point[1] == 0x41 and point[2] == 0x04: # x = int(point[3:35].hex(), 16) # y = int(point[35:].hex(), 16) # multisig += '21' # multisig += ('%02x' % (2+(y&1))) + ('%064x' % x)