1 /* Support of PKCS#7 data structures
2 * Copyright (C) 2005 Jan Hutter, Martin Willi
3 * Copyright (C) 2002-2005 Andreas Steffen
4 * Hochschule fuer Technik Rapperswil, Switzerland
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * RCSID $Id: pkcs7.c,v 1.13 2005/12/22 22:11:24 as Exp $
21 #include <crypto/des.h>
25 #include "constants.h"
35 const contentInfo_t empty_contentInfo
= {
36 OID_UNKNOWN
, /* type */
37 { NULL
, 0 } /* content */
40 /* ASN.1 definition of the PKCS#7 ContentInfo type */
42 static const asn1Object_t contentInfoObjects
[] = {
43 { 0, "contentInfo", ASN1_SEQUENCE
, ASN1_NONE
}, /* 0 */
44 { 1, "contentType", ASN1_OID
, ASN1_BODY
}, /* 1 */
45 { 1, "content", ASN1_CONTEXT_C_0
, ASN1_OPT
|
47 { 1, "end opt", ASN1_EOC
, ASN1_END
} /* 3 */
50 #define PKCS7_INFO_TYPE 1
51 #define PKCS7_INFO_CONTENT 2
52 #define PKCS7_INFO_ROOF 4
54 /* ASN.1 definition of the PKCS#7 signedData type */
56 static const asn1Object_t signedDataObjects
[] = {
57 { 0, "signedData", ASN1_SEQUENCE
, ASN1_NONE
}, /* 0 */
58 { 1, "version", ASN1_INTEGER
, ASN1_BODY
}, /* 1 */
59 { 1, "digestAlgorithms", ASN1_SET
, ASN1_LOOP
}, /* 2 */
60 { 2, "algorithm", ASN1_EOC
, ASN1_RAW
}, /* 3 */
61 { 1, "end loop", ASN1_EOC
, ASN1_END
}, /* 4 */
62 { 1, "contentInfo", ASN1_EOC
, ASN1_RAW
}, /* 5 */
63 { 1, "certificates", ASN1_CONTEXT_C_0
, ASN1_OPT
|
65 { 2, "certificate", ASN1_SEQUENCE
, ASN1_OBJ
}, /* 7 */
66 { 1, "end opt or loop", ASN1_EOC
, ASN1_END
}, /* 8 */
67 { 1, "crls", ASN1_CONTEXT_C_1
, ASN1_OPT
|
69 { 2, "crl", ASN1_SEQUENCE
, ASN1_OBJ
}, /* 10 */
70 { 1, "end opt or loop", ASN1_EOC
, ASN1_END
}, /* 11 */
71 { 1, "signerInfos", ASN1_SET
, ASN1_LOOP
}, /* 12 */
72 { 2, "signerInfo", ASN1_SEQUENCE
, ASN1_NONE
}, /* 13 */
73 { 3, "version", ASN1_INTEGER
, ASN1_BODY
}, /* 14 */
74 { 3, "issuerAndSerialNumber", ASN1_SEQUENCE
, ASN1_BODY
}, /* 15 */
75 { 4, "issuer", ASN1_SEQUENCE
, ASN1_OBJ
}, /* 16 */
76 { 4, "serial", ASN1_INTEGER
, ASN1_BODY
}, /* 17 */
77 { 3, "digestAlgorithm", ASN1_EOC
, ASN1_RAW
}, /* 18 */
78 { 3, "authenticatedAttributes", ASN1_CONTEXT_C_0
, ASN1_OPT
|
80 { 3, "end opt", ASN1_EOC
, ASN1_END
}, /* 20 */
81 { 3, "digestEncryptionAlgorithm", ASN1_EOC
, ASN1_RAW
}, /* 21 */
82 { 3, "encryptedDigest", ASN1_OCTET_STRING
, ASN1_BODY
}, /* 22 */
83 { 3, "unauthenticatedAttributes", ASN1_CONTEXT_C_1
, ASN1_OPT
}, /* 23 */
84 { 3, "end opt", ASN1_EOC
, ASN1_END
}, /* 24 */
85 { 1, "end loop", ASN1_EOC
, ASN1_END
} /* 25 */
88 #define PKCS7_DIGEST_ALG 3
89 #define PKCS7_SIGNED_CONTENT_INFO 5
90 #define PKCS7_SIGNED_CERT 7
91 #define PKCS7_SIGNER_INFO 13
92 #define PKCS7_SIGNED_ISSUER 16
93 #define PKCS7_SIGNED_SERIAL_NUMBER 17
94 #define PKCS7_DIGEST_ALGORITHM 18
95 #define PKCS7_AUTH_ATTRIBUTES 19
96 #define PKCS7_DIGEST_ENC_ALGORITHM 21
97 #define PKCS7_ENCRYPTED_DIGEST 22
98 #define PKCS7_SIGNED_ROOF 26
100 /* ASN.1 definition of the PKCS#7 envelopedData type */
102 static const asn1Object_t envelopedDataObjects
[] = {
103 { 0, "envelopedData", ASN1_SEQUENCE
, ASN1_NONE
}, /* 0 */
104 { 1, "version", ASN1_INTEGER
, ASN1_BODY
}, /* 1 */
105 { 1, "recipientInfos", ASN1_SET
, ASN1_LOOP
}, /* 2 */
106 { 2, "recipientInfo", ASN1_SEQUENCE
, ASN1_BODY
}, /* 3 */
107 { 3, "version", ASN1_INTEGER
, ASN1_BODY
}, /* 4 */
108 { 3, "issuerAndSerialNumber", ASN1_SEQUENCE
, ASN1_BODY
}, /* 5 */
109 { 4, "issuer", ASN1_SEQUENCE
, ASN1_OBJ
}, /* 6 */
110 { 4, "serial", ASN1_INTEGER
, ASN1_BODY
}, /* 7 */
111 { 3, "encryptionAlgorithm", ASN1_EOC
, ASN1_RAW
}, /* 8 */
112 { 3, "encryptedKey", ASN1_OCTET_STRING
, ASN1_BODY
}, /* 9 */
113 { 1, "end loop", ASN1_EOC
, ASN1_END
}, /* 10 */
114 { 1, "encryptedContentInfo", ASN1_SEQUENCE
, ASN1_OBJ
}, /* 11 */
115 { 2, "contentType", ASN1_OID
, ASN1_BODY
}, /* 12 */
116 { 2, "contentEncryptionAlgorithm", ASN1_EOC
, ASN1_RAW
}, /* 13 */
117 { 2, "encryptedContent", ASN1_CONTEXT_S_0
, ASN1_BODY
} /* 14 */
120 #define PKCS7_ENVELOPED_VERSION 1
121 #define PKCS7_RECIPIENT_INFO_VERSION 4
122 #define PKCS7_ISSUER 6
123 #define PKCS7_SERIAL_NUMBER 7
124 #define PKCS7_ENCRYPTION_ALG 8
125 #define PKCS7_ENCRYPTED_KEY 9
126 #define PKCS7_CONTENT_TYPE 12
127 #define PKCS7_CONTENT_ENC_ALGORITHM 13
128 #define PKCS7_ENCRYPTED_CONTENT 14
129 #define PKCS7_ENVELOPED_ROOF 15
131 /* PKCS7 contentInfo OIDs */
133 static u_char ASN1_pkcs7_data_oid_str
[] = {
134 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01
137 static u_char ASN1_pkcs7_signed_data_oid_str
[] = {
138 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02
141 static u_char ASN1_pkcs7_enveloped_data_oid_str
[] = {
142 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x03
145 static u_char ASN1_pkcs7_signed_enveloped_data_oid_str
[] = {
146 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x04
149 static u_char ASN1_pkcs7_digested_data_oid_str
[] = {
150 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x05
153 static char ASN1_pkcs7_encrypted_data_oid_str
[] = {
154 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x06
157 static const chunk_t ASN1_pkcs7_data_oid
=
158 strchunk(ASN1_pkcs7_data_oid_str
);
159 static const chunk_t ASN1_pkcs7_signed_data_oid
=
160 strchunk(ASN1_pkcs7_signed_data_oid_str
);
161 static const chunk_t ASN1_pkcs7_enveloped_data_oid
=
162 strchunk(ASN1_pkcs7_enveloped_data_oid_str
);
163 static const chunk_t ASN1_pkcs7_signed_enveloped_data_oid
=
164 strchunk(ASN1_pkcs7_signed_enveloped_data_oid_str
);
165 static const chunk_t ASN1_pkcs7_digested_data_oid
=
166 strchunk(ASN1_pkcs7_digested_data_oid_str
);
167 static const chunk_t ASN1_pkcs7_encrypted_data_oid
=
168 strchunk(ASN1_pkcs7_encrypted_data_oid_str
);
170 /* 3DES and DES encryption OIDs */
172 static u_char ASN1_3des_ede_cbc_oid_str
[] = {
173 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x03, 0x07
176 static u_char ASN1_des_cbc_oid_str
[] = {
177 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x07
180 static const chunk_t ASN1_3des_ede_cbc_oid
=
181 strchunk(ASN1_3des_ede_cbc_oid_str
);
182 static const chunk_t ASN1_des_cbc_oid
=
183 strchunk(ASN1_des_cbc_oid_str
);
185 /* PKCS#7 attribute type OIDs */
187 static u_char ASN1_contentType_oid_str
[] = {
188 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x03
191 static u_char ASN1_messageDigest_oid_str
[] = {
192 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x04
195 static const chunk_t ASN1_contentType_oid
=
196 strchunk(ASN1_contentType_oid_str
);
197 static const chunk_t ASN1_messageDigest_oid
=
198 strchunk(ASN1_messageDigest_oid_str
);
201 * Parse PKCS#7 ContentInfo object
204 pkcs7_parse_contentInfo(chunk_t blob
, u_int level0
, contentInfo_t
*cInfo
)
211 asn1_init(&ctx
, blob
, level0
, FALSE
, DBG_RAW
);
213 while (objectID
< PKCS7_INFO_ROOF
)
215 if (!extract_object(contentInfoObjects
, &objectID
, &object
, &level
, &ctx
))
218 if (objectID
== PKCS7_INFO_TYPE
)
220 cInfo
->type
= known_oid(object
);
221 if (cInfo
->type
< OID_PKCS7_DATA
222 || cInfo
->type
> OID_PKCS7_ENCRYPTED_DATA
)
224 plog("unknown pkcs7 content type");
228 else if (objectID
== PKCS7_INFO_CONTENT
)
230 cInfo
->content
= object
;
238 * Parse a PKCS#7 signedData object
241 pkcs7_parse_signedData(chunk_t blob
, contentInfo_t
*data
, x509cert_t
**cert
242 , chunk_t
*attributes
, const x509cert_t
*cacert
)
248 int digest_alg
= OID_UNKNOWN
;
249 int enc_alg
= OID_UNKNOWN
;
253 contentInfo_t cInfo
= empty_contentInfo
;
254 chunk_t encrypted_digest
= empty_chunk
;
256 if (!pkcs7_parse_contentInfo(blob
, 0, &cInfo
))
259 if (cInfo
.type
!= OID_PKCS7_SIGNED_DATA
)
261 plog("pkcs7 content type is not signedData");
265 asn1_init(&ctx
, cInfo
.content
, 2, FALSE
, DBG_RAW
);
267 while (objectID
< PKCS7_SIGNED_ROOF
)
269 if (!extract_object(signedDataObjects
, &objectID
, &object
, &level
, &ctx
))
274 case PKCS7_DIGEST_ALG
:
275 digest_alg
= parse_algorithmIdentifier(object
, level
, NULL
);
277 case PKCS7_SIGNED_CONTENT_INFO
:
280 pkcs7_parse_contentInfo(object
, level
, data
);
283 case PKCS7_SIGNED_CERT
:
288 x509cert_t
*newcert
= alloc_thing(x509cert_t
289 , "pkcs7 wrapped x509cert");
291 clonetochunk(cert_blob
, object
.ptr
, object
.len
292 , "pkcs7 cert blob");
293 *newcert
= empty_x509cert
;
295 DBG(DBG_CONTROL
| DBG_PARSING
,
296 DBG_log("parsing pkcs7-wrapped certificate")
298 if (parse_x509cert(cert_blob
, level
+1, newcert
))
300 newcert
->next
= *cert
;
305 free_x509cert(newcert
);
309 case PKCS7_SIGNER_INFO
:
312 DBG_log(" signer #%d", signerInfos
)
315 case PKCS7_SIGNED_ISSUER
:
317 dntoa(buf
, BUF_LEN
, object
);
321 case PKCS7_AUTH_ATTRIBUTES
:
322 if (attributes
!= NULL
)
324 *attributes
= object
;
325 *attributes
->ptr
= ASN1_SET
;
328 case PKCS7_DIGEST_ALGORITHM
:
329 digest_alg
= parse_algorithmIdentifier(object
, level
, NULL
);
331 case PKCS7_DIGEST_ENC_ALGORITHM
:
332 enc_alg
= parse_algorithmIdentifier(object
, level
, NULL
);
334 case PKCS7_ENCRYPTED_DIGEST
:
335 encrypted_digest
= object
;
340 /* check the signature only if a cacert is available */
343 if (signerInfos
== 0)
345 plog("no signerInfo object found");
348 else if (signerInfos
> 1)
350 plog("more than one signerInfo object found");
353 if (attributes
->ptr
== NULL
)
355 plog("no authenticatedAttributes object found");
358 if (!check_signature(*attributes
, encrypted_digest
, digest_alg
361 plog("invalid signature");
367 DBG_log("signature is valid")
375 * Parse a PKCS#7 envelopedData object
378 pkcs7_parse_envelopedData(chunk_t blob
, chunk_t
*data
379 , chunk_t serialNumber
, const RSA_private_key_t
*key
)
383 chunk_t iv
= empty_chunk
;
384 chunk_t symmetric_key
= empty_chunk
;
385 chunk_t encrypted_content
= empty_chunk
;
389 u_int total_keys
= 3;
390 int enc_alg
= OID_UNKNOWN
;
391 int content_enc_alg
= OID_UNKNOWN
;
394 contentInfo_t cInfo
= empty_contentInfo
;
397 if (!pkcs7_parse_contentInfo(blob
, 0, &cInfo
))
400 if (cInfo
.type
!= OID_PKCS7_ENVELOPED_DATA
)
402 plog("pkcs7 content type is not envelopedData");
406 asn1_init(&ctx
, cInfo
.content
, 2, FALSE
, DBG_RAW
);
408 while (objectID
< PKCS7_ENVELOPED_ROOF
)
410 if (!extract_object(envelopedDataObjects
, &objectID
, &object
, &level
, &ctx
))
415 case PKCS7_ENVELOPED_VERSION
:
416 if (*object
.ptr
!= 0)
418 plog("envelopedData version is not 0");
422 case PKCS7_RECIPIENT_INFO_VERSION
:
423 if (*object
.ptr
!= 0)
425 plog("recipient info version is not 0");
431 dntoa(buf
, BUF_LEN
, object
);
432 DBG_log(" '%s'", buf
)
435 case PKCS7_SERIAL_NUMBER
:
436 if (!same_chunk(serialNumber
, object
))
438 plog("serial numbers do not match");
442 case PKCS7_ENCRYPTION_ALG
:
443 enc_alg
= parse_algorithmIdentifier(object
, level
, NULL
);
444 if (enc_alg
!= OID_RSA_ENCRYPTION
)
446 plog("only rsa encryption supported");
450 case PKCS7_ENCRYPTED_KEY
:
451 if (!RSA_decrypt(key
, object
, &symmetric_key
))
453 plog("symmetric key could not be decrypted with rsa");
457 DBG_dump_chunk("symmetric key :", symmetric_key
)
460 case PKCS7_CONTENT_TYPE
:
461 if (known_oid(object
) != OID_PKCS7_DATA
)
463 plog("encrypted content not of type pkcs7 data");
467 case PKCS7_CONTENT_ENC_ALGORITHM
:
468 content_enc_alg
= parse_algorithmIdentifier(object
, level
, &iv
);
470 switch (content_enc_alg
)
475 case OID_3DES_EDE_CBC
:
479 plog("Only DES and 3DES supported for symmetric encryption");
482 if (symmetric_key
.len
!= (total_keys
* DES_CBC_BLOCK_SIZE
))
484 plog("key length is not %d",(total_keys
* DES_CBC_BLOCK_SIZE
));
487 if (!parse_asn1_simple_object(&iv
, ASN1_OCTET_STRING
, level
+1, "IV"))
489 plog("IV could not be parsed");
492 if (iv
.len
!= DES_CBC_BLOCK_SIZE
)
494 plog("IV has wrong length");
498 case PKCS7_ENCRYPTED_CONTENT
:
499 encrypted_content
= object
;
505 /* decrypt the content */
508 des_cblock des_key
[3], des_iv
;
509 des_key_schedule key_s
[3];
511 memcpy((char *)des_key
, symmetric_key
.ptr
, symmetric_key
.len
);
512 memcpy((char *)des_iv
, iv
.ptr
, iv
.len
);
514 for (i
= 0; i
< total_keys
; i
++)
516 if (des_set_key(&des_key
[i
], key_s
[i
]))
518 plog("des key schedule failed");
523 data
->len
= encrypted_content
.len
;
524 data
->ptr
= alloc_bytes(data
->len
, "decrypted data");
526 switch (content_enc_alg
)
529 des_cbc_encrypt((des_cblock
*)encrypted_content
.ptr
530 , (des_cblock
*)data
->ptr
, data
->len
531 , key_s
[0], &des_iv
, DES_DECRYPT
);
533 case OID_3DES_EDE_CBC
:
534 des_ede3_cbc_encrypt( (des_cblock
*)encrypted_content
.ptr
535 , (des_cblock
*)data
->ptr
, data
->len
536 , key_s
[0], key_s
[1], key_s
[2]
537 , &des_iv
, DES_DECRYPT
);
540 DBG_dump_chunk("decrypted content with padding:\n", *data
)
544 /* remove the padding */
546 u_char
*pos
= data
->ptr
+ data
->len
- 1;
547 u_char pattern
= *pos
;
548 size_t padding
= pattern
;
550 if (padding
> data
->len
)
552 plog("padding greater than data length");
555 data
->len
-= padding
;
557 while (padding
-- > 0)
559 if (*pos
-- != pattern
)
561 plog("wrong padding pattern");
566 freeanychunk(symmetric_key
);
570 freeanychunk(symmetric_key
);
576 * @brief Builds a contentType attribute
578 * @return ASN.1 encoded contentType attribute
581 pkcs7_contentType_attribute(void)
583 return asn1_wrap(ASN1_SEQUENCE
, "cm"
584 , ASN1_contentType_oid
585 , asn1_simple_object(ASN1_SET
, ASN1_pkcs7_data_oid
));
589 * @brief Builds a messageDigest attribute
592 * @param[in] blob content to create digest of
593 * @param[in] digest_alg digest algorithm to be used
594 * @return ASN.1 encoded messageDigest attribute
598 pkcs7_messageDigest_attribute(chunk_t content
, int digest_alg
)
600 u_char digest_buf
[MAX_DIGEST_LEN
];
601 chunk_t digest
= { digest_buf
, MAX_DIGEST_LEN
};
603 compute_digest(content
, digest_alg
, &digest
);
605 return asn1_wrap(ASN1_SEQUENCE
, "cm"
606 , ASN1_messageDigest_oid
607 , asn1_wrap(ASN1_SET
, "m"
608 , asn1_simple_object(ASN1_OCTET_STRING
, digest
)
613 * build a DER-encoded contentInfo object
616 pkcs7_build_contentInfo(contentInfo_t
*cInfo
)
618 chunk_t content_type
;
620 /* select DER-encoded OID for pkcs7 contentInfo type */
624 content_type
= ASN1_pkcs7_data_oid
;
626 case OID_PKCS7_SIGNED_DATA
:
627 content_type
= ASN1_pkcs7_signed_data_oid
;
629 case OID_PKCS7_ENVELOPED_DATA
:
630 content_type
= ASN1_pkcs7_enveloped_data_oid
;
632 case OID_PKCS7_SIGNED_ENVELOPED_DATA
:
633 content_type
= ASN1_pkcs7_signed_enveloped_data_oid
;
635 case OID_PKCS7_DIGESTED_DATA
:
636 content_type
= ASN1_pkcs7_digested_data_oid
;
638 case OID_PKCS7_ENCRYPTED_DATA
:
639 content_type
= ASN1_pkcs7_encrypted_data_oid
;
643 fprintf(stderr
, "invalid pkcs7 contentInfo type");
647 return (cInfo
->content
.ptr
== NULL
)
648 ? asn1_simple_object(ASN1_SEQUENCE
, content_type
)
649 : asn1_wrap(ASN1_SEQUENCE
, "cm"
651 , asn1_simple_object(ASN1_CONTEXT_C_0
, cInfo
->content
)
656 * build issuerAndSerialNumber object
659 pkcs7_build_issuerAndSerialNumber(const x509cert_t
*cert
)
661 return asn1_wrap(ASN1_SEQUENCE
, "cm"
663 , asn1_simple_object(ASN1_INTEGER
, cert
->serialNumber
));
667 * create a signed pkcs7 contentInfo object
670 pkcs7_build_signedData(chunk_t data
, chunk_t attributes
, const x509cert_t
*cert
671 , int digest_alg
, const RSA_private_key_t
*key
)
673 contentInfo_t pkcs7Data
, signedData
;
674 chunk_t authenticatedAttributes
, encryptedDigest
, signerInfo
, cInfo
;
676 chunk_t digestAlgorithm
= asn1_algorithmIdentifier(digest_alg
);
678 if (attributes
.ptr
!= NULL
)
680 encryptedDigest
= pkcs1_build_signature(attributes
, digest_alg
682 clonetochunk(authenticatedAttributes
, attributes
.ptr
, attributes
.len
683 , "authenticatedAttributes");
684 *authenticatedAttributes
.ptr
= ASN1_CONTEXT_C_0
;
688 encryptedDigest
= (data
.ptr
== NULL
)? empty_chunk
689 : pkcs1_build_signature(data
, digest_alg
, key
, FALSE
);
690 authenticatedAttributes
= empty_chunk
;
693 signerInfo
= asn1_wrap(ASN1_SEQUENCE
, "cmcmcm"
695 , pkcs7_build_issuerAndSerialNumber(cert
)
697 , authenticatedAttributes
698 , ASN1_rsaEncryption_id
701 pkcs7Data
.type
= OID_PKCS7_DATA
;
702 pkcs7Data
.content
= (data
.ptr
== NULL
)? empty_chunk
703 : asn1_simple_object(ASN1_OCTET_STRING
, data
);
705 signedData
.type
= OID_PKCS7_SIGNED_DATA
;
706 signedData
.content
= asn1_wrap(ASN1_SEQUENCE
, "cmmmm"
708 , asn1_simple_object(ASN1_SET
, digestAlgorithm
)
709 , pkcs7_build_contentInfo(&pkcs7Data
)
710 , asn1_simple_object(ASN1_CONTEXT_C_0
, cert
->certificate
)
711 , asn1_wrap(ASN1_SET
, "m", signerInfo
));
713 cInfo
= pkcs7_build_contentInfo(&signedData
);
715 DBG_dump_chunk("signedData:\n", cInfo
)
718 freeanychunk(pkcs7Data
.content
);
719 freeanychunk(signedData
.content
);
724 * create a symmetrically encrypted pkcs7 contentInfo object
727 pkcs7_build_envelopedData(chunk_t data
, const x509cert_t
*cert
, int cipher
)
729 bool des_check_key_save
;
730 des_key_schedule ks
[3];
731 des_cblock key
[3], des_iv
, des_iv_buf
;
733 chunk_t iv
= { (u_char
*)des_iv_buf
, DES_CBC_BLOCK_SIZE
};
738 size_t padding
= pad_up(data
.len
, DES_CBC_BLOCK_SIZE
);
740 RSA_public_key_t public_key
;
742 init_RSA_public_key(&public_key
, cert
->publicExponent
746 padding
+= DES_CBC_BLOCK_SIZE
;
748 out
.len
= data
.len
+ padding
;
749 out
.ptr
= alloc_bytes(out
.len
, "DES-encrypted output");
752 DBG_log("padding %d bytes of data to multiple DES block size of %d bytes"
753 , (int)data
.len
, (int)out
.len
)
757 memcpy(out
.ptr
, data
.ptr
, data
.len
);
759 memset(out
.ptr
+ data
.len
, padding
, padding
);
762 DBG_dump_chunk("Padded unencrypted data:\n", out
)
765 /* select OID and keylength for specified cipher */
770 cipher_oid
= ASN1_des_cbc_oid
;
772 case OID_3DES_EDE_CBC
:
775 cipher_oid
= ASN1_3des_ede_cbc_oid
;
778 DBG_log("pkcs7 encryption cipher: %s", oid_names
[cipher
].name
)
781 /* generate a strong random key for DES/3DES */
782 des_check_key_save
= des_check_key
;
783 des_check_key
= TRUE
;
784 for (i
= 0; i
< total_keys
;i
++)
788 get_rnd_bytes((char*)key
[i
], DES_CBC_BLOCK_SIZE
);
789 des_set_odd_parity(&key
[i
]);
790 if (!des_set_key(&key
[i
], ks
[i
]))
792 plog("weak DES key discarded - we try again");
795 DBG_dump("DES key:", key
[i
], 8)
798 des_check_key
= des_check_key_save
;
800 /* generate an iv for DES/3DES CBC */
801 get_rnd_bytes(des_iv
, DES_CBC_BLOCK_SIZE
);
802 memcpy(iv
.ptr
, des_iv
, DES_CBC_BLOCK_SIZE
);
804 DBG_dump_chunk("DES IV :", iv
)
807 /* encryption using specified cipher */
811 des_cbc_encrypt((des_cblock
*)out
.ptr
, (des_cblock
*)out
.ptr
, out
.len
812 , ks
[0], &des_iv
, DES_ENCRYPT
);
814 case OID_3DES_EDE_CBC
:
816 des_ede3_cbc_encrypt((des_cblock
*)out
.ptr
, (des_cblock
*)out
.ptr
, out
.len
817 , ks
[0], ks
[1], ks
[2], &des_iv
, DES_ENCRYPT
);
820 DBG_dump_chunk("Encrypted data:\n", out
));
822 /* build pkcs7 enveloped data object */
824 chunk_t contentEncryptionAlgorithm
= asn1_wrap(ASN1_SEQUENCE
, "cm"
826 , asn1_simple_object(ASN1_OCTET_STRING
, iv
));
828 chunk_t encryptedContentInfo
= asn1_wrap(ASN1_SEQUENCE
, "cmm"
829 , ASN1_pkcs7_data_oid
830 , contentEncryptionAlgorithm
831 , asn1_wrap(ASN1_CONTEXT_S_0
, "m", out
));
833 chunk_t plainKey
= { (u_char
*)key
, DES_CBC_BLOCK_SIZE
* total_keys
};
835 chunk_t encryptedKey
= asn1_wrap(ASN1_OCTET_STRING
, "m"
836 , RSA_encrypt(&public_key
, plainKey
));
838 chunk_t recipientInfo
= asn1_wrap(ASN1_SEQUENCE
, "cmcm"
840 , pkcs7_build_issuerAndSerialNumber(cert
)
841 , ASN1_rsaEncryption_id
845 contentInfo_t envelopedData
;
847 envelopedData
.type
= OID_PKCS7_ENVELOPED_DATA
;
848 envelopedData
.content
= asn1_wrap(ASN1_SEQUENCE
, "cmm"
850 , asn1_wrap(ASN1_SET
, "m", recipientInfo
)
851 , encryptedContentInfo
);
853 cInfo
= pkcs7_build_contentInfo(&envelopedData
);
855 DBG_dump_chunk("envelopedData:\n", cInfo
)
858 free_RSA_public_content(&public_key
);
859 freeanychunk(envelopedData
.content
);