Ejemplo n.º 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,
                },
            })
Ejemplo n.º 2
0
def get_piv_info(session: PivSession) -> str:
    """Get human readable information about the PIV configuration."""
    pivman = get_pivman_data(session)
    lines = []

    lines.append("PIV version: %d.%d.%d" % session.version)

    try:
        pin_data = session.get_pin_metadata()
        if pin_data.default_value:
            lines.append("WARNING: Using default PIN!")
        tries_str = "%d/%d" % (pin_data.attempts_remaining,
                               pin_data.total_attempts)
    except NotSupportedError:
        # Largest possible number of PIN tries to get back is 15
        tries = session.get_pin_attempts()
        tries_str = "15 or more." if tries == 15 else str(tries)
    lines.append(f"PIN tries remaining: {tries_str}")
    if pivman.puk_blocked:
        lines.append("PUK blocked.")

    try:
        metadata = session.get_management_key_metadata()
        if metadata.default_value:
            lines.append("WARNING: Using default Management key!")
        key_type = metadata.key_type
    except NotSupportedError:
        key_type = MANAGEMENT_KEY_TYPE.TDES
    lines.append(f"Management key algorithm: {key_type.name}")

    if pivman.has_derived_key:
        lines.append("Management key is derived from PIN.")
    if pivman.has_stored_key:
        lines.append(
            "Management key is stored on the YubiKey, protected by PIN.")

    try:
        chuid = session.get_object(OBJECT_ID.CHUID).hex()
    except ApduError as e:
        if e.sw == SW.FILE_NOT_FOUND:
            chuid = "No data available."
    lines.append("CHUID:\t" + chuid)

    try:
        ccc = session.get_object(OBJECT_ID.CAPABILITY).hex()
    except ApduError as e:
        if e.sw == SW.FILE_NOT_FOUND:
            ccc = "No data available."
    lines.append("CCC: \t" + ccc)

    for (slot, cert) in list_certificates(session).items():
        lines.append(f"Slot {slot:02x}:")

        if isinstance(cert, x509.Certificate):
            try:
                # Try to read out full DN, fallback to only CN.
                # Support for DN was added in crytography 2.5
                subject_dn = cert.subject.rfc4514_string()
                issuer_dn = cert.issuer.rfc4514_string()
                print_dn = True
            except AttributeError:
                print_dn = False
                logger.debug("Failed to read DN, falling back to only CNs")
                cn = cert.subject.get_attributes_for_oid(
                    x509.NameOID.COMMON_NAME)
                subject_cn = cn[0].value if cn else "None"
                cn = cert.issuer.get_attributes_for_oid(
                    x509.NameOID.COMMON_NAME)
                issuer_cn = cn[0].value if cn else "None"
            except ValueError as e:
                # Malformed certificates may throw ValueError
                logger.debug("Failed parsing certificate", exc_info=e)
                lines.append(f"\tMalformed certificate: {e}")
                continue

            fingerprint = cert.fingerprint(hashes.SHA256()).hex()
            try:
                key_algo = KEY_TYPE.from_public_key(cert.public_key()).name
            except ValueError:
                key_algo = "Unsupported"
            serial = cert.serial_number
            try:
                not_before: Optional[datetime] = cert.not_valid_before
            except ValueError as e:
                logger.debug("Failed reading not_valid_before", exc_info=e)
                not_before = None
            try:
                not_after: Optional[datetime] = cert.not_valid_after
            except ValueError as e:
                logger.debug("Failed reading not_valid_after", exc_info=e)
                not_after = None
            # Print out everything
            lines.append(f"\tAlgorithm:\t{key_algo}")
            if print_dn:
                lines.append(f"\tSubject DN:\t{subject_dn}")
                lines.append(f"\tIssuer DN:\t{issuer_dn}")
            else:
                lines.append(f"\tSubject CN:\t{subject_cn}")
                lines.append(f"\tIssuer CN:\t{issuer_cn}")
            lines.append(f"\tSerial:\t\t{serial}")
            lines.append(f"\tFingerprint:\t{fingerprint}")
            if not_before:
                lines.append(f"\tNot before:\t{not_before}")
            if not_after:
                lines.append(f"\tNot after:\t{not_after}")
        else:
            lines.append("\tError: Failed to parse certificate.")

    return "\n".join(lines)