class PivTestCase(DestructiveYubikeyTestCase): def setUp(self): self.dev = open_device(transports=TRANSPORT.CCID) self.controller = PivController(self.dev.driver) def tearDown(self): self.dev.driver.close() def assertMgmKeyIs(self, key): self.controller.authenticate(key) def assertMgmKeyIsNot(self, key): with self.assertRaises(AuthenticationFailed): self.controller.authenticate(key) def assertStoredMgmKeyEquals(self, key): self.assertEqual(self.controller._pivman_protected_data.key, key) def assertStoredMgmKeyNotEquals(self, key): self.assertNotEqual(self.controller._pivman_protected_data.key, key) def reconnect(self): self.dev.driver.close() self.dev = open_device(transports=TRANSPORT.CCID) self.controller = PivController(self.dev.driver)
class PivTestCase(unittest.TestCase): def setUp(self): self.conn = open_device()[0] self.controller = PivController(PivSession(self.conn)) def tearDown(self): self.conn.close() def assertMgmKeyIs(self, key): self.controller.authenticate(key) def assertMgmKeyIsNot(self, key): with self.assertRaises(ApduError): self.controller.authenticate(key) def assertStoredMgmKeyEquals(self, key): self.assertEqual(self.controller._pivman_protected_data.key, key) def assertStoredMgmKeyNotEquals(self, key): self.assertNotEqual(self.controller._pivman_protected_data.key, key) def reconnect(self): self.conn.close() self.conn = open_device()[0] self.controller = PivController(PivSession(self.conn))
def piv_reset(self): try: with self._open_device(TRANSPORT.CCID) as dev: controller = PivController(dev.driver) controller.reset() return True except Exception as e: logger.error('Failed to reset PIV applet', exc_info=e) return False
def _get_jwt(yubikey: YubiKey, slot: int, prompt_management_key: bool, service_account_email: str, audience: str, scopes: List[str], token_lifetime: int, cache_lifetime: int, stream=sys.stderr): """ Generates a general-purpose Google JWT with a YubiKey """ authenticate(yubikey, prompt_management_key, cache_lifetime, stream) iat = time() header = { 'typ': 'JWT', 'alg': 'RS256', } payload = { 'iss': service_account_email, 'aud': audience, 'iat': iat, 'exp': iat + token_lifetime, } if scopes: payload['scope'] = ' '.join(scopes) msg = f'{_json_b64encode(header)}.{_json_b64encode(payload)}' sig = yubikey.sign(slot, _KEY_ALG, msg.encode('utf-8')) sig = _b64encode_str(sig) return f'{msg}.{sig}'
def gen_private_key(yubikey: YubiKey, slot: SLOT, prompt_management_key: bool, pin_policy: PIN_POLICY, touch_policy: TOUCH_POLICY, subject: str, valid_days: int): """ Generates a private key and certificate on the YubiKey """ authenticate(yubikey, prompt_management_key) _log('Generating private key on YubiKey...') public_key = yubikey.generate_key( slot.value, _KEY_ALG, pin_policy.value, touch_policy.value, ) _log('Generating certificate on YubiKey...') start = datetime.now() end = start + timedelta(days=valid_days) yubikey.generate_self_signed_certificate( slot.value, public_key, subject, start, end, touch_callback=prompt_for_touch, ) return get_public_key(yubikey, slot)
def authenticate(yubikey: YubiKey, prompt_management_key: bool, cache_lifetime=CachedItem.DEFAULT_LIFETIME_SEC, stream=sys.stderr): """ Authenticates user to the YubiKey """ global _CACHED_PIN, _CACHED_MGMT_KEY # pylint: disable=global-statement _log('Authenticating to the YubiKey...', stream) pin = _CACHED_PIN.value if _CACHED_PIN.expired(): pin = getpass('Enter PIN: ', stream) _CACHED_PIN = CachedItem(None, pin, cache_lifetime) yubikey.verify(pin, touch_callback=prompt_for_touch) mgmt_key = _CACHED_MGMT_KEY.value if not prompt_management_key: mgmt_key = DEFAULT_MANAGEMENT_KEY elif _CACHED_MGMT_KEY.expired(): mgmt_key = getpass('Enter management key: ', stream) _CACHED_MGMT_KEY = CachedItem(None, mgmt_key, cache_lifetime) yubikey.authenticate(mgmt_key, touch_callback=prompt_for_touch) _log('Authenticated', stream)
def reconnect(self): self.dev.driver.close() self.dev = open_device() self.controller = PivController(self.dev.driver)
class ManagementKeyReadWrite(PivTestCase): """ Tests after which the management key may not be the default management key. """ def setUp(self): self.dev = open_device(transports=TRANSPORT.CCID) self.controller = PivController(self.dev.driver) self.controller.reset() def test_set_mgm_key_changes_mgm_key(self): self.controller.authenticate(a2b_hex(DEFAULT_MANAGEMENT_KEY)) self.controller.set_mgm_key(a2b_hex(NON_DEFAULT_MANAGEMENT_KEY)) self.assertMgmKeyIsNot(DEFAULT_MANAGEMENT_KEY) self.assertMgmKeyIs(NON_DEFAULT_MANAGEMENT_KEY) def test_set_stored_mgm_key_succeeds_if_pin_is_verified(self): self.controller.verify(DEFAULT_PIN) self.controller.authenticate(a2b_hex(DEFAULT_MANAGEMENT_KEY)) self.controller.set_mgm_key(a2b_hex(NON_DEFAULT_MANAGEMENT_KEY), store_on_device=True) self.assertMgmKeyIsNot(DEFAULT_MANAGEMENT_KEY) self.assertMgmKeyIs(NON_DEFAULT_MANAGEMENT_KEY) self.assertStoredMgmKeyEquals(NON_DEFAULT_MANAGEMENT_KEY) self.assertMgmKeyIs(self.controller._pivman_protected_data.key) def test_set_stored_random_mgm_key_succeeds_if_pin_is_verified(self): self.controller.verify(DEFAULT_PIN) self.controller.authenticate(a2b_hex(DEFAULT_MANAGEMENT_KEY)) self.controller.set_mgm_key(None, store_on_device=True) self.assertMgmKeyIsNot(DEFAULT_MANAGEMENT_KEY) self.assertMgmKeyIsNot(NON_DEFAULT_MANAGEMENT_KEY) self.assertMgmKeyIs(self.controller._pivman_protected_data.key) self.assertStoredMgmKeyNotEquals(DEFAULT_MANAGEMENT_KEY) self.assertStoredMgmKeyNotEquals(NON_DEFAULT_MANAGEMENT_KEY)
def setUpClass(cls): dev = open_device(transports=TRANSPORT.CCID) controller = PivController(dev.driver) controller.reset()
def reconnect(self): self.dev.driver.close() self.dev = open_device(transports=TRANSPORT.CCID) self.controller = PivController(self.dev.driver)
def setUpClass(cls): with open_device(transports=TRANSPORT.CCID) as dev: controller = PivController(dev.driver) controller.reset()
def get_public_key(yubikey: YubiKey, slot: SLOT): """ Reads public key from YubiKey """ cert = yubikey.read_certificate(slot.value) return cert.public_bytes(serialization.Encoding.PEM)
def setUpClass(cls): with open_device() as dev: controller = PivController(dev.driver) controller.reset()
def setUp(self): self.dev = open_device(transports=TRANSPORT.CCID) self.controller = PivController(self.dev.driver)
def setUp(self): self.conn = open_device()[0] self.controller = PivController(PivSession(self.conn))
def _yk_piv_ctrl(): yk = open_device(transports=TRANSPORT.CCID) yield PivController(yk.driver) yk.close()
def reconnect(self): self.conn.close() self.conn = open_device()[0] self.controller = PivController(PivSession(self.conn))
class ManagementKeyReadOnly(PivTestCase): """ Tests after which the management key is always the default management key. Placing compatible tests here reduces the amount of slow reset calls needed. """ @classmethod def setUpClass(cls): dev = open_device(transports=TRANSPORT.CCID) controller = PivController(dev.driver) controller.reset() def setUp(self): self.dev = open_device(transports=TRANSPORT.CCID) self.controller = PivController(self.dev.driver) def test_authenticate_twice_does_not_throw(self): self.controller.authenticate(a2b_hex(DEFAULT_MANAGEMENT_KEY)) self.controller.authenticate(a2b_hex(DEFAULT_MANAGEMENT_KEY)) def test_reset_resets_has_stored_key_flag(self): self.assertFalse(self.controller.has_stored_key) self.controller.verify(DEFAULT_PIN) self.controller.authenticate(a2b_hex(DEFAULT_MANAGEMENT_KEY)) self.controller.set_mgm_key(None, store_on_device=True) self.assertTrue(self.controller.has_stored_key) self.reconnect() self.controller.reset() self.assertFalse(self.controller.has_stored_key) def test_reset_while_verified_throws_nice_ValueError(self): self.controller.verify(DEFAULT_PIN) with self.assertRaisesRegex(ValueError, '^Failed reading remaining'): self.controller.reset() def test_set_mgm_key_does_not_change_key_if_not_authenticated(self): with self.assertRaises(APDUError): self.controller.set_mgm_key(a2b_hex(NON_DEFAULT_MANAGEMENT_KEY)) self.assertMgmKeyIs(DEFAULT_MANAGEMENT_KEY) def test_set_stored_mgm_key_does_not_destroy_key_if_pin_not_verified(self): self.controller.authenticate(a2b_hex(DEFAULT_MANAGEMENT_KEY)) with self.assertRaises(APDUError): self.controller.set_mgm_key(None, store_on_device=True) self.assertMgmKeyIs(DEFAULT_MANAGEMENT_KEY)
def setUpClass(cls): with open_device()[0] as conn: controller = PivController(PivSession(conn)) controller.reset()
def setUpClass(cls): with open_device(transports=TRANSPORT.CCID) as dev: PivController(dev.driver).reset()
def __enter__(self): return PivController(self._dev.driver)
def setUp(self): self.dev = open_device() self.controller = PivController(self.dev.driver)