def test3(self): """Verify unwrapping with encryption""" for t in self.wrapped_enc_keys: res1, res2, res3 = PKCS8.unwrap(t[4], b("TestTest")) self.assertEqual(res1, self.oid_key) self.assertEqual(res2, self.clear_key)
def _importKeyDER(extern_key, passphrase, verify_x509_cert): """Import an RSA key (public or private half), encoded in DER form.""" try: der = DerSequence().decode(extern_key) # Try PKCS#1 first, for a private key if len(der) == 9 and der.hasOnlyInts() and der[0] == 0: # ASN.1 RSAPrivateKey element del der[6:] # Remove d mod (p-1), # d mod (q-1), and # q^{-1} mod p der.append(Integer(der[4]).inverse(der[5])) # Add p^{-1} mod q del der[0] # Remove version return construct(der[:]) # Keep on trying PKCS#1, but now for a public key if len(der) == 2: try: # The DER object is an RSAPublicKey SEQUENCE with # two elements if der.hasOnlyInts(): return construct(der[:]) # The DER object is a SubjectPublicKeyInfo SEQUENCE # with two elements: an 'algorithmIdentifier' and a # 'subjectPublicKey'BIT STRING. # 'algorithmIdentifier' takes the value given at the # module level. # 'subjectPublicKey' encapsulates the actual ASN.1 # RSAPublicKey element. if der[0] == algorithmIdentifier: bitmap = DerBitString().decode(der[1]) rsaPub = DerSequence().decode(bitmap.value) if len(rsaPub) == 2 and rsaPub.hasOnlyInts(): return construct(rsaPub[:]) except (ValueError, EOFError): pass # Try to see if this is an X.509 DER certificate # (Certificate ASN.1 type) if len(der) == 3: from Crypto.PublicKey import _extract_sp_info try: sp_info = _extract_sp_info(der) if verify_x509_cert: raise NotImplementedError("X.509 certificate validation is not supported") return _importKeyDER(sp_info, passphrase, False) except ValueError: pass # Try PKCS#8 (possibly encrypted) k = PKCS8.unwrap(extern_key, passphrase) if k[0] == oid: return _importKeyDER(k[1], passphrase, False) except (ValueError, EOFError): pass raise ValueError("RSA key format is not supported")
def _import_pkcs8(encoded, passphrase, params): if params: raise ValueError("PKCS#8 already includes parameters") k = PKCS8.unwrap(encoded, passphrase) if k[0] != oid: raise ValueError("No PKCS#8 encoded DSA key") x = DerInteger().decode(k[1]).value p, q, g = list(DerSequence().decode(k[2])) tup = (pow(g, x, p), g, p, q, x) return construct(tup)
def _importKeyDER(self, key_data, passphrase=None, params=None): """Import a DSA key (public or private half), encoded in DER form.""" try: # # Dss-Parms ::= SEQUENCE { # p OCTET STRING, # q OCTET STRING, # g OCTET STRING # } # # Try a simple private key first if params: x = decode_der(DerInteger, key_data).value params = decode_der(DerSequence, params) # Dss-Parms p, q, g = list(params) y = pow(g, x, p) tup = (y, g, p, q, x) return self.construct(tup) der = decode_der(DerSequence, key_data) # Try OpenSSL format for private keys if len(der) == 6 and der.hasOnlyInts() and der[0] == 0: tup = [der[comp] for comp in (4, 3, 1, 2, 5)] return self.construct(tup) # Try SubjectPublicKeyInfo if len(der) == 2: try: algo = decode_der(DerSequence, der[0]) algo_oid = decode_der(DerObjectId, algo[0]).value params = decode_der(DerSequence, algo[1]) # Dss-Parms if algo_oid == oid and len(params) == 3 and\ params.hasOnlyInts(): bitmap = decode_der(DerBitString, der[1]) pub_key = decode_der(DerInteger, bitmap.value) tup = [pub_key.value] tup += [params[comp] for comp in (2, 0, 1)] return self.construct(tup) except (ValueError, EOFError): pass # Try unencrypted PKCS#8 p8_pair = PKCS8.unwrap(key_data, passphrase) if p8_pair[0] == oid: return self._importKeyDER(p8_pair[1], passphrase, p8_pair[2]) except (ValueError, EOFError): pass raise KeyFormatError("DSA key format is not supported")
def _parse_key_pkcs8(self, data: bytes) -> bytes: parsed = pem.parse(data) if parsed and len(parsed) == 1: data = base64.b64decode(''.join( parsed[0].as_text().strip().split("\n")[1:-1])) try: (_, key, _) = pkcs8.unwrap(data, self.password.encode("utf-8")) except ValueError as error: raise X509AdapterError( "invalid password or PKCS#8 data") from error return key
def _load_private_key(self): """Load the private key used to sign HTTP requests. The private key is used to sign HTTP requests as defined in https://datatracker.ietf.org/doc/draft-cavage-http-signatures/. """ if self.private_key is not None: return with open(self.private_key_path, 'r') as f: pem_data = f.read() # Verify PEM Pre-Encapsulation Boundary r = re.compile(r"\s*-----BEGIN (.*)-----\s+") m = r.match(pem_data) if not m: raise ValueError("Not a valid PEM pre boundary") pem_header = m.group(1) if pem_header == 'RSA PRIVATE KEY': self.private_key = RSA.importKey(pem_data, self.private_key_passphrase) elif pem_header == 'EC PRIVATE KEY': self.private_key = ECC.import_key(pem_data, self.private_key_passphrase) elif pem_header in {'PRIVATE KEY', 'ENCRYPTED PRIVATE KEY'}: # Key is in PKCS8 format, which is capable of holding many different # types of private keys, not just EC keys. (key_binary, pem_header, is_encrypted) = \ PEM.decode(pem_data, self.private_key_passphrase) (oid, privkey, params) = \ PKCS8.unwrap(key_binary, passphrase=self.private_key_passphrase) if oid == '1.2.840.10045.2.1': self.private_key = ECC.import_key( pem_data, self.private_key_passphrase) else: raise Exception("Unsupported key: {0}. OID: {1}".format( pem_header, oid)) else: raise Exception("Unsupported key: {0}".format(pem_header)) # Validate the specified signature algorithm is compatible with the private key. if self.signing_algorithm is not None: supported_algs = None if isinstance(self.private_key, RSA.RsaKey): supported_algs = { ALGORITHM_RSASSA_PSS, ALGORITHM_RSASSA_PKCS1v15 } elif isinstance(self.private_key, ECC.EccKey): supported_algs = ALGORITHM_ECDSA_KEY_SIGNING_ALGORITHMS if supported_algs is not None and self.signing_algorithm not in supported_algs: raise Exception( "Signing algorithm {0} is not compatible with private key" .format(self.signing_algorithm))
def _importKeyDER(self, extern_key, passphrase=None): """Import an RSA key (public or private half), encoded in DER form.""" try: der = decode_der(DerSequence, extern_key) # Try PKCS#1 first, for a private key if len(der) == 9 and der.hasOnlyInts() and der[0] == 0: # ASN.1 RSAPrivateKey element del der[6:] # Remove d mod (p-1), # d mod (q-1), and # q^{-1} mod p der.append(inverse(der[4], der[5])) # Add p^{-1} mod q del der[0] # Remove version return self.construct(der[:]) # Keep on trying PKCS#1, but now for a public key if len(der) == 2: try: # The DER object is an RSAPublicKey SEQUENCE with # two elements if der.hasOnlyInts(): return self.construct(der[:]) # The DER object is a SubjectPublicKeyInfo SEQUENCE # with two elements: an 'algorithmIdentifier' and a # 'subjectPublicKey'BIT STRING. # 'algorithmIdentifier' takes the value given at the # module level. # 'subjectPublicKey' encapsulates the actual ASN.1 # RSAPublicKey element. if der[0] == algorithmIdentifier: bitmap = decode_der(DerBitString, der[1]) rsaPub = decode_der(DerSequence, bitmap.value) if len(rsaPub) == 2 and rsaPub.hasOnlyInts(): return self.construct(rsaPub[:]) except (ValueError, EOFError): pass # Try PKCS#8 (possibly encrypted) k = PKCS8.unwrap(extern_key, passphrase) if k[0] == oid: return self._importKeyDER(k[1], passphrase) except (ValueError, EOFError): pass raise ValueError("RSA key format is not supported")
def _import_pkcs8(encoded, passphrase): # From RFC5915, Section 1: # # Distributing an EC private key with PKCS#8 [RFC5208] involves including: # a) id-ecPublicKey, id-ecDH, or id-ecMQV (from [RFC5480]) with the # namedCurve as the parameters in the privateKeyAlgorithm field; and # b) ECPrivateKey in the PrivateKey field, which is an OCTET STRING. algo_oid, private_key, params = PKCS8.unwrap(encoded, passphrase) # We accept id-ecPublicKey, id-ecDH, id-ecMQV without making any # distiction for now. unrestricted_oid = "1.2.840.10045.2.1" ecdh_oid = "1.3.132.1.12" ecmqv_oid = "1.3.132.1.13" if algo_oid not in (unrestricted_oid, ecdh_oid, ecmqv_oid): raise UnsupportedEccFeature("Unsupported ECC purpose (OID: %s)" % oid) curve_name = DerObjectId().decode(params).value return _import_private_der(private_key, passphrase, curve_name)
def _import_pkcs8(encoded, passphrase): # From RFC5915, Section 1: # # Distributing an EC private key with PKCS#8 [RFC5208] involves including: # a) id-ecPublicKey, id-ecDH, or id-ecMQV (from [RFC5480]) with the # namedCurve as the parameters in the privateKeyAlgorithm field; and # b) ECPrivateKey in the PrivateKey field, which is an OCTET STRING. algo_oid, private_key, params = PKCS8.unwrap(encoded, passphrase) # We accept id-ecPublicKey, id-ecDH, id-ecMQV without making any # distiction for now. unrestricted_oid = "1.2.840.10045.2.1" ecdh_oid = "1.3.132.1.12" ecmqv_oid = "1.3.132.1.13" if algo_oid not in (unrestricted_oid, ecdh_oid, ecmqv_oid): raise ValueError("No PKCS#8 encoded ECC key") curve_name = DerObjectId().decode(params).value return _import_private_der(private_key, passphrase, curve_name)
def _importKeyDER(key_data, passphrase, params): """Import a DSA key (public or private half), encoded in DER form.""" try: # # Dss-Parms ::= SEQUENCE { # p OCTET STRING, # q OCTET STRING, # g OCTET STRING # } # # Try a simple private key first if params: x = DerInteger().decode(key_data).value p, q, g = list(DerSequence().decode(params)) # Dss-Parms tup = (pow(g, x, p), g, p, q, x) return construct(tup) der = DerSequence().decode(key_data) # Try OpenSSL format for private keys if len(der) == 6 and der.hasOnlyInts() and der[0] == 0: tup = [der[comp] for comp in (4, 3, 1, 2, 5)] return construct(tup) # Try SubjectPublicKeyInfo if len(der) == 2: try: algo = DerSequence().decode(der[0]) algo_oid = DerObjectId().decode(algo[0]).value params = DerSequence().decode(algo[1]) # Dss-Parms if algo_oid == oid and len(params) == 3 and\ params.hasOnlyInts(): bitmap = DerBitString().decode(der[1]) pub_key = DerInteger().decode(bitmap.value) tup = [pub_key.value] tup += [params[comp] for comp in (2, 0, 1)] return construct(tup) except (ValueError, EOFError): pass # Try to see if this is an X.509 DER certificate # (Certificate ASN.1 type) if len(der) == 3: from Crypto.PublicKey import _extract_sp_info try: sp_info = _extract_sp_info(der) return _importKeyDER(sp_info, passphrase, None) except ValueError: pass # Try unencrypted PKCS#8 p8_pair = PKCS8.unwrap(key_data, passphrase) if p8_pair[0] == oid: return _importKeyDER(p8_pair[1], passphrase, p8_pair[2]) except (ValueError, EOFError): pass raise ValueError("DSA key format is not supported")
def test2(self): """Verify wrapping w/o encryption""" wrapped = PKCS8.wrap(self.clear_key, self.oid_key) res1, res2, res3 = PKCS8.unwrap(wrapped) self.assertEqual(res1, self.oid_key) self.assertEqual(res2, self.clear_key)
def test1(self): """Verify unwrapping w/o encryption""" res1, res2, res3 = PKCS8.unwrap(self.wrapped_clear_key) self.assertEqual(res1, self.oid_key) self.assertEqual(res2, self.clear_key)
def _import_pkcs8(encoded, passphrase): k = PKCS8.unwrap(encoded, passphrase) if k[0] != oid: raise ValueError("No PKCS#8 encoded RSA key") return _import_keyDER(k[1], passphrase)