-
Notifications
You must be signed in to change notification settings - Fork 117
Description
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:
Lines 196 to 198 in 8a37809
| 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 keyThe 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.