def piv_import_file(self, slot, file_url, password=None, pin=None, mgm_key=None): is_cert = False is_private_key = False file_path = self._get_file_path(file_url) if password: password = password.encode() with open(file_path, 'r+b') as file: data = file.read() try: certs = parse_certificates(data, password) is_cert = True except (ValueError, TypeError): pass try: private_key = parse_private_key(data, password) is_private_key = True except (ValueError, TypeError, InvalidPasswordError): pass if not (is_cert or is_private_key): return failure('failed_parsing') with self._open_device([SmartCardConnection]) as conn: session = PivSession(conn) with PromptTimeout(): auth_failed = self._piv_ensure_authenticated( session, pin, mgm_key) if auth_failed: return auth_failed if is_private_key: session.put_key(SLOT[slot], private_key) if is_cert: if len(certs) > 1: leafs = get_leaf_certificates(certs) cert_to_import = leafs[0] else: cert_to_import = certs[0] session.put_certificate(SLOT[slot], cert_to_import) session.put_object(OBJECT_ID.CHUID, generate_chuid()) return success({ 'imported_cert': is_cert, 'imported_key': is_private_key })
def piv_delete_certificate(self, slot_name, pin=None, mgm_key_hex=None): logger.debug('piv_delete_certificate %s', slot_name) with self._open_device([SmartCardConnection]) as conn: session = PivSession(conn) with PromptTimeout(): auth_failed = self._piv_ensure_authenticated( session, pin=pin, mgm_key_hex=mgm_key_hex) if auth_failed: return auth_failed try: session.delete_certificate(SLOT[slot_name]) session.put_object(OBJECT_ID.CHUID, generate_chuid()) return success() except ApduError as e: if e.sw == SW.SECURITY_CONDITION_NOT_SATISFIED: logger.debug("Wrong management key", exc_info=e) return failure('wrong_mgm_key')
def reset_piv(self): '''Resets YubiKey PIV app and generates new key for GAM to use.''' reply = str( input( 'This will wipe all PIV keys and configuration from your YubiKey. Are you sure? (y/N) ' ).lower().strip()) if reply != 'y': sys.exit(1) try: conn = self._connect() with conn: piv = PivSession(conn) piv.reset() rnd = SystemRandom() pin_puk_chars = string.ascii_letters + string.digits + string.punctuation new_puk = ''.join(rnd.choice(pin_puk_chars) for _ in range(8)) new_pin = ''.join(rnd.choice(pin_puk_chars) for _ in range(8)) piv.change_puk('12345678', new_puk) piv.change_pin('123456', new_pin) print(f'PIN set to: {new_pin}') piv.authenticate(MANAGEMENT_KEY_TYPE.TDES, DEFAULT_MANAGEMENT_KEY) piv.verify_pin(new_pin) print('YubiKey is generating a non-exportable private key...') pubkey = piv.generate_key(SLOT.AUTHENTICATION, KEY_TYPE.RSA2048, PIN_POLICY.ALWAYS, TOUCH_POLICY.NEVER) now = datetime.datetime.utcnow() valid_to = now + datetime.timedelta(days=36500) subject = 'CN=GAM Created Key' piv.authenticate(MANAGEMENT_KEY_TYPE.TDES, DEFAULT_MANAGEMENT_KEY) piv.verify_pin(new_pin) cert = generate_self_signed_certificate( piv, SLOT.AUTHENTICATION, pubkey, subject, now, valid_to) piv.put_certificate(SLOT.AUTHENTICATION, cert) piv.put_object(OBJECT_ID.CHUID, generate_chuid()) except ValueError as err: controlflow.system_error_exit(8, f'YubiKey - {err}')
def piv_generate_certificate( self, slot_name, algorithm, subject, expiration_date, self_sign=True, csr_file_url=None, pin=None, mgm_key_hex=None): logger.debug('slot_name=%s algorithm=%s common_name=%s ' 'expiration_date=%s self_sign=%s csr_file_url=%s', slot_name, algorithm, subject, expiration_date, self_sign, csr_file_url) if csr_file_url: file_path = self._get_file_path(csr_file_url) with self._open_device([SmartCardConnection]) as conn: session = PivSession(conn) with PromptTimeout(): auth_failed = self._piv_ensure_authenticated( session, pin=pin, mgm_key_hex=mgm_key_hex) if auth_failed: return auth_failed pin_failed = self._piv_verify_pin(session, pin) if pin_failed: return pin_failed if self_sign: now = datetime.datetime.utcnow() try: year = int(expiration_date[0:4]) month = int(expiration_date[(4+1):(4+1+2)]) day = int(expiration_date[(4+1+2+1):(4+1+2+1+2)]) valid_to = datetime.datetime(year, month, day) except ValueError as e: logger.debug( 'Failed to parse date: ' + expiration_date, exc_info=e) return failure( 'invalid_iso8601_date', {'date': expiration_date}) try: public_key = session.generate_key( SLOT[slot_name], KEY_TYPE[algorithm]) except ApduError as e: if e.sw == SW.SECURITY_CONDITION_NOT_SATISFIED: logger.debug("Wrong management key", exc_info=e) return failure('wrong_mgm_key') pin_failed = self._piv_verify_pin(session, pin) if pin_failed: return pin_failed if "=" not in subject: # Old style, common name only. subject = "CN=" + subject try: if self_sign: cert = generate_self_signed_certificate(session, SLOT[slot_name], public_key, subject, now, valid_to) session.put_certificate(SLOT[slot_name], cert) session.put_object(OBJECT_ID.CHUID, generate_chuid()) else: csr = generate_csr(session, SLOT[slot_name], public_key, subject) with open(file_path, 'w+b') as csr_file: csr_file.write(csr.public_bytes( encoding=serialization.Encoding.PEM)) except ApduError as e: if e.sw == SW.SECURITY_CONDITION_NOT_SATISFIED: return failure('pin_required') raise return success()