Beispiel #1
0
def print_p12_secretBag(secretbag_der,
                        password,
                        show_pem=False,
                        list_only=False,
                        indent=''):
    """Parse PKCS#12 secretBag ASN.1 data"""
    # SecretBag ::= SEQUENCE {
    #     secretTypeId   BAG-TYPE.&id ({SecretTypes}),
    #     secretValue    [0] EXPLICIT BAG-TYPE.&Type ({SecretTypes} {@secretTypeId})
    # }
    secret_type_id_der, secret_value_der = util_asn1.decode_sequence(
        secretbag_der, 2)
    secret_type_id = util_asn1.decode_oid(secret_type_id_der)
    secret_value_der = util_asn1.decode_object(secret_value_der)
    print("{}* secret type: {}".format(indent, secret_type_id))
    secret_value = util_asn1.decode_octet_string(secret_value_der)
    if secret_type_id == 'keyBag':
        print_p12_keybag(secret_value,
                         password,
                         show_pem=show_pem,
                         list_only=list_only,
                         indent=indent)
    else:
        raise NotImplementedError(
            "Unimplemented secretBag type {}".format(secret_type_id))
Beispiel #2
0
def print_p12_certBag(certbag_der, show_pem=False, list_only=False, indent=''):
    """Parse PKCS#12 certBag ASN.1 data"""
    # CertBag ::= SEQUENCE {
    #     certId      BAG-TYPE.&id   ({CertTypes}),
    #     certValue   [0] EXPLICIT BAG-TYPE.&Type ({CertTypes}{@certId})
    # }
    cert_id_der, cert_value_der = util_asn1.decode_sequence(certbag_der, 2)
    cert_id = util_asn1.decode_oid(cert_id_der)
    cert_value_der = util_asn1.decode_object(cert_value_der)
    if cert_id != 'x509Certificate':
        raise NotImplementedError("Unknown certificate format {}".format(repr(cert_id)))
    cert = util_asn1.decode_octet_string(cert_value_der)

    description = describe_der_certificate(cert)
    if description:
        print("{}* Certificate: {}".format(indent, description))
    else:
        print("{}* Certificate: (no description available)".format(indent))
    run_openssl_show_cert(cert, list_only=list_only, show_pem=show_pem, indent=indent)
Beispiel #3
0
def print_p12_keystore(ks_content, password, show_pem=False, list_only=False):
    """Parse a PKCS#12 KeyStore file and print it"""
    # run_process_with_input(['openssl', 'asn1parse', '-i', '-inform', 'DER'], ks_content, fatal=True)

    # PFX (Personal Information Exchange) is defined as:
    # PFX ::= SEQUENCE {
    #     version     INTEGER {v3(3)}(v3,...),
    #     authSafe    ContentInfo,
    #     macData     MacData OPTIONAL
    # }
    version, authsafe_der, macdata_der = util_asn1.decode_sequence(
        ks_content, 3)
    if version != 3:
        raise NotImplementedError(
            "Unimplemented PFX version {}".format(version))

    # ContentInfo ::= SEQUENCE {
    #     contentType ContentType,
    #     content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL
    # }
    # ContentType ::= OBJECT IDENTIFIER
    authsafe_content_type_der, authsafe_content_der = util_asn1.decode_sequence(
        authsafe_der, 2)
    authsafe_content_type = util_asn1.decode_oid(authsafe_content_type_der)
    if authsafe_content_type != 'pkcs7-data':
        raise NotImplementedError(
            "Unimplemented PFX content type {}".format(authsafe_content_type))
    authsafe_content_der = util_asn1.decode_object(authsafe_content_der)
    authsafe_content = util_asn1.decode_octet_string(authsafe_content_der)

    # MacData ::= SEQUENCE {
    #     mac         DigestInfo,
    #     macSalt     OCTET STRING,
    #     iterations  INTEGER DEFAULT 1
    # }
    macdata_asn1 = util_asn1.decode_sequence(macdata_der)
    if len(macdata_asn1) == 2:
        mac_der, mac_salt_der = macdata_asn1
        mac_iterations = 1
    elif len(macdata_asn1) == 3:
        mac_der, mac_salt_der, mac_iterations = macdata_asn1
    else:
        raise ValueError(
            "Unexpected number of items in ASN.1 MacData sequence")
    mac_salt = util_asn1.decode_octet_string(mac_salt_der)

    # DigestInfo ::= SEQUENCE {
    #     digestAlgorithm DigestAlgorithmIdentifier,
    #     digest Digest
    # }
    # DigestAlgorithmIdentifier ::= AlgorithmIdentifier
    # Digest ::= OCTET STRING
    mac_digest_algorithm_der, mac_digest_der = util_asn1.decode_sequence(
        mac_der, 2)
    mac_digest_algorithm = util_asn1.decode_x509_algid(
        mac_digest_algorithm_der)
    mac_digest = util_asn1.decode_octet_string(mac_digest_der)

    print("* PKCS#12 Keystore MAC:")
    print("    * algorithm: {}".format(mac_digest_algorithm))
    print("    * salt: {}".format(xx(mac_salt)))
    print("    * iterations: {}".format(mac_iterations))
    print("    * HMAC digest: {}".format(xx(mac_digest)))

    mac_key = pkcs12_derivation(alg=mac_digest_algorithm,
                                id_byte=3,
                                password=password,
                                salt=mac_salt,
                                iterations=mac_iterations)

    mac_hmac = hmac.new(key=mac_key,
                        msg=authsafe_content,
                        digestmod=hashlib.sha1).digest()
    if mac_hmac == mac_digest:
        print("    (password: {})".format(repr(password)))
        print("    (HMAC key: {})".format(xx(mac_key)))
    else:
        print("    (computed HMAC: {})".format(xx(mac_hmac)))
        print("    * wrong password (pad HMAC digest)")

    # AuthenticatedSafe ::= SEQUENCE OF ContentInfo
    #     -- Data if unencrypted
    #     -- EncryptedData if password-encrypted
    #     -- EnvelopedData if public key-encrypted
    authsafe_seq = util_asn1.decode_sequence(authsafe_content)
    print("* {} data blocks:".format(len(authsafe_seq)))
    for blk_index, blk_der in enumerate(authsafe_seq):
        blk_content_type_der, blk_content_der = util_asn1.decode_sequence(
            blk_der, 2)
        blk_content_type = util_asn1.decode_oid(blk_content_type_der)
        blk_content_der = util_asn1.decode_object(
            blk_content_der)  # tag "cont[0]"

        if blk_content_type == 'pkcs7-data':
            safe_contents = util_asn1.decode_octet_string(blk_content_der)
            print("  [{}] unencrypted safe contents:".format(blk_index + 1))
            print_p12_safe_contents(safe_contents,
                                    password,
                                    show_pem=show_pem,
                                    list_only=list_only,
                                    indent="    ")
        elif blk_content_type == 'pkcs7-encryptedData':
            print("  [{}] encrypted safe contents:".format(blk_index + 1))
            # EncryptedData ::= SEQUENCE {
            #      version Version,
            #      encryptedContentInfo EncryptedContentInfo
            # }
            encblk_version, encrypted_ci_der = util_asn1.decode_sequence(
                blk_content_der, 2)
            if encblk_version != 0:
                raise NotImplementedError(
                    "Unimplemented PKCS#7 EncryptedData version {}".format(
                        encblk_version))

            # EncryptedContentInfo ::= SEQUENCE {
            #     contentType ContentType,
            #     contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
            #     encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
            # }
            # ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
            # EncryptedContent ::= OCTET STRING
            enc_ctype_der, enc_alg_der, enc_content_der = util_asn1.decode_sequence(
                encrypted_ci_der, 3)
            enc_ctype = util_asn1.decode_oid(enc_ctype_der)
            enc_alg = util_asn1.decode_x509_algid(enc_alg_der)
            enc_content = util_asn1.decode_object(
                enc_content_der)  # tag "cont[0]"
            if enc_ctype != 'pkcs7-data':
                raise NotImplementedError(
                    "Unimplemented PKCS#7 EncryptedData content type {}".
                    format(enc_ctype))
            print("    * encryption algorithm: {}".format(enc_alg))
            safe_contents = try_pkcs12_decrypt(enc_content,
                                               enc_alg,
                                               password,
                                               indent="    ")
            if safe_contents is not None:
                print_p12_safe_contents(safe_contents,
                                        password,
                                        show_pem=show_pem,
                                        list_only=list_only,
                                        indent="    ")
        else:
            raise NotImplementedError(
                "Unimplemented bag content type {}".format(blk_content_type))
Beispiel #4
0
def print_p12_safe_contents(safe_contents_der,
                            password,
                            show_pem=False,
                            list_only=False,
                            indent=''):
    """Parse PKCS#12 SafeContents ASN.1 data

    https://tools.ietf.org/html/rfc7292#section-4.2
        The SafeContents type is made up of SafeBags.  Each SafeBag holds one
        piece of information -- a key, a certificate, etc. -- which is
        identified by an object identifier.
    """
    # SafeContents ::= SEQUENCE OF SafeBag
    # SafeBag ::= SEQUENCE {
    #     bagId          BAG-TYPE.&id ({PKCS12BagSet})
    #     bagValue       [0] EXPLICIT BAG-TYPE.&Type({PKCS12BagSet}{@bagId}),
    #     bagAttributes  SET OF PKCS12Attribute OPTIONAL
    # }
    # PKCS12Attribute ::= SEQUENCE {
    #     attrId      ATTRIBUTE.&id ({PKCS12AttrSet}),
    #     attrValues  SET OF ATTRIBUTE.&Type ({PKCS12AttrSet}{@attrId})
    # } -- This type is compatible with the X.500 type 'Attribute'
    # PKCS12AttrSet ATTRIBUTE ::= {
    #     friendlyName | -- from PKCS #9
    #     localKeyId,    -- from PKCS #9
    #     ... -- Other attributes are allowed
    # }
    safe_bags = util_asn1.decode_sequence(safe_contents_der)
    print("{}* {} {}:".format(
        indent, len(safe_bags),
        "safe bags" if len(safe_bags) >= 2 else "safe bag"))
    for idx_safe_bag, safe_bag_der in enumerate(safe_bags):
        safe_bag = util_asn1.decode_sequence(safe_bag_der, counts=(2, 3))
        bag_id = util_asn1.decode_oid(safe_bag[0])
        bag_value = util_asn1.decode_object(safe_bag[1])
        try:
            bag_attributes = util_asn1.decode_set(
                safe_bag[2]) if len(safe_bag) >= 3 else []
        except NotImplementedError as exc:
            # Recover from error caused by old PyCrypto
            logger.warning("Unable to decode bag attributes: %s", exc)
            attr_descs = ['?']
        else:
            attr_descs = []
            for bag_attribute_der in bag_attributes:
                attr_id_der, attr_values_der = util_asn1.decode_sequence(
                    bag_attribute_der, 2)
                attr_id = util_asn1.decode_oid(attr_id_der)
                attr_values_der = util_asn1.decode_set(attr_values_der)
                attr_values = [
                    util_asn1.decode_any_string(v) for v in attr_values_der
                ]
                attr_descs.append("{}={}".format(
                    attr_id, ','.join(repr(v) for v in attr_values)))
                if attr_id == 'localKeyID' and len(attr_values) == 1:
                    m = re.match(r'^Time ([0-9]+)$', attr_values[0])
                    if m:
                        # Parse the timestamp from the local key ID
                        timestamp = int(m.group(1))
                        attr_descs.append("date='{}'".format(
                            datetime.datetime.fromtimestamp(timestamp / 1000)))
        print("{}  [{}] {} ({})".format(indent, idx_safe_bag + 1, bag_id,
                                        ', '.join(attr_descs)))

        if bag_id == 'keyBag':
            print_p12_keybag(bag_value,
                             password,
                             show_pem=show_pem,
                             list_only=list_only,
                             indent=indent + "    ")

        elif bag_id == 'certBag':
            print_p12_certBag(bag_value,
                              show_pem=show_pem,
                              list_only=list_only,
                              indent=indent + "    ")

        elif bag_id == 'secretBag':
            print_p12_secretBag(bag_value,
                                password,
                                show_pem=show_pem,
                                list_only=list_only,
                                indent=indent + "    ")

        else:
            print("{}        * bag value: {}".format(indent, repr(bag_value)))
            raise NotImplementedError("Unimplemented bag id {}".format(bag_id))