Line data Source code
1 : /*
2 : * Copyright (c) 2003 - 2007 Kungliga Tekniska Högskolan
3 : * (Royal Institute of Technology, Stockholm, Sweden).
4 : * All rights reserved.
5 : *
6 : * Redistribution and use in source and binary forms, with or without
7 : * modification, are permitted provided that the following conditions
8 : * are met:
9 : *
10 : * 1. Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : *
13 : * 2. Redistributions in binary form must reproduce the above copyright
14 : * notice, this list of conditions and the following disclaimer in the
15 : * documentation and/or other materials provided with the distribution.
16 : *
17 : * 3. Neither the name of the Institute nor the names of its contributors
18 : * may be used to endorse or promote products derived from this software
19 : * without specific prior written permission.
20 : *
21 : * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 : * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 : * SUCH DAMAGE.
32 : */
33 :
34 : #include "hx_locl.h"
35 :
36 : /**
37 : * @page page_cms CMS/PKCS7 message functions.
38 : *
39 : * CMS is defined in RFC 3369 and is an continuation of the RSA Labs
40 : * standard PKCS7. The basic messages in CMS is
41 : *
42 : * - SignedData
43 : * Data signed with private key (RSA, DSA, ECDSA) or secret
44 : * (symmetric) key
45 : * - EnvelopedData
46 : * Data encrypted with private key (RSA)
47 : * - EncryptedData
48 : * Data encrypted with secret (symmetric) key.
49 : * - ContentInfo
50 : * Wrapper structure including type and data.
51 : *
52 : *
53 : * See the library functions here: @ref hx509_cms
54 : */
55 :
56 : #define ALLOC(X, N) (X) = calloc((N), sizeof(*(X)))
57 : #define ALLOC_SEQ(X, N) do { (X)->len = (N); ALLOC((X)->val, (N)); } while(0)
58 :
59 : /**
60 : * Wrap data and oid in a ContentInfo and encode it.
61 : *
62 : * @param oid type of the content.
63 : * @param buf data to be wrapped. If a NULL pointer is passed in, the
64 : * optional content field in the ContentInfo is not going be filled
65 : * in.
66 : * @param res the encoded buffer, the result should be freed with
67 : * der_free_octet_string().
68 : *
69 : * @return Returns an hx509 error code.
70 : *
71 : * @ingroup hx509_cms
72 : */
73 :
74 : HX509_LIB_FUNCTION int HX509_LIB_CALL
75 128 : hx509_cms_wrap_ContentInfo(const heim_oid *oid,
76 : const heim_octet_string *buf,
77 : heim_octet_string *res)
78 : {
79 0 : ContentInfo ci;
80 0 : size_t size;
81 0 : int ret;
82 :
83 128 : memset(res, 0, sizeof(*res));
84 128 : memset(&ci, 0, sizeof(ci));
85 :
86 128 : ret = der_copy_oid(oid, &ci.contentType);
87 128 : if (ret)
88 0 : return ret;
89 128 : if (buf) {
90 128 : ALLOC(ci.content, 1);
91 128 : if (ci.content == NULL) {
92 0 : free_ContentInfo(&ci);
93 0 : return ENOMEM;
94 : }
95 128 : ci.content->data = malloc(buf->length);
96 128 : if (ci.content->data == NULL) {
97 0 : free_ContentInfo(&ci);
98 0 : return ENOMEM;
99 : }
100 128 : memcpy(ci.content->data, buf->data, buf->length);
101 128 : ci.content->length = buf->length;
102 : }
103 :
104 128 : ASN1_MALLOC_ENCODE(ContentInfo, res->data, res->length, &ci, &size, ret);
105 128 : free_ContentInfo(&ci);
106 128 : if (ret)
107 0 : return ret;
108 128 : if (res->length != size)
109 0 : _hx509_abort("internal ASN.1 encoder error");
110 :
111 128 : return 0;
112 : }
113 :
114 : /**
115 : * Decode an ContentInfo and unwrap data and oid it.
116 : *
117 : * @param in the encoded buffer.
118 : * @param oid type of the content.
119 : * @param out data to be wrapped.
120 : * @param have_data since the data is optional, this flag shows the
121 : * difference between no data and the zero length data.
122 : *
123 : * @return Returns an hx509 error code.
124 : *
125 : * @ingroup hx509_cms
126 : */
127 :
128 : HX509_LIB_FUNCTION int HX509_LIB_CALL
129 74 : hx509_cms_unwrap_ContentInfo(const heim_octet_string *in,
130 : heim_oid *oid,
131 : heim_octet_string *out,
132 : int *have_data)
133 : {
134 0 : ContentInfo ci;
135 0 : size_t size;
136 0 : int ret;
137 :
138 74 : memset(oid, 0, sizeof(*oid));
139 74 : memset(out, 0, sizeof(*out));
140 :
141 74 : ret = decode_ContentInfo(in->data, in->length, &ci, &size);
142 74 : if (ret)
143 0 : return ret;
144 :
145 74 : ret = der_copy_oid(&ci.contentType, oid);
146 74 : if (ret) {
147 0 : free_ContentInfo(&ci);
148 0 : return ret;
149 : }
150 74 : if (ci.content) {
151 74 : ret = der_copy_octet_string(ci.content, out);
152 74 : if (ret) {
153 0 : der_free_oid(oid);
154 0 : free_ContentInfo(&ci);
155 0 : return ret;
156 : }
157 : } else
158 0 : memset(out, 0, sizeof(*out));
159 :
160 74 : if (have_data)
161 61 : *have_data = (ci.content != NULL) ? 1 : 0;
162 :
163 74 : free_ContentInfo(&ci);
164 :
165 74 : return 0;
166 : }
167 :
168 : #define CMS_ID_SKI 0
169 : #define CMS_ID_NAME 1
170 :
171 : static int
172 86 : fill_CMSIdentifier(const hx509_cert cert,
173 : int type,
174 : CMSIdentifier *id)
175 : {
176 0 : int ret;
177 :
178 86 : switch (type) {
179 86 : case CMS_ID_SKI:
180 86 : id->element = choice_CMSIdentifier_subjectKeyIdentifier;
181 86 : ret = _hx509_find_extension_subject_key_id(_hx509_get_cert(cert),
182 : &id->u.subjectKeyIdentifier);
183 86 : if (ret == 0)
184 86 : break;
185 0 : HEIM_FALLTHROUGH;
186 : case CMS_ID_NAME: {
187 0 : hx509_name name;
188 :
189 0 : id->element = choice_CMSIdentifier_issuerAndSerialNumber;
190 0 : ret = hx509_cert_get_issuer(cert, &name);
191 0 : if (ret)
192 0 : return ret;
193 0 : ret = hx509_name_to_Name(name, &id->u.issuerAndSerialNumber.issuer);
194 0 : hx509_name_free(&name);
195 0 : if (ret)
196 0 : return ret;
197 :
198 0 : ret = hx509_cert_get_serialnumber(cert, &id->u.issuerAndSerialNumber.serialNumber);
199 0 : break;
200 : }
201 0 : default:
202 0 : _hx509_abort("CMS fill identifier with unknown type");
203 : }
204 86 : return ret;
205 : }
206 :
207 : static int
208 0 : unparse_CMSIdentifier(hx509_context context,
209 : CMSIdentifier *id,
210 : char **str)
211 : {
212 0 : int ret = -1;
213 :
214 0 : *str = NULL;
215 0 : switch (id->element) {
216 0 : case choice_CMSIdentifier_issuerAndSerialNumber: {
217 0 : IssuerAndSerialNumber *iasn;
218 0 : char *serial, *name;
219 :
220 0 : iasn = &id->u.issuerAndSerialNumber;
221 :
222 0 : ret = _hx509_Name_to_string(&iasn->issuer, &name);
223 0 : if(ret)
224 0 : return ret;
225 0 : ret = der_print_hex_heim_integer(&iasn->serialNumber, &serial);
226 0 : if (ret) {
227 0 : free(name);
228 0 : return ret;
229 : }
230 0 : ret = asprintf(str, "certificate issued by %s with serial number %s",
231 : name, serial);
232 0 : free(name);
233 0 : free(serial);
234 0 : break;
235 : }
236 0 : case choice_CMSIdentifier_subjectKeyIdentifier: {
237 0 : KeyIdentifier *ki = &id->u.subjectKeyIdentifier;
238 0 : char *keyid;
239 0 : ssize_t len;
240 :
241 0 : len = hex_encode(ki->data, ki->length, &keyid);
242 0 : if (len < 0)
243 0 : return ENOMEM;
244 :
245 0 : if (len)
246 0 : ret = asprintf(str, "certificate with id %s", keyid);
247 : else
248 0 : ret = asprintf(str, "certificate");
249 0 : free(keyid);
250 0 : break;
251 : }
252 0 : default:
253 0 : ret = asprintf(str, "certificate has unknown CMSidentifier type");
254 0 : break;
255 : }
256 : /*
257 : * In the following if, we check ret and *str which should be returned/set
258 : * by asprintf(3) in every branch of the switch statement.
259 : */
260 0 : if (ret == -1 || *str == NULL)
261 0 : return ENOMEM;
262 0 : return 0;
263 : }
264 :
265 : static int
266 74 : find_CMSIdentifier(hx509_context context,
267 : CMSIdentifier *client,
268 : hx509_certs certs,
269 : time_t time_now,
270 : hx509_cert *signer_cert,
271 : int match)
272 : {
273 0 : hx509_query q;
274 0 : hx509_cert cert;
275 0 : Certificate c;
276 0 : int ret;
277 :
278 74 : memset(&c, 0, sizeof(c));
279 74 : _hx509_query_clear(&q);
280 :
281 74 : *signer_cert = NULL;
282 :
283 74 : switch (client->element) {
284 0 : case choice_CMSIdentifier_issuerAndSerialNumber:
285 0 : q.serial = &client->u.issuerAndSerialNumber.serialNumber;
286 0 : q.issuer_name = &client->u.issuerAndSerialNumber.issuer;
287 0 : q.match = HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME;
288 0 : break;
289 74 : case choice_CMSIdentifier_subjectKeyIdentifier:
290 74 : q.subject_id = &client->u.subjectKeyIdentifier;
291 74 : q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID;
292 74 : break;
293 0 : default:
294 0 : hx509_set_error_string(context, 0, HX509_CMS_NO_RECIPIENT_CERTIFICATE,
295 : "unknown CMS identifier element");
296 0 : return HX509_CMS_NO_RECIPIENT_CERTIFICATE;
297 : }
298 :
299 74 : q.match |= match;
300 :
301 74 : q.match |= HX509_QUERY_MATCH_TIME;
302 74 : if (time_now)
303 61 : q.timenow = time_now;
304 : else
305 13 : q.timenow = time(NULL);
306 :
307 74 : ret = hx509_certs_find(context, certs, &q, &cert);
308 74 : if (ret == HX509_CERT_NOT_FOUND) {
309 0 : char *str;
310 :
311 0 : ret = unparse_CMSIdentifier(context, client, &str);
312 0 : if (ret == 0) {
313 0 : hx509_set_error_string(context, 0,
314 : HX509_CMS_NO_RECIPIENT_CERTIFICATE,
315 : "Failed to find %s", str);
316 : } else
317 0 : hx509_clear_error_string(context);
318 0 : return HX509_CMS_NO_RECIPIENT_CERTIFICATE;
319 74 : } else if (ret) {
320 0 : hx509_set_error_string(context, HX509_ERROR_APPEND,
321 : HX509_CMS_NO_RECIPIENT_CERTIFICATE,
322 : "Failed to find CMS id in cert store");
323 0 : return HX509_CMS_NO_RECIPIENT_CERTIFICATE;
324 : }
325 :
326 74 : *signer_cert = cert;
327 :
328 74 : return 0;
329 : }
330 :
331 : /**
332 : * Decode and unencrypt EnvelopedData.
333 : *
334 : * Extract data and parameters from the EnvelopedData. Also
335 : * supports using detached EnvelopedData.
336 : *
337 : * @param context A hx509 context.
338 : * @param certs Certificate that can decrypt the EnvelopedData
339 : * encryption key.
340 : * @param flags HX509_CMS_UE flags to control the behavior.
341 : * @param data pointer the structure the contains the DER/BER encoded
342 : * EnvelopedData stucture.
343 : * @param length length of the data that data point to.
344 : * @param encryptedContent in case of detached signature, this
345 : * contains the actual encrypted data, otherwise it should be NULL.
346 : * @param time_now set the current time, if zero the library uses now as the date.
347 : * @param contentType output type oid, should be freed with der_free_oid().
348 : * @param content the data, free with der_free_octet_string().
349 : *
350 : * @return an hx509 error code.
351 : *
352 : * @ingroup hx509_cms
353 : */
354 :
355 : HX509_LIB_FUNCTION int HX509_LIB_CALL
356 0 : hx509_cms_unenvelope(hx509_context context,
357 : hx509_certs certs,
358 : int flags,
359 : const void *data,
360 : size_t length,
361 : const heim_octet_string *encryptedContent,
362 : time_t time_now,
363 : heim_oid *contentType,
364 : heim_octet_string *content)
365 : {
366 0 : heim_octet_string key;
367 0 : EnvelopedData ed;
368 0 : hx509_cert cert;
369 0 : AlgorithmIdentifier *ai;
370 0 : const heim_octet_string *enccontent;
371 0 : heim_octet_string *params, params_data;
372 0 : heim_octet_string ivec;
373 0 : size_t size;
374 0 : int ret, matched = 0, findflags = 0;
375 0 : size_t i;
376 :
377 :
378 0 : memset(&key, 0, sizeof(key));
379 0 : memset(&ed, 0, sizeof(ed));
380 0 : memset(&ivec, 0, sizeof(ivec));
381 0 : memset(content, 0, sizeof(*content));
382 0 : memset(contentType, 0, sizeof(*contentType));
383 :
384 0 : if ((flags & HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT) == 0)
385 0 : findflags |= HX509_QUERY_KU_ENCIPHERMENT;
386 :
387 0 : ret = decode_EnvelopedData(data, length, &ed, &size);
388 0 : if (ret) {
389 0 : hx509_set_error_string(context, 0, ret,
390 : "Failed to decode EnvelopedData");
391 0 : return ret;
392 : }
393 :
394 0 : if (ed.recipientInfos.len == 0) {
395 0 : ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
396 0 : hx509_set_error_string(context, 0, ret,
397 : "No recipient info in enveloped data");
398 0 : goto out;
399 : }
400 :
401 0 : enccontent = ed.encryptedContentInfo.encryptedContent;
402 0 : if (enccontent == NULL) {
403 0 : if (encryptedContent == NULL) {
404 0 : ret = HX509_CMS_NO_DATA_AVAILABLE;
405 0 : hx509_set_error_string(context, 0, ret,
406 : "Content missing from encrypted data");
407 0 : goto out;
408 : }
409 0 : enccontent = encryptedContent;
410 0 : } else if (encryptedContent != NULL) {
411 0 : ret = HX509_CMS_NO_DATA_AVAILABLE;
412 0 : hx509_set_error_string(context, 0, ret,
413 : "Both internal and external encrypted data");
414 0 : goto out;
415 : }
416 :
417 0 : cert = NULL;
418 0 : for (i = 0; i < ed.recipientInfos.len; i++) {
419 0 : KeyTransRecipientInfo *ri;
420 0 : char *str;
421 0 : int ret2;
422 :
423 0 : ri = &ed.recipientInfos.val[i];
424 :
425 0 : ret = find_CMSIdentifier(context, &ri->rid, certs,
426 : time_now, &cert,
427 : HX509_QUERY_PRIVATE_KEY|findflags);
428 0 : if (ret)
429 0 : continue;
430 :
431 0 : matched = 1; /* found a matching certificate, let decrypt */
432 :
433 0 : ret = _hx509_cert_private_decrypt(context,
434 0 : &ri->encryptedKey,
435 0 : &ri->keyEncryptionAlgorithm.algorithm,
436 : cert, &key);
437 :
438 0 : hx509_cert_free(cert);
439 0 : if (ret == 0)
440 0 : break; /* successfully decrypted cert */
441 0 : cert = NULL;
442 0 : ret2 = unparse_CMSIdentifier(context, &ri->rid, &str);
443 0 : if (ret2 == 0) {
444 0 : hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
445 : "Failed to decrypt with %s", str);
446 0 : free(str);
447 : }
448 : }
449 :
450 0 : if (!matched) {
451 0 : ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
452 0 : hx509_set_error_string(context, 0, ret,
453 : "No private key matched any certificate");
454 0 : goto out;
455 : }
456 :
457 0 : if (cert == NULL) {
458 0 : ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
459 0 : hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
460 : "No private key decrypted the transfer key");
461 0 : goto out;
462 : }
463 :
464 0 : ret = der_copy_oid(&ed.encryptedContentInfo.contentType, contentType);
465 0 : if (ret) {
466 0 : hx509_set_error_string(context, 0, ret,
467 : "Failed to copy EnvelopedData content oid");
468 0 : goto out;
469 : }
470 :
471 0 : ai = &ed.encryptedContentInfo.contentEncryptionAlgorithm;
472 0 : if (ai->parameters) {
473 0 : params_data.data = ai->parameters->data;
474 0 : params_data.length = ai->parameters->length;
475 0 : params = ¶ms_data;
476 : } else
477 0 : params = NULL;
478 :
479 : {
480 0 : hx509_crypto crypto;
481 :
482 0 : ret = hx509_crypto_init(context, NULL, &ai->algorithm, &crypto);
483 0 : if (ret)
484 0 : goto out;
485 :
486 0 : if (flags & HX509_CMS_UE_ALLOW_WEAK)
487 0 : hx509_crypto_allow_weak(crypto);
488 :
489 0 : if (params) {
490 0 : ret = hx509_crypto_set_params(context, crypto, params, &ivec);
491 0 : if (ret) {
492 0 : hx509_crypto_destroy(crypto);
493 0 : goto out;
494 : }
495 : }
496 :
497 0 : ret = hx509_crypto_set_key_data(crypto, key.data, key.length);
498 0 : if (ret) {
499 0 : hx509_crypto_destroy(crypto);
500 0 : hx509_set_error_string(context, 0, ret,
501 : "Failed to set key for decryption "
502 : "of EnvelopedData");
503 0 : goto out;
504 : }
505 :
506 0 : ret = hx509_crypto_decrypt(crypto,
507 0 : enccontent->data,
508 0 : enccontent->length,
509 0 : ivec.length ? &ivec : NULL,
510 : content);
511 0 : hx509_crypto_destroy(crypto);
512 0 : if (ret) {
513 0 : hx509_set_error_string(context, 0, ret,
514 : "Failed to decrypt EnvelopedData");
515 0 : goto out;
516 : }
517 : }
518 :
519 0 : out:
520 :
521 0 : free_EnvelopedData(&ed);
522 0 : der_free_octet_string(&key);
523 0 : if (ivec.length)
524 0 : der_free_octet_string(&ivec);
525 0 : if (ret) {
526 0 : der_free_oid(contentType);
527 0 : der_free_octet_string(content);
528 : }
529 :
530 0 : return ret;
531 : }
532 :
533 : /**
534 : * Encrypt and encode EnvelopedData.
535 : *
536 : * Encrypt and encode EnvelopedData. The data is encrypted with a
537 : * random key and the the random key is encrypted with the
538 : * certificate's private key. This limits what private key type can be
539 : * used to RSA.
540 : *
541 : * @param context A hx509 context.
542 : * @param flags flags to control the behavior.
543 : * - HX509_CMS_EV_NO_KU_CHECK - Don't check KU on certificate
544 : * - HX509_CMS_EV_ALLOW_WEAK - Allow weak crypto
545 : * - HX509_CMS_EV_ID_NAME - prefer issuer name and serial number
546 : * @param cert Certificate to encrypt the EnvelopedData encryption key
547 : * with.
548 : * @param data pointer the data to encrypt.
549 : * @param length length of the data that data point to.
550 : * @param encryption_type Encryption cipher to use for the bulk data,
551 : * use NULL to get default.
552 : * @param contentType type of the data that is encrypted
553 : * @param content the output of the function,
554 : * free with der_free_octet_string().
555 : *
556 : * @return an hx509 error code.
557 : *
558 : * @ingroup hx509_cms
559 : */
560 :
561 : HX509_LIB_FUNCTION int HX509_LIB_CALL
562 21 : hx509_cms_envelope_1(hx509_context context,
563 : int flags,
564 : hx509_cert cert,
565 : const void *data,
566 : size_t length,
567 : const heim_oid *encryption_type,
568 : const heim_oid *contentType,
569 : heim_octet_string *content)
570 : {
571 0 : KeyTransRecipientInfo *ri;
572 0 : heim_octet_string ivec;
573 0 : heim_octet_string key;
574 21 : hx509_crypto crypto = NULL;
575 0 : int ret, cmsidflag;
576 0 : EnvelopedData ed;
577 0 : size_t size;
578 :
579 21 : memset(&ivec, 0, sizeof(ivec));
580 21 : memset(&key, 0, sizeof(key));
581 21 : memset(&ed, 0, sizeof(ed));
582 21 : memset(content, 0, sizeof(*content));
583 :
584 21 : if (encryption_type == NULL)
585 17 : encryption_type = &asn1_oid_id_aes_256_cbc;
586 :
587 21 : if ((flags & HX509_CMS_EV_NO_KU_CHECK) == 0) {
588 0 : ret = _hx509_check_key_usage(context, cert, 1 << 2, TRUE);
589 0 : if (ret)
590 0 : goto out;
591 : }
592 :
593 21 : ret = hx509_crypto_init(context, NULL, encryption_type, &crypto);
594 21 : if (ret)
595 0 : goto out;
596 :
597 21 : if (flags & HX509_CMS_EV_ALLOW_WEAK)
598 0 : hx509_crypto_allow_weak(crypto);
599 :
600 21 : ret = hx509_crypto_set_random_key(crypto, &key);
601 21 : if (ret) {
602 0 : hx509_set_error_string(context, 0, ret,
603 : "Create random key for EnvelopedData content");
604 0 : goto out;
605 : }
606 :
607 21 : ret = hx509_crypto_random_iv(crypto, &ivec);
608 21 : if (ret) {
609 0 : hx509_set_error_string(context, 0, ret,
610 : "Failed to create a random iv");
611 0 : goto out;
612 : }
613 :
614 21 : ret = hx509_crypto_encrypt(crypto,
615 : data,
616 : length,
617 : &ivec,
618 : &ed.encryptedContentInfo.encryptedContent);
619 21 : if (ret) {
620 0 : hx509_set_error_string(context, 0, ret,
621 : "Failed to encrypt EnvelopedData content");
622 0 : goto out;
623 : }
624 :
625 : {
626 0 : AlgorithmIdentifier *enc_alg;
627 21 : enc_alg = &ed.encryptedContentInfo.contentEncryptionAlgorithm;
628 21 : ret = der_copy_oid(encryption_type, &enc_alg->algorithm);
629 21 : if (ret) {
630 0 : hx509_set_error_string(context, 0, ret,
631 : "Failed to set crypto oid "
632 : "for EnvelopedData");
633 0 : goto out;
634 : }
635 21 : ALLOC(enc_alg->parameters, 1);
636 21 : if (enc_alg->parameters == NULL) {
637 0 : ret = ENOMEM;
638 0 : hx509_set_error_string(context, 0, ret,
639 : "Failed to allocate crypto parameters "
640 : "for EnvelopedData");
641 0 : goto out;
642 : }
643 :
644 21 : ret = hx509_crypto_get_params(context,
645 : crypto,
646 : &ivec,
647 21 : enc_alg->parameters);
648 21 : if (ret) {
649 0 : goto out;
650 : }
651 : }
652 :
653 21 : ALLOC_SEQ(&ed.recipientInfos, 1);
654 21 : if (ed.recipientInfos.val == NULL) {
655 0 : ret = ENOMEM;
656 0 : hx509_set_error_string(context, 0, ret,
657 : "Failed to allocate recipients info "
658 : "for EnvelopedData");
659 0 : goto out;
660 : }
661 :
662 21 : ri = &ed.recipientInfos.val[0];
663 :
664 21 : if (flags & HX509_CMS_EV_ID_NAME) {
665 0 : ri->version = 0;
666 0 : cmsidflag = CMS_ID_NAME;
667 : } else {
668 21 : ri->version = 2;
669 21 : cmsidflag = CMS_ID_SKI;
670 : }
671 :
672 21 : ret = fill_CMSIdentifier(cert, cmsidflag, &ri->rid);
673 21 : if (ret) {
674 0 : hx509_set_error_string(context, 0, ret,
675 : "Failed to set CMS identifier info "
676 : "for EnvelopedData");
677 0 : goto out;
678 : }
679 :
680 21 : ret = hx509_cert_public_encrypt(context,
681 : &key, cert,
682 : &ri->keyEncryptionAlgorithm.algorithm,
683 21 : &ri->encryptedKey);
684 21 : if (ret) {
685 0 : hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
686 : "Failed to encrypt transport key for "
687 : "EnvelopedData");
688 0 : goto out;
689 : }
690 :
691 : /*
692 : *
693 : */
694 :
695 21 : ed.version = 0;
696 21 : ed.originatorInfo = NULL;
697 :
698 21 : ret = der_copy_oid(contentType, &ed.encryptedContentInfo.contentType);
699 21 : if (ret) {
700 0 : hx509_set_error_string(context, 0, ret,
701 : "Failed to copy content oid for "
702 : "EnvelopedData");
703 0 : goto out;
704 : }
705 :
706 21 : ed.unprotectedAttrs = NULL;
707 :
708 21 : ASN1_MALLOC_ENCODE(EnvelopedData, content->data, content->length,
709 : &ed, &size, ret);
710 21 : if (ret) {
711 0 : hx509_set_error_string(context, 0, ret,
712 : "Failed to encode EnvelopedData");
713 0 : goto out;
714 : }
715 21 : if (size != content->length)
716 0 : _hx509_abort("internal ASN.1 encoder error");
717 :
718 21 : out:
719 21 : if (crypto)
720 21 : hx509_crypto_destroy(crypto);
721 21 : if (ret)
722 0 : der_free_octet_string(content);
723 21 : der_free_octet_string(&key);
724 21 : der_free_octet_string(&ivec);
725 21 : free_EnvelopedData(&ed);
726 :
727 21 : return ret;
728 : }
729 :
730 : static int
731 74 : any_to_certs(hx509_context context, const SignedData *sd, hx509_certs certs)
732 : {
733 0 : int ret;
734 0 : size_t i;
735 :
736 74 : if (sd->certificates == NULL)
737 0 : return 0;
738 :
739 148 : for (i = 0; i < sd->certificates->len; i++) {
740 0 : heim_error_t error;
741 0 : hx509_cert c;
742 :
743 74 : c = hx509_cert_init_data(context,
744 74 : sd->certificates->val[i].data,
745 74 : sd->certificates->val[i].length,
746 : &error);
747 74 : if (c == NULL) {
748 0 : ret = heim_error_get_code(error);
749 0 : heim_release(error);
750 0 : return ret;
751 : }
752 74 : ret = hx509_certs_add(context, certs, c);
753 74 : hx509_cert_free(c);
754 74 : if (ret)
755 0 : return ret;
756 : }
757 :
758 74 : return 0;
759 : }
760 :
761 : static const Attribute *
762 56 : find_attribute(const CMSAttributes *attr, const heim_oid *oid)
763 : {
764 0 : size_t i;
765 84 : for (i = 0; i < attr->len; i++)
766 84 : if (der_heim_oid_cmp(&attr->val[i].type, oid) == 0)
767 56 : return &attr->val[i];
768 0 : return NULL;
769 : }
770 :
771 : /**
772 : * Decode SignedData and verify that the signature is correct.
773 : *
774 : * @param context A hx509 context.
775 : * @param ctx a hx509 verify context.
776 : * @param flags to control the behavior of the function.
777 : * - HX509_CMS_VS_NO_KU_CHECK - Don't check KeyUsage
778 : * - HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH - allow oid mismatch
779 : * - HX509_CMS_VS_ALLOW_ZERO_SIGNER - no signer, see below.
780 : * @param data pointer to CMS SignedData encoded data.
781 : * @param length length of the data that data points to.
782 : * @param signedContent external data used for signature.
783 : * @param pool certificate pool to build certificates paths.
784 : * @param contentType free with der_free_oid().
785 : * @param content the output of the function, free with
786 : * der_free_octet_string().
787 : * @param signer_certs list of the cerficates used to sign this
788 : * request, free with hx509_certs_free().
789 : *
790 : * @return an hx509 error code.
791 : *
792 : * @ingroup hx509_cms
793 : */
794 :
795 : HX509_LIB_FUNCTION int HX509_LIB_CALL
796 61 : hx509_cms_verify_signed(hx509_context context,
797 : hx509_verify_ctx ctx,
798 : unsigned int flags,
799 : const void *data,
800 : size_t length,
801 : const heim_octet_string *signedContent,
802 : hx509_certs pool,
803 : heim_oid *contentType,
804 : heim_octet_string *content,
805 : hx509_certs *signer_certs)
806 : {
807 0 : unsigned int verify_flags;
808 :
809 61 : return hx509_cms_verify_signed_ext(context,
810 : ctx,
811 : flags,
812 : data,
813 : length,
814 : signedContent,
815 : pool,
816 : contentType,
817 : content,
818 : signer_certs,
819 : &verify_flags);
820 : }
821 :
822 : /**
823 : * Decode SignedData and verify that the signature is correct.
824 : *
825 : * @param context A hx509 context.
826 : * @param ctx a hx509 verify context.
827 : * @param flags to control the behaivor of the function.
828 : * - HX509_CMS_VS_NO_KU_CHECK - Don't check KeyUsage
829 : * - HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH - allow oid mismatch
830 : * - HX509_CMS_VS_ALLOW_ZERO_SIGNER - no signer, see below.
831 : * @param data pointer to CMS SignedData encoded data.
832 : * @param length length of the data that data points to.
833 : * @param signedContent external data used for signature.
834 : * @param pool certificate pool to build certificates paths.
835 : * @param contentType free with der_free_oid().
836 : * @param content the output of the function, free with
837 : * der_free_octet_string().
838 : * @param signer_certs list of the cerficates used to sign this
839 : * request, free with hx509_certs_free().
840 : * @param verify_flags flags indicating whether the certificate
841 : * was verified or not
842 : *
843 : * @return an hx509 error code.
844 : *
845 : * @ingroup hx509_cms
846 : */
847 :
848 : HX509_LIB_FUNCTION int HX509_LIB_CALL
849 74 : hx509_cms_verify_signed_ext(hx509_context context,
850 : hx509_verify_ctx ctx,
851 : unsigned int flags,
852 : const void *data,
853 : size_t length,
854 : const heim_octet_string *signedContent,
855 : hx509_certs pool,
856 : heim_oid *contentType,
857 : heim_octet_string *content,
858 : hx509_certs *signer_certs,
859 : unsigned int *verify_flags)
860 : {
861 0 : SignerInfo *signer_info;
862 74 : hx509_cert cert = NULL;
863 74 : hx509_certs certs = NULL;
864 0 : SignedData sd;
865 0 : size_t size;
866 0 : int ret, found_valid_sig;
867 0 : size_t i;
868 :
869 74 : *signer_certs = NULL;
870 74 : *verify_flags = 0;
871 :
872 74 : content->data = NULL;
873 74 : content->length = 0;
874 74 : contentType->length = 0;
875 74 : contentType->components = NULL;
876 :
877 74 : memset(&sd, 0, sizeof(sd));
878 :
879 74 : ret = decode_SignedData(data, length, &sd, &size);
880 74 : if (ret) {
881 0 : hx509_set_error_string(context, 0, ret,
882 : "Failed to decode SignedData");
883 0 : goto out;
884 : }
885 :
886 74 : if (sd.encapContentInfo.eContent == NULL && signedContent == NULL) {
887 0 : ret = HX509_CMS_NO_DATA_AVAILABLE;
888 0 : hx509_set_error_string(context, 0, ret,
889 : "No content data in SignedData");
890 0 : goto out;
891 : }
892 74 : if (sd.encapContentInfo.eContent && signedContent) {
893 0 : ret = HX509_CMS_NO_DATA_AVAILABLE;
894 0 : hx509_set_error_string(context, 0, ret,
895 : "Both external and internal SignedData");
896 0 : goto out;
897 : }
898 :
899 74 : if (sd.encapContentInfo.eContent)
900 74 : ret = der_copy_octet_string(sd.encapContentInfo.eContent, content);
901 : else
902 0 : ret = der_copy_octet_string(signedContent, content);
903 74 : if (ret) {
904 0 : hx509_set_error_string(context, 0, ret, "malloc: out of memory");
905 0 : goto out;
906 : }
907 :
908 74 : ret = hx509_certs_init(context, "MEMORY:cms-cert-buffer",
909 : 0, NULL, &certs);
910 74 : if (ret)
911 0 : goto out;
912 :
913 74 : ret = hx509_certs_init(context, "MEMORY:cms-signer-certs",
914 : 0, NULL, signer_certs);
915 74 : if (ret)
916 0 : goto out;
917 :
918 : /* XXX Check CMS version */
919 :
920 74 : ret = any_to_certs(context, &sd, certs);
921 74 : if (ret)
922 0 : goto out;
923 :
924 74 : if (pool) {
925 74 : ret = hx509_certs_merge(context, certs, pool);
926 74 : if (ret)
927 0 : goto out;
928 : }
929 :
930 148 : for (found_valid_sig = 0, i = 0; i < sd.signerInfos.len; i++) {
931 74 : heim_octet_string signed_data = { 0, NULL };
932 0 : const heim_oid *match_oid;
933 0 : heim_oid decode_oid;
934 :
935 74 : signer_info = &sd.signerInfos.val[i];
936 74 : match_oid = NULL;
937 :
938 74 : if (signer_info->signature.length == 0) {
939 0 : ret = HX509_CMS_MISSING_SIGNER_DATA;
940 0 : hx509_set_error_string(context, 0, ret,
941 : "SignerInfo %zu in SignedData "
942 : "missing signature", i);
943 0 : continue;
944 : }
945 :
946 74 : ret = find_CMSIdentifier(context, &signer_info->sid, certs,
947 : _hx509_verify_get_time(ctx), &cert,
948 : HX509_QUERY_KU_DIGITALSIGNATURE);
949 74 : if (ret) {
950 : /**
951 : * If HX509_CMS_VS_NO_KU_CHECK is set, allow more liberal
952 : * search for matching certificates by not considering
953 : * KeyUsage bits on the certificates.
954 : */
955 0 : if ((flags & HX509_CMS_VS_NO_KU_CHECK) == 0)
956 0 : continue;
957 :
958 0 : ret = find_CMSIdentifier(context, &signer_info->sid, certs,
959 : _hx509_verify_get_time(ctx), &cert,
960 : 0);
961 0 : if (ret)
962 0 : continue;
963 :
964 : }
965 :
966 74 : if (signer_info->signedAttrs) {
967 0 : const Attribute *attr;
968 :
969 0 : CMSAttributes sa;
970 0 : heim_octet_string os;
971 :
972 28 : sa.val = signer_info->signedAttrs->val;
973 28 : sa.len = signer_info->signedAttrs->len;
974 :
975 : /* verify that signature exists */
976 28 : attr = find_attribute(&sa, &asn1_oid_id_pkcs9_messageDigest);
977 28 : if (attr == NULL) {
978 0 : ret = HX509_CRYPTO_SIGNATURE_MISSING;
979 0 : hx509_set_error_string(context, 0, ret,
980 : "SignerInfo has signed attributes "
981 : "but messageDigest (signature) "
982 : "is missing");
983 0 : goto next_signature;
984 : }
985 28 : if (attr->value.len != 1) {
986 0 : ret = HX509_CRYPTO_SIGNATURE_MISSING;
987 0 : hx509_set_error_string(context, 0, ret,
988 : "SignerInfo has more than one "
989 : "messageDigest (signature)");
990 0 : goto next_signature;
991 : }
992 :
993 28 : ret = decode_MessageDigest(attr->value.val[0].data,
994 28 : attr->value.val[0].length,
995 : &os,
996 : &size);
997 28 : if (ret) {
998 0 : hx509_set_error_string(context, 0, ret,
999 : "Failed to decode "
1000 : "messageDigest (signature)");
1001 0 : goto next_signature;
1002 : }
1003 :
1004 28 : ret = _hx509_verify_signature(context,
1005 : NULL,
1006 28 : &signer_info->digestAlgorithm,
1007 : content,
1008 : &os);
1009 28 : der_free_octet_string(&os);
1010 28 : if (ret) {
1011 0 : hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
1012 : "Failed to verify messageDigest");
1013 0 : goto next_signature;
1014 : }
1015 :
1016 : /*
1017 : * Fetch content oid inside signedAttrs or set it to
1018 : * id-pkcs7-data.
1019 : */
1020 28 : attr = find_attribute(&sa, &asn1_oid_id_pkcs9_contentType);
1021 28 : if (attr == NULL) {
1022 0 : match_oid = &asn1_oid_id_pkcs7_data;
1023 : } else {
1024 28 : if (attr->value.len != 1) {
1025 0 : ret = HX509_CMS_DATA_OID_MISMATCH;
1026 0 : hx509_set_error_string(context, 0, ret,
1027 : "More than one oid in signedAttrs");
1028 0 : goto next_signature;
1029 :
1030 : }
1031 28 : ret = decode_ContentType(attr->value.val[0].data,
1032 28 : attr->value.val[0].length,
1033 : &decode_oid,
1034 : &size);
1035 28 : if (ret) {
1036 0 : hx509_set_error_string(context, 0, ret,
1037 : "Failed to decode "
1038 : "oid in signedAttrs");
1039 0 : goto next_signature;
1040 : }
1041 28 : match_oid = &decode_oid;
1042 : }
1043 :
1044 28 : ASN1_MALLOC_ENCODE(CMSAttributes,
1045 : signed_data.data,
1046 : signed_data.length,
1047 : &sa,
1048 : &size, ret);
1049 28 : if (ret) {
1050 0 : if (match_oid == &decode_oid)
1051 0 : der_free_oid(&decode_oid);
1052 0 : hx509_clear_error_string(context);
1053 0 : goto next_signature;
1054 : }
1055 28 : if (size != signed_data.length)
1056 0 : _hx509_abort("internal ASN.1 encoder error");
1057 :
1058 : } else {
1059 46 : signed_data.data = content->data;
1060 46 : signed_data.length = content->length;
1061 46 : match_oid = &asn1_oid_id_pkcs7_data;
1062 : }
1063 :
1064 : /**
1065 : * If HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH, allow
1066 : * encapContentInfo mismatch with the oid in signedAttributes
1067 : * (or if no signedAttributes where use, pkcs7-data oid).
1068 : * This is only needed to work with broken CMS implementations
1069 : * that doesn't follow CMS signedAttributes rules.
1070 : */
1071 :
1072 74 : if (der_heim_oid_cmp(match_oid, &sd.encapContentInfo.eContentType) &&
1073 46 : (flags & HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH) == 0) {
1074 0 : ret = HX509_CMS_DATA_OID_MISMATCH;
1075 0 : hx509_set_error_string(context, 0, ret,
1076 : "Oid in message mismatch from the expected");
1077 : }
1078 74 : if (match_oid == &decode_oid)
1079 28 : der_free_oid(&decode_oid);
1080 :
1081 74 : if (ret == 0) {
1082 74 : ret = hx509_verify_signature(context,
1083 : cert,
1084 74 : &signer_info->signatureAlgorithm,
1085 : &signed_data,
1086 74 : &signer_info->signature);
1087 74 : if (ret)
1088 0 : hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
1089 : "Failed to verify signature in "
1090 : "CMS SignedData");
1091 : }
1092 74 : if (signed_data.data != NULL && content->data != signed_data.data) {
1093 28 : free(signed_data.data);
1094 28 : signed_data.data = NULL;
1095 : }
1096 74 : if (ret)
1097 0 : goto next_signature;
1098 :
1099 : /**
1100 : * If HX509_CMS_VS_NO_VALIDATE flags is set, return the signer
1101 : * certificate unconditionally but do not set HX509_CMS_VSE_VALIDATED.
1102 : */
1103 74 : ret = hx509_verify_path(context, ctx, cert, certs);
1104 74 : if (ret == 0 || (flags & HX509_CMS_VS_NO_VALIDATE)) {
1105 72 : if (ret == 0)
1106 72 : *verify_flags |= HX509_CMS_VSE_VALIDATED;
1107 :
1108 72 : ret = hx509_certs_add(context, *signer_certs, cert);
1109 72 : if (ret == 0)
1110 72 : found_valid_sig++;
1111 : }
1112 :
1113 2 : next_signature:
1114 74 : if (cert)
1115 74 : hx509_cert_free(cert);
1116 74 : cert = NULL;
1117 : }
1118 : /**
1119 : * If HX509_CMS_VS_ALLOW_ZERO_SIGNER is set, allow empty
1120 : * SignerInfo (no signatures). If SignedData has no signatures,
1121 : * the function will return 0 with signer_certs set to NULL. Zero
1122 : * signers is allowed by the standard, but since it's only useful
1123 : * in corner cases, it's made into a flag that the caller has to
1124 : * turn on.
1125 : */
1126 74 : if (sd.signerInfos.len == 0 && (flags & HX509_CMS_VS_ALLOW_ZERO_SIGNER)) {
1127 0 : if (*signer_certs)
1128 0 : hx509_certs_free(signer_certs);
1129 74 : } else if (found_valid_sig == 0) {
1130 2 : if (ret == 0) {
1131 0 : ret = HX509_CMS_SIGNER_NOT_FOUND;
1132 0 : hx509_set_error_string(context, 0, ret,
1133 : "No signers were found");
1134 : }
1135 2 : goto out;
1136 : }
1137 :
1138 72 : ret = der_copy_oid(&sd.encapContentInfo.eContentType, contentType);
1139 72 : if (ret) {
1140 0 : hx509_clear_error_string(context);
1141 0 : goto out;
1142 : }
1143 :
1144 72 : out:
1145 74 : free_SignedData(&sd);
1146 74 : if (certs)
1147 74 : hx509_certs_free(&certs);
1148 74 : if (ret) {
1149 2 : if (content->data)
1150 2 : der_free_octet_string(content);
1151 2 : if (*signer_certs)
1152 2 : hx509_certs_free(signer_certs);
1153 2 : der_free_oid(contentType);
1154 2 : der_free_octet_string(content);
1155 : }
1156 :
1157 74 : return ret;
1158 : }
1159 :
1160 : static int
1161 122 : add_one_attribute(Attribute **attr,
1162 : unsigned int *len,
1163 : const heim_oid *oid,
1164 : heim_octet_string *data)
1165 : {
1166 0 : void *d;
1167 0 : int ret;
1168 :
1169 122 : d = realloc(*attr, sizeof((*attr)[0]) * (*len + 1));
1170 122 : if (d == NULL)
1171 0 : return ENOMEM;
1172 122 : (*attr) = d;
1173 :
1174 122 : ret = der_copy_oid(oid, &(*attr)[*len].type);
1175 122 : if (ret)
1176 0 : return ret;
1177 :
1178 122 : ALLOC_SEQ(&(*attr)[*len].value, 1);
1179 122 : if ((*attr)[*len].value.val == NULL) {
1180 0 : der_free_oid(&(*attr)[*len].type);
1181 0 : return ENOMEM;
1182 : }
1183 :
1184 122 : (*attr)[*len].value.val[0].data = data->data;
1185 122 : (*attr)[*len].value.val[0].length = data->length;
1186 :
1187 122 : *len += 1;
1188 :
1189 122 : return 0;
1190 : }
1191 :
1192 : /**
1193 : * Sign and encode a SignedData structure.
1194 : *
1195 : * @param context A hx509 context.
1196 : * @param flags
1197 : * @param eContentType the type of the data.
1198 : * @param data data to sign
1199 : * @param length length of the data that data points to.
1200 : * @param digest_alg digest algorithm to use, use NULL to get the
1201 : * default or the peer determined algorithm.
1202 : * @param cert certificate to use for signing the data.
1203 : * @param peer info about the peer the message to send the message to,
1204 : * like what digest algorithm to use.
1205 : * @param anchors trust anchors that the client will use, used to
1206 : * polulate the certificates included in the message
1207 : * @param pool certificates to use in try to build the path to the
1208 : * trust anchors.
1209 : * @param signed_data the output of the function, free with
1210 : * der_free_octet_string().
1211 : *
1212 : * @return Returns an hx509 error code.
1213 : *
1214 : * @ingroup hx509_cms
1215 : */
1216 :
1217 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1218 169 : hx509_cms_create_signed_1(hx509_context context,
1219 : int flags,
1220 : const heim_oid *eContentType,
1221 : const void *data, size_t length,
1222 : const AlgorithmIdentifier *digest_alg,
1223 : hx509_cert cert,
1224 : hx509_peer_info peer,
1225 : hx509_certs anchors,
1226 : hx509_certs pool,
1227 : heim_octet_string *signed_data)
1228 : {
1229 0 : hx509_certs certs;
1230 169 : int ret = 0;
1231 :
1232 169 : signed_data->data = NULL;
1233 169 : signed_data->length = 0;
1234 :
1235 169 : ret = hx509_certs_init(context, "MEMORY:certs", 0, NULL, &certs);
1236 169 : if (ret)
1237 0 : return ret;
1238 169 : ret = hx509_certs_add(context, certs, cert);
1239 169 : if (ret)
1240 0 : goto out;
1241 :
1242 169 : ret = hx509_cms_create_signed(context, flags, eContentType, data, length,
1243 : digest_alg, certs, peer, anchors, pool,
1244 : signed_data);
1245 :
1246 169 : out:
1247 169 : hx509_certs_free(&certs);
1248 169 : return ret;
1249 : }
1250 :
1251 : struct sigctx {
1252 : SignedData sd;
1253 : const AlgorithmIdentifier *digest_alg;
1254 : const heim_oid *eContentType;
1255 : heim_octet_string content;
1256 : hx509_peer_info peer;
1257 : int cmsidflag;
1258 : int leafonly;
1259 : hx509_certs certs;
1260 : hx509_certs anchors;
1261 : hx509_certs pool;
1262 : };
1263 :
1264 : static int HX509_LIB_CALL
1265 65 : sig_process(hx509_context context, void *ctx, hx509_cert cert)
1266 : {
1267 65 : struct sigctx *sigctx = ctx;
1268 65 : heim_octet_string buf, sigdata = { 0, NULL };
1269 65 : SignerInfo *signer_info = NULL;
1270 0 : AlgorithmIdentifier digest;
1271 0 : size_t size;
1272 0 : void *ptr;
1273 0 : int ret;
1274 65 : SignedData *sd = &sigctx->sd;
1275 0 : hx509_path path;
1276 :
1277 65 : memset(&digest, 0, sizeof(digest));
1278 65 : memset(&path, 0, sizeof(path));
1279 :
1280 65 : if (_hx509_cert_private_key(cert) == NULL) {
1281 0 : hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING,
1282 : "Private key missing for signing");
1283 0 : return HX509_PRIVATE_KEY_MISSING;
1284 : }
1285 :
1286 65 : if (sigctx->digest_alg) {
1287 0 : ret = copy_AlgorithmIdentifier(sigctx->digest_alg, &digest);
1288 0 : if (ret)
1289 0 : hx509_clear_error_string(context);
1290 : } else {
1291 65 : ret = hx509_crypto_select(context, HX509_SELECT_DIGEST,
1292 : _hx509_cert_private_key(cert),
1293 : sigctx->peer, &digest);
1294 : }
1295 65 : if (ret)
1296 0 : goto out;
1297 :
1298 : /*
1299 : * Allocate on more signerInfo and do the signature processing
1300 : */
1301 :
1302 65 : ptr = realloc(sd->signerInfos.val,
1303 65 : (sd->signerInfos.len + 1) * sizeof(sd->signerInfos.val[0]));
1304 65 : if (ptr == NULL) {
1305 0 : ret = ENOMEM;
1306 0 : goto out;
1307 : }
1308 65 : sd->signerInfos.val = ptr;
1309 :
1310 65 : signer_info = &sd->signerInfos.val[sd->signerInfos.len];
1311 :
1312 65 : memset(signer_info, 0, sizeof(*signer_info));
1313 :
1314 65 : signer_info->version = 1;
1315 :
1316 65 : ret = fill_CMSIdentifier(cert, sigctx->cmsidflag, &signer_info->sid);
1317 65 : if (ret) {
1318 0 : hx509_clear_error_string(context);
1319 0 : goto out;
1320 : }
1321 :
1322 65 : signer_info->signedAttrs = NULL;
1323 65 : signer_info->unsignedAttrs = NULL;
1324 :
1325 65 : ret = copy_AlgorithmIdentifier(&digest, &signer_info->digestAlgorithm);
1326 65 : if (ret) {
1327 0 : hx509_clear_error_string(context);
1328 0 : goto out;
1329 : }
1330 :
1331 : /*
1332 : * If it isn't pkcs7-data send signedAttributes
1333 : */
1334 :
1335 65 : if (der_heim_oid_cmp(sigctx->eContentType, &asn1_oid_id_pkcs7_data) != 0) {
1336 0 : CMSAttributes sa;
1337 0 : heim_octet_string sig;
1338 :
1339 61 : ALLOC(signer_info->signedAttrs, 1);
1340 61 : if (signer_info->signedAttrs == NULL) {
1341 0 : ret = ENOMEM;
1342 0 : goto out;
1343 : }
1344 :
1345 61 : ret = _hx509_create_signature(context,
1346 : NULL,
1347 : &digest,
1348 61 : &sigctx->content,
1349 : NULL,
1350 : &sig);
1351 61 : if (ret)
1352 0 : goto out;
1353 :
1354 61 : ASN1_MALLOC_ENCODE(MessageDigest,
1355 : buf.data,
1356 : buf.length,
1357 : &sig,
1358 : &size,
1359 : ret);
1360 61 : der_free_octet_string(&sig);
1361 61 : if (ret) {
1362 0 : hx509_clear_error_string(context);
1363 0 : goto out;
1364 : }
1365 61 : if (size != buf.length)
1366 0 : _hx509_abort("internal ASN.1 encoder error");
1367 :
1368 61 : ret = add_one_attribute(&signer_info->signedAttrs->val,
1369 61 : &signer_info->signedAttrs->len,
1370 : &asn1_oid_id_pkcs9_messageDigest,
1371 : &buf);
1372 61 : if (ret) {
1373 0 : free(buf.data);
1374 0 : hx509_clear_error_string(context);
1375 0 : goto out;
1376 : }
1377 :
1378 :
1379 61 : ASN1_MALLOC_ENCODE(ContentType,
1380 : buf.data,
1381 : buf.length,
1382 : sigctx->eContentType,
1383 : &size,
1384 : ret);
1385 61 : if (ret)
1386 0 : goto out;
1387 61 : if (size != buf.length)
1388 0 : _hx509_abort("internal ASN.1 encoder error");
1389 :
1390 61 : ret = add_one_attribute(&signer_info->signedAttrs->val,
1391 61 : &signer_info->signedAttrs->len,
1392 : &asn1_oid_id_pkcs9_contentType,
1393 : &buf);
1394 61 : if (ret) {
1395 0 : free(buf.data);
1396 0 : hx509_clear_error_string(context);
1397 0 : goto out;
1398 : }
1399 :
1400 61 : sa.val = signer_info->signedAttrs->val;
1401 61 : sa.len = signer_info->signedAttrs->len;
1402 :
1403 61 : ASN1_MALLOC_ENCODE(CMSAttributes,
1404 : sigdata.data,
1405 : sigdata.length,
1406 : &sa,
1407 : &size,
1408 : ret);
1409 61 : if (ret) {
1410 0 : hx509_clear_error_string(context);
1411 0 : goto out;
1412 : }
1413 61 : if (size != sigdata.length)
1414 0 : _hx509_abort("internal ASN.1 encoder error");
1415 : } else {
1416 4 : sigdata.data = sigctx->content.data;
1417 4 : sigdata.length = sigctx->content.length;
1418 : }
1419 :
1420 : {
1421 0 : AlgorithmIdentifier sigalg;
1422 :
1423 65 : ret = hx509_crypto_select(context, HX509_SELECT_PUBLIC_SIG,
1424 : _hx509_cert_private_key(cert), sigctx->peer,
1425 : &sigalg);
1426 65 : if (ret)
1427 0 : goto out;
1428 :
1429 65 : ret = _hx509_create_signature(context,
1430 : _hx509_cert_private_key(cert),
1431 : &sigalg,
1432 : &sigdata,
1433 65 : &signer_info->signatureAlgorithm,
1434 65 : &signer_info->signature);
1435 65 : free_AlgorithmIdentifier(&sigalg);
1436 65 : if (ret)
1437 0 : goto out;
1438 : }
1439 :
1440 65 : sigctx->sd.signerInfos.len++;
1441 65 : signer_info = NULL;
1442 :
1443 : /*
1444 : * Provide best effort path
1445 : */
1446 65 : if (sigctx->certs) {
1447 0 : unsigned int i;
1448 :
1449 65 : if (sigctx->pool && sigctx->leafonly == 0) {
1450 65 : _hx509_calculate_path(context,
1451 : HX509_CALCULATE_PATH_NO_ANCHOR,
1452 : time(NULL),
1453 : sigctx->anchors,
1454 : 0,
1455 : cert,
1456 : sigctx->pool,
1457 : &path);
1458 : } else
1459 0 : _hx509_path_append(context, &path, cert);
1460 :
1461 130 : for (i = 0; i < path.len; i++) {
1462 : /* XXX remove dups */
1463 65 : ret = hx509_certs_add(context, sigctx->certs, path.val[i]);
1464 65 : if (ret) {
1465 0 : hx509_clear_error_string(context);
1466 0 : goto out;
1467 : }
1468 : }
1469 : }
1470 :
1471 65 : out:
1472 65 : if (signer_info)
1473 0 : free_SignerInfo(signer_info);
1474 65 : if (sigdata.data != sigctx->content.data)
1475 61 : der_free_octet_string(&sigdata);
1476 65 : _hx509_path_free(&path);
1477 65 : free_AlgorithmIdentifier(&digest);
1478 :
1479 65 : return ret;
1480 : }
1481 :
1482 : static int HX509_LIB_CALL
1483 65 : cert_process(hx509_context context, void *ctx, hx509_cert cert)
1484 : {
1485 65 : struct sigctx *sigctx = ctx;
1486 65 : const unsigned int i = sigctx->sd.certificates->len;
1487 0 : void *ptr;
1488 0 : int ret;
1489 :
1490 65 : ptr = realloc(sigctx->sd.certificates->val,
1491 65 : (i + 1) * sizeof(sigctx->sd.certificates->val[0]));
1492 65 : if (ptr == NULL)
1493 0 : return ENOMEM;
1494 65 : sigctx->sd.certificates->val = ptr;
1495 :
1496 65 : ret = hx509_cert_binary(context, cert,
1497 65 : &sigctx->sd.certificates->val[i]);
1498 65 : if (ret == 0)
1499 65 : sigctx->sd.certificates->len++;
1500 :
1501 65 : return ret;
1502 : }
1503 :
1504 : static int
1505 0 : cmp_AlgorithmIdentifier(const AlgorithmIdentifier *p, const AlgorithmIdentifier *q)
1506 : {
1507 0 : return der_heim_oid_cmp(&p->algorithm, &q->algorithm);
1508 : }
1509 :
1510 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1511 169 : hx509_cms_create_signed(hx509_context context,
1512 : int flags,
1513 : const heim_oid *eContentType,
1514 : const void *data, size_t length,
1515 : const AlgorithmIdentifier *digest_alg,
1516 : hx509_certs certs,
1517 : hx509_peer_info peer,
1518 : hx509_certs anchors,
1519 : hx509_certs pool,
1520 : heim_octet_string *signed_data)
1521 : {
1522 0 : unsigned int i, j;
1523 0 : int ret;
1524 0 : size_t size;
1525 0 : struct sigctx sigctx;
1526 :
1527 169 : memset(&sigctx, 0, sizeof(sigctx));
1528 :
1529 169 : if (eContentType == NULL)
1530 0 : eContentType = &asn1_oid_id_pkcs7_data;
1531 :
1532 169 : sigctx.digest_alg = digest_alg;
1533 169 : sigctx.content.data = rk_UNCONST(data);
1534 169 : sigctx.content.length = length;
1535 169 : sigctx.eContentType = eContentType;
1536 169 : sigctx.peer = peer;
1537 : /**
1538 : * Use HX509_CMS_SIGNATURE_ID_NAME to preferred use of issuer name
1539 : * and serial number if possible. Otherwise subject key identifier
1540 : * will preferred.
1541 : */
1542 169 : if (flags & HX509_CMS_SIGNATURE_ID_NAME)
1543 0 : sigctx.cmsidflag = CMS_ID_NAME;
1544 : else
1545 169 : sigctx.cmsidflag = CMS_ID_SKI;
1546 :
1547 : /**
1548 : * Use HX509_CMS_SIGNATURE_LEAF_ONLY to only request leaf
1549 : * certificates to be added to the SignedData.
1550 : */
1551 169 : sigctx.leafonly = (flags & HX509_CMS_SIGNATURE_LEAF_ONLY) ? 1 : 0;
1552 :
1553 : /**
1554 : * Use HX509_CMS_NO_CERTS to make the SignedData contain no
1555 : * certificates, overrides HX509_CMS_SIGNATURE_LEAF_ONLY.
1556 : */
1557 :
1558 169 : if ((flags & HX509_CMS_SIGNATURE_NO_CERTS) == 0) {
1559 169 : ret = hx509_certs_init(context, "MEMORY:certs", 0, NULL, &sigctx.certs);
1560 169 : if (ret)
1561 0 : return ret;
1562 : }
1563 :
1564 169 : sigctx.anchors = anchors;
1565 169 : sigctx.pool = pool;
1566 :
1567 169 : sigctx.sd.version = cMSVersion_v3;
1568 :
1569 169 : ret = der_copy_oid(eContentType, &sigctx.sd.encapContentInfo.eContentType);
1570 169 : if (ret)
1571 0 : goto out;
1572 :
1573 : /**
1574 : * Use HX509_CMS_SIGNATURE_DETACHED to create detached signatures.
1575 : */
1576 169 : if ((flags & HX509_CMS_SIGNATURE_DETACHED) == 0) {
1577 169 : ALLOC(sigctx.sd.encapContentInfo.eContent, 1);
1578 169 : if (sigctx.sd.encapContentInfo.eContent == NULL) {
1579 0 : hx509_clear_error_string(context);
1580 0 : ret = ENOMEM;
1581 0 : goto out;
1582 : }
1583 :
1584 169 : sigctx.sd.encapContentInfo.eContent->data = malloc(length);
1585 169 : if (sigctx.sd.encapContentInfo.eContent->data == NULL) {
1586 0 : hx509_clear_error_string(context);
1587 0 : ret = ENOMEM;
1588 0 : goto out;
1589 : }
1590 169 : memcpy(sigctx.sd.encapContentInfo.eContent->data, data, length);
1591 169 : sigctx.sd.encapContentInfo.eContent->length = length;
1592 : }
1593 :
1594 : /**
1595 : * Use HX509_CMS_SIGNATURE_NO_SIGNER to create no sigInfo (no
1596 : * signatures).
1597 : */
1598 169 : if ((flags & HX509_CMS_SIGNATURE_NO_SIGNER) == 0) {
1599 65 : ret = hx509_certs_iter_f(context, certs, sig_process, &sigctx);
1600 65 : if (ret)
1601 0 : goto out;
1602 : }
1603 :
1604 169 : if (sigctx.sd.signerInfos.len) {
1605 :
1606 : /*
1607 : * For each signerInfo, collect all different digest types.
1608 : */
1609 130 : for (i = 0; i < sigctx.sd.signerInfos.len; i++) {
1610 65 : AlgorithmIdentifier *di =
1611 65 : &sigctx.sd.signerInfos.val[i].digestAlgorithm;
1612 :
1613 65 : for (j = 0; j < sigctx.sd.digestAlgorithms.len; j++)
1614 0 : if (cmp_AlgorithmIdentifier(di, &sigctx.sd.digestAlgorithms.val[j]) == 0)
1615 0 : break;
1616 65 : if (j == sigctx.sd.digestAlgorithms.len) {
1617 65 : ret = add_DigestAlgorithmIdentifiers(&sigctx.sd.digestAlgorithms, di);
1618 65 : if (ret) {
1619 0 : hx509_clear_error_string(context);
1620 0 : goto out;
1621 : }
1622 : }
1623 : }
1624 : }
1625 :
1626 : /*
1627 : * Add certs we think are needed, build as part of sig_process
1628 : */
1629 169 : if (sigctx.certs) {
1630 169 : ALLOC(sigctx.sd.certificates, 1);
1631 169 : if (sigctx.sd.certificates == NULL) {
1632 0 : hx509_clear_error_string(context);
1633 0 : ret = ENOMEM;
1634 0 : goto out;
1635 : }
1636 :
1637 169 : ret = hx509_certs_iter_f(context, sigctx.certs, cert_process, &sigctx);
1638 169 : if (ret)
1639 0 : goto out;
1640 : }
1641 :
1642 169 : ASN1_MALLOC_ENCODE(SignedData,
1643 : signed_data->data, signed_data->length,
1644 : &sigctx.sd, &size, ret);
1645 169 : if (ret) {
1646 0 : hx509_clear_error_string(context);
1647 0 : goto out;
1648 : }
1649 169 : if (signed_data->length != size)
1650 0 : _hx509_abort("internal ASN.1 encoder error");
1651 :
1652 169 : out:
1653 169 : hx509_certs_free(&sigctx.certs);
1654 169 : free_SignedData(&sigctx.sd);
1655 :
1656 169 : return ret;
1657 : }
1658 :
1659 : HX509_LIB_FUNCTION int HX509_LIB_CALL
1660 0 : hx509_cms_decrypt_encrypted(hx509_context context,
1661 : hx509_lock lock,
1662 : const void *data,
1663 : size_t length,
1664 : heim_oid *contentType,
1665 : heim_octet_string *content)
1666 : {
1667 0 : heim_octet_string cont;
1668 0 : CMSEncryptedData ed;
1669 0 : AlgorithmIdentifier *ai;
1670 0 : int ret;
1671 :
1672 0 : memset(content, 0, sizeof(*content));
1673 0 : memset(&cont, 0, sizeof(cont));
1674 :
1675 0 : ret = decode_CMSEncryptedData(data, length, &ed, NULL);
1676 0 : if (ret) {
1677 0 : hx509_set_error_string(context, 0, ret,
1678 : "Failed to decode CMSEncryptedData");
1679 0 : return ret;
1680 : }
1681 :
1682 0 : if (ed.encryptedContentInfo.encryptedContent == NULL) {
1683 0 : ret = HX509_CMS_NO_DATA_AVAILABLE;
1684 0 : hx509_set_error_string(context, 0, ret,
1685 : "No content in EncryptedData");
1686 0 : goto out;
1687 : }
1688 :
1689 0 : ret = der_copy_oid(&ed.encryptedContentInfo.contentType, contentType);
1690 0 : if (ret) {
1691 0 : hx509_clear_error_string(context);
1692 0 : goto out;
1693 : }
1694 :
1695 0 : ai = &ed.encryptedContentInfo.contentEncryptionAlgorithm;
1696 0 : if (ai->parameters == NULL) {
1697 0 : ret = HX509_ALG_NOT_SUPP;
1698 0 : hx509_clear_error_string(context);
1699 0 : goto out;
1700 : }
1701 :
1702 0 : ret = _hx509_pbe_decrypt(context,
1703 : lock,
1704 : ai,
1705 0 : ed.encryptedContentInfo.encryptedContent,
1706 : &cont);
1707 0 : if (ret)
1708 0 : goto out;
1709 :
1710 0 : *content = cont;
1711 :
1712 0 : out:
1713 0 : if (ret) {
1714 0 : if (cont.data)
1715 0 : free(cont.data);
1716 : }
1717 0 : free_CMSEncryptedData(&ed);
1718 0 : return ret;
1719 : }
|