def generate_ec_key(self, key_slot, curve_name, timestamp=None): require_version(self.version, (5, 2, 0)) """Requires Admin PIN verification.""" if timestamp is None: timestamp = int(time.time()) attributes = _format_ec_attributes(key_slot, curve_name) self._put_data(key_slot.key_id, attributes) resp = self._app.send_apdu(0, INS.GENERATE_ASYM, 0x80, 0x00, key_slot.crt) data = Tlv.parse_dict(Tlv.unpack(0x7F49, resp)) pubkey_enc = data[0x86] self._put_data(key_slot.gen_time, struct.pack(">I", timestamp)) # TODO: Calculate and write fingerprint if curve_name == "x25519": # Added in 2.0 from cryptography.hazmat.primitives.asymmetric import x25519 return x25519.X25519PublicKey.from_public_bytes(pubkey_enc) if curve_name == "ed25519": # Added in 2.6 from cryptography.hazmat.primitives.asymmetric import ed25519 return ed25519.Ed25519PublicKey.from_public_bytes(pubkey_enc) curve = getattr(ec, curve_name.upper()) try: # Added in cryptography 2.5 return ec.EllipticCurvePublicKey.from_encoded_point(curve(), pubkey_enc) except AttributeError: return ec.EllipticCurvePublicNumbers.from_encoded_point( curve(), pubkey_enc ).public_key(default_backend())
def sign_csr_builder( session: PivSession, slot: SLOT, public_key: Union[rsa.RSAPublicKey, ec.EllipticCurvePublicKey], builder: x509.CertificateSigningRequestBuilder, hash_algorithm: Type[hashes.HashAlgorithm] = hashes.SHA256, ) -> x509.CertificateSigningRequest: """Sign a CSR.""" key_type = KEY_TYPE.from_public_key(public_key) dummy_key = _dummy_key(key_type) csr = builder.sign(dummy_key, hash_algorithm(), default_backend()) seq = Tlv.parse_list(Tlv.unpack(0x30, csr.public_bytes(Encoding.DER))) # Replace public key pub_format = (PublicFormat.PKCS1 if key_type.algorithm == ALGORITHM.RSA else PublicFormat.SubjectPublicKeyInfo) dummy_bytes = dummy_key.public_key().public_bytes(Encoding.DER, pub_format) pub_bytes = public_key.public_bytes(Encoding.DER, pub_format) seq[0] = Tlv(seq[0].replace(dummy_bytes, pub_bytes)) sig = session.sign( slot, key_type, seq[0], hash_algorithm(), padding.PKCS1v15(), # Only used for RSA ) # Replace signature, add unused bits = 0 seq[2] = Tlv(seq[2].tag, b"\0" + sig) # Re-assemble sequence der = Tlv(0x30, b"".join(seq)) return x509.load_der_x509_csr(der, default_backend())
def sign_certificate_builder( session: PivSession, slot: SLOT, key_type: KEY_TYPE, builder: x509.CertificateBuilder, hash_algorithm: Type[hashes.HashAlgorithm] = hashes.SHA256, ) -> x509.Certificate: """Sign a Certificate.""" dummy_key = _dummy_key(key_type) cert = builder.sign(dummy_key, hash_algorithm(), default_backend()) sig = session.sign( slot, key_type, cert.tbs_certificate_bytes, hash_algorithm(), padding.PKCS1v15(), # Only used for RSA ) seq = Tlv.parse_list(Tlv.unpack(0x30, cert.public_bytes(Encoding.DER))) # Replace signature, add unused bits = 0 seq[2] = Tlv(seq[2].tag, b"\0" + sig) # Re-assemble sequence der = Tlv(0x30, b"".join(seq)) return x509.load_der_x509_certificate(der, default_backend())
def generate_rsa_key(self, key_slot, key_size, timestamp=None): """Requires Admin PIN verification.""" if (4, 2, 0) <= self.version < (4, 3, 5): raise NotSupportedError( "RSA key generation not supported on this YubiKey") if timestamp is None: timestamp = int(time.time()) neo = self.version < (4, 0, 0) if not neo: attributes = _format_rsa_attributes(key_size) self._put_data(key_slot.key_id, attributes) elif key_size != 2048: raise ValueError("Unsupported key size!") resp = self._app.send_apdu(0, INS.GENERATE_ASYM, 0x80, 0x00, key_slot.crt) data = Tlv.parse_dict(Tlv.unpack(0x7F49, resp)) numbers = rsa.RSAPublicNumbers(bytes2int(data[0x82]), bytes2int(data[0x81])) self._put_data(key_slot.gen_time, struct.pack(">I", timestamp)) # TODO: Calculate and write fingerprint return numbers.public_key(default_backend())
def is_pkcs12(data): """ Tries to identify a PKCS12 container. The PFX PDU version is assumed to be v3. See: https://tools.ietf.org/html/rfc7292. """ try: header = Tlv.parse_list(Tlv.unpack(0x30, data))[0] return header.tag == 0x02 and header.value == b"\x03" except ValueError: return False
def is_pkcs12(data): """ Tries to identify a PKCS12 container. The PFX PDU version is assumed to be v3. See: https://tools.ietf.org/html/rfc7292. """ try: header = Tlv.parse_from(Tlv.unpack(0x30, data))[0] return header.tag == 0x02 and header.value == b"\x03" except ValueError as e: logger.debug("Unable to parse TLV", exc_info=e) return False