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_keybag(keybag_der,
                     password,
                     show_pem=False,
                     list_only=False,
                     indent=''):
    """Parse PKCS#12 keyBag ASN.1 data"""
    # KeyBag ::= PrivateKeyInfo -- from PKCS #8
    # EncryptedPrivateKeyInfo ::= SEQUENCE {
    #     encryptionAlgorithm  EncryptionAlgorithmIdentifier,
    #     encryptedData        EncryptedData
    # }
    # EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
    # EncryptedData ::= OCTET STRING
    enc_alg_der, enc_data_der = util_asn1.decode_sequence(keybag_der, 2)
    enc_alg = util_asn1.decode_x509_algid(enc_alg_der)
    enc_data = util_asn1.decode_octet_string(enc_data_der)
    print("{}* encryption algorithm: {}".format(indent, enc_alg))
    if not isinstance(enc_alg, util_asn1.PKCS12PbeAlg):
        raise NotImplementedError(
            "Unimplemented encryption algorithm {}".format(enc_alg))

    decrypted = try_pkcs12_decrypt(enc_data, enc_alg, password, indent=indent)
    if decrypted is not None:
        # Show the private key
        util_asn1.show_pkcs8_private_key_info(decrypted,
                                              list_only=list_only,
                                              show_pem=show_pem,
                                              indent=indent)
Beispiel #3
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 #4
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 #5
0
def print_ks_private_key(ks_content, password, offset=0, show_pem=False, list_only=False):
    """Print a private contained in a JKS or a JCEKS"""
    privkey_size, = struct.unpack('>I', ks_content[offset:offset + 4])
    offset += 4
    privkey = ks_content[offset:offset + privkey_size]
    offset += privkey_size
    print("  * private key ({} bytes)".format(len(privkey)))
    # run_process_with_input(['openssl', 'asn1parse', '-i', '-inform', 'DER'], privkey, fatal=True)

    privkey_type_der, privkey_octetstring_der = util_asn1.decode_sequence(privkey, 2)
    privkey_type_oid_der, privkey_type_params_der = util_asn1.decode_sequence(privkey_type_der)
    privkey_type_oid = util_asn1.decode_oid(privkey_type_oid_der)
    privkey_encrypted = util_asn1.decode_octet_string(privkey_octetstring_der)

    decrypted = None
    if privkey_type_oid == '1.3.6.1.4.1.42.2.17.1.1':
        # OID 1.3.6.1.4.1.42.2.17.1.1 is proprietary JavaSoft algorithm
        # {iso(1) identified-organization(3) dod(6) internet(1) private(4)
        #  enterprise(1) Sun Microsystems (42) products(2) 17 1 1}
        assert privkey_type_params_der == b'\x05\x00'  # NULL in ASN.1 DER notation
        print("    * JKS encryption")
        iv = privkey_encrypted[:20]
        integrity_hash = privkey_encrypted[-20:]
        print("    * IV: {}".format(xx(iv)))
        print("    * SHA1 hash: {}".format(xx(integrity_hash)))

        password_bytes = password.encode('utf-16be')
        keystream = []
        while len(keystream) < len(privkey_encrypted) - 40:
            iv = hashlib.sha1(password_bytes + iv).digest()
            keystream += struct.unpack('20B', iv)

        data_struct_fmt = '{}B'.format(len(privkey_encrypted) - 40)
        enc_data = struct.unpack(data_struct_fmt, privkey_encrypted[20:-20])
        decrypted = struct.pack(data_struct_fmt, *[x ^ k for x, k in zip(enc_data, keystream)])
        computed_hash = hashlib.sha1(password_bytes + decrypted).digest()
        if computed_hash != integrity_hash:
            print("    * wrong password (bad SHA1 hash)")
            decrypted = None

    elif privkey_type_oid == '1.3.6.1.4.1.42.2.19.1':
        # OID 1.3.6.1.4.1.42.2.19.1 is PBE_WITH_MD5_AND_DES3_CBC (JCEKS)
        salt_der, iterations = util_asn1.decode_sequence(privkey_type_params_der, 2)
        salt = util_asn1.decode_octet_string(salt_der)
        print("    * JCEKS encryption")
        print("    * salt ({} bytes): {}".format(len(salt), xx(salt)))
        print("    * iterations: {}".format(iterations))

        key, iv = PBEWithMD5AndTripleDES_derivation(password, salt, iterations)
        crypto_3des = Crypto.Cipher.DES3.new(key, Crypto.Cipher.DES3.MODE_CBC, iv)
        decrypted = crypto_3des.decrypt(privkey_encrypted)
        padlen, = struct.unpack('B', decrypted[-1:])
        # Check PKCS#5 padding
        if not (1 <= padlen <= 0x10) or any(x != decrypted[-1] for x in decrypted[-padlen:]):
            print("    * wrong password (bad PKCS#5 padding)")
            decrypted = None
        else:
            decrypted = decrypted[:-padlen]

    else:
        raise ValueError("Unknown private key with OID {}".format(privkey_type_oid))

    if decrypted:
        print("    (password: {})".format(repr(password)))
        # print("    (key: {})".format(xx(key)))
        # print("    (iv: {})".format(xx(iv)))
        util_asn1.show_pkcs8_private_key_info(decrypted, list_only=list_only, show_pem=show_pem, indent="    ")

    chain_length, = struct.unpack('>I', ks_content[offset:offset + 4])
    offset += 4
    for chain_index in range(chain_length):
        offset = print_ks_certificate(ks_content, offset=offset, show_pem=show_pem, list_only=list_only)
    return offset