]>
Commit | Line | Data |
---|---|---|
0f113f3e | 1 | /* |
33388b44 | 2 | * Copyright 2008-2020 The OpenSSL Project Authors. All Rights Reserved. |
8931b30d | 3 | * |
08ddd302 | 4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
b1322259 RS |
5 | * this file except in compliance with the License. You can obtain a copy |
6 | * in the file LICENSE in the source distribution or at | |
7 | * https://www.openssl.org/source/license.html | |
8931b30d DSH |
8 | */ |
9 | ||
b39fc560 | 10 | #include "internal/cryptlib.h" |
8931b30d DSH |
11 | #include <openssl/asn1t.h> |
12 | #include <openssl/pem.h> | |
13 | #include <openssl/x509v3.h> | |
14 | #include <openssl/err.h> | |
15 | #include <openssl/cms.h> | |
2852c672 | 16 | #include <openssl/evp.h> |
25f2138b DMSP |
17 | #include "crypto/asn1.h" |
18 | #include "crypto/evp.h" | |
c1669f41 SL |
19 | #include "crypto/x509.h" |
20 | #include "cms_local.h" | |
8931b30d DSH |
21 | |
22 | /* CMS EnvelopedData Utilities */ | |
71434aed DB |
23 | static void cms_env_set_version(CMS_EnvelopedData *env); |
24 | ||
924663c3 JZ |
25 | #define CMS_ENVELOPED_STANDARD 1 |
26 | #define CMS_ENVELOPED_AUTH 2 | |
27 | ||
28 | static int cms_get_enveloped_type(const CMS_ContentInfo *cms) | |
29 | { | |
30 | int nid = OBJ_obj2nid(cms->contentType); | |
31 | ||
32 | switch (nid) { | |
33 | case NID_pkcs7_enveloped: | |
34 | return CMS_ENVELOPED_STANDARD; | |
35 | ||
36 | case NID_id_smime_ct_authEnvelopedData: | |
37 | return CMS_ENVELOPED_AUTH; | |
38 | ||
39 | default: | |
40 | CMSerr(0, CMS_R_CONTENT_TYPE_NOT_ENVELOPED_DATA); | |
41 | return 0; | |
42 | } | |
43 | } | |
44 | ||
d2a53c22 | 45 | CMS_EnvelopedData *cms_get0_enveloped(CMS_ContentInfo *cms) |
0f113f3e MC |
46 | { |
47 | if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_enveloped) { | |
48 | CMSerr(CMS_F_CMS_GET0_ENVELOPED, | |
49 | CMS_R_CONTENT_TYPE_NOT_ENVELOPED_DATA); | |
50 | return NULL; | |
51 | } | |
52 | return cms->d.envelopedData; | |
53 | } | |
8931b30d | 54 | |
924663c3 JZ |
55 | CMS_AuthEnvelopedData *cms_get0_auth_enveloped(CMS_ContentInfo *cms) |
56 | { | |
57 | if (OBJ_obj2nid(cms->contentType) != NID_id_smime_ct_authEnvelopedData) { | |
58 | CMSerr(0, CMS_R_CONTENT_TYPE_NOT_ENVELOPED_DATA); | |
59 | return NULL; | |
60 | } | |
61 | return cms->d.authEnvelopedData; | |
62 | } | |
63 | ||
8931b30d | 64 | static CMS_EnvelopedData *cms_enveloped_data_init(CMS_ContentInfo *cms) |
0f113f3e MC |
65 | { |
66 | if (cms->d.other == NULL) { | |
67 | cms->d.envelopedData = M_ASN1_new_of(CMS_EnvelopedData); | |
924663c3 | 68 | if (cms->d.envelopedData == NULL) { |
0f113f3e MC |
69 | CMSerr(CMS_F_CMS_ENVELOPED_DATA_INIT, ERR_R_MALLOC_FAILURE); |
70 | return NULL; | |
71 | } | |
72 | cms->d.envelopedData->version = 0; | |
73 | cms->d.envelopedData->encryptedContentInfo->contentType = | |
74 | OBJ_nid2obj(NID_pkcs7_data); | |
75 | ASN1_OBJECT_free(cms->contentType); | |
76 | cms->contentType = OBJ_nid2obj(NID_pkcs7_enveloped); | |
77 | return cms->d.envelopedData; | |
78 | } | |
79 | return cms_get0_enveloped(cms); | |
80 | } | |
8931b30d | 81 | |
924663c3 JZ |
82 | static CMS_AuthEnvelopedData * |
83 | cms_auth_enveloped_data_init(CMS_ContentInfo *cms) | |
84 | { | |
85 | if (cms->d.other == NULL) { | |
86 | cms->d.authEnvelopedData = M_ASN1_new_of(CMS_AuthEnvelopedData); | |
87 | if (cms->d.authEnvelopedData == NULL) { | |
88 | CMSerr(0, ERR_R_MALLOC_FAILURE); | |
89 | return NULL; | |
90 | } | |
91 | /* Defined in RFC 5083 - Section 2.1. "AuthEnvelopedData Type" */ | |
92 | cms->d.authEnvelopedData->version = 0; | |
93 | cms->d.authEnvelopedData->authEncryptedContentInfo->contentType = | |
94 | OBJ_nid2obj(NID_pkcs7_data); | |
95 | ASN1_OBJECT_free(cms->contentType); | |
96 | cms->contentType = OBJ_nid2obj(NID_id_smime_ct_authEnvelopedData); | |
97 | return cms->d.authEnvelopedData; | |
98 | } | |
99 | return cms_get0_auth_enveloped(cms); | |
100 | } | |
101 | ||
17c2764d | 102 | int cms_env_asn1_ctrl(CMS_RecipientInfo *ri, int cmd) |
0f113f3e MC |
103 | { |
104 | EVP_PKEY *pkey; | |
105 | int i; | |
106 | if (ri->type == CMS_RECIPINFO_TRANS) | |
107 | pkey = ri->d.ktri->pkey; | |
108 | else if (ri->type == CMS_RECIPINFO_AGREE) { | |
109 | EVP_PKEY_CTX *pctx = ri->d.kari->pctx; | |
12a765a5 RS |
110 | |
111 | if (pctx == NULL) | |
0f113f3e MC |
112 | return 0; |
113 | pkey = EVP_PKEY_CTX_get0_pkey(pctx); | |
12a765a5 | 114 | if (pkey == NULL) |
0f113f3e MC |
115 | return 0; |
116 | } else | |
117 | return 0; | |
0b3a4ef2 | 118 | |
9ab7fe48 | 119 | #ifndef OPENSSL_NO_DH |
0b3a4ef2 MC |
120 | if (EVP_PKEY_is_a(pkey, "DHX")) |
121 | return cms_dh_envelope(ri, cmd); | |
9ab7fe48 MC |
122 | else |
123 | #endif | |
124 | #ifndef OPENSSL_NO_EC | |
125 | if (EVP_PKEY_is_a(pkey, "EC")) | |
0b3a4ef2 | 126 | return cms_ecdh_envelope(ri, cmd); |
9ab7fe48 MC |
127 | else |
128 | #endif | |
129 | if (EVP_PKEY_is_a(pkey, "RSA")) | |
0b3a4ef2 MC |
130 | return cms_rsa_envelope(ri, cmd); |
131 | ||
132 | /* Something else? We'll give engines etc a chance to handle this */ | |
12a765a5 | 133 | if (pkey->ameth == NULL || pkey->ameth->pkey_ctrl == NULL) |
0f113f3e MC |
134 | return 1; |
135 | i = pkey->ameth->pkey_ctrl(pkey, ASN1_PKEY_CTRL_CMS_ENVELOPE, cmd, ri); | |
136 | if (i == -2) { | |
137 | CMSerr(CMS_F_CMS_ENV_ASN1_CTRL, | |
138 | CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE); | |
139 | return 0; | |
140 | } | |
141 | if (i <= 0) { | |
142 | CMSerr(CMS_F_CMS_ENV_ASN1_CTRL, CMS_R_CTRL_FAILURE); | |
143 | return 0; | |
144 | } | |
145 | return 1; | |
146 | } | |
e365352d | 147 | |
924663c3 JZ |
148 | CMS_EncryptedContentInfo* cms_get0_env_enc_content(const CMS_ContentInfo *cms) |
149 | { | |
150 | switch (cms_get_enveloped_type(cms)) { | |
151 | case CMS_ENVELOPED_STANDARD: | |
152 | return cms->d.envelopedData->encryptedContentInfo; | |
153 | ||
154 | case CMS_ENVELOPED_AUTH: | |
155 | return cms->d.authEnvelopedData->authEncryptedContentInfo; | |
156 | ||
157 | default: | |
158 | return NULL; | |
159 | } | |
160 | } | |
161 | ||
4f1aa191 | 162 | STACK_OF(CMS_RecipientInfo) *CMS_get0_RecipientInfos(CMS_ContentInfo *cms) |
0f113f3e | 163 | { |
924663c3 JZ |
164 | switch (cms_get_enveloped_type(cms)) { |
165 | case CMS_ENVELOPED_STANDARD: | |
166 | return cms->d.envelopedData->recipientInfos; | |
167 | ||
168 | case CMS_ENVELOPED_AUTH: | |
169 | return cms->d.authEnvelopedData->recipientInfos; | |
170 | ||
171 | default: | |
0f113f3e | 172 | return NULL; |
924663c3 | 173 | } |
0f113f3e | 174 | } |
4f1aa191 | 175 | |
c1669f41 SL |
176 | void cms_RecipientInfos_set_cmsctx(CMS_ContentInfo *cms) |
177 | { | |
178 | int i; | |
179 | CMS_RecipientInfo *ri; | |
180 | const CMS_CTX *ctx = cms_get0_cmsctx(cms); | |
181 | STACK_OF(CMS_RecipientInfo) *rinfos = CMS_get0_RecipientInfos(cms); | |
182 | ||
183 | for (i = 0; i < sk_CMS_RecipientInfo_num(rinfos); i++) { | |
184 | ri = sk_CMS_RecipientInfo_value(rinfos, i); | |
185 | if (ri != NULL) { | |
186 | switch (ri->type) { | |
187 | case CMS_RECIPINFO_AGREE: | |
188 | ri->d.kari->cms_ctx = ctx; | |
189 | break; | |
190 | case CMS_RECIPINFO_TRANS: | |
191 | ri->d.ktri->cms_ctx = ctx; | |
192 | x509_set0_libctx(ri->d.ktri->recip, ctx->libctx, ctx->propq); | |
193 | break; | |
194 | case CMS_RECIPINFO_KEK: | |
195 | ri->d.kekri->cms_ctx = ctx; | |
196 | break; | |
197 | case CMS_RECIPINFO_PASS: | |
198 | ri->d.pwri->cms_ctx = ctx; | |
199 | break; | |
200 | default: | |
201 | break; | |
202 | } | |
203 | } | |
204 | } | |
205 | } | |
206 | ||
4f1aa191 | 207 | int CMS_RecipientInfo_type(CMS_RecipientInfo *ri) |
0f113f3e MC |
208 | { |
209 | return ri->type; | |
210 | } | |
4f1aa191 | 211 | |
e365352d | 212 | EVP_PKEY_CTX *CMS_RecipientInfo_get0_pkey_ctx(CMS_RecipientInfo *ri) |
0f113f3e MC |
213 | { |
214 | if (ri->type == CMS_RECIPINFO_TRANS) | |
215 | return ri->d.ktri->pctx; | |
216 | else if (ri->type == CMS_RECIPINFO_AGREE) | |
217 | return ri->d.kari->pctx; | |
218 | return NULL; | |
219 | } | |
e365352d | 220 | |
d8652be0 | 221 | CMS_ContentInfo *CMS_EnvelopedData_create_ex(const EVP_CIPHER *cipher, |
b4250010 | 222 | OSSL_LIB_CTX *libctx, |
d8652be0 | 223 | const char *propq) |
0f113f3e MC |
224 | { |
225 | CMS_ContentInfo *cms; | |
226 | CMS_EnvelopedData *env; | |
c1669f41 | 227 | |
d8652be0 | 228 | cms = CMS_ContentInfo_new_ex(libctx, propq); |
90945fa3 | 229 | if (cms == NULL) |
0f113f3e MC |
230 | goto merr; |
231 | env = cms_enveloped_data_init(cms); | |
90945fa3 | 232 | if (env == NULL) |
0f113f3e | 233 | goto merr; |
c1669f41 SL |
234 | |
235 | if (!cms_EncryptedContent_init(env->encryptedContentInfo, cipher, NULL, 0, | |
236 | cms_get0_cmsctx(cms))) | |
0f113f3e MC |
237 | goto merr; |
238 | return cms; | |
239 | merr: | |
25aaa98a | 240 | CMS_ContentInfo_free(cms); |
c1669f41 | 241 | CMSerr(0, ERR_R_MALLOC_FAILURE); |
0f113f3e MC |
242 | return NULL; |
243 | } | |
761ffa72 | 244 | |
c1669f41 SL |
245 | CMS_ContentInfo *CMS_EnvelopedData_create(const EVP_CIPHER *cipher) |
246 | { | |
d8652be0 | 247 | return CMS_EnvelopedData_create_ex(cipher, NULL, NULL); |
c1669f41 SL |
248 | } |
249 | ||
924663c3 | 250 | CMS_ContentInfo * |
b4250010 | 251 | CMS_AuthEnvelopedData_create_ex(const EVP_CIPHER *cipher, OSSL_LIB_CTX *libctx, |
d8652be0 | 252 | const char *propq) |
71434aed | 253 | { |
924663c3 JZ |
254 | CMS_ContentInfo *cms; |
255 | CMS_AuthEnvelopedData *aenv; | |
71434aed | 256 | |
d8652be0 | 257 | cms = CMS_ContentInfo_new_ex(libctx, propq); |
924663c3 JZ |
258 | if (cms == NULL) |
259 | goto merr; | |
260 | aenv = cms_auth_enveloped_data_init(cms); | |
261 | if (aenv == NULL) | |
262 | goto merr; | |
263 | if (!cms_EncryptedContent_init(aenv->authEncryptedContentInfo, | |
264 | cipher, NULL, 0, cms_get0_cmsctx(cms))) | |
265 | goto merr; | |
266 | return cms; | |
267 | merr: | |
268 | CMS_ContentInfo_free(cms); | |
269 | CMSerr(0, ERR_R_MALLOC_FAILURE); | |
270 | return NULL; | |
271 | } | |
71434aed | 272 | |
71434aed | 273 | |
924663c3 JZ |
274 | CMS_ContentInfo *CMS_AuthEnvelopedData_create(const EVP_CIPHER *cipher) |
275 | { | |
d8652be0 | 276 | return CMS_AuthEnvelopedData_create_ex(cipher, NULL, NULL); |
71434aed DB |
277 | } |
278 | ||
ab124380 DSH |
279 | /* Key Transport Recipient Info (KTRI) routines */ |
280 | ||
17c2764d | 281 | /* Initialise a ktri based on passed certificate and key */ |
ab124380 | 282 | |
17c2764d | 283 | static int cms_RecipientInfo_ktri_init(CMS_RecipientInfo *ri, X509 *recip, |
c1669f41 SL |
284 | EVP_PKEY *pk, unsigned int flags, |
285 | const CMS_CTX *ctx) | |
0f113f3e MC |
286 | { |
287 | CMS_KeyTransRecipientInfo *ktri; | |
288 | int idtype; | |
289 | ||
290 | ri->d.ktri = M_ASN1_new_of(CMS_KeyTransRecipientInfo); | |
291 | if (!ri->d.ktri) | |
292 | return 0; | |
293 | ri->type = CMS_RECIPINFO_TRANS; | |
294 | ||
295 | ktri = ri->d.ktri; | |
c1669f41 | 296 | ktri->cms_ctx = ctx; |
0f113f3e MC |
297 | |
298 | if (flags & CMS_USE_KEYID) { | |
299 | ktri->version = 2; | |
300 | idtype = CMS_RECIPINFO_KEYIDENTIFIER; | |
301 | } else { | |
302 | ktri->version = 0; | |
303 | idtype = CMS_RECIPINFO_ISSUER_SERIAL; | |
304 | } | |
305 | ||
306 | /* | |
307 | * Not a typo: RecipientIdentifier and SignerIdentifier are the same | |
308 | * structure. | |
309 | */ | |
310 | ||
c1669f41 | 311 | if (!cms_set1_SignerIdentifier(ktri->rid, recip, idtype, ctx)) |
0f113f3e MC |
312 | return 0; |
313 | ||
05f0fb9f | 314 | X509_up_ref(recip); |
03273d61 AG |
315 | EVP_PKEY_up_ref(pk); |
316 | ||
0f113f3e MC |
317 | ktri->pkey = pk; |
318 | ktri->recip = recip; | |
319 | ||
320 | if (flags & CMS_KEY_PARAM) { | |
c1669f41 SL |
321 | ktri->pctx = EVP_PKEY_CTX_new_from_pkey(ctx->libctx, ktri->pkey, |
322 | ctx->propq); | |
90945fa3 | 323 | if (ktri->pctx == NULL) |
0f113f3e MC |
324 | return 0; |
325 | if (EVP_PKEY_encrypt_init(ktri->pctx) <= 0) | |
326 | return 0; | |
327 | } else if (!cms_env_asn1_ctrl(ri, 0)) | |
328 | return 0; | |
329 | return 1; | |
330 | } | |
331 | ||
332 | /* | |
333 | * Add a recipient certificate using appropriate type of RecipientInfo | |
17c2764d DSH |
334 | */ |
335 | ||
71434aed DB |
336 | CMS_RecipientInfo *CMS_add1_recipient(CMS_ContentInfo *cms, X509 *recip, |
337 | EVP_PKEY *originatorPrivKey, | |
338 | X509 *originator, unsigned int flags) | |
0f113f3e MC |
339 | { |
340 | CMS_RecipientInfo *ri = NULL; | |
924663c3 | 341 | STACK_OF(CMS_RecipientInfo) *ris; |
0f113f3e | 342 | EVP_PKEY *pk = NULL; |
c1669f41 SL |
343 | const CMS_CTX *ctx = cms_get0_cmsctx(cms); |
344 | ||
924663c3 JZ |
345 | ris = CMS_get0_RecipientInfos(cms); |
346 | if (ris == NULL) | |
0f113f3e MC |
347 | goto err; |
348 | ||
349 | /* Initialize recipient info */ | |
350 | ri = M_ASN1_new_of(CMS_RecipientInfo); | |
924663c3 | 351 | if (ri == NULL) |
0f113f3e MC |
352 | goto merr; |
353 | ||
8382fd3a | 354 | pk = X509_get0_pubkey(recip); |
12a765a5 | 355 | if (pk == NULL) { |
71434aed | 356 | CMSerr(CMS_F_CMS_ADD1_RECIPIENT, CMS_R_ERROR_GETTING_PUBLIC_KEY); |
0f113f3e MC |
357 | goto err; |
358 | } | |
359 | ||
360 | switch (cms_pkey_get_ri_type(pk)) { | |
361 | ||
362 | case CMS_RECIPINFO_TRANS: | |
c1669f41 | 363 | if (!cms_RecipientInfo_ktri_init(ri, recip, pk, flags, ctx)) |
0f113f3e MC |
364 | goto err; |
365 | break; | |
366 | ||
367 | case CMS_RECIPINFO_AGREE: | |
c1669f41 SL |
368 | if (!cms_RecipientInfo_kari_init(ri, recip, pk, originator, |
369 | originatorPrivKey, flags, ctx)) | |
0f113f3e MC |
370 | goto err; |
371 | break; | |
372 | ||
373 | default: | |
71434aed | 374 | CMSerr(CMS_F_CMS_ADD1_RECIPIENT, |
0f113f3e MC |
375 | CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE); |
376 | goto err; | |
377 | ||
378 | } | |
379 | ||
924663c3 | 380 | if (!sk_CMS_RecipientInfo_push(ris, ri)) |
0f113f3e MC |
381 | goto merr; |
382 | ||
0f113f3e MC |
383 | return ri; |
384 | ||
385 | merr: | |
71434aed | 386 | CMSerr(CMS_F_CMS_ADD1_RECIPIENT, ERR_R_MALLOC_FAILURE); |
0f113f3e | 387 | err: |
2ace7450 | 388 | M_ASN1_free_of(ri, CMS_RecipientInfo); |
0f113f3e MC |
389 | return NULL; |
390 | ||
391 | } | |
8931b30d | 392 | |
924663c3 JZ |
393 | CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms, X509 *recip, |
394 | unsigned int flags) | |
71434aed DB |
395 | { |
396 | return CMS_add1_recipient(cms, recip, NULL, NULL, flags); | |
397 | } | |
398 | ||
8931b30d | 399 | int CMS_RecipientInfo_ktri_get0_algs(CMS_RecipientInfo *ri, |
0f113f3e MC |
400 | EVP_PKEY **pk, X509 **recip, |
401 | X509_ALGOR **palg) | |
402 | { | |
403 | CMS_KeyTransRecipientInfo *ktri; | |
404 | if (ri->type != CMS_RECIPINFO_TRANS) { | |
405 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_ALGS, | |
406 | CMS_R_NOT_KEY_TRANSPORT); | |
407 | return 0; | |
408 | } | |
409 | ||
410 | ktri = ri->d.ktri; | |
411 | ||
412 | if (pk) | |
413 | *pk = ktri->pkey; | |
414 | if (recip) | |
415 | *recip = ktri->recip; | |
416 | if (palg) | |
417 | *palg = ktri->keyEncryptionAlgorithm; | |
418 | return 1; | |
419 | } | |
8931b30d DSH |
420 | |
421 | int CMS_RecipientInfo_ktri_get0_signer_id(CMS_RecipientInfo *ri, | |
0f113f3e MC |
422 | ASN1_OCTET_STRING **keyid, |
423 | X509_NAME **issuer, | |
424 | ASN1_INTEGER **sno) | |
425 | { | |
426 | CMS_KeyTransRecipientInfo *ktri; | |
427 | if (ri->type != CMS_RECIPINFO_TRANS) { | |
428 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_SIGNER_ID, | |
429 | CMS_R_NOT_KEY_TRANSPORT); | |
430 | return 0; | |
431 | } | |
432 | ktri = ri->d.ktri; | |
433 | ||
434 | return cms_SignerIdentifier_get0_signer_id(ktri->rid, keyid, issuer, sno); | |
435 | } | |
8931b30d DSH |
436 | |
437 | int CMS_RecipientInfo_ktri_cert_cmp(CMS_RecipientInfo *ri, X509 *cert) | |
0f113f3e MC |
438 | { |
439 | if (ri->type != CMS_RECIPINFO_TRANS) { | |
440 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_CERT_CMP, | |
441 | CMS_R_NOT_KEY_TRANSPORT); | |
442 | return -2; | |
443 | } | |
444 | return cms_SignerIdentifier_cert_cmp(ri->d.ktri->rid, cert); | |
445 | } | |
4f1aa191 | 446 | |
6e3bc4f0 | 447 | int CMS_RecipientInfo_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pkey) |
0f113f3e MC |
448 | { |
449 | if (ri->type != CMS_RECIPINFO_TRANS) { | |
450 | CMSerr(CMS_F_CMS_RECIPIENTINFO_SET0_PKEY, CMS_R_NOT_KEY_TRANSPORT); | |
451 | return 0; | |
452 | } | |
3d551b20 | 453 | EVP_PKEY_free(ri->d.ktri->pkey); |
0f113f3e MC |
454 | ri->d.ktri->pkey = pkey; |
455 | return 1; | |
456 | } | |
6e3bc4f0 | 457 | |
761ffa72 DSH |
458 | /* Encrypt content key in key transport recipient info */ |
459 | ||
9fdcc21f | 460 | static int cms_RecipientInfo_ktri_encrypt(const CMS_ContentInfo *cms, |
0f113f3e MC |
461 | CMS_RecipientInfo *ri) |
462 | { | |
463 | CMS_KeyTransRecipientInfo *ktri; | |
464 | CMS_EncryptedContentInfo *ec; | |
465 | EVP_PKEY_CTX *pctx; | |
466 | unsigned char *ek = NULL; | |
467 | size_t eklen; | |
c1669f41 | 468 | const CMS_CTX *ctx = cms_get0_cmsctx(cms); |
0f113f3e MC |
469 | |
470 | int ret = 0; | |
471 | ||
472 | if (ri->type != CMS_RECIPINFO_TRANS) { | |
473 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT, CMS_R_NOT_KEY_TRANSPORT); | |
474 | return 0; | |
475 | } | |
476 | ktri = ri->d.ktri; | |
924663c3 | 477 | ec = cms_get0_env_enc_content(cms); |
0f113f3e MC |
478 | |
479 | pctx = ktri->pctx; | |
480 | ||
481 | if (pctx) { | |
482 | if (!cms_env_asn1_ctrl(ri, 0)) | |
483 | goto err; | |
484 | } else { | |
c1669f41 | 485 | pctx = EVP_PKEY_CTX_new_from_pkey(ctx->libctx, ktri->pkey, ctx->propq); |
90945fa3 | 486 | if (pctx == NULL) |
0f113f3e MC |
487 | return 0; |
488 | ||
489 | if (EVP_PKEY_encrypt_init(pctx) <= 0) | |
490 | goto err; | |
491 | } | |
492 | ||
493 | if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_ENCRYPT, | |
494 | EVP_PKEY_CTRL_CMS_ENCRYPT, 0, ri) <= 0) { | |
495 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT, CMS_R_CTRL_ERROR); | |
496 | goto err; | |
497 | } | |
498 | ||
499 | if (EVP_PKEY_encrypt(pctx, NULL, &eklen, ec->key, ec->keylen) <= 0) | |
500 | goto err; | |
501 | ||
502 | ek = OPENSSL_malloc(eklen); | |
503 | ||
504 | if (ek == NULL) { | |
505 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT, ERR_R_MALLOC_FAILURE); | |
506 | goto err; | |
507 | } | |
508 | ||
509 | if (EVP_PKEY_encrypt(pctx, ek, &eklen, ec->key, ec->keylen) <= 0) | |
510 | goto err; | |
511 | ||
512 | ASN1_STRING_set0(ktri->encryptedKey, ek, eklen); | |
513 | ek = NULL; | |
514 | ||
515 | ret = 1; | |
516 | ||
517 | err: | |
25aaa98a RS |
518 | EVP_PKEY_CTX_free(pctx); |
519 | ktri->pctx = NULL; | |
b548a1f1 | 520 | OPENSSL_free(ek); |
0f113f3e | 521 | return ret; |
0f113f3e | 522 | } |
761ffa72 | 523 | |
ab124380 DSH |
524 | /* Decrypt content key from KTRI */ |
525 | ||
6e3bc4f0 | 526 | static int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms, |
0f113f3e MC |
527 | CMS_RecipientInfo *ri) |
528 | { | |
529 | CMS_KeyTransRecipientInfo *ktri = ri->d.ktri; | |
530 | EVP_PKEY *pkey = ktri->pkey; | |
531 | unsigned char *ek = NULL; | |
532 | size_t eklen; | |
533 | int ret = 0; | |
5840ed0c | 534 | size_t fixlen = 0; |
1acb2e6f SL |
535 | const EVP_CIPHER *cipher = NULL; |
536 | EVP_CIPHER *fetched_cipher = NULL; | |
0f113f3e | 537 | CMS_EncryptedContentInfo *ec; |
c1669f41 SL |
538 | const CMS_CTX *ctx = cms_get0_cmsctx(cms); |
539 | ||
924663c3 | 540 | ec = cms_get0_env_enc_content(cms); |
0f113f3e MC |
541 | |
542 | if (ktri->pkey == NULL) { | |
543 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_NO_PRIVATE_KEY); | |
544 | return 0; | |
545 | } | |
546 | ||
5840ed0c BE |
547 | if (cms->d.envelopedData->encryptedContentInfo->havenocert |
548 | && !cms->d.envelopedData->encryptedContentInfo->debug) { | |
549 | X509_ALGOR *calg = ec->contentEncryptionAlgorithm; | |
c1669f41 | 550 | const char *name = OBJ_nid2sn(OBJ_obj2nid(calg->algorithm)); |
5840ed0c | 551 | |
1acb2e6f SL |
552 | (void)ERR_set_mark(); |
553 | fetched_cipher = EVP_CIPHER_fetch(ctx->libctx, name, ctx->propq); | |
554 | ||
555 | if (fetched_cipher != NULL) | |
556 | cipher = fetched_cipher; | |
557 | else | |
558 | cipher = EVP_get_cipherbyobj(calg->algorithm); | |
559 | if (cipher == NULL) { | |
560 | (void)ERR_clear_last_mark(); | |
5840ed0c BE |
561 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_UNKNOWN_CIPHER); |
562 | return 0; | |
563 | } | |
1acb2e6f | 564 | (void)ERR_pop_to_mark(); |
5840ed0c | 565 | |
1acb2e6f SL |
566 | fixlen = EVP_CIPHER_key_length(cipher); |
567 | EVP_CIPHER_free(fetched_cipher); | |
5840ed0c BE |
568 | } |
569 | ||
c1669f41 | 570 | ktri->pctx = EVP_PKEY_CTX_new_from_pkey(ctx->libctx, pkey, ctx->propq); |
90945fa3 | 571 | if (ktri->pctx == NULL) |
c1669f41 | 572 | goto err; |
0f113f3e MC |
573 | |
574 | if (EVP_PKEY_decrypt_init(ktri->pctx) <= 0) | |
575 | goto err; | |
576 | ||
577 | if (!cms_env_asn1_ctrl(ri, 1)) | |
578 | goto err; | |
579 | ||
580 | if (EVP_PKEY_CTX_ctrl(ktri->pctx, -1, EVP_PKEY_OP_DECRYPT, | |
581 | EVP_PKEY_CTRL_CMS_DECRYPT, 0, ri) <= 0) { | |
582 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_CTRL_ERROR); | |
583 | goto err; | |
584 | } | |
585 | ||
586 | if (EVP_PKEY_decrypt(ktri->pctx, NULL, &eklen, | |
587 | ktri->encryptedKey->data, | |
588 | ktri->encryptedKey->length) <= 0) | |
589 | goto err; | |
590 | ||
591 | ek = OPENSSL_malloc(eklen); | |
0f113f3e MC |
592 | if (ek == NULL) { |
593 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, ERR_R_MALLOC_FAILURE); | |
594 | goto err; | |
595 | } | |
596 | ||
597 | if (EVP_PKEY_decrypt(ktri->pctx, ek, &eklen, | |
598 | ktri->encryptedKey->data, | |
5840ed0c BE |
599 | ktri->encryptedKey->length) <= 0 |
600 | || eklen == 0 | |
601 | || (fixlen != 0 && eklen != fixlen)) { | |
0f113f3e MC |
602 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_CMS_LIB); |
603 | goto err; | |
604 | } | |
605 | ||
606 | ret = 1; | |
607 | ||
4b45c6e5 | 608 | OPENSSL_clear_free(ec->key, ec->keylen); |
0f113f3e MC |
609 | ec->key = ek; |
610 | ec->keylen = eklen; | |
611 | ||
612 | err: | |
c5ba2d99 RS |
613 | EVP_PKEY_CTX_free(ktri->pctx); |
614 | ktri->pctx = NULL; | |
b548a1f1 | 615 | if (!ret) |
0f113f3e MC |
616 | OPENSSL_free(ek); |
617 | ||
618 | return ret; | |
619 | } | |
4f1aa191 | 620 | |
ab124380 DSH |
621 | /* Key Encrypted Key (KEK) RecipientInfo routines */ |
622 | ||
0f113f3e MC |
623 | int CMS_RecipientInfo_kekri_id_cmp(CMS_RecipientInfo *ri, |
624 | const unsigned char *id, size_t idlen) | |
625 | { | |
626 | ASN1_OCTET_STRING tmp_os; | |
627 | CMS_KEKRecipientInfo *kekri; | |
628 | if (ri->type != CMS_RECIPINFO_KEK) { | |
629 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ID_CMP, CMS_R_NOT_KEK); | |
630 | return -2; | |
631 | } | |
632 | kekri = ri->d.kekri; | |
633 | tmp_os.type = V_ASN1_OCTET_STRING; | |
634 | tmp_os.flags = 0; | |
635 | tmp_os.data = (unsigned char *)id; | |
636 | tmp_os.length = (int)idlen; | |
637 | return ASN1_OCTET_STRING_cmp(&tmp_os, kekri->kekid->keyIdentifier); | |
638 | } | |
eeb9cdfc | 639 | |
ab124380 DSH |
640 | /* For now hard code AES key wrap info */ |
641 | ||
642 | static size_t aes_wrap_keylen(int nid) | |
0f113f3e MC |
643 | { |
644 | switch (nid) { | |
645 | case NID_id_aes128_wrap: | |
646 | return 16; | |
ab124380 | 647 | |
0f113f3e MC |
648 | case NID_id_aes192_wrap: |
649 | return 24; | |
ab124380 | 650 | |
0f113f3e MC |
651 | case NID_id_aes256_wrap: |
652 | return 32; | |
ab124380 | 653 | |
0f113f3e MC |
654 | default: |
655 | return 0; | |
656 | } | |
657 | } | |
ab124380 DSH |
658 | |
659 | CMS_RecipientInfo *CMS_add0_recipient_key(CMS_ContentInfo *cms, int nid, | |
0f113f3e MC |
660 | unsigned char *key, size_t keylen, |
661 | unsigned char *id, size_t idlen, | |
662 | ASN1_GENERALIZEDTIME *date, | |
663 | ASN1_OBJECT *otherTypeId, | |
664 | ASN1_TYPE *otherType) | |
665 | { | |
666 | CMS_RecipientInfo *ri = NULL; | |
0f113f3e | 667 | CMS_KEKRecipientInfo *kekri; |
924663c3 JZ |
668 | STACK_OF(CMS_RecipientInfo) *ris = CMS_get0_RecipientInfos(cms); |
669 | ||
670 | if (ris == NULL) | |
0f113f3e | 671 | goto err; |
ab124380 | 672 | |
0f113f3e MC |
673 | if (nid == NID_undef) { |
674 | switch (keylen) { | |
675 | case 16: | |
676 | nid = NID_id_aes128_wrap; | |
677 | break; | |
ab124380 | 678 | |
0f113f3e MC |
679 | case 24: |
680 | nid = NID_id_aes192_wrap; | |
681 | break; | |
682 | ||
683 | case 32: | |
684 | nid = NID_id_aes256_wrap; | |
685 | break; | |
686 | ||
687 | default: | |
688 | CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY, CMS_R_INVALID_KEY_LENGTH); | |
689 | goto err; | |
690 | } | |
691 | ||
692 | } else { | |
693 | ||
694 | size_t exp_keylen = aes_wrap_keylen(nid); | |
695 | ||
696 | if (!exp_keylen) { | |
697 | CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY, | |
698 | CMS_R_UNSUPPORTED_KEK_ALGORITHM); | |
699 | goto err; | |
700 | } | |
701 | ||
702 | if (keylen != exp_keylen) { | |
703 | CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY, CMS_R_INVALID_KEY_LENGTH); | |
704 | goto err; | |
705 | } | |
706 | ||
707 | } | |
708 | ||
709 | /* Initialize recipient info */ | |
710 | ri = M_ASN1_new_of(CMS_RecipientInfo); | |
711 | if (!ri) | |
712 | goto merr; | |
713 | ||
714 | ri->d.kekri = M_ASN1_new_of(CMS_KEKRecipientInfo); | |
715 | if (!ri->d.kekri) | |
716 | goto merr; | |
717 | ri->type = CMS_RECIPINFO_KEK; | |
718 | ||
719 | kekri = ri->d.kekri; | |
720 | ||
721 | if (otherTypeId) { | |
722 | kekri->kekid->other = M_ASN1_new_of(CMS_OtherKeyAttribute); | |
723 | if (kekri->kekid->other == NULL) | |
724 | goto merr; | |
725 | } | |
ab124380 | 726 | |
924663c3 | 727 | if (!sk_CMS_RecipientInfo_push(ris, ri)) |
0f113f3e MC |
728 | goto merr; |
729 | ||
730 | /* After this point no calls can fail */ | |
731 | ||
732 | kekri->version = 4; | |
733 | ||
734 | kekri->key = key; | |
735 | kekri->keylen = keylen; | |
736 | ||
737 | ASN1_STRING_set0(kekri->kekid->keyIdentifier, id, idlen); | |
738 | ||
739 | kekri->kekid->date = date; | |
740 | ||
741 | if (kekri->kekid->other) { | |
742 | kekri->kekid->other->keyAttrId = otherTypeId; | |
743 | kekri->kekid->other->keyAttr = otherType; | |
744 | } | |
745 | ||
746 | X509_ALGOR_set0(kekri->keyEncryptionAlgorithm, | |
747 | OBJ_nid2obj(nid), V_ASN1_UNDEF, NULL); | |
748 | ||
749 | return ri; | |
750 | ||
751 | merr: | |
752 | CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY, ERR_R_MALLOC_FAILURE); | |
753 | err: | |
2ace7450 | 754 | M_ASN1_free_of(ri, CMS_RecipientInfo); |
0f113f3e | 755 | return NULL; |
0f113f3e MC |
756 | } |
757 | ||
758 | int CMS_RecipientInfo_kekri_get0_id(CMS_RecipientInfo *ri, | |
759 | X509_ALGOR **palg, | |
760 | ASN1_OCTET_STRING **pid, | |
761 | ASN1_GENERALIZEDTIME **pdate, | |
762 | ASN1_OBJECT **potherid, | |
763 | ASN1_TYPE **pothertype) | |
764 | { | |
765 | CMS_KEKIdentifier *rkid; | |
766 | if (ri->type != CMS_RECIPINFO_KEK) { | |
767 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_GET0_ID, CMS_R_NOT_KEK); | |
768 | return 0; | |
769 | } | |
770 | rkid = ri->d.kekri->kekid; | |
771 | if (palg) | |
772 | *palg = ri->d.kekri->keyEncryptionAlgorithm; | |
773 | if (pid) | |
774 | *pid = rkid->keyIdentifier; | |
775 | if (pdate) | |
776 | *pdate = rkid->date; | |
777 | if (potherid) { | |
778 | if (rkid->other) | |
779 | *potherid = rkid->other->keyAttrId; | |
780 | else | |
781 | *potherid = NULL; | |
782 | } | |
783 | if (pothertype) { | |
784 | if (rkid->other) | |
785 | *pothertype = rkid->other->keyAttr; | |
786 | else | |
787 | *pothertype = NULL; | |
788 | } | |
789 | return 1; | |
790 | } | |
791 | ||
792 | int CMS_RecipientInfo_set0_key(CMS_RecipientInfo *ri, | |
793 | unsigned char *key, size_t keylen) | |
794 | { | |
795 | CMS_KEKRecipientInfo *kekri; | |
796 | if (ri->type != CMS_RECIPINFO_KEK) { | |
797 | CMSerr(CMS_F_CMS_RECIPIENTINFO_SET0_KEY, CMS_R_NOT_KEK); | |
798 | return 0; | |
799 | } | |
800 | ||
801 | kekri = ri->d.kekri; | |
802 | kekri->key = key; | |
803 | kekri->keylen = keylen; | |
804 | return 1; | |
805 | } | |
6e3bc4f0 | 806 | |
c1669f41 | 807 | static EVP_CIPHER *cms_get_key_wrap_cipher(size_t keylen, const CMS_CTX *ctx) |
2852c672 | 808 | { |
c1669f41 SL |
809 | const char *alg = NULL; |
810 | ||
2852c672 MC |
811 | switch(keylen) { |
812 | case 16: | |
c1669f41 SL |
813 | alg = "AES-128-WRAP"; |
814 | break; | |
2852c672 | 815 | case 24: |
c1669f41 SL |
816 | alg = "AES-192-WRAP"; |
817 | break; | |
2852c672 | 818 | case 32: |
c1669f41 SL |
819 | alg = "AES-256-WRAP"; |
820 | break; | |
821 | default: | |
822 | return NULL; | |
2852c672 | 823 | } |
c1669f41 | 824 | return EVP_CIPHER_fetch(ctx->libctx, alg, ctx->propq); |
2852c672 MC |
825 | } |
826 | ||
827 | ||
6e3bc4f0 DSH |
828 | /* Encrypt content key in KEK recipient info */ |
829 | ||
9fdcc21f | 830 | static int cms_RecipientInfo_kekri_encrypt(const CMS_ContentInfo *cms, |
0f113f3e MC |
831 | CMS_RecipientInfo *ri) |
832 | { | |
833 | CMS_EncryptedContentInfo *ec; | |
834 | CMS_KEKRecipientInfo *kekri; | |
0f113f3e MC |
835 | unsigned char *wkey = NULL; |
836 | int wkeylen; | |
837 | int r = 0; | |
c1669f41 | 838 | EVP_CIPHER *cipher = NULL; |
2852c672 MC |
839 | int outlen = 0; |
840 | EVP_CIPHER_CTX *ctx = NULL; | |
c1669f41 | 841 | const CMS_CTX *cms_ctx = cms_get0_cmsctx(cms); |
6e3bc4f0 | 842 | |
924663c3 JZ |
843 | ec = cms_get0_env_enc_content(cms); |
844 | if (ec == NULL) | |
845 | return 0; | |
6e3bc4f0 | 846 | |
0f113f3e | 847 | kekri = ri->d.kekri; |
6e3bc4f0 | 848 | |
2852c672 | 849 | if (kekri->key == NULL) { |
0f113f3e MC |
850 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, CMS_R_NO_KEY); |
851 | return 0; | |
852 | } | |
6e3bc4f0 | 853 | |
c1669f41 | 854 | cipher = cms_get_key_wrap_cipher(kekri->keylen, cms_ctx); |
2852c672 MC |
855 | if (cipher == NULL) { |
856 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, CMS_R_INVALID_KEY_LENGTH); | |
0f113f3e MC |
857 | goto err; |
858 | } | |
6e3bc4f0 | 859 | |
2852c672 | 860 | /* 8 byte prefix for AES wrap ciphers */ |
0f113f3e | 861 | wkey = OPENSSL_malloc(ec->keylen + 8); |
90945fa3 | 862 | if (wkey == NULL) { |
0f113f3e MC |
863 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, ERR_R_MALLOC_FAILURE); |
864 | goto err; | |
865 | } | |
6e3bc4f0 | 866 | |
2852c672 MC |
867 | ctx = EVP_CIPHER_CTX_new(); |
868 | if (ctx == NULL) { | |
869 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, ERR_R_MALLOC_FAILURE); | |
870 | goto err; | |
871 | } | |
6e3bc4f0 | 872 | |
2852c672 MC |
873 | EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); |
874 | if (!EVP_EncryptInit_ex(ctx, cipher, NULL, kekri->key, NULL) | |
875 | || !EVP_EncryptUpdate(ctx, wkey, &wkeylen, ec->key, ec->keylen) | |
876 | || !EVP_EncryptFinal_ex(ctx, wkey + wkeylen, &outlen)) { | |
877 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, CMS_R_WRAP_ERROR); | |
878 | goto err; | |
879 | } | |
880 | wkeylen += outlen; | |
881 | if (!ossl_assert((size_t)wkeylen == ec->keylen + 8)) { | |
0f113f3e MC |
882 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, CMS_R_WRAP_ERROR); |
883 | goto err; | |
884 | } | |
6e3bc4f0 | 885 | |
0f113f3e | 886 | ASN1_STRING_set0(kekri->encryptedKey, wkey, wkeylen); |
6e3bc4f0 | 887 | |
0f113f3e | 888 | r = 1; |
6e3bc4f0 | 889 | |
0f113f3e | 890 | err: |
c1669f41 | 891 | EVP_CIPHER_free(cipher); |
b548a1f1 | 892 | if (!r) |
0f113f3e | 893 | OPENSSL_free(wkey); |
2852c672 | 894 | EVP_CIPHER_CTX_free(ctx); |
6e3bc4f0 | 895 | |
0f113f3e | 896 | return r; |
0f113f3e | 897 | } |
6e3bc4f0 | 898 | |
ab124380 DSH |
899 | /* Decrypt content key in KEK recipient info */ |
900 | ||
6e3bc4f0 | 901 | static int cms_RecipientInfo_kekri_decrypt(CMS_ContentInfo *cms, |
0f113f3e MC |
902 | CMS_RecipientInfo *ri) |
903 | { | |
904 | CMS_EncryptedContentInfo *ec; | |
905 | CMS_KEKRecipientInfo *kekri; | |
0f113f3e MC |
906 | unsigned char *ukey = NULL; |
907 | int ukeylen; | |
908 | int r = 0, wrap_nid; | |
c1669f41 | 909 | EVP_CIPHER *cipher = NULL; |
2852c672 MC |
910 | int outlen = 0; |
911 | EVP_CIPHER_CTX *ctx = NULL; | |
c1669f41 | 912 | const CMS_CTX *cms_ctx = cms_get0_cmsctx(cms); |
0f113f3e | 913 | |
924663c3 JZ |
914 | ec = cms_get0_env_enc_content(cms); |
915 | if (ec == NULL) | |
916 | return 0; | |
0f113f3e MC |
917 | |
918 | kekri = ri->d.kekri; | |
919 | ||
920 | if (!kekri->key) { | |
921 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, CMS_R_NO_KEY); | |
922 | return 0; | |
923 | } | |
924 | ||
925 | wrap_nid = OBJ_obj2nid(kekri->keyEncryptionAlgorithm->algorithm); | |
926 | if (aes_wrap_keylen(wrap_nid) != kekri->keylen) { | |
927 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, | |
928 | CMS_R_INVALID_KEY_LENGTH); | |
929 | return 0; | |
930 | } | |
931 | ||
932 | /* If encrypted key length is invalid don't bother */ | |
933 | ||
934 | if (kekri->encryptedKey->length < 16) { | |
935 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, | |
936 | CMS_R_INVALID_ENCRYPTED_KEY_LENGTH); | |
937 | goto err; | |
938 | } | |
939 | ||
c1669f41 | 940 | cipher = cms_get_key_wrap_cipher(kekri->keylen, cms_ctx); |
2852c672 MC |
941 | if (cipher == NULL) { |
942 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, CMS_R_INVALID_KEY_LENGTH); | |
0f113f3e MC |
943 | goto err; |
944 | } | |
945 | ||
946 | ukey = OPENSSL_malloc(kekri->encryptedKey->length - 8); | |
90945fa3 | 947 | if (ukey == NULL) { |
0f113f3e MC |
948 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, ERR_R_MALLOC_FAILURE); |
949 | goto err; | |
950 | } | |
951 | ||
2852c672 MC |
952 | ctx = EVP_CIPHER_CTX_new(); |
953 | if (ctx == NULL) { | |
954 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, ERR_R_MALLOC_FAILURE); | |
955 | goto err; | |
956 | } | |
0f113f3e | 957 | |
2852c672 MC |
958 | if (!EVP_DecryptInit_ex(ctx, cipher, NULL, kekri->key, NULL) |
959 | || !EVP_DecryptUpdate(ctx, ukey, &ukeylen, | |
960 | kekri->encryptedKey->data, | |
961 | kekri->encryptedKey->length) | |
962 | || !EVP_DecryptFinal_ex(ctx, ukey + ukeylen, &outlen)) { | |
0f113f3e MC |
963 | CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, CMS_R_UNWRAP_ERROR); |
964 | goto err; | |
965 | } | |
2852c672 | 966 | ukeylen += outlen; |
0f113f3e MC |
967 | |
968 | ec->key = ukey; | |
969 | ec->keylen = ukeylen; | |
970 | ||
971 | r = 1; | |
972 | ||
973 | err: | |
c1669f41 | 974 | EVP_CIPHER_free(cipher); |
b548a1f1 | 975 | if (!r) |
0f113f3e | 976 | OPENSSL_free(ukey); |
2852c672 | 977 | EVP_CIPHER_CTX_free(ctx); |
0f113f3e MC |
978 | |
979 | return r; | |
0f113f3e | 980 | } |
6e3bc4f0 DSH |
981 | |
982 | int CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri) | |
0f113f3e MC |
983 | { |
984 | switch (ri->type) { | |
985 | case CMS_RECIPINFO_TRANS: | |
986 | return cms_RecipientInfo_ktri_decrypt(cms, ri); | |
6e3bc4f0 | 987 | |
0f113f3e MC |
988 | case CMS_RECIPINFO_KEK: |
989 | return cms_RecipientInfo_kekri_decrypt(cms, ri); | |
6e3bc4f0 | 990 | |
0f113f3e MC |
991 | case CMS_RECIPINFO_PASS: |
992 | return cms_RecipientInfo_pwri_crypt(cms, ri, 0); | |
d2a53c22 | 993 | |
0f113f3e MC |
994 | default: |
995 | CMSerr(CMS_F_CMS_RECIPIENTINFO_DECRYPT, | |
df578aa0 | 996 | CMS_R_UNSUPPORTED_RECIPIENTINFO_TYPE); |
0f113f3e MC |
997 | return 0; |
998 | } | |
999 | } | |
6e3bc4f0 | 1000 | |
9fdcc21f | 1001 | int CMS_RecipientInfo_encrypt(const CMS_ContentInfo *cms, CMS_RecipientInfo *ri) |
0f113f3e MC |
1002 | { |
1003 | switch (ri->type) { | |
1004 | case CMS_RECIPINFO_TRANS: | |
1005 | return cms_RecipientInfo_ktri_encrypt(cms, ri); | |
1006 | ||
1007 | case CMS_RECIPINFO_AGREE: | |
1008 | return cms_RecipientInfo_kari_encrypt(cms, ri); | |
1009 | ||
1010 | case CMS_RECIPINFO_KEK: | |
1011 | return cms_RecipientInfo_kekri_encrypt(cms, ri); | |
0f113f3e MC |
1012 | |
1013 | case CMS_RECIPINFO_PASS: | |
1014 | return cms_RecipientInfo_pwri_crypt(cms, ri, 1); | |
0f113f3e MC |
1015 | |
1016 | default: | |
1017 | CMSerr(CMS_F_CMS_RECIPIENTINFO_ENCRYPT, | |
1018 | CMS_R_UNSUPPORTED_RECIPIENT_TYPE); | |
1019 | return 0; | |
1020 | } | |
1021 | } | |
e1f1d28f | 1022 | |
ff7b6ce9 DSH |
1023 | /* Check structures and fixup version numbers (if necessary) */ |
1024 | ||
1025 | static void cms_env_set_originfo_version(CMS_EnvelopedData *env) | |
0f113f3e MC |
1026 | { |
1027 | CMS_OriginatorInfo *org = env->originatorInfo; | |
1028 | int i; | |
1029 | if (org == NULL) | |
1030 | return; | |
1031 | for (i = 0; i < sk_CMS_CertificateChoices_num(org->certificates); i++) { | |
1032 | CMS_CertificateChoices *cch; | |
1033 | cch = sk_CMS_CertificateChoices_value(org->certificates, i); | |
1034 | if (cch->type == CMS_CERTCHOICE_OTHER) { | |
1035 | env->version = 4; | |
1036 | return; | |
1037 | } else if (cch->type == CMS_CERTCHOICE_V2ACERT) { | |
1038 | if (env->version < 3) | |
1039 | env->version = 3; | |
1040 | } | |
1041 | } | |
1042 | ||
1043 | for (i = 0; i < sk_CMS_RevocationInfoChoice_num(org->crls); i++) { | |
1044 | CMS_RevocationInfoChoice *rch; | |
1045 | rch = sk_CMS_RevocationInfoChoice_value(org->crls, i); | |
1046 | if (rch->type == CMS_REVCHOICE_OTHER) { | |
1047 | env->version = 4; | |
1048 | return; | |
1049 | } | |
1050 | } | |
1051 | } | |
ff7b6ce9 DSH |
1052 | |
1053 | static void cms_env_set_version(CMS_EnvelopedData *env) | |
0f113f3e MC |
1054 | { |
1055 | int i; | |
1056 | CMS_RecipientInfo *ri; | |
1057 | ||
1058 | /* | |
1059 | * Can't set version higher than 4 so if 4 or more already nothing to do. | |
1060 | */ | |
1061 | if (env->version >= 4) | |
1062 | return; | |
1063 | ||
1064 | cms_env_set_originfo_version(env); | |
1065 | ||
1066 | if (env->version >= 3) | |
1067 | return; | |
1068 | ||
1069 | for (i = 0; i < sk_CMS_RecipientInfo_num(env->recipientInfos); i++) { | |
1070 | ri = sk_CMS_RecipientInfo_value(env->recipientInfos, i); | |
1071 | if (ri->type == CMS_RECIPINFO_PASS || ri->type == CMS_RECIPINFO_OTHER) { | |
1072 | env->version = 3; | |
1073 | return; | |
1074 | } else if (ri->type != CMS_RECIPINFO_TRANS | |
1075 | || ri->d.ktri->version != 0) { | |
1076 | env->version = 2; | |
1077 | } | |
1078 | } | |
0f113f3e MC |
1079 | if (env->originatorInfo || env->unprotectedAttrs) |
1080 | env->version = 2; | |
35096e91 RS |
1081 | if (env->version == 2) |
1082 | return; | |
0f113f3e MC |
1083 | env->version = 0; |
1084 | } | |
ff7b6ce9 | 1085 | |
924663c3 JZ |
1086 | static int cms_env_encrypt_content_key(const CMS_ContentInfo *cms, |
1087 | STACK_OF(CMS_RecipientInfo) *ris) | |
1088 | { | |
1089 | int i; | |
1090 | CMS_RecipientInfo *ri; | |
1091 | ||
1092 | for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) { | |
1093 | ri = sk_CMS_RecipientInfo_value(ris, i); | |
1094 | if (CMS_RecipientInfo_encrypt(cms, ri) <= 0) | |
1095 | return -1; | |
1096 | } | |
1097 | return 1; | |
1098 | } | |
1099 | ||
1100 | static void cms_env_clear_ec(CMS_EncryptedContentInfo *ec) | |
1101 | { | |
1102 | ec->cipher = NULL; | |
1103 | OPENSSL_clear_free(ec->key, ec->keylen); | |
1104 | ec->key = NULL; | |
1105 | ec->keylen = 0; | |
1106 | } | |
1107 | ||
71434aed DB |
1108 | static BIO *cms_EnvelopedData_Decryption_init_bio(CMS_ContentInfo *cms) |
1109 | { | |
1110 | CMS_EncryptedContentInfo *ec = cms->d.envelopedData->encryptedContentInfo; | |
c1669f41 | 1111 | BIO *contentBio = cms_EncryptedContent_init_bio(ec, cms_get0_cmsctx(cms)); |
71434aed DB |
1112 | EVP_CIPHER_CTX *ctx = NULL; |
1113 | ||
1114 | if (contentBio == NULL) | |
1115 | return NULL; | |
1116 | ||
1117 | BIO_get_cipher_ctx(contentBio, &ctx); | |
1118 | if (ctx == NULL) { | |
1119 | BIO_free(contentBio); | |
1120 | return NULL; | |
1121 | } | |
924663c3 JZ |
1122 | /* |
1123 | * If the selected cipher supports unprotected attributes, | |
1124 | * deal with it using special ctrl function | |
1125 | */ | |
71434aed DB |
1126 | if ((EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_CIPHER_WITH_MAC) |
1127 | && EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_PROCESS_UNPROTECTED, 0, | |
1128 | cms->d.envelopedData->unprotectedAttrs) <= 0) { | |
1129 | BIO_free(contentBio); | |
1130 | return NULL; | |
1131 | } | |
1132 | return contentBio; | |
1133 | } | |
1134 | ||
1135 | static BIO *cms_EnvelopedData_Encryption_init_bio(CMS_ContentInfo *cms) | |
0f113f3e MC |
1136 | { |
1137 | CMS_EncryptedContentInfo *ec; | |
1138 | STACK_OF(CMS_RecipientInfo) *rinfos; | |
924663c3 | 1139 | int ok = 0; |
0f113f3e | 1140 | BIO *ret; |
924663c3 | 1141 | CMS_EnvelopedData *env = cms->d.envelopedData; |
0f113f3e MC |
1142 | |
1143 | /* Get BIO first to set up key */ | |
1144 | ||
924663c3 | 1145 | ec = env->encryptedContentInfo; |
c1669f41 | 1146 | ret = cms_EncryptedContent_init_bio(ec, cms_get0_cmsctx(cms)); |
0f113f3e | 1147 | |
71434aed DB |
1148 | /* If error end of processing */ |
1149 | if (!ret) | |
0f113f3e MC |
1150 | return ret; |
1151 | ||
1152 | /* Now encrypt content key according to each RecipientInfo type */ | |
924663c3 JZ |
1153 | rinfos = env->recipientInfos; |
1154 | if (cms_env_encrypt_content_key(cms, rinfos) < 0) { | |
1155 | CMSerr(CMS_F_CMS_ENVELOPEDDATA_ENCRYPTION_INIT_BIO, | |
1156 | CMS_R_ERROR_SETTING_RECIPIENTINFO); | |
1157 | goto err; | |
0f113f3e | 1158 | } |
924663c3 JZ |
1159 | |
1160 | /* And finally set the version */ | |
1161 | cms_env_set_version(env); | |
0f113f3e MC |
1162 | |
1163 | ok = 1; | |
1164 | ||
1165 | err: | |
924663c3 | 1166 | cms_env_clear_ec(ec); |
0f113f3e MC |
1167 | if (ok) |
1168 | return ret; | |
1169 | BIO_free(ret); | |
1170 | return NULL; | |
71434aed DB |
1171 | } |
1172 | ||
1173 | BIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms) | |
1174 | { | |
1175 | if (cms->d.envelopedData->encryptedContentInfo->cipher != NULL) { | |
1176 | /* If cipher is set it's encryption */ | |
1177 | return cms_EnvelopedData_Encryption_init_bio(cms); | |
1178 | } | |
0f113f3e | 1179 | |
71434aed DB |
1180 | /* If cipher is not set it's decryption */ |
1181 | return cms_EnvelopedData_Decryption_init_bio(cms); | |
0f113f3e MC |
1182 | } |
1183 | ||
924663c3 JZ |
1184 | BIO *cms_AuthEnvelopedData_init_bio(CMS_ContentInfo *cms) |
1185 | { | |
1186 | CMS_EncryptedContentInfo *ec; | |
1187 | STACK_OF(CMS_RecipientInfo) *rinfos; | |
1188 | int ok = 0; | |
1189 | BIO *ret; | |
1190 | CMS_AuthEnvelopedData *aenv = cms->d.authEnvelopedData; | |
1191 | ||
1192 | /* Get BIO first to set up key */ | |
1193 | ec = aenv->authEncryptedContentInfo; | |
1194 | /* Set tag for decryption */ | |
1195 | if (ec->cipher == NULL) { | |
1196 | ec->tag = aenv->mac->data; | |
1197 | ec->taglen = aenv->mac->length; | |
1198 | } | |
1199 | ret = cms_EncryptedContent_init_bio(ec, cms_get0_cmsctx(cms)); | |
1200 | ||
1201 | /* If error or no cipher end of processing */ | |
1202 | if (ret == NULL || ec->cipher == NULL) | |
1203 | return ret; | |
1204 | ||
1205 | /* Now encrypt content key according to each RecipientInfo type */ | |
1206 | rinfos = aenv->recipientInfos; | |
1207 | if (cms_env_encrypt_content_key(cms, rinfos) < 0) { | |
1208 | CMSerr(0, CMS_R_ERROR_SETTING_RECIPIENTINFO); | |
1209 | goto err; | |
1210 | } | |
1211 | ||
1212 | /* And finally set the version */ | |
1213 | aenv->version = 0; | |
1214 | ||
1215 | ok = 1; | |
1216 | ||
1217 | err: | |
1218 | cms_env_clear_ec(ec); | |
1219 | if (ok) | |
1220 | return ret; | |
1221 | BIO_free(ret); | |
1222 | return NULL; | |
1223 | } | |
1224 | ||
1225 | int cms_EnvelopedData_final(CMS_ContentInfo *cms, BIO *chain) | |
1226 | { | |
1227 | CMS_EnvelopedData *env = NULL; | |
1228 | EVP_CIPHER_CTX *ctx = NULL; | |
1229 | BIO *mbio = BIO_find_type(chain, BIO_TYPE_CIPHER); | |
1230 | ||
1231 | env = cms_get0_enveloped(cms); | |
1232 | if (env == NULL) | |
1233 | return 0; | |
1234 | ||
1235 | if (mbio == NULL) { | |
1236 | CMSerr(CMS_F_CMS_ENVELOPEDDATA_FINAL, CMS_R_CONTENT_NOT_FOUND); | |
1237 | return 0; | |
1238 | } | |
1239 | ||
1240 | BIO_get_cipher_ctx(mbio, &ctx); | |
1241 | ||
1242 | /* | |
1243 | * If the selected cipher supports unprotected attributes, | |
1244 | * deal with it using special ctrl function | |
1245 | */ | |
1246 | if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_CIPHER_WITH_MAC) { | |
1247 | if (env->unprotectedAttrs == NULL) | |
1248 | env->unprotectedAttrs = sk_X509_ATTRIBUTE_new_null(); | |
1249 | ||
1250 | if (env->unprotectedAttrs == NULL) { | |
1251 | CMSerr(CMS_F_CMS_ENVELOPEDDATA_FINAL, ERR_R_MALLOC_FAILURE); | |
1252 | return 0; | |
1253 | } | |
1254 | ||
1255 | if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_PROCESS_UNPROTECTED, | |
1256 | 1, env->unprotectedAttrs) <= 0) { | |
1257 | CMSerr(CMS_F_CMS_ENVELOPEDDATA_FINAL, CMS_R_CTRL_FAILURE); | |
1258 | return 0; | |
1259 | } | |
1260 | } | |
1261 | ||
1262 | cms_env_set_version(cms->d.envelopedData); | |
1263 | return 1; | |
1264 | } | |
1265 | ||
1266 | int cms_AuthEnvelopedData_final(CMS_ContentInfo *cms, BIO *cmsbio) | |
1267 | { | |
1268 | EVP_CIPHER_CTX *ctx; | |
1269 | unsigned char *tag = NULL; | |
1270 | int taglen, ok = 0; | |
1271 | ||
1272 | BIO_get_cipher_ctx(cmsbio, &ctx); | |
1273 | ||
1274 | /* | |
1275 | * The tag is set only for encryption. There is nothing to do for | |
1276 | * decryption. | |
1277 | */ | |
1278 | if (!EVP_CIPHER_CTX_encrypting(ctx)) | |
1279 | return 1; | |
1280 | ||
1281 | taglen = EVP_CIPHER_CTX_tag_length(ctx); | |
1282 | if (taglen <= 0 | |
1283 | || (tag = OPENSSL_malloc(taglen)) == NULL | |
1284 | || EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, taglen, | |
1285 | tag) <= 0) { | |
1286 | CMSerr(0, CMS_R_CIPHER_GET_TAG); | |
1287 | goto err; | |
1288 | } | |
1289 | ||
1290 | if (!ASN1_OCTET_STRING_set(cms->d.authEnvelopedData->mac, tag, taglen)) | |
1291 | goto err; | |
1292 | ||
1293 | ok = 1; | |
1294 | err: | |
1295 | OPENSSL_free(tag); | |
1296 | return ok; | |
1297 | } | |
1298 | ||
0f113f3e MC |
1299 | /* |
1300 | * Get RecipientInfo type (if any) supported by a key (public or private). To | |
1301 | * retain compatibility with previous behaviour if the ctrl value isn't | |
17c2764d DSH |
1302 | * supported we assume key transport. |
1303 | */ | |
1304 | int cms_pkey_get_ri_type(EVP_PKEY *pk) | |
0f113f3e | 1305 | { |
7022d9b9 MC |
1306 | /* Check types that we know about */ |
1307 | if (EVP_PKEY_is_a(pk, "DH")) | |
1308 | return CMS_RECIPINFO_AGREE; | |
1309 | else if (EVP_PKEY_is_a(pk, "DSA")) | |
1310 | return CMS_RECIPINFO_NONE; | |
1311 | else if (EVP_PKEY_is_a(pk, "EC")) | |
1312 | return CMS_RECIPINFO_AGREE; | |
1313 | else if (EVP_PKEY_is_a(pk, "RSA")) | |
1314 | return CMS_RECIPINFO_TRANS; | |
1315 | ||
1316 | /* | |
1317 | * Otherwise this might ben an engine implementation, so see if we can get | |
1318 | * the type from the ameth. | |
1319 | */ | |
0f113f3e MC |
1320 | if (pk->ameth && pk->ameth->pkey_ctrl) { |
1321 | int i, r; | |
1322 | i = pk->ameth->pkey_ctrl(pk, ASN1_PKEY_CTRL_CMS_RI_TYPE, 0, &r); | |
1323 | if (i > 0) | |
1324 | return r; | |
1325 | } | |
1326 | return CMS_RECIPINFO_TRANS; | |
1327 | } | |
71434aed DB |
1328 | |
1329 | int cms_pkey_is_ri_type_supported(EVP_PKEY *pk, int ri_type) | |
1330 | { | |
1331 | int supportedRiType; | |
1332 | ||
1333 | if (pk->ameth != NULL && pk->ameth->pkey_ctrl != NULL) { | |
1334 | int i, r; | |
1335 | ||
c1669f41 SL |
1336 | i = pk->ameth->pkey_ctrl(pk, ASN1_PKEY_CTRL_CMS_IS_RI_TYPE_SUPPORTED, |
1337 | ri_type, &r); | |
71434aed DB |
1338 | if (i > 0) |
1339 | return r; | |
1340 | } | |
1341 | ||
1342 | supportedRiType = cms_pkey_get_ri_type(pk); | |
1343 | if (supportedRiType < 0) | |
1344 | return 0; | |
1345 | ||
1346 | return (supportedRiType == ri_type); | |
1347 | } |