RSA implementation written using GMP.
[heimdal.git] / lib / hx509 / cms.c
blobfb2a0407d7990628a791c95ac9c033f05a4564ba
1 /*
2 * Copyright (c) 2003 - 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
34 #include "hx_locl.h"
35 RCSID("$Id$");
37 #define ALLOC(X, N) (X) = calloc((N), sizeof(*(X)))
38 #define ALLOC_SEQ(X, N) do { (X)->len = (N); ALLOC((X)->val, (N)); } while(0)
40 int
41 hx509_cms_wrap_ContentInfo(const heim_oid *oid,
42 const heim_octet_string *buf,
43 heim_octet_string *res)
45 ContentInfo ci;
46 size_t size;
47 int ret;
49 memset(res, 0, sizeof(*res));
50 memset(&ci, 0, sizeof(ci));
52 ret = der_copy_oid(oid, &ci.contentType);
53 if (ret)
54 return ret;
55 ALLOC(ci.content, 1);
56 if (ci.content == NULL) {
57 free_ContentInfo(&ci);
58 return ENOMEM;
60 ci.content->data = malloc(buf->length);
61 if (ci.content->data == NULL) {
62 free_ContentInfo(&ci);
63 return ENOMEM;
65 memcpy(ci.content->data, buf->data, buf->length);
66 ci.content->length = buf->length;
68 ASN1_MALLOC_ENCODE(ContentInfo, res->data, res->length, &ci, &size, ret);
69 free_ContentInfo(&ci);
70 if (ret)
71 return ret;
72 if (res->length != size)
73 _hx509_abort("internal ASN.1 encoder error");
75 return 0;
78 int
79 hx509_cms_unwrap_ContentInfo(const heim_octet_string *in,
80 heim_oid *oid,
81 heim_octet_string *out,
82 int *have_data)
84 ContentInfo ci;
85 size_t size;
86 int ret;
88 memset(oid, 0, sizeof(*oid));
89 memset(out, 0, sizeof(*out));
91 ret = decode_ContentInfo(in->data, in->length, &ci, &size);
92 if (ret)
93 return ret;
95 ret = der_copy_oid(&ci.contentType, oid);
96 if (ret) {
97 free_ContentInfo(&ci);
98 return ret;
100 if (ci.content) {
101 ret = der_copy_octet_string(ci.content, out);
102 if (ret) {
103 der_free_oid(oid);
104 free_ContentInfo(&ci);
105 return ret;
107 } else
108 memset(out, 0, sizeof(*out));
110 if (have_data)
111 *have_data = (ci.content != NULL) ? 1 : 0;
113 free_ContentInfo(&ci);
115 return 0;
118 #define CMS_ID_SKI 0
119 #define CMS_ID_NAME 1
121 static int
122 fill_CMSIdentifier(const hx509_cert cert,
123 int type,
124 CMSIdentifier *id)
126 int ret;
128 switch (type) {
129 case CMS_ID_SKI:
130 id->element = choice_CMSIdentifier_subjectKeyIdentifier;
131 ret = _hx509_find_extension_subject_key_id(_hx509_get_cert(cert),
132 &id->u.subjectKeyIdentifier);
133 if (ret == 0)
134 break;
135 /* FALL THOUGH */
136 case CMS_ID_NAME: {
137 hx509_name name;
139 id->element = choice_CMSIdentifier_issuerAndSerialNumber;
140 ret = hx509_cert_get_issuer(cert, &name);
141 if (ret)
142 return ret;
143 ret = hx509_name_to_Name(name, &id->u.issuerAndSerialNumber.issuer);
144 hx509_name_free(&name);
145 if (ret)
146 return ret;
148 ret = hx509_cert_get_serialnumber(cert, &id->u.issuerAndSerialNumber.serialNumber);
149 break;
151 default:
152 _hx509_abort("CMS fill identifier with unknown type");
154 return ret;
157 static int
158 unparse_CMSIdentifier(hx509_context context,
159 CMSIdentifier *id,
160 char **str)
162 int ret;
164 *str = NULL;
165 switch (id->element) {
166 case choice_CMSIdentifier_issuerAndSerialNumber: {
167 IssuerAndSerialNumber *iasn;
168 char *serial, *name;
170 iasn = &id->u.issuerAndSerialNumber;
172 ret = _hx509_Name_to_string(&iasn->issuer, &name);
173 if(ret)
174 return ret;
175 ret = der_print_hex_heim_integer(&iasn->serialNumber, &serial);
176 if (ret) {
177 free(name);
178 return ret;
180 asprintf(str, "certificate issued by %s with serial number %s",
181 name, serial);
182 free(name);
183 free(serial);
184 break;
186 case choice_CMSIdentifier_subjectKeyIdentifier: {
187 KeyIdentifier *ki = &id->u.subjectKeyIdentifier;
188 char *keyid;
189 ssize_t len;
191 len = hex_encode(ki->data, ki->length, &keyid);
192 if (len < 0)
193 return ENOMEM;
195 asprintf(str, "certificate with id %s", keyid);
196 free(keyid);
197 break;
199 default:
200 asprintf(str, "certificate have unknown CMSidentifier type");
201 break;
203 if (*str == NULL)
204 return ENOMEM;
205 return 0;
208 static int
209 find_CMSIdentifier(hx509_context context,
210 CMSIdentifier *client,
211 hx509_certs certs,
212 hx509_cert *signer_cert,
213 int match)
215 hx509_query q;
216 hx509_cert cert;
217 Certificate c;
218 int ret;
220 memset(&c, 0, sizeof(c));
221 _hx509_query_clear(&q);
223 *signer_cert = NULL;
225 switch (client->element) {
226 case choice_CMSIdentifier_issuerAndSerialNumber:
227 q.serial = &client->u.issuerAndSerialNumber.serialNumber;
228 q.issuer_name = &client->u.issuerAndSerialNumber.issuer;
229 q.match = HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME;
230 break;
231 case choice_CMSIdentifier_subjectKeyIdentifier:
232 q.subject_id = &client->u.subjectKeyIdentifier;
233 q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID;
234 break;
235 default:
236 hx509_set_error_string(context, 0, HX509_CMS_NO_RECIPIENT_CERTIFICATE,
237 "unknown CMS identifier element");
238 return HX509_CMS_NO_RECIPIENT_CERTIFICATE;
241 q.match |= match;
243 q.match |= HX509_QUERY_MATCH_TIME;
244 q.timenow = time(NULL);
246 ret = hx509_certs_find(context, certs, &q, &cert);
247 if (ret == HX509_CERT_NOT_FOUND) {
248 char *str;
250 ret = unparse_CMSIdentifier(context, client, &str);
251 if (ret == 0) {
252 hx509_set_error_string(context, 0,
253 HX509_CMS_NO_RECIPIENT_CERTIFICATE,
254 "Failed to find %s", str);
255 } else
256 hx509_clear_error_string(context);
257 return HX509_CMS_NO_RECIPIENT_CERTIFICATE;
258 } else if (ret) {
259 hx509_set_error_string(context, HX509_ERROR_APPEND,
260 HX509_CMS_NO_RECIPIENT_CERTIFICATE,
261 "Failed to find CMS id in cert store");
262 return HX509_CMS_NO_RECIPIENT_CERTIFICATE;
265 *signer_cert = cert;
267 return 0;
271 hx509_cms_unenvelope(hx509_context context,
272 hx509_certs certs,
273 int flags,
274 const void *data,
275 size_t length,
276 const heim_octet_string *encryptedContent,
277 heim_oid *contentType,
278 heim_octet_string *content)
280 heim_octet_string key;
281 EnvelopedData ed;
282 hx509_cert cert;
283 AlgorithmIdentifier *ai;
284 const heim_octet_string *enccontent;
285 heim_octet_string *params, params_data;
286 heim_octet_string ivec;
287 size_t size;
288 int ret, i, matched = 0, findflags = 0;
291 memset(&key, 0, sizeof(key));
292 memset(&ed, 0, sizeof(ed));
293 memset(&ivec, 0, sizeof(ivec));
294 memset(content, 0, sizeof(*content));
295 memset(contentType, 0, sizeof(*contentType));
297 if ((flags & HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT) == 0)
298 findflags |= HX509_QUERY_KU_ENCIPHERMENT;
300 ret = decode_EnvelopedData(data, length, &ed, &size);
301 if (ret) {
302 hx509_set_error_string(context, 0, ret,
303 "Failed to decode EnvelopedData");
304 return ret;
307 if (ed.recipientInfos.len == 0) {
308 ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
309 hx509_set_error_string(context, 0, ret,
310 "No recipient info in enveloped data");
311 goto out;
314 enccontent = ed.encryptedContentInfo.encryptedContent;
315 if (enccontent == NULL) {
316 if (encryptedContent == NULL) {
317 ret = HX509_CMS_NO_DATA_AVAILABLE;
318 hx509_set_error_string(context, 0, ret,
319 "Content missing from encrypted data");
320 goto out;
322 enccontent = encryptedContent;
323 } else if (encryptedContent != NULL) {
324 ret = HX509_CMS_NO_DATA_AVAILABLE;
325 hx509_set_error_string(context, 0, ret,
326 "Both internal and external encrypted data");
327 goto out;
330 cert = NULL;
331 for (i = 0; i < ed.recipientInfos.len; i++) {
332 KeyTransRecipientInfo *ri;
333 char *str;
334 int ret2;
336 ri = &ed.recipientInfos.val[i];
338 ret = find_CMSIdentifier(context, &ri->rid, certs, &cert,
339 HX509_QUERY_PRIVATE_KEY|findflags);
340 if (ret)
341 continue;
343 matched = 1; /* found a matching certificate, let decrypt */
345 ret = _hx509_cert_private_decrypt(context,
346 &ri->encryptedKey,
347 &ri->keyEncryptionAlgorithm.algorithm,
348 cert, &key);
350 hx509_cert_free(cert);
351 if (ret == 0)
352 break; /* succuessfully decrypted cert */
353 cert = NULL;
354 ret2 = unparse_CMSIdentifier(context, &ri->rid, &str);
355 if (ret2 == 0) {
356 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
357 "Failed to decrypt with %s", str);
358 free(str);
362 if (!matched) {
363 ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
364 hx509_set_error_string(context, 0, ret,
365 "No private key matched any certificate");
366 goto out;
369 if (cert == NULL) {
370 ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
371 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
372 "No private key decrypted the transfer key");
373 goto out;
376 ret = der_copy_oid(&ed.encryptedContentInfo.contentType, contentType);
377 if (ret) {
378 hx509_set_error_string(context, 0, ret,
379 "Failed to copy EnvelopedData content oid");
380 goto out;
383 ai = &ed.encryptedContentInfo.contentEncryptionAlgorithm;
384 if (ai->parameters) {
385 params_data.data = ai->parameters->data;
386 params_data.length = ai->parameters->length;
387 params = &params_data;
388 } else
389 params = NULL;
392 hx509_crypto crypto;
394 ret = hx509_crypto_init(context, NULL, &ai->algorithm, &crypto);
395 if (ret)
396 goto out;
398 if (params) {
399 ret = hx509_crypto_set_params(context, crypto, params, &ivec);
400 if (ret) {
401 hx509_crypto_destroy(crypto);
402 goto out;
406 ret = hx509_crypto_set_key_data(crypto, key.data, key.length);
407 if (ret) {
408 hx509_crypto_destroy(crypto);
409 hx509_set_error_string(context, 0, ret,
410 "Failed to set key for decryption "
411 "of EnvelopedData");
412 goto out;
415 ret = hx509_crypto_decrypt(crypto,
416 enccontent->data,
417 enccontent->length,
418 ivec.length ? &ivec : NULL,
419 content);
420 hx509_crypto_destroy(crypto);
421 if (ret) {
422 hx509_set_error_string(context, 0, ret,
423 "Failed to decrypt EnvelopedData");
424 goto out;
428 out:
430 free_EnvelopedData(&ed);
431 der_free_octet_string(&key);
432 if (ivec.length)
433 der_free_octet_string(&ivec);
434 if (ret) {
435 der_free_oid(contentType);
436 der_free_octet_string(content);
439 return ret;
443 hx509_cms_envelope_1(hx509_context context,
444 int flags,
445 hx509_cert cert,
446 const void *data,
447 size_t length,
448 const heim_oid *encryption_type,
449 const heim_oid *contentType,
450 heim_octet_string *content)
452 KeyTransRecipientInfo *ri;
453 heim_octet_string ivec;
454 heim_octet_string key;
455 hx509_crypto crypto = NULL;
456 EnvelopedData ed;
457 size_t size;
458 int ret;
460 memset(&ivec, 0, sizeof(ivec));
461 memset(&key, 0, sizeof(key));
462 memset(&ed, 0, sizeof(ed));
463 memset(content, 0, sizeof(*content));
465 if (encryption_type == NULL)
466 encryption_type = oid_id_aes_256_cbc();
468 ret = _hx509_check_key_usage(context, cert, 1 << 2, TRUE);
469 if (ret)
470 goto out;
472 ret = hx509_crypto_init(context, NULL, encryption_type, &crypto);
473 if (ret)
474 goto out;
476 ret = hx509_crypto_set_random_key(crypto, &key);
477 if (ret) {
478 hx509_set_error_string(context, 0, ret,
479 "Create random key for EnvelopedData content");
480 goto out;
483 ret = hx509_crypto_random_iv(crypto, &ivec);
484 if (ret) {
485 hx509_set_error_string(context, 0, ret,
486 "Failed to create a random iv");
487 goto out;
490 ret = hx509_crypto_encrypt(crypto,
491 data,
492 length,
493 &ivec,
494 &ed.encryptedContentInfo.encryptedContent);
495 if (ret) {
496 hx509_set_error_string(context, 0, ret,
497 "Failed to encrypt EnvelopedData content");
498 goto out;
502 AlgorithmIdentifier *enc_alg;
503 enc_alg = &ed.encryptedContentInfo.contentEncryptionAlgorithm;
504 ret = der_copy_oid(encryption_type, &enc_alg->algorithm);
505 if (ret) {
506 hx509_set_error_string(context, 0, ret,
507 "Failed to set crypto oid "
508 "for EnvelopedData");
509 goto out;
511 ALLOC(enc_alg->parameters, 1);
512 if (enc_alg->parameters == NULL) {
513 ret = ENOMEM;
514 hx509_set_error_string(context, 0, ret,
515 "Failed to allocate crypto paramaters "
516 "for EnvelopedData");
517 goto out;
520 ret = hx509_crypto_get_params(context,
521 crypto,
522 &ivec,
523 enc_alg->parameters);
524 if (ret) {
525 goto out;
529 ALLOC_SEQ(&ed.recipientInfos, 1);
530 if (ed.recipientInfos.val == NULL) {
531 ret = ENOMEM;
532 hx509_set_error_string(context, 0, ret,
533 "Failed to allocate recipients info "
534 "for EnvelopedData");
535 goto out;
538 ri = &ed.recipientInfos.val[0];
540 ri->version = 0;
541 ret = fill_CMSIdentifier(cert, CMS_ID_SKI, &ri->rid);
542 if (ret) {
543 hx509_set_error_string(context, 0, ret,
544 "Failed to set CMS identifier info "
545 "for EnvelopedData");
546 goto out;
549 ret = _hx509_cert_public_encrypt(context,
550 &key, cert,
551 &ri->keyEncryptionAlgorithm.algorithm,
552 &ri->encryptedKey);
553 if (ret) {
554 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
555 "Failed to encrypt transport key for "
556 "EnvelopedData");
557 goto out;
564 ed.version = 0;
565 ed.originatorInfo = NULL;
567 ret = der_copy_oid(contentType, &ed.encryptedContentInfo.contentType);
568 if (ret) {
569 hx509_set_error_string(context, 0, ret,
570 "Failed to copy content oid for "
571 "EnvelopedData");
572 goto out;
575 ed.unprotectedAttrs = NULL;
577 ASN1_MALLOC_ENCODE(EnvelopedData, content->data, content->length,
578 &ed, &size, ret);
579 if (ret) {
580 hx509_set_error_string(context, 0, ret,
581 "Failed to encode EnvelopedData");
582 goto out;
584 if (size != content->length)
585 _hx509_abort("internal ASN.1 encoder error");
587 out:
588 if (crypto)
589 hx509_crypto_destroy(crypto);
590 if (ret)
591 der_free_octet_string(content);
592 der_free_octet_string(&key);
593 der_free_octet_string(&ivec);
594 free_EnvelopedData(&ed);
596 return ret;
599 static int
600 any_to_certs(hx509_context context, const SignedData *sd, hx509_certs certs)
602 int ret, i;
604 if (sd->certificates == NULL)
605 return 0;
607 for (i = 0; i < sd->certificates->len; i++) {
608 hx509_cert c;
610 ret = hx509_cert_init_data(context,
611 sd->certificates->val[i].data,
612 sd->certificates->val[i].length,
613 &c);
614 if (ret)
615 return ret;
616 ret = hx509_certs_add(context, certs, c);
617 hx509_cert_free(c);
618 if (ret)
619 return ret;
622 return 0;
625 static const Attribute *
626 find_attribute(const CMSAttributes *attr, const heim_oid *oid)
628 int i;
629 for (i = 0; i < attr->len; i++)
630 if (der_heim_oid_cmp(&attr->val[i].type, oid) == 0)
631 return &attr->val[i];
632 return NULL;
636 hx509_cms_verify_signed(hx509_context context,
637 hx509_verify_ctx ctx,
638 const void *data,
639 size_t length,
640 const heim_octet_string *signedContent,
641 hx509_certs store,
642 heim_oid *contentType,
643 heim_octet_string *content,
644 hx509_certs *signer_certs)
646 SignerInfo *signer_info;
647 hx509_cert cert = NULL;
648 hx509_certs certs = NULL;
649 SignedData sd;
650 size_t size;
651 int ret, i, found_valid_sig;
653 *signer_certs = NULL;
654 content->data = NULL;
655 content->length = 0;
656 contentType->length = 0;
657 contentType->components = NULL;
659 memset(&sd, 0, sizeof(sd));
661 ret = decode_SignedData(data, length, &sd, &size);
662 if (ret) {
663 hx509_set_error_string(context, 0, ret,
664 "Failed to decode SignedData");
665 goto out;
668 if (sd.encapContentInfo.eContent == NULL && signedContent == NULL) {
669 ret = HX509_CMS_NO_DATA_AVAILABLE;
670 hx509_set_error_string(context, 0, ret,
671 "No content data in SignedData");
672 goto out;
674 if (sd.encapContentInfo.eContent && signedContent) {
675 ret = HX509_CMS_NO_DATA_AVAILABLE;
676 hx509_set_error_string(context, 0, ret,
677 "Both external and internal SignedData");
678 goto out;
680 if (sd.encapContentInfo.eContent)
681 signedContent = sd.encapContentInfo.eContent;
683 ret = hx509_certs_init(context, "MEMORY:cms-cert-buffer",
684 0, NULL, &certs);
685 if (ret)
686 goto out;
688 ret = hx509_certs_init(context, "MEMORY:cms-signer-certs",
689 0, NULL, signer_certs);
690 if (ret)
691 goto out;
693 /* XXX Check CMS version */
695 ret = any_to_certs(context, &sd, certs);
696 if (ret)
697 goto out;
699 if (store) {
700 ret = hx509_certs_merge(context, certs, store);
701 if (ret)
702 goto out;
705 for (found_valid_sig = 0, i = 0; i < sd.signerInfos.len; i++) {
706 heim_octet_string *signed_data;
707 const heim_oid *match_oid;
708 heim_oid decode_oid;
710 signer_info = &sd.signerInfos.val[i];
711 match_oid = NULL;
713 if (signer_info->signature.length == 0) {
714 ret = HX509_CMS_MISSING_SIGNER_DATA;
715 hx509_set_error_string(context, 0, ret,
716 "SignerInfo %d in SignedData "
717 "missing sigature", i);
718 continue;
721 ret = find_CMSIdentifier(context, &signer_info->sid, certs, &cert,
722 HX509_QUERY_KU_DIGITALSIGNATURE);
723 if (ret)
724 continue;
726 if (signer_info->signedAttrs) {
727 const Attribute *attr;
729 CMSAttributes sa;
730 heim_octet_string os;
732 sa.val = signer_info->signedAttrs->val;
733 sa.len = signer_info->signedAttrs->len;
735 /* verify that sigature exists */
736 attr = find_attribute(&sa, oid_id_pkcs9_messageDigest());
737 if (attr == NULL) {
738 ret = HX509_CRYPTO_SIGNATURE_MISSING;
739 hx509_set_error_string(context, 0, ret,
740 "SignerInfo have signed attributes "
741 "but messageDigest (signature) "
742 "is missing");
743 goto next_sigature;
745 if (attr->value.len != 1) {
746 ret = HX509_CRYPTO_SIGNATURE_MISSING;
747 hx509_set_error_string(context, 0, ret,
748 "SignerInfo have more then one "
749 "messageDigest (signature)");
750 goto next_sigature;
753 ret = decode_MessageDigest(attr->value.val[0].data,
754 attr->value.val[0].length,
755 &os,
756 &size);
757 if (ret) {
758 hx509_set_error_string(context, 0, ret,
759 "Failed to decode "
760 "messageDigest (signature)");
761 goto next_sigature;
764 ret = _hx509_verify_signature(context,
765 NULL,
766 &signer_info->digestAlgorithm,
767 signedContent,
768 &os);
769 der_free_octet_string(&os);
770 if (ret) {
771 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
772 "Failed to verify messageDigest");
773 goto next_sigature;
777 * Fetch content oid inside signedAttrs or set it to
778 * id-pkcs7-data.
780 attr = find_attribute(&sa, oid_id_pkcs9_contentType());
781 if (attr == NULL) {
782 match_oid = oid_id_pkcs7_data();
783 } else {
784 if (attr->value.len != 1) {
785 ret = HX509_CMS_DATA_OID_MISMATCH;
786 hx509_set_error_string(context, 0, ret,
787 "More then one oid in signedAttrs");
788 goto next_sigature;
791 ret = decode_ContentType(attr->value.val[0].data,
792 attr->value.val[0].length,
793 &decode_oid,
794 &size);
795 if (ret) {
796 hx509_set_error_string(context, 0, ret,
797 "Failed to decode "
798 "oid in signedAttrs");
799 goto next_sigature;
801 match_oid = &decode_oid;
804 ALLOC(signed_data, 1);
805 if (signed_data == NULL) {
806 if (match_oid == &decode_oid)
807 der_free_oid(&decode_oid);
808 ret = ENOMEM;
809 hx509_clear_error_string(context);
810 goto next_sigature;
813 ASN1_MALLOC_ENCODE(CMSAttributes,
814 signed_data->data,
815 signed_data->length,
816 &sa,
817 &size, ret);
818 if (ret) {
819 if (match_oid == &decode_oid)
820 der_free_oid(&decode_oid);
821 free(signed_data);
822 hx509_clear_error_string(context);
823 goto next_sigature;
825 if (size != signed_data->length)
826 _hx509_abort("internal ASN.1 encoder error");
828 } else {
829 signed_data = rk_UNCONST(signedContent);
830 match_oid = oid_id_pkcs7_data();
833 if (der_heim_oid_cmp(match_oid, &sd.encapContentInfo.eContentType)) {
834 ret = HX509_CMS_DATA_OID_MISMATCH;
835 hx509_set_error_string(context, 0, ret,
836 "Oid in message mismatch from the expected");
838 if (match_oid == &decode_oid)
839 der_free_oid(&decode_oid);
841 if (ret == 0) {
842 ret = hx509_verify_signature(context,
843 cert,
844 &signer_info->signatureAlgorithm,
845 signed_data,
846 &signer_info->signature);
847 if (ret)
848 hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
849 "Failed to verify sigature in "
850 "CMS SignedData");
852 if (signed_data != signedContent) {
853 der_free_octet_string(signed_data);
854 free(signed_data);
856 if (ret)
857 goto next_sigature;
859 ret = hx509_verify_path(context, ctx, cert, certs);
860 if (ret)
861 goto next_sigature;
863 ret = hx509_certs_add(context, *signer_certs, cert);
864 if (ret)
865 goto next_sigature;
867 found_valid_sig++;
869 next_sigature:
870 if (cert)
871 hx509_cert_free(cert);
872 cert = NULL;
874 if (found_valid_sig == 0) {
875 if (ret == 0) {
876 ret = HX509_CMS_SIGNER_NOT_FOUND;
877 hx509_set_error_string(context, 0, ret,
878 "No signers where found");
880 goto out;
883 ret = der_copy_oid(&sd.encapContentInfo.eContentType, contentType);
884 if (ret) {
885 hx509_clear_error_string(context);
886 goto out;
889 content->data = malloc(signedContent->length);
890 if (content->data == NULL) {
891 hx509_clear_error_string(context);
892 ret = ENOMEM;
893 goto out;
895 content->length = signedContent->length;
896 memcpy(content->data, signedContent->data, content->length);
898 out:
899 free_SignedData(&sd);
900 if (certs)
901 hx509_certs_free(&certs);
902 if (ret) {
903 if (*signer_certs)
904 hx509_certs_free(signer_certs);
905 der_free_oid(contentType);
906 der_free_octet_string(content);
909 return ret;
912 static int
913 add_one_attribute(Attribute **attr,
914 unsigned int *len,
915 const heim_oid *oid,
916 heim_octet_string *data)
918 void *d;
919 int ret;
921 d = realloc(*attr, sizeof((*attr)[0]) * (*len + 1));
922 if (d == NULL)
923 return ENOMEM;
924 (*attr) = d;
926 ret = der_copy_oid(oid, &(*attr)[*len].type);
927 if (ret)
928 return ret;
930 ALLOC_SEQ(&(*attr)[*len].value, 1);
931 if ((*attr)[*len].value.val == NULL) {
932 der_free_oid(&(*attr)[*len].type);
933 return ENOMEM;
936 (*attr)[*len].value.val[0].data = data->data;
937 (*attr)[*len].value.val[0].length = data->length;
939 *len += 1;
941 return 0;
945 hx509_cms_create_signed_1(hx509_context context,
946 int flags,
947 const heim_oid *eContentType,
948 const void *data, size_t length,
949 const AlgorithmIdentifier *digest_alg,
950 hx509_cert cert,
951 hx509_peer_info peer,
952 hx509_certs anchors,
953 hx509_certs pool,
954 heim_octet_string *signed_data)
956 AlgorithmIdentifier digest;
957 hx509_name name;
958 SignerInfo *signer_info;
959 heim_octet_string buf, content, sigdata = { 0, NULL };
960 SignedData sd;
961 int ret;
962 size_t size;
963 hx509_path path;
964 int cmsidflag = CMS_ID_SKI;
966 memset(&sd, 0, sizeof(sd));
967 memset(&name, 0, sizeof(name));
968 memset(&path, 0, sizeof(path));
969 memset(&digest, 0, sizeof(digest));
971 content.data = rk_UNCONST(data);
972 content.length = length;
974 if (flags & HX509_CMS_SIGATURE_ID_NAME)
975 cmsidflag = CMS_ID_NAME;
977 if (_hx509_cert_private_key(cert) == NULL) {
978 hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING,
979 "Private key missing for signing");
980 return HX509_PRIVATE_KEY_MISSING;
983 if (digest_alg == NULL) {
984 ret = hx509_crypto_select(context, HX509_SELECT_DIGEST,
985 _hx509_cert_private_key(cert), peer, &digest);
986 } else {
987 ret = copy_AlgorithmIdentifier(digest_alg, &digest);
988 if (ret)
989 hx509_clear_error_string(context);
991 if (ret)
992 goto out;
994 sd.version = CMSVersion_v3;
996 if (eContentType == NULL)
997 eContentType = oid_id_pkcs7_data();
999 der_copy_oid(eContentType, &sd.encapContentInfo.eContentType);
1001 /* */
1002 if ((flags & HX509_CMS_SIGATURE_DETACHED) == 0) {
1003 ALLOC(sd.encapContentInfo.eContent, 1);
1004 if (sd.encapContentInfo.eContent == NULL) {
1005 hx509_clear_error_string(context);
1006 ret = ENOMEM;
1007 goto out;
1010 sd.encapContentInfo.eContent->data = malloc(length);
1011 if (sd.encapContentInfo.eContent->data == NULL) {
1012 hx509_clear_error_string(context);
1013 ret = ENOMEM;
1014 goto out;
1016 memcpy(sd.encapContentInfo.eContent->data, data, length);
1017 sd.encapContentInfo.eContent->length = length;
1020 ALLOC_SEQ(&sd.signerInfos, 1);
1021 if (sd.signerInfos.val == NULL) {
1022 hx509_clear_error_string(context);
1023 ret = ENOMEM;
1024 goto out;
1027 signer_info = &sd.signerInfos.val[0];
1029 signer_info->version = 1;
1031 ret = fill_CMSIdentifier(cert, cmsidflag, &signer_info->sid);
1032 if (ret) {
1033 hx509_clear_error_string(context);
1034 goto out;
1037 signer_info->signedAttrs = NULL;
1038 signer_info->unsignedAttrs = NULL;
1041 ret = copy_AlgorithmIdentifier(&digest, &signer_info->digestAlgorithm);
1042 if (ret) {
1043 hx509_clear_error_string(context);
1044 goto out;
1048 * If it isn't pkcs7-data send signedAttributes
1051 if (der_heim_oid_cmp(eContentType, oid_id_pkcs7_data()) != 0) {
1052 CMSAttributes sa;
1053 heim_octet_string sig;
1055 ALLOC(signer_info->signedAttrs, 1);
1056 if (signer_info->signedAttrs == NULL) {
1057 ret = ENOMEM;
1058 goto out;
1061 ret = _hx509_create_signature(context,
1062 NULL,
1063 &digest,
1064 &content,
1065 NULL,
1066 &sig);
1067 if (ret)
1068 goto out;
1070 ASN1_MALLOC_ENCODE(MessageDigest,
1071 buf.data,
1072 buf.length,
1073 &sig,
1074 &size,
1075 ret);
1076 der_free_octet_string(&sig);
1077 if (ret) {
1078 hx509_clear_error_string(context);
1079 goto out;
1081 if (size != buf.length)
1082 _hx509_abort("internal ASN.1 encoder error");
1084 ret = add_one_attribute(&signer_info->signedAttrs->val,
1085 &signer_info->signedAttrs->len,
1086 oid_id_pkcs9_messageDigest(),
1087 &buf);
1088 if (ret) {
1089 hx509_clear_error_string(context);
1090 goto out;
1094 ASN1_MALLOC_ENCODE(ContentType,
1095 buf.data,
1096 buf.length,
1097 eContentType,
1098 &size,
1099 ret);
1100 if (ret)
1101 goto out;
1102 if (size != buf.length)
1103 _hx509_abort("internal ASN.1 encoder error");
1105 ret = add_one_attribute(&signer_info->signedAttrs->val,
1106 &signer_info->signedAttrs->len,
1107 oid_id_pkcs9_contentType(),
1108 &buf);
1109 if (ret) {
1110 hx509_clear_error_string(context);
1111 goto out;
1114 sa.val = signer_info->signedAttrs->val;
1115 sa.len = signer_info->signedAttrs->len;
1117 ASN1_MALLOC_ENCODE(CMSAttributes,
1118 sigdata.data,
1119 sigdata.length,
1120 &sa,
1121 &size,
1122 ret);
1123 if (ret) {
1124 hx509_clear_error_string(context);
1125 goto out;
1127 if (size != sigdata.length)
1128 _hx509_abort("internal ASN.1 encoder error");
1129 } else {
1130 sigdata.data = content.data;
1131 sigdata.length = content.length;
1136 AlgorithmIdentifier sigalg;
1138 ret = hx509_crypto_select(context, HX509_SELECT_PUBLIC_SIG,
1139 _hx509_cert_private_key(cert), peer,
1140 &sigalg);
1141 if (ret)
1142 goto out;
1144 ret = _hx509_create_signature(context,
1145 _hx509_cert_private_key(cert),
1146 &sigalg,
1147 &sigdata,
1148 &signer_info->signatureAlgorithm,
1149 &signer_info->signature);
1150 free_AlgorithmIdentifier(&sigalg);
1151 if (ret)
1152 goto out;
1155 ALLOC_SEQ(&sd.digestAlgorithms, 1);
1156 if (sd.digestAlgorithms.val == NULL) {
1157 ret = ENOMEM;
1158 hx509_clear_error_string(context);
1159 goto out;
1162 ret = copy_AlgorithmIdentifier(&digest, &sd.digestAlgorithms.val[0]);
1163 if (ret) {
1164 hx509_clear_error_string(context);
1165 goto out;
1169 * Provide best effort path
1171 if (pool) {
1172 _hx509_calculate_path(context,
1173 HX509_CALCULATE_PATH_NO_ANCHOR,
1174 time(NULL),
1175 anchors,
1177 cert,
1178 pool,
1179 &path);
1180 } else
1181 _hx509_path_append(context, &path, cert);
1184 if (path.len) {
1185 int i;
1187 ALLOC(sd.certificates, 1);
1188 if (sd.certificates == NULL) {
1189 hx509_clear_error_string(context);
1190 ret = ENOMEM;
1191 goto out;
1193 ALLOC_SEQ(sd.certificates, path.len);
1194 if (sd.certificates->val == NULL) {
1195 hx509_clear_error_string(context);
1196 ret = ENOMEM;
1197 goto out;
1200 for (i = 0; i < path.len; i++) {
1201 ret = hx509_cert_binary(context, path.val[i],
1202 &sd.certificates->val[i]);
1203 if (ret) {
1204 hx509_clear_error_string(context);
1205 goto out;
1210 ASN1_MALLOC_ENCODE(SignedData,
1211 signed_data->data, signed_data->length,
1212 &sd, &size, ret);
1213 if (ret) {
1214 hx509_clear_error_string(context);
1215 goto out;
1217 if (signed_data->length != size)
1218 _hx509_abort("internal ASN.1 encoder error");
1220 out:
1221 if (sigdata.data != content.data)
1222 der_free_octet_string(&sigdata);
1223 free_AlgorithmIdentifier(&digest);
1224 _hx509_path_free(&path);
1225 free_SignedData(&sd);
1227 return ret;
1231 hx509_cms_decrypt_encrypted(hx509_context context,
1232 hx509_lock lock,
1233 const void *data,
1234 size_t length,
1235 heim_oid *contentType,
1236 heim_octet_string *content)
1238 heim_octet_string cont;
1239 CMSEncryptedData ed;
1240 AlgorithmIdentifier *ai;
1241 int ret;
1243 memset(content, 0, sizeof(*content));
1244 memset(&cont, 0, sizeof(cont));
1246 ret = decode_CMSEncryptedData(data, length, &ed, NULL);
1247 if (ret) {
1248 hx509_set_error_string(context, 0, ret,
1249 "Failed to decode CMSEncryptedData");
1250 return ret;
1253 if (ed.encryptedContentInfo.encryptedContent == NULL) {
1254 ret = HX509_CMS_NO_DATA_AVAILABLE;
1255 hx509_set_error_string(context, 0, ret,
1256 "No content in EncryptedData");
1257 goto out;
1260 ret = der_copy_oid(&ed.encryptedContentInfo.contentType, contentType);
1261 if (ret) {
1262 hx509_clear_error_string(context);
1263 goto out;
1266 ai = &ed.encryptedContentInfo.contentEncryptionAlgorithm;
1267 if (ai->parameters == NULL) {
1268 ret = HX509_ALG_NOT_SUPP;
1269 hx509_clear_error_string(context);
1270 goto out;
1273 ret = _hx509_pbe_decrypt(context,
1274 lock,
1276 ed.encryptedContentInfo.encryptedContent,
1277 &cont);
1278 if (ret)
1279 goto out;
1281 *content = cont;
1283 out:
1284 if (ret) {
1285 if (cont.data)
1286 free(cont.data);
1288 free_CMSEncryptedData(&ed);
1289 return ret;