cencryptionopensslpkcs#12openssl-engine

OpenSSL debugging - how to dump intermediate ASN.1 inside openssl?


I have a PKCS#12 test file with a single entry encrypted with PBES2 (PBEWithHmacSHA256AndAES_256) that is not working inside OpenSSL (but works elsewhere).

So I'm trying to figure out if my file is broken or if OpenSSL is unable to handle PBES2 properly.

The file is attached: test.p12 (pass:test)

The output from openssl pkcs12 (v.1.0.2p-dev) is:

$ openssl pkcs12 -info -nodes -in out.p12 -passin pass:test
MAC Iteration 100000
MAC verified OK
PKCS7 Data
Shrouded Keybag: PBES2<unsupported parameters>
Bag Attributes
    friendlyName: test
    localKeyID: 54 69 6D 65 20 31 35 33 30 38 32 31 38 34 39 32 39 39
Error outputting keys and certificates
10564:error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag:.\crypto\asn1\tasn_dec.c:1220:
10564:error:0D07803A:asn1 encoding routines:ASN1_ITEM_EX_D2I:nested asn1 error:.\crypto\asn1\tasn_dec.c:386:Type=X509_ALGOR
10564:error:0D08303A:asn1 encoding routines:ASN1_TEMPLATE_NOEXP_D2I:nested asn1 error:.\crypto\asn1\tasn_dec.c:720:Field=keyfunc, Type=PBE2PARAM

I've traced it to these lines in pkcs12.c:

if (pbenid == NID_pbes2) {
    PBE2PARAM *pbe2 = NULL;
    int encnid;
    if (aparamtype == V_ASN1_SEQUENCE)
        pbe2 = ASN1_item_unpack(aparam, ASN1_ITEM_rptr(PBE2PARAM)); // <=== fails here
    if (pbe2 == NULL) {
        BIO_puts(x, "<unsupported parameters>");
        goto done;
    }

Hence my main question: what's the best way to debug this further?

I've been thinking about two approaches:

  1. Inspect the ASN.1 fragment while inside ASN1_item_unpack() (how?)
  2. Get the decrypted PKCS#12 stream and run asn1parse on it (how?)

Solution

  • TLDR: your file is broken.

    You can't decrypt that portion of the file because of the error, but you don't need to because the encryption parameters are unencrypted, precisely because the decrypter needs to parse them before it can decrypt, and we can mimic that with commandline asn1parse. First parse the outer structure:

    $ openssl asn1parse -in test.p12 -inform der -i 
        0:d=0  hl=4 l=2450 cons: SEQUENCE
        4:d=1  hl=2 l=   1 prim:  INTEGER           :03
        7:d=1  hl=4 l=2379 cons:  SEQUENCE
       11:d=2  hl=2 l=   9 prim:   OBJECT            :pkcs7-data
       22:d=2  hl=4 l=2364 cons:   cont [ 0 ]
       26:d=3  hl=4 l=2360 prim:    OCTET STRING      [HEX DUMP]:308209343[REDACTED]
     2390:d=1  hl=2 l=  62 cons:  SEQUENCE
     2392:d=2  hl=2 l=  33 cons:   SEQUENCE
     2394:d=3  hl=2 l=   9 cons:    SEQUENCE
     2396:d=4  hl=2 l=   5 prim:     OBJECT            :sha1
     2403:d=4  hl=2 l=   0 prim:     NULL
     2405:d=3  hl=2 l=  20 prim:    OCTET STRING      [HEX DUMP]:17774B593A099F0332A817D2510FE15A0C699159
     2427:d=2  hl=2 l=  20 prim:   OCTET STRING      [HEX DUMP]:814F2DB1C2EBCB64D38CD56881BC9AC2FD2936FB
     2449:d=2  hl=2 l=   3 prim:   INTEGER           :0186A0
    

    which correctly matches PFX from rfc2898 section 4. All of the useful content is in the contentinfo, at 26+4=30, so parse that:

    $ openssl asn1parse -in test.p12 -inform der -i -strparse 30
        0:d=0  hl=4 l=2356 cons: SEQUENCE
        4:d=1  hl=4 l=1464 cons:  SEQUENCE
        8:d=2  hl=2 l=   9 prim:   OBJECT            :pkcs7-data
       19:d=2  hl=4 l=1449 cons:   cont [ 0 ]
       23:d=3  hl=4 l=1445 prim:    OCTET STRING      [HEX DUMP]:308205A1[REDACTED]
     1472:d=1  hl=4 l= 884 cons:  SEQUENCE
     1476:d=2  hl=2 l=   9 prim:   OBJECT            :pkcs7-encryptedData
     1487:d=2  hl=4 l= 869 cons:   cont [ 0 ]
     1491:d=3  hl=4 l= 865 cons:    SEQUENCE
     1495:d=4  hl=2 l=   1 prim:     INTEGER           :00
     1498:d=4  hl=4 l= 858 cons:     SEQUENCE
     1502:d=5  hl=2 l=   9 prim:      OBJECT            :pkcs7-data
     1513:d=5  hl=2 l=  41 cons:      SEQUENCE
     1515:d=6  hl=2 l=  10 prim:       OBJECT            :pbeWithSHA1And40BitRC2-CBC
     1527:d=6  hl=2 l=  27 cons:       SEQUENCE
     1529:d=7  hl=2 l=  20 prim:        OCTET STRING      [HEX DUMP]:B74DD380AAF9CBE6A327F74BC93C688A5E690AC2
     1551:d=7  hl=2 l=   3 prim:        INTEGER           :C350
     1556:d=5  hl=4 l= 800 prim:      cont [ 0 ]
    

    This has two 'bags': the Data at 30+4 actually contains the ShroudedKeyBag and the EncryptedData at 30+1472 is the cert bag, which is standard and I ignore. Breaking down the ShroudedKeyBag:

    $ openssl asn1parse -in test.p12 -inform der -i -strparse 57
        0:d=0  hl=4 l=1441 cons: SEQUENCE
        4:d=1  hl=4 l=1437 cons:  SEQUENCE
        8:d=2  hl=2 l=  11 prim:   OBJECT            :pkcs8ShroudedKeyBag
       21:d=2  hl=4 l=1358 cons:   cont [ 0 ]
       25:d=3  hl=4 l=1354 cons:    SEQUENCE
       29:d=4  hl=2 l= 116 cons:     SEQUENCE
       31:d=5  hl=2 l=   9 prim:      OBJECT            :PBES2
       42:d=5  hl=2 l= 103 cons:      SEQUENCE
       44:d=6  hl=2 l=   9 prim:       OBJECT            :PBES2
       55:d=6  hl=2 l=  90 cons:       SEQUENCE
       57:d=7  hl=2 l=  57 cons:        SEQUENCE
       59:d=8  hl=2 l=   9 prim:         OBJECT            :PBKDF2
       70:d=8  hl=2 l=  44 cons:         SEQUENCE
       72:d=9  hl=2 l=  20 prim:          OCTET STRING      [HEX DUMP]:547DFCB4975830F2A455BE611128B2188BB237E
       94:d=9  hl=2 l=   3 prim:          INTEGER           :0186A0
       99:d=9  hl=2 l=   1 prim:          INTEGER           :20
      102:d=9  hl=2 l=  12 cons:          SEQUENCE
      104:d=10 hl=2 l=   8 prim:           OBJECT            :hmacWithSHA256
      114:d=10 hl=2 l=   0 prim:           NULL
      116:d=7  hl=2 l=  29 cons:        SEQUENCE
      118:d=8  hl=2 l=   9 prim:         OBJECT            :aes-256-cbc
      129:d=8  hl=2 l=  16 prim:         OCTET STRING      [HEX DUMP]:12A6696B879EFB885F7C979904314FC
      147:d=4  hl=4 l=1232 prim:     OCTET STRING      [HEX DUMP]:[REDACTED]
     1383:d=2  hl=2 l=  60 cons:   SET
     1385:d=3  hl=2 l=  23 cons:    SEQUENCE
     1387:d=4  hl=2 l=   9 prim:     OBJECT            :friendlyName
     1398:d=4  hl=2 l=  10 cons:     SET
     1400:d=5  hl=2 l=   8 prim:      BMPSTRING
     1410:d=3  hl=2 l=  33 cons:    SEQUENCE
     1412:d=4  hl=2 l=   9 prim:     OBJECT            :localKeyID
     1423:d=4  hl=2 l=  20 cons:     SET
     1425:d=5  hl=2 l=  18 prim:      OCTET STRING      :Time 1530821849299
    

    The value (ignoring the attributes, which look okay) of a ShroudedKeyBag (4.2 and 4.2.2) should be a PKCS8 EncryptedPrivateKeyInfo from rfc 5208 section 6:

      EncryptedPrivateKeyInfo ::= SEQUENCE {
        encryptionAlgorithm  EncryptionAlgorithmIdentifier,
        encryptedData        EncryptedData }
      EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
      EncryptedData ::= OCTET STRING
    

    And since the identified algorithm is PBES2, its parameters at 30+27+42 should be PBES2-params from rfc2898 appendix A.4:

    PBES2-params ::= SEQUENCE {
       keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
       encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} }
    

    However, you can see what is actually present there is a SEQUENCE containing (OID) PBES2 and the correct PBES2-params structure, i.e. it is nested a level too deep. It appears something actually constructed the PBES2 AlgorithmIdentifier and then used it as the parameters of a second PBES2 AlgorithmIdentifier, which is wrong.

    However, since the intent is clear, we can (manually) compute PBKDF2 salt=547DFCB49758030F2A455BE611128B2188BB237E iter=100000 size=32 alg=hmacSHA256 of pass=test giving key 2E896C4F2D9549FD D2BE8B8F895D7C56 DD9008A6D7B7196E 1A30000F7F545B37 and use that with AES-256-CBC (with PKCS7padding) IV=12A6696B879EFCB885F7C979904314FC to decrypt the RSA key:

    $ dd if=test.p12 bs=1 skip=208 count=1232 | \
    > openssl aes-256-cbc -d -K 2E896C4F2D9549FDD2BE8B8F895D7C56DD9008A6D7B7196E1A30000F7F545B37 -iv 12A6696B879EFCB885F7C979904314FC >test.out
    $ openssl pkey -in test.out -inform der -text -noout 
    Private-Key: (2048 bit)
    modulus:
        00:d5:a7:ef:74:dd:ab:60:12:69:0d:dd:29:61:f7:
        0b:46:27:8d:c6:c3:5c:a6:b0:0e:59:01:d3:ff:65:
    [rest redacted]
    

    Since the cert bag is correctly formatted (and encrypted), it can be read with simply:

    $ openssl pkcs12 -in test.p12 -passin pass:test -nokeys
    MAC verified OK
    Bag Attributes
        friendlyName: test
        localKeyID: 54 69 6D 65 20 31 35 33 30 38 32 31 38 34 39 32 39 39
    subject=/CN=test
    issuer=/CN=test
    -----BEGIN CERTIFICATE-----
    MIICrDCCAZSgAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDDAR0ZXN0
    MB4XDTE4MDcwNTIwMTcyOVoXDTE5MDcwNTIwMTcyOVowDzENMAsGA1UEAwwEdGVz
    dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANWn73Tdq2ASaQ3dKWH3
    C0YnjcbDXKawDlkB0/9l53T4kQgy/CCsCPbv+LpcOLWIw61rPVzjlWTmg384GqAF
    s7Ewn98v8JsxKw7HXeYCvw+li2x3Y+DVtkqWchnsJWnmksXAynQnrhb2ayczM+YR
    OGli0Yvs6pQKNDuRKXrL2/cX212wFC42QE0NxfSblUdxrl2x4INqg9ME0fsHc2TO
    lt3JItxGK7vQkU/tNIOlhKOWUxt9lVPNaIGFW0w2CkGxV1HYGRy8VCDqAfsI4x18
    4WJTPTXjQ+EMl1yu5jPuRNdt7Gzvhll9O6LRUsJ2fNXAeQl7wOG/xZ9Rf73q1aTp
    CBECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEA
    UL2dfILp69CBPF8DD8Pzso6QIcMDtBltXumv2/NL/YO1SXY3Rt3LZ4EJtrYvb/H3
    E3fH8qT9Yhfcrz+0F1aFt0WCdcOWDtZ5s7pn36a3Wye9LoBjPcB36BttzaBku+49
    PIOQwQGjc6vg3prFS/OBOpWsa94GZemI4xpfwHE2EXANKN4ufb9fyPRyrXGR8SQD
    3EdejRwLuICvxS/u8wO4+SfiHGLuR/i+w74nQeMsyrphWtPs9cDe4NMMN0I6WGKA
    u9XeWzxSmEswYmmm2y/KX+fVmeNoKbht5Oiaej9aVFS77hT/OdjO281R/1osIdPi
    8EJw1sCq5Tk7jkWxxZh+6Q==
    -----END CERTIFICATE-----
    

    QEF.