def parse_pkcs12(data, password=None):
if not isinstance(data, byte_cls):<EOL><INDENT>raise TypeError(pretty_message(<EOL>'''<STR_LIT>''',<EOL>type_name(data)<EOL>))<EOL><DEDENT>if password is not None:<EOL><INDENT>if not isinstance(password, byte_cls):<EOL><INDENT>raise TypeError(pretty_message(<EOL>'''<STR_LIT>''',<EOL>type_name(password)<EOL>))<EOL><DEDENT><DEDENT>else:<EOL><INDENT>password = b'<STR_LIT>'<EOL><DEDENT>certs = {}<EOL>private_keys = {}<EOL>pfx = pkcs12.Pfx.load(data)<EOL>auth_safe = pfx['<STR_LIT>']<EOL>if auth_safe['<STR_LIT>'].native != '<STR_LIT:data>':<EOL><INDENT>raise ValueError(pretty_message(<EOL>'''<STR_LIT>'''<EOL>))<EOL><DEDENT>authenticated_safe = pfx.authenticated_safe<EOL>mac_data = pfx['<STR_LIT>']<EOL>if mac_data:<EOL><INDENT>mac_algo = mac_data['<STR_LIT>']['<STR_LIT>']['<STR_LIT>'].native<EOL>key_length = {<EOL>'<STR_LIT>': <NUM_LIT:20>,<EOL>'<STR_LIT>': <NUM_LIT>,<EOL>'<STR_LIT>': <NUM_LIT:32>,<EOL>'<STR_LIT>': <NUM_LIT>,<EOL>'<STR_LIT>': <NUM_LIT:64>,<EOL>'<STR_LIT>': <NUM_LIT>,<EOL>'<STR_LIT>': <NUM_LIT:32>,<EOL>}[mac_algo]<EOL>mac_key = pkcs12_kdf(<EOL>mac_algo,<EOL>password,<EOL>mac_data['<STR_LIT>'].native,<EOL>mac_data['<STR_LIT>'].native,<EOL>key_length,<EOL><NUM_LIT:3>  <EOL>)<EOL>hash_mod = getattr(hashlib, mac_algo)<EOL>computed_hmac = hmac.new(mac_key, auth_safe['<STR_LIT:content>'].contents, hash_mod).digest()<EOL>stored_hmac = mac_data['<STR_LIT>']['<STR_LIT>'].native<EOL>if not constant_compare(computed_hmac, stored_hmac):<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT><DEDENT>for content_info in authenticated_safe:<EOL><INDENT>content = content_info['<STR_LIT:content>']<EOL>if isinstance(content, core.OctetString):<EOL><INDENT>_parse_safe_contents(content.native, certs, private_keys, password)<EOL><DEDENT>elif isinstance(content, cms.EncryptedData):<EOL><INDENT>encrypted_content_info = content['<STR_LIT>']<EOL>encryption_algorithm_info = encrypted_content_info['<STR_LIT>']<EOL>encrypted_content = encrypted_content_info['<STR_LIT>'].native<EOL>decrypted_content = _decrypt_encrypted_data(encryption_algorithm_info, encrypted_content, password)<EOL>_parse_safe_contents(decrypted_content, certs, private_keys, password)<EOL><DEDENT>else:<EOL><INDENT>raise ValueError(pretty_message(<EOL>'''<STR_LIT>'''<EOL>))<EOL><DEDENT><DEDENT>key_fingerprints = set(private_keys.keys())<EOL>cert_fingerprints = set(certs.keys())<EOL>common_fingerprints = sorted(list(key_fingerprints & cert_fingerprints))<EOL>key = None<EOL>cert = None<EOL>other_certs = []<EOL>if len(common_fingerprints) >= <NUM_LIT:1>:<EOL><INDENT>fingerprint = common_fingerprints[<NUM_LIT:0>]<EOL>key = private_keys[fingerprint]<EOL>cert = certs[fingerprint]<EOL>other_certs = [certs[f] for f in certs if f != fingerprint]<EOL>return (key, cert, other_certs)<EOL><DEDENT>if len(private_keys) > <NUM_LIT:0>:<EOL><INDENT>first_key = sorted(list(private_keys.keys()))[<NUM_LIT:0>]<EOL>key = private_keys[first_key]<EOL><DEDENT>if len(certs) > <NUM_LIT:0>:<EOL><INDENT>first_key = sorted(list(certs.keys()))[<NUM_LIT:0>]<EOL>cert = certs[first_key]<EOL>del certs[first_key]<EOL><DEDENT>if len(certs) > <NUM_LIT:0>:<EOL><INDENT>other_certs = sorted(list(certs.values()))<EOL><DEDENT>return (key, cert, other_certs)<EOL>
Parses a PKCS#12 ANS.1 DER-encoded structure and extracts certs and keys

:param data:
    A byte string of a DER-encoded PKCS#12 file

:param password:
    A byte string of the password to any encrypted data

:raises:
    ValueError - when any of the parameters are of the wrong type or value
    OSError - when an error is returned by one of the OS decryption functions

:return:
    A three-element tuple of:
     1. An asn1crypto.keys.PrivateKeyInfo object
     2. An asn1crypto.x509.Certificate object
     3. A list of zero or more asn1crypto.x509.Certificate objects that are
        "extra" certificates, possibly intermediates from the cert chain