Esempio n. 1
0
def get_pivman_data(session: PivSession) -> PivmanData:
    """Reads out the Pivman data from a YubiKey."""
    try:
        return PivmanData(session.get_object(OBJECT_ID_PIVMAN_DATA))
    except ApduError as e:
        if e.sw == SW.FILE_NOT_FOUND:
            # No data there, initialise a new object.
            return PivmanData()
        raise
Esempio n. 2
0
def get_pivman_protected_data(session: PivSession) -> PivmanProtectedData:
    """Reads out the Pivman protected data from a YubiKey.

    This function requires PIN verification prior to being called.
    """
    try:
        return PivmanProtectedData(session.get_object(OBJECT_ID_PIVMAN_PROTECTED_DATA))
    except ApduError as e:
        if e.sw == SW.FILE_NOT_FOUND:
            # No data there, initialise a new object.
            return PivmanProtectedData()
        raise
Esempio n. 3
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)