xref: /openbsd/lib/libcrypto/cms/cms_kari.c (revision b8a66e7e)
1 /* $OpenBSD: cms_kari.c,v 1.17 2024/11/01 18:34:06 tb Exp $ */
2 /*
3  * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
4  * project.
5  */
6 /* ====================================================================
7  * Copyright (c) 2013 The OpenSSL Project.  All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in
18  *    the documentation and/or other materials provided with the
19  *    distribution.
20  *
21  * 3. All advertising materials mentioning features or use of this
22  *    software must display the following acknowledgment:
23  *    "This product includes software developed by the OpenSSL Project
24  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25  *
26  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27  *    endorse or promote products derived from this software without
28  *    prior written permission. For written permission, please contact
29  *    licensing@OpenSSL.org.
30  *
31  * 5. Products derived from this software may not be called "OpenSSL"
32  *    nor may "OpenSSL" appear in their names without prior written
33  *    permission of the OpenSSL Project.
34  *
35  * 6. Redistributions of any form whatsoever must retain the following
36  *    acknowledgment:
37  *    "This product includes software developed by the OpenSSL Project
38  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39  *
40  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
44  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51  * OF THE POSSIBILITY OF SUCH DAMAGE.
52  * ====================================================================
53  */
54 
55 #include <stdlib.h>
56 #include <string.h>
57 
58 #include <openssl/asn1.h>
59 #include <openssl/cms.h>
60 #include <openssl/err.h>
61 #include <openssl/evp.h>
62 
63 #include "cms_local.h"
64 
65 /* Key Agreement Recipient Info (KARI) routines */
66 
67 int
CMS_RecipientInfo_kari_get0_alg(CMS_RecipientInfo * ri,X509_ALGOR ** palg,ASN1_OCTET_STRING ** pukm)68 CMS_RecipientInfo_kari_get0_alg(CMS_RecipientInfo *ri, X509_ALGOR **palg,
69     ASN1_OCTET_STRING **pukm)
70 {
71 	if (ri->type != CMS_RECIPINFO_AGREE) {
72 		CMSerror(CMS_R_NOT_KEY_AGREEMENT);
73 		return 0;
74 	}
75 	if (palg)
76 		*palg = ri->d.kari->keyEncryptionAlgorithm;
77 	if (pukm)
78 		*pukm = ri->d.kari->ukm;
79 
80 	return 1;
81 }
82 LCRYPTO_ALIAS(CMS_RecipientInfo_kari_get0_alg);
83 
84 /* Retrieve recipient encrypted keys from a kari */
85 
STACK_OF(CMS_RecipientEncryptedKey)86 STACK_OF(CMS_RecipientEncryptedKey) *
87 CMS_RecipientInfo_kari_get0_reks(CMS_RecipientInfo *ri)
88 {
89 	if (ri->type != CMS_RECIPINFO_AGREE) {
90 		CMSerror(CMS_R_NOT_KEY_AGREEMENT);
91 		return NULL;
92 	}
93 	return ri->d.kari->recipientEncryptedKeys;
94 }
95 LCRYPTO_ALIAS(CMS_RecipientInfo_kari_get0_reks);
96 
97 int
CMS_RecipientInfo_kari_get0_orig_id(CMS_RecipientInfo * ri,X509_ALGOR ** pubalg,ASN1_BIT_STRING ** pubkey,ASN1_OCTET_STRING ** keyid,X509_NAME ** issuer,ASN1_INTEGER ** sno)98 CMS_RecipientInfo_kari_get0_orig_id(CMS_RecipientInfo *ri, X509_ALGOR **pubalg,
99     ASN1_BIT_STRING **pubkey, ASN1_OCTET_STRING **keyid, X509_NAME **issuer,
100     ASN1_INTEGER **sno)
101 {
102 	CMS_OriginatorIdentifierOrKey *oik;
103 
104 	if (ri->type != CMS_RECIPINFO_AGREE) {
105 		CMSerror(CMS_R_NOT_KEY_AGREEMENT);
106 		return 0;
107 	}
108 	oik = ri->d.kari->originator;
109 	if (issuer)
110 		*issuer = NULL;
111 	if (sno)
112 		*sno = NULL;
113 	if (keyid)
114 		*keyid = NULL;
115 	if (pubalg)
116 		*pubalg = NULL;
117 	if (pubkey)
118 		*pubkey = NULL;
119 	if (oik->type == CMS_OIK_ISSUER_SERIAL) {
120 		if (issuer)
121 			*issuer = oik->d.issuerAndSerialNumber->issuer;
122 		if (sno)
123 			*sno = oik->d.issuerAndSerialNumber->serialNumber;
124 	} else if (oik->type == CMS_OIK_KEYIDENTIFIER) {
125 		if (keyid)
126 			*keyid = oik->d.subjectKeyIdentifier;
127 	} else if (oik->type == CMS_OIK_PUBKEY) {
128 		if (pubalg)
129 			*pubalg = oik->d.originatorKey->algorithm;
130 		if (pubkey)
131 			*pubkey = oik->d.originatorKey->publicKey;
132 	} else
133 		return 0;
134 
135 	return 1;
136 }
137 LCRYPTO_ALIAS(CMS_RecipientInfo_kari_get0_orig_id);
138 
139 int
CMS_RecipientInfo_kari_orig_id_cmp(CMS_RecipientInfo * ri,X509 * cert)140 CMS_RecipientInfo_kari_orig_id_cmp(CMS_RecipientInfo *ri, X509 *cert)
141 {
142 	CMS_OriginatorIdentifierOrKey *oik;
143 
144 	if (ri->type != CMS_RECIPINFO_AGREE) {
145 		CMSerror(CMS_R_NOT_KEY_AGREEMENT);
146 		return -2;
147 	}
148 	oik = ri->d.kari->originator;
149 	if (oik->type == CMS_OIK_ISSUER_SERIAL)
150 		return cms_ias_cert_cmp(oik->d.issuerAndSerialNumber, cert);
151 	else if (oik->type == CMS_OIK_KEYIDENTIFIER)
152 		return cms_keyid_cert_cmp(oik->d.subjectKeyIdentifier, cert);
153 
154 	return -1;
155 }
156 LCRYPTO_ALIAS(CMS_RecipientInfo_kari_orig_id_cmp);
157 
158 int
CMS_RecipientEncryptedKey_get0_id(CMS_RecipientEncryptedKey * rek,ASN1_OCTET_STRING ** keyid,ASN1_GENERALIZEDTIME ** tm,CMS_OtherKeyAttribute ** other,X509_NAME ** issuer,ASN1_INTEGER ** sno)159 CMS_RecipientEncryptedKey_get0_id(CMS_RecipientEncryptedKey *rek,
160     ASN1_OCTET_STRING **keyid, ASN1_GENERALIZEDTIME **tm,
161     CMS_OtherKeyAttribute **other, X509_NAME **issuer, ASN1_INTEGER **sno)
162 {
163 	CMS_KeyAgreeRecipientIdentifier *rid = rek->rid;
164 
165 	if (rid->type == CMS_REK_ISSUER_SERIAL) {
166 		if (issuer)
167 			*issuer = rid->d.issuerAndSerialNumber->issuer;
168 		if (sno)
169 			*sno = rid->d.issuerAndSerialNumber->serialNumber;
170 		if (keyid)
171 			*keyid = NULL;
172 		if (tm)
173 			*tm = NULL;
174 		if (other)
175 			*other = NULL;
176 	} else if (rid->type == CMS_REK_KEYIDENTIFIER) {
177 		if (keyid)
178 			*keyid = rid->d.rKeyId->subjectKeyIdentifier;
179 		if (tm)
180 			*tm = rid->d.rKeyId->date;
181 		if (other)
182 			*other = rid->d.rKeyId->other;
183 		if (issuer)
184 			*issuer = NULL;
185 		if (sno)
186 			*sno = NULL;
187 	} else
188 		return 0;
189 
190 	return 1;
191 }
192 LCRYPTO_ALIAS(CMS_RecipientEncryptedKey_get0_id);
193 
194 int
CMS_RecipientEncryptedKey_cert_cmp(CMS_RecipientEncryptedKey * rek,X509 * cert)195 CMS_RecipientEncryptedKey_cert_cmp(CMS_RecipientEncryptedKey *rek, X509 *cert)
196 {
197 	CMS_KeyAgreeRecipientIdentifier *rid = rek->rid;
198 
199 	if (rid->type == CMS_REK_ISSUER_SERIAL)
200 		return cms_ias_cert_cmp(rid->d.issuerAndSerialNumber, cert);
201 	else if (rid->type == CMS_REK_KEYIDENTIFIER)
202 		return cms_keyid_cert_cmp(rid->d.rKeyId->subjectKeyIdentifier, cert);
203 	else
204 		return -1;
205 }
206 LCRYPTO_ALIAS(CMS_RecipientEncryptedKey_cert_cmp);
207 
208 int
CMS_RecipientInfo_kari_set0_pkey(CMS_RecipientInfo * ri,EVP_PKEY * pk)209 CMS_RecipientInfo_kari_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pk)
210 {
211 	EVP_PKEY_CTX *pctx;
212 	CMS_KeyAgreeRecipientInfo *kari = ri->d.kari;
213 
214 	EVP_PKEY_CTX_free(kari->pctx);
215 	kari->pctx = NULL;
216 	if (!pk)
217 		return 1;
218 	pctx = EVP_PKEY_CTX_new(pk, NULL);
219 	if (!pctx || !EVP_PKEY_derive_init(pctx))
220 		goto err;
221 	kari->pctx = pctx;
222 	return 1;
223 
224  err:
225 	EVP_PKEY_CTX_free(pctx);
226 	return 0;
227 }
228 LCRYPTO_ALIAS(CMS_RecipientInfo_kari_set0_pkey);
229 
230 EVP_CIPHER_CTX *
CMS_RecipientInfo_kari_get0_ctx(CMS_RecipientInfo * ri)231 CMS_RecipientInfo_kari_get0_ctx(CMS_RecipientInfo *ri)
232 {
233 	if (ri->type == CMS_RECIPINFO_AGREE)
234 		return ri->d.kari->ctx;
235 	return NULL;
236 }
237 LCRYPTO_ALIAS(CMS_RecipientInfo_kari_get0_ctx);
238 
239 /*
240  * Derive KEK and decrypt/encrypt with it to produce either the original CEK
241  * or the encrypted CEK.
242  */
243 
244 static int
cms_kek_cipher(unsigned char ** pout,size_t * poutlen,const unsigned char * in,size_t inlen,CMS_KeyAgreeRecipientInfo * kari,int enc)245 cms_kek_cipher(unsigned char **pout, size_t *poutlen, const unsigned char *in,
246     size_t inlen, CMS_KeyAgreeRecipientInfo *kari, int enc)
247 {
248 	/* Key encryption key */
249 	unsigned char kek[EVP_MAX_KEY_LENGTH];
250 	size_t keklen;
251 	int rv = 0;
252 	unsigned char *out = NULL;
253 	int outlen;
254 
255 	keklen = EVP_CIPHER_CTX_key_length(kari->ctx);
256 	if (keklen > EVP_MAX_KEY_LENGTH)
257 		return 0;
258 	/* Derive KEK */
259 	if (EVP_PKEY_derive(kari->pctx, kek, &keklen) <= 0)
260 		goto err;
261 	/* Set KEK in context */
262 	if (!EVP_CipherInit_ex(kari->ctx, NULL, NULL, kek, NULL, enc))
263 		goto err;
264 	/* obtain output length of ciphered key */
265 	if (!EVP_CipherUpdate(kari->ctx, NULL, &outlen, in, inlen))
266 		goto err;
267 	out = malloc(outlen);
268 	if (out == NULL)
269 		goto err;
270 	if (!EVP_CipherUpdate(kari->ctx, out, &outlen, in, inlen))
271 		goto err;
272 	*pout = out;
273 	*poutlen = (size_t)outlen;
274 	rv = 1;
275 
276  err:
277 	explicit_bzero(kek, keklen);
278 	if (!rv)
279 		free(out);
280 	(void)EVP_CIPHER_CTX_reset(kari->ctx);
281 	/* FIXME: WHY IS kari->pctx freed here?  /RL */
282 	EVP_PKEY_CTX_free(kari->pctx);
283 	kari->pctx = NULL;
284 
285 	return rv;
286 }
287 
288 int
CMS_RecipientInfo_kari_decrypt(CMS_ContentInfo * cms,CMS_RecipientInfo * ri,CMS_RecipientEncryptedKey * rek)289 CMS_RecipientInfo_kari_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri,
290     CMS_RecipientEncryptedKey *rek)
291 {
292 	int rv = 0;
293 	unsigned char *enckey = NULL, *cek = NULL;
294 	size_t enckeylen;
295 	size_t ceklen;
296 	CMS_EncryptedContentInfo *ec;
297 
298 	enckeylen = rek->encryptedKey->length;
299 	enckey = rek->encryptedKey->data;
300 	/* Setup all parameters to derive KEK */
301 	if (!cms_env_asn1_ctrl(ri, 1))
302 		goto err;
303 	/* Attempt to decrypt CEK */
304 	if (!cms_kek_cipher(&cek, &ceklen, enckey, enckeylen, ri->d.kari, 0))
305 		goto err;
306 	ec = cms->d.envelopedData->encryptedContentInfo;
307 	freezero(ec->key, ec->keylen);
308 	ec->key = cek;
309 	ec->keylen = ceklen;
310 	cek = NULL;
311 	rv = 1;
312 
313  err:
314 	free(cek);
315 
316 	return rv;
317 }
318 LCRYPTO_ALIAS(CMS_RecipientInfo_kari_decrypt);
319 
320 /* Create ephemeral key and initialise context based on it */
321 static int
cms_kari_create_ephemeral_key(CMS_KeyAgreeRecipientInfo * kari,EVP_PKEY * pk)322 cms_kari_create_ephemeral_key(CMS_KeyAgreeRecipientInfo *kari, EVP_PKEY *pk)
323 {
324 	EVP_PKEY_CTX *pctx = NULL;
325 	EVP_PKEY *ekey = NULL;
326 	int rv = 0;
327 
328 	pctx = EVP_PKEY_CTX_new(pk, NULL);
329 	if (!pctx)
330 		goto err;
331 	if (EVP_PKEY_keygen_init(pctx) <= 0)
332 		goto err;
333 	if (EVP_PKEY_keygen(pctx, &ekey) <= 0)
334 		goto err;
335 	EVP_PKEY_CTX_free(pctx);
336 	pctx = EVP_PKEY_CTX_new(ekey, NULL);
337 	if (!pctx)
338 		goto err;
339 	if (EVP_PKEY_derive_init(pctx) <= 0)
340 		goto err;
341 	kari->pctx = pctx;
342 	rv = 1;
343 
344  err:
345 	if (!rv)
346 		EVP_PKEY_CTX_free(pctx);
347 	EVP_PKEY_free(ekey);
348 
349 	return rv;
350 }
351 
352 /* Initialise a kari based on passed certificate and key */
353 
354 int
cms_RecipientInfo_kari_init(CMS_RecipientInfo * ri,X509 * recip,EVP_PKEY * pk,unsigned int flags)355 cms_RecipientInfo_kari_init(CMS_RecipientInfo *ri, X509 *recip, EVP_PKEY *pk,
356     unsigned int flags)
357 {
358 	CMS_KeyAgreeRecipientInfo *kari;
359 	CMS_RecipientEncryptedKey *rek = NULL;
360 
361 	ri->d.kari = (CMS_KeyAgreeRecipientInfo *)ASN1_item_new(&CMS_KeyAgreeRecipientInfo_it);
362 	if (!ri->d.kari)
363 		return 0;
364 	ri->type = CMS_RECIPINFO_AGREE;
365 
366 	kari = ri->d.kari;
367 	kari->version = 3;
368 
369 	rek = (CMS_RecipientEncryptedKey *)ASN1_item_new(&CMS_RecipientEncryptedKey_it);
370 	if (rek == NULL)
371 		return 0;
372 
373 	if (!sk_CMS_RecipientEncryptedKey_push(kari->recipientEncryptedKeys, rek)) {
374 		ASN1_item_free((ASN1_VALUE *)rek, &CMS_RecipientEncryptedKey_it);
375 		return 0;
376 	}
377 
378 	if (flags & CMS_USE_KEYID) {
379 		rek->rid->type = CMS_REK_KEYIDENTIFIER;
380 		rek->rid->d.rKeyId = (CMS_RecipientKeyIdentifier *)ASN1_item_new(&CMS_RecipientKeyIdentifier_it);
381 		if (rek->rid->d.rKeyId == NULL)
382 			return 0;
383 		if (!cms_set1_keyid(&rek->rid->d.rKeyId->subjectKeyIdentifier, recip))
384 			return 0;
385 	} else {
386 		rek->rid->type = CMS_REK_ISSUER_SERIAL;
387 		if (!cms_set1_ias(&rek->rid->d.issuerAndSerialNumber, recip))
388 			return 0;
389 	}
390 
391 	/* Create ephemeral key */
392 	if (!cms_kari_create_ephemeral_key(kari, pk))
393 		return 0;
394 
395 	EVP_PKEY_up_ref(pk);
396 	rek->pkey = pk;
397 
398 	return 1;
399 }
400 
401 static int
cms_wrap_init(CMS_KeyAgreeRecipientInfo * kari,const EVP_CIPHER * cipher)402 cms_wrap_init(CMS_KeyAgreeRecipientInfo *kari, const EVP_CIPHER *cipher)
403 {
404 	EVP_CIPHER_CTX *ctx = kari->ctx;
405 	const EVP_CIPHER *kekcipher;
406 	int keylen = EVP_CIPHER_key_length(cipher);
407 
408 	/* If a suitable wrap algorithm is already set nothing to do */
409 	kekcipher = EVP_CIPHER_CTX_cipher(ctx);
410 
411 	if (kekcipher) {
412 		if (EVP_CIPHER_CTX_mode(ctx) != EVP_CIPH_WRAP_MODE)
413 			return 0;
414 		return 1;
415 	}
416 	/*
417 	 * Pick a cipher based on content encryption cipher. If it is DES3 use
418 	 * DES3 wrap otherwise use AES wrap similar to key size.
419 	 */
420 #ifndef OPENSSL_NO_DES
421 #if 0
422 	/*
423 	 * XXX - we do not currently support DES3 wrap and probably should just
424 	 * drop this code.
425 	 */
426 	if (EVP_CIPHER_type(cipher) == NID_des_ede3_cbc)
427 		kekcipher = EVP_des_ede3_wrap();
428 	else
429 #endif
430 #endif
431 	if (keylen <= 16)
432 		kekcipher = EVP_aes_128_wrap();
433 	else if (keylen <= 24)
434 		kekcipher = EVP_aes_192_wrap();
435 	else
436 		kekcipher = EVP_aes_256_wrap();
437 
438 	return EVP_EncryptInit_ex(ctx, kekcipher, NULL, NULL, NULL);
439 }
440 
441 /* Encrypt content key in key agreement recipient info */
442 
443 int
cms_RecipientInfo_kari_encrypt(CMS_ContentInfo * cms,CMS_RecipientInfo * ri)444 cms_RecipientInfo_kari_encrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri)
445 {
446 	CMS_KeyAgreeRecipientInfo *kari;
447 	CMS_EncryptedContentInfo *ec;
448 	CMS_RecipientEncryptedKey *rek;
449 	STACK_OF(CMS_RecipientEncryptedKey) *reks;
450 	int i;
451 
452 	if (ri->type != CMS_RECIPINFO_AGREE) {
453 		CMSerror(CMS_R_NOT_KEY_AGREEMENT);
454 		return 0;
455 	}
456 	kari = ri->d.kari;
457 	reks = kari->recipientEncryptedKeys;
458 	ec = cms->d.envelopedData->encryptedContentInfo;
459 	/* Initialise wrap algorithm parameters */
460 	if (!cms_wrap_init(kari, ec->cipher))
461 		return 0;
462 	/*
463 	 * If no originator key set up initialise for ephemeral key the public key
464 	 * ASN1 structure will set the actual public key value.
465 	 */
466 	if (kari->originator->type == -1) {
467 		CMS_OriginatorIdentifierOrKey *oik = kari->originator;
468 		oik->type = CMS_OIK_PUBKEY;
469 		oik->d.originatorKey = (CMS_OriginatorPublicKey *)ASN1_item_new(&CMS_OriginatorPublicKey_it);
470 		if (!oik->d.originatorKey)
471 			return 0;
472 	}
473 	/* Initialise KDF algorithm */
474 	if (!cms_env_asn1_ctrl(ri, 0))
475 		return 0;
476 	/* For each rek, derive KEK, encrypt CEK */
477 	for (i = 0; i < sk_CMS_RecipientEncryptedKey_num(reks); i++) {
478 		unsigned char *enckey;
479 		size_t enckeylen;
480 		rek = sk_CMS_RecipientEncryptedKey_value(reks, i);
481 		if (EVP_PKEY_derive_set_peer(kari->pctx, rek->pkey) <= 0)
482 			return 0;
483 		if (!cms_kek_cipher(&enckey, &enckeylen, ec->key, ec->keylen,
484 			                kari, 1))
485 			return 0;
486 		ASN1_STRING_set0(rek->encryptedKey, enckey, enckeylen);
487 	}
488 
489 	return 1;
490 }
491