def sign(self, message): if 'mplock' in globals(): mplock.acquire() try: conn = self._connect() with conn: session = PivSession(conn) if self.pin: try: session.verify_pin(self.pin) except InvalidPinError as err: controlflow.system_error_exit(7, f'YubiKey - {err}') try: signed = session.sign(slot=self.slot, key_type=self.key_type, message=message, hash_algorithm=hashes.SHA256(), padding=padding.PKCS1v15()) except ApduError as err: controlflow.system_error_exit(8, f'YubiKey - {err}') except ValueError as err: controlflow.system_error_exit(9, f'YubiKey - {err}') if 'mplock' in globals(): mplock.release() return signed
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 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 check_key( session: PivSession, slot: SLOT, public_key: Union[rsa.RSAPublicKey, ec.EllipticCurvePublicKey], ) -> bool: """Check that a given public key corresponds to the private key in a slot. This will create a signature using the private key, so the PIN must be verified prior to calling this function if the PIN policy requires it. """ try: test_data = b"test" test_sig = session.sign( slot, KEY_TYPE.from_public_key(public_key), test_data, hashes.SHA256(), padding.PKCS1v15(), # Only used for RSA ) if isinstance(public_key, rsa.RSAPublicKey): public_key.verify( test_sig, test_data, padding.PKCS1v15(), hashes.SHA256(), ) elif isinstance(public_key, ec.EllipticCurvePublicKey): public_key.verify(test_sig, test_data, ec.ECDSA(hashes.SHA256())) else: raise ValueError("Unknown key type: " + type(public_key)) return True except ApduError as e: if e.sw in (SW.INCORRECT_PARAMETERS, SW.WRONG_PARAMETERS_P1P2): return False raise except InvalidSignature: return False