예제 #1
0
    def refresh_piv(self):
        with self._open_device([SmartCardConnection]) as conn:
            session = PivSession(conn)
            pivman = get_pivman_data(session)

            try:
                key_type = session.get_management_key_metadata().key_type
            except NotSupportedError:
                key_type = MANAGEMENT_KEY_TYPE.TDES

            return success({
                'piv_data': {
                    'certs':
                    self._piv_list_certificates(session),
                    'has_derived_key':
                    pivman.has_derived_key,
                    'has_protected_key':
                    pivman.has_protected_key,
                    'has_stored_key':
                    pivman.has_stored_key,
                    'pin_tries':
                    session.get_pin_attempts(),
                    'puk_blocked':
                    pivman.puk_blocked,
                    'supported_algorithms':
                    _supported_algorithms(
                        self._dev_info['version'].split('.')),
                    'key_type':
                    key_type,
                },
            })
예제 #2
0
    def piv_change_mgm_key(self, pin, current_key_hex, new_key_hex, key_type,
                           store_on_device=False):
        with self._open_device([SmartCardConnection]) as conn:
            session = PivSession(conn)

            pivman = get_pivman_data(session)

            if pivman.has_protected_key or store_on_device:
                pin_failed = self._piv_verify_pin(
                    session, pin=pin)
                if pin_failed:
                    return pin_failed
            with PromptTimeout():

                auth_failed = self._piv_ensure_authenticated(
                    session, pin=pin, mgm_key_hex=current_key_hex)
            if auth_failed:
                return auth_failed

            try:

                new_key = a2b_hex(new_key_hex) if new_key_hex else None
            except Exception as e:
                logger.debug('Failed to parse new management key', exc_info=e)
                return failure('new_mgm_key_bad_hex')

            if new_key is not None and len(new_key) != MANAGEMENT_KEY_TYPE(key_type).key_len:
                logger.debug('Wrong length for new management key: %d',
                             len(new_key))
                return failure('new_mgm_key_bad_length')

            pivman_set_mgm_key(
                        session, new_key, MANAGEMENT_KEY_TYPE(key_type), touch=False, store_on_device=store_on_device
                    )
            return success()
예제 #3
0
파일: yubikey.py 프로젝트: rsvargas/GAM
 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
예제 #4
0
    def piv_change_pin(self, old_pin, new_pin):
        with self._open_device([SmartCardConnection]) as conn:
            session = PivSession(conn)
            try:
                session.change_pin(old_pin, new_pin)
                logger.debug('PIN change successful!')
                return success()
            except InvalidPinError as e:
                attempts = e.attempts_remaining
                if attempts:
                    logger.debug("Failed to change PIN, %d tries left", attempts, exc_info=e)
                    return failure('wrong_pin', {'tries_left': attempts})
                else:
                    logger.debug("PIN is blocked.", exc_info=e)
                    return failure('pin_blocked')
            except ApduError as e:
                if e.sw == SW.INCORRECT_PARAMETERS:
                    return failure('incorrect_parameters')

                tries_left = e.attempts_remaining
                logger.debug('PIN change failed. %s tries left.',
                             tries_left, exc_info=e)
                return {
                    'success': False,
                    'tries_left': tries_left,
                }
예제 #5
0
def piv(ctx):
    """
    Manage PIV Application.

    Examples:

    \b
      Generate an ECC P-256 private key and a self-signed certificate in
      slot 9a:
      $ ykman piv generate-key --algorithm ECCP256 9a pubkey.pem
      $ ykman piv generate-certificate --subject "yubico" 9a pubkey.pem

    \b
      Change the PIN from 123456 to 654321:
      $ ykman piv change-pin --pin 123456 --new-pin 654321

    \b
      Reset all PIV data and restore default settings:
      $ ykman piv reset
    """
    try:
        app = PivSession(ctx.obj["conn"])
        ctx.obj["controller"] = PivController(app)
    except ApduError as e:
        if e.sw == SW.FILE_NOT_FOUND:
            ctx.fail("The PIV application can't be found on this YubiKey.")
        raise
예제 #6
0
def piv_info(conn):
    try:
        piv = PivSession(conn)
        return ["\tPIV"] + [
            f"\t\t{ln}" for ln in get_piv_info(piv).splitlines() if ln
        ]
    except Exception as e:
        return [f"\tPIV not accessible {e}"]
예제 #7
0
 def piv_export_certificate(self, slot, file_url):
     file_path = self._get_file_path(file_url)
     with self._open_device([SmartCardConnection]) as conn:
         session = PivSession(conn)
         cert = session.get_certificate(SLOT[slot])
         with open(file_path, 'wb') as file:
             file.write(
                 cert.public_bytes(encoding=serialization.Encoding.PEM))
     return success()
예제 #8
0
 def piv_unblock_pin(self, puk, new_pin):
     with self._open_device([SmartCardConnection]) as conn:
         session = PivSession(conn)
         try:
             session.unblock_pin(puk, new_pin)
             return success()
         except InvalidPinError as e:
             attempts = e.attempts_remaining
             if attempts:
                 logger.debug("Failed to unblock PIN, %d tries left", attempts, exc_info=e)
                 return failure('wrong_puk', {'tries_left': attempts})
             else:
                 logger.debug("PUK is blocked.", exc_info=e)
                 return failure('puk_blocked')
예제 #9
0
    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
        })
예제 #10
0
    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')
예제 #11
0
파일: yubikey.py 프로젝트: rsvargas/GAM
 def get_certificate(self):
     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:
                 cert = session.get_certificate(self.slot)
             except ApduError as err:
                 controlflow.system_error_exit(9, f'YubiKey - {err}')
         cert_pem = cert.public_bytes(serialization.Encoding.PEM).decode()
         publicKeyData = b64encode(cert_pem.encode())
         if isinstance(publicKeyData, bytes):
             publicKeyData = publicKeyData.decode()
         return publicKeyData
     except ValueError as err:
         controlflow.system_error_exit(9, f'YubiKey - {err}')
예제 #12
0
파일: yubikey.py 프로젝트: rsvargas/GAM
    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}')
예제 #13
0
def piv(ctx):
    """
    Manage the PIV application.

    Examples:

    \b
      Generate an ECC P-256 private key and a self-signed certificate in
      slot 9a:
      $ ykman piv keys generate --algorithm ECCP256 9a pubkey.pem
      $ ykman piv certificates generate --subject "yubico" 9a pubkey.pem

    \b
      Change the PIN from 123456 to 654321:
      $ ykman piv access change-pin --pin 123456 --new-pin 654321

    \b
      Reset all PIV data and restore default settings:
      $ ykman piv reset
    """
    session = PivSession(ctx.obj["conn"])
    ctx.obj["session"] = session
    ctx.obj["pivman_data"] = get_pivman_data(session)
예제 #14
0
 def setUp(self):
     self.conn = open_device()[0]
     self.controller = PivController(PivSession(self.conn))
예제 #15
0
def session(ccid_connection):
    piv = PivSession(ccid_connection)
    piv.reset()
    yield piv
    reset_state(piv)
예제 #16
0
 def setUpClass(cls):
     with open_device()[0] as conn:
         controller = PivController(PivSession(conn))
         controller.reset()
예제 #17
0
 def piv_reset(self):
     with self._open_device([SmartCardConnection]) as conn:
         session = PivSession(conn)
         session.reset()
         return success()
예제 #18
0
 def reconnect(self):
     self.conn.close()
     self.conn = open_device()[0]
     self.controller = PivController(PivSession(self.conn))
예제 #19
0
    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()