Skip to content

lib: ecdh1 derive: is missing non-null KDF #914

@hnez

Description

@hnez

Hi,

I have been experimenting with decrypting CMS files using openssl cms, the openssl pkcs11-provider and tpm2-pkcs11, with the ultimate goal of decrypting encrypted RAUC update bundles, which use the CMS format under the hood.

With RSA based keys this works just fine and out of the box, but trying to get prime256v1 based keys to work took me down a bit of a rabbit hole.

This GitHub issue is one third a reminder for myself on how to reproduce this, one third a hint for others that are trying something similar and one third a feature request. If I find the time I will try implementing this myself.

TL;DR: decrypting a CMS file that was encrypted for a recipient with a prime256v1 public key (using default openssl settings) requires us to do an ECDH key exchange using the TPM-based private key and an ephermal key stored in the CMS file (this should already work). It then requires using SHA1 as a KDF to generate a secret of arbitrary length from the fixed-length shared secret. This is not yet implemented, resulting in CKR_MECHANISM_PARAM_INVALID being returned from derive:

if (mecha_params->kdf != CKD_NULL) {
return CKR_MECHANISM_PARAM_INVALID;
}

The tpm_ec_ecdh1_derive() function actually has support for different KDF functions and it should also be possible to perform key derivation outside the TPM since the shared secret can be read from the TPM. Implementing this may just mean forwarding the mecha_params->kdf to tpm_ec_ecdh1_derive().

Thank you to @ldts for laying the groundwork when it comes to ECDH support by the way.

How to reproduce

(This assumes that you have #913 in your tree)

$ export PKCS11_PROVIDER_MODULE=/usr/lib/pkcs11/libtpm2_pkcs11.so.0

# Generate keypair and self-signed certificate using the prime256v1
# elliptic curve.

$ pkcs11-tool \
    --module "${PKCS11_PROVIDER_MODULE}" \
    --keypairgen --login --pin 0000 \
    --label="example-key" \
    --usage-sign --usage-decrypt --usage-derive \
    --key-type EC:prime256v1

$ openssl req \
    -new -x509 \
    -provider default -provider base -provider pkcs11 \
    -days 36500 \
    -subj "/CN=example-cert" \
    -key "pkcs11:object=example-key;pin-value=0000" \
    -out example.cert.pem

$ pkcs11-tool \
    --module "${PKCS11_PROVIDER_MODULE}" \
    --login --pin 0000 \
    --label="example-key" \
    --write-object example.cert.pem --type cert

# Encrypt message using openssl cms

$ echo "Hello World" > input.txt

$ openssl cms -encrypt \
  -in input.txt \
  -out encrypted.cms.pem \
  -outform PEM \
  example.cert.pem

# Inspect CMS file

$ openssl cms -cmsout -print -inform PEM -in encrypted.cms.pem
CMS_ContentInfo:
  contentType: pkcs7-envelopedData (1.2.840.113549.1.7.3)
  d.envelopedData:
    version: 2
    originatorInfo: <ABSENT>
    recipientInfos:
      d.kari:
        version: 3
        d.originatorKey:
          algorithm:
            algorithm: id-ecPublicKey (1.2.840.10045.2.1)
            parameter: <ABSENT>
          publicKey:  (0 unused bits)
            0000 - 04 3c 99 e3 d1 d6 6a ae-70 d7 9c 17 1d 01   .<....j.p.....
            000e - 28 d4 ee 8f c9 c7 80 d2-99 4b 42 fd 73 aa   (........KB.s.
            001c - 50 12 84 e3 0c a1 30 02-47 6f 36 ce ae 17   P.....0.Go6...
            002a - 8f 7c 8b 71 c5 96 12 a9-27 e3 99 7e 24 ce   .|.q....'..~$.
            0038 - 3d 55 90 1c c3 3e 8b c8-65                  =U...>..e
        ukm: <ABSENT>
        keyEncryptionAlgorithm:
          algorithm: dhSinglePass-stdDH-sha1kdf-scheme (1.3.133.16.840.63.0.2)
          parameter: SEQUENCE:
    0:d=0  hl=2 l=  15 cons: SEQUENCE
    2:d=1  hl=2 l=  11 prim:  OBJECT            :id-smime-alg-CMS3DESwrap
   15:d=1  hl=2 l=   0 prim:  NULL
        recipientEncryptedKeys:
            d.issuerAndSerialNumber:
              issuer: CN=example-cert
              serialNumber: 0x5FC0C5FE9943F656D5380893B39A1239AACF0632
            encryptedKey:
              0000 - 08 a3 ea 77 27 81 68 65-3b 09 f1 df 65 75   ...w'.he;...eu
              000e - 04 f2 20 30 6a d3 5b 12-be 7d a2 1c a9 d4   .. 0j.[..}....
              001c - fa 41 03 78 27 d9 fc 36-72 7d 73 ed         .A.x'..6r}s.
    encryptedContentInfo:
      contentType: pkcs7-data (1.2.840.113549.1.7.1)
      contentEncryptionAlgorithm:
        algorithm: des-ede3-cbc (1.2.840.113549.3.7)
        parameter: OCTET STRING:
          0000 - f7 1d 17 94 69 84 6c c2-                       ....i.l.
      encryptedContent:
        0000 - 89 ab 4b 4f 3e b5 74 cf-ad 9a 85 ec b2 c9 b3   ..KO>.t........
        000f - da                                             .
    unprotectedAttrs:
      <ABSENT>

# Decrypt message

$ openssl cms -decrypt \
  -in encrypted.cms.pem \
  -out output.txt \
  -inform PEM \
  -provider default -provider base -provider pkcs11 \
  -inkey 'pkcs11:object=example-key;pin-value=0000' \
  -recip example.cert.pem
Error decrypting CMS using private key
40177724967F0000:error:41000054:pkcs11:cache_key:reason(84):../pkcs11-provider-1.1.0/src/objects.c:405:Failed to cache key

The error message is in fact a bit confusing, but by using TPM2_PKCS11_LOG_LEVEL=2 we can see that CKR_MECHANISM_PARAM_INVALID is in fact returned.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions