2 * Copyright (C) 2012 Martin Willi
3 * Copyright (C) 2012 revosec AG
4 * Copyright (C) 2012 Tobias Brunner
5 * Copyright (C) 2002-2008 Andreas Steffen
6 * Copyright (C) 2005 Jan Hutter, Martin Willi
7 * HSR Hochschule fuer Technik Rapperswil
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 #include "pkcs7_enveloped_data.h"
22 #include <asn1/asn1.h>
23 #include <asn1/asn1_parser.h>
25 #include <credentials/certificates/x509.h>
26 #include <utils/debug.h>
28 typedef struct private_pkcs7_enveloped_data_t private_pkcs7_enveloped_data_t
;
31 * Private data of a PKCS#7 signed-data container.
33 struct private_pkcs7_enveloped_data_t
{
46 * Encrypted and encoded PKCS#7 enveloped-data
52 * ASN.1 definition of the PKCS#7 envelopedData type
54 static const asn1Object_t envelopedDataObjects
[] = {
55 { 0, "envelopedData", ASN1_SEQUENCE
, ASN1_NONE
}, /* 0 */
56 { 1, "version", ASN1_INTEGER
, ASN1_BODY
}, /* 1 */
57 { 1, "recipientInfos", ASN1_SET
, ASN1_LOOP
}, /* 2 */
58 { 2, "recipientInfo", ASN1_SEQUENCE
, ASN1_BODY
}, /* 3 */
59 { 3, "version", ASN1_INTEGER
, ASN1_BODY
}, /* 4 */
60 { 3, "issuerAndSerialNumber", ASN1_SEQUENCE
, ASN1_BODY
}, /* 5 */
61 { 4, "issuer", ASN1_SEQUENCE
, ASN1_OBJ
}, /* 6 */
62 { 4, "serial", ASN1_INTEGER
, ASN1_BODY
}, /* 7 */
63 { 3, "encryptionAlgorithm", ASN1_EOC
, ASN1_RAW
}, /* 8 */
64 { 3, "encryptedKey", ASN1_OCTET_STRING
, ASN1_BODY
}, /* 9 */
65 { 1, "end loop", ASN1_EOC
, ASN1_END
}, /* 10 */
66 { 1, "encryptedContentInfo", ASN1_SEQUENCE
, ASN1_OBJ
}, /* 11 */
67 { 2, "contentType", ASN1_OID
, ASN1_BODY
}, /* 12 */
68 { 2, "contentEncryptionAlgorithm", ASN1_EOC
, ASN1_RAW
}, /* 13 */
69 { 2, "encryptedContent", ASN1_CONTEXT_S_0
, ASN1_BODY
}, /* 14 */
70 { 0, "exit", ASN1_EOC
, ASN1_EXIT
}
72 #define PKCS7_VERSION 1
73 #define PKCS7_RECIPIENT_INFO_VERSION 4
74 #define PKCS7_ISSUER 6
75 #define PKCS7_SERIAL_NUMBER 7
76 #define PKCS7_ENCRYPTION_ALG 8
77 #define PKCS7_ENCRYPTED_KEY 9
78 #define PKCS7_CONTENT_TYPE 12
79 #define PKCS7_CONTENT_ENC_ALGORITHM 13
80 #define PKCS7_ENCRYPTED_CONTENT 14
83 * Find a private key for issuerAndSerialNumber
85 static private_key_t
*find_private(identification_t
*issuer
,
86 identification_t
*serial
)
88 enumerator_t
*enumerator
;
91 private_key_t
*private = NULL
;
95 enumerator
= lib
->credmgr
->create_cert_enumerator(lib
->credmgr
,
96 CERT_X509
, KEY_RSA
, serial
, FALSE
);
97 while (enumerator
->enumerate(enumerator
, &cert
))
99 if (issuer
->equals(issuer
, cert
->get_issuer(cert
)))
101 public = cert
->get_public_key(cert
);
104 if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1
, &fp
))
106 id
= identification_create_from_encoding(ID_KEY_ID
, fp
);
107 private = lib
->credmgr
->get_private(lib
->credmgr
,
111 public->destroy(public);
119 enumerator
->destroy(enumerator
);
124 * Decrypt content using a private key from "issuer"
126 static bool decrypt(private_key_t
*private, chunk_t key
, chunk_t iv
, int oid
,
127 chunk_t encrypted
, chunk_t
*plain
)
129 encryption_algorithm_t alg
;
134 alg
= encryption_algorithm_from_oid(oid
, &key_size
);
135 if (alg
== ENCR_UNDEFINED
)
137 DBG1(DBG_LIB
, "unsupported content encryption algorithm");
140 if (!private->decrypt(private, ENCRYPT_RSA_PKCS1
, key
, &plain_key
))
142 DBG1(DBG_LIB
, "symmetric key could not be decrypted with rsa");
145 crypter
= lib
->crypto
->create_crypter(lib
->crypto
, alg
, key_size
/ 8);
148 DBG1(DBG_LIB
, "crypter %N-%d not available",
149 encryption_algorithm_names
, alg
, key_size
);
153 if (plain_key
.len
!= crypter
->get_key_size(crypter
))
155 DBG1(DBG_LIB
, "symmetric key length %d is wrong", plain_key
.len
);
157 crypter
->destroy(crypter
);
160 if (iv
.len
!= crypter
->get_iv_size(crypter
))
162 DBG1(DBG_LIB
, "IV length %d is wrong", iv
.len
);
164 crypter
->destroy(crypter
);
167 if (!crypter
->set_key(crypter
, plain_key
) ||
168 !crypter
->decrypt(crypter
, encrypted
, iv
, plain
))
171 crypter
->destroy(crypter
);
174 DBG4(DBG_LIB
, "decrypted content with padding: %B", plain
);
176 crypter
->destroy(crypter
);
181 * Remove the padding from plain data
183 static bool remove_padding(private_pkcs7_enveloped_data_t
*this)
185 u_char
*pos
= this->content
.ptr
+ this->content
.len
- 1;
186 u_char pattern
= *pos
;
187 size_t padding
= pattern
;
189 if (padding
> this->content
.len
)
191 DBG1(DBG_LIB
, "padding greater than data length");
194 this->content
.len
-= padding
;
196 while (padding
-- > 0)
198 if (*pos
-- != pattern
)
200 DBG1(DBG_LIB
, "wrong padding pattern");
208 * Parse and decrypt enveloped-data
210 static bool parse(private_pkcs7_enveloped_data_t
*this, chunk_t content
)
212 asn1_parser_t
*parser
;
214 int objectID
, version
, alg
= OID_UNKNOWN
;
215 bool success
= FALSE
;
216 identification_t
*issuer
= NULL
, *serial
= NULL
;
217 private_key_t
*private = NULL
;
218 chunk_t iv
= chunk_empty
, key
= chunk_empty
, encrypted
= chunk_empty
;
220 parser
= asn1_parser_create(envelopedDataObjects
, content
);
221 parser
->set_top_level(parser
, 0);
223 while (parser
->iterate(parser
, &objectID
, &object
))
225 u_int level
= parser
->get_level(parser
);
230 version
= object
.len
? (int)*object
.ptr
: 0;
231 DBG2(DBG_LIB
, " v%d", version
);
234 DBG1(DBG_LIB
, "envelopedData version is not 0");
238 case PKCS7_RECIPIENT_INFO_VERSION
:
239 version
= object
.len
? (int)*object
.ptr
: 0;
240 DBG2(DBG_LIB
, " v%d", version
);
243 DBG1(DBG_LIB
, "recipient info version is not 0");
250 issuer
= identification_create_from_encoding(ID_DER_ASN1_DN
,
254 case PKCS7_SERIAL_NUMBER
:
257 serial
= identification_create_from_encoding(ID_KEY_ID
,
261 case PKCS7_ENCRYPTION_ALG
:
262 if (asn1_parse_algorithmIdentifier(object
, level
,
263 NULL
) != OID_RSA_ENCRYPTION
)
265 DBG1(DBG_LIB
, "only rsa encryption supported");
269 case PKCS7_ENCRYPTED_KEY
:
272 case PKCS7_CONTENT_TYPE
:
273 if (asn1_known_oid(object
) != OID_PKCS7_DATA
)
275 DBG1(DBG_LIB
, "encrypted content not of type pkcs7 data");
279 case PKCS7_CONTENT_ENC_ALGORITHM
:
280 alg
= asn1_parse_algorithmIdentifier(object
, level
, &iv
);
281 if (!asn1_parse_simple_object(&iv
, ASN1_OCTET_STRING
,
284 DBG1(DBG_LIB
, "IV could not be parsed");
288 case PKCS7_ENCRYPTED_CONTENT
:
293 success
= parser
->success(parser
);
296 parser
->destroy(parser
);
306 private = find_private(issuer
, serial
);
309 DBG1(DBG_LIB
, "no private key found to decrypt pkcs7");
312 if (!decrypt(private, key
, iv
, alg
, encrypted
, &this->content
))
316 if (!remove_padding(this))
329 METHOD(container_t
, get_type
, container_type_t
,
330 private_pkcs7_enveloped_data_t
*this)
332 return CONTAINER_PKCS7_ENVELOPED_DATA
;
335 METHOD(container_t
, create_signature_enumerator
, enumerator_t
*,
336 private_pkcs7_enveloped_data_t
*this)
338 return enumerator_create_empty();
341 METHOD(container_t
, get_data
, bool,
342 private_pkcs7_enveloped_data_t
*this, chunk_t
*data
)
344 if (this->content
.len
)
346 *data
= chunk_clone(this->content
);
352 METHOD(container_t
, get_encoding
, bool,
353 private_pkcs7_enveloped_data_t
*this, chunk_t
*data
)
355 *data
= chunk_clone(this->encoding
);
359 METHOD(container_t
, destroy
, void,
360 private_pkcs7_enveloped_data_t
*this)
362 free(this->content
.ptr
);
363 free(this->encoding
.ptr
);
368 * Generic constructor
370 static private_pkcs7_enveloped_data_t
* create_empty()
372 private_pkcs7_enveloped_data_t
*this;
377 .get_type
= _get_type
,
378 .create_signature_enumerator
= _create_signature_enumerator
,
379 .get_data
= _get_data
,
380 .get_encoding
= _get_encoding
,
383 .create_cert_enumerator
= (void*)enumerator_create_empty
,
384 .get_attribute
= (void*)return_false
,
394 pkcs7_t
*pkcs7_enveloped_data_load(chunk_t encoding
, chunk_t content
)
396 private_pkcs7_enveloped_data_t
*this = create_empty();
398 this->encoding
= chunk_clone(encoding
);
399 if (!parse(this, content
))
405 return &this->public;
409 * Allocate data with an RNG
411 static bool get_random(rng_quality_t quality
, size_t size
, chunk_t
*out
)
415 rng
= lib
->crypto
->create_rng(lib
->crypto
, quality
);
420 if (!rng
->allocate_bytes(rng
, size
, out
))
430 * Encrypt symmetric key using a public key from a certificate
432 static bool encrypt_key(certificate_t
*cert
, chunk_t in
, chunk_t
*out
)
436 key
= cert
->get_public_key(cert
);
441 if (!key
->encrypt(key
, ENCRYPT_RSA_PKCS1
, in
, out
))
451 * build a DER-encoded issuerAndSerialNumber object
453 static chunk_t
build_issuerAndSerialNumber(certificate_t
*cert
)
455 identification_t
*issuer
= cert
->get_issuer(cert
);
456 chunk_t serial
= chunk_empty
;
458 if (cert
->get_type(cert
) == CERT_X509
)
460 x509_t
*x509
= (x509_t
*)cert
;
461 serial
= x509
->get_serial(x509
);
464 return asn1_wrap(ASN1_SEQUENCE
, "cm",
465 issuer
->get_encoding(issuer
),
466 asn1_integer("c", serial
));
470 * Generate a new PKCS#7 enveloped-data container
472 static bool generate(private_pkcs7_enveloped_data_t
*this,
473 certificate_t
*cert
, encryption_algorithm_t alg
, int key_size
)
475 chunk_t contentEncryptionAlgorithm
, encryptedContentInfo
, recipientInfo
;
476 chunk_t iv
, symmetricKey
, protectedKey
, content
;
481 alg_oid
= encryption_algorithm_to_oid(alg
, key_size
);
482 if (alg_oid
== OID_UNKNOWN
)
484 DBG1(DBG_LIB
, " encryption algorithm %N not supported",
485 encryption_algorithm_names
, alg
);
488 crypter
= lib
->crypto
->create_crypter(lib
->crypto
, alg
, key_size
/ 8);
491 DBG1(DBG_LIB
, " could not create crypter for algorithm %N",
492 encryption_algorithm_names
, alg
);
496 if (!get_random(RNG_TRUE
, crypter
->get_key_size(crypter
), &symmetricKey
))
498 DBG1(DBG_LIB
, " failed to allocate symmetric encryption key");
499 crypter
->destroy(crypter
);
502 DBG4(DBG_LIB
, " symmetric encryption key: %B", &symmetricKey
);
504 if (!get_random(RNG_WEAK
, crypter
->get_iv_size(crypter
), &iv
))
506 DBG1(DBG_LIB
, " failed to allocate initialization vector");
507 crypter
->destroy(crypter
);
510 DBG4(DBG_LIB
, " initialization vector: %B", &iv
);
512 bs
= crypter
->get_block_size(crypter
);
513 padding
= bs
- this->content
.len
% bs
;
514 content
= chunk_alloc(this->content
.len
+ padding
);
515 memcpy(content
.ptr
, this->content
.ptr
, this->content
.len
);
516 memset(content
.ptr
+ this->content
.len
, padding
, padding
);
517 DBG3(DBG_LIB
, " padded unencrypted data: %B", &content
);
519 /* symmetric inline encryption of content */
520 if (!crypter
->set_key(crypter
, symmetricKey
) ||
521 !crypter
->encrypt(crypter
, content
, iv
, NULL
))
523 crypter
->destroy(crypter
);
524 chunk_clear(&symmetricKey
);
528 crypter
->destroy(crypter
);
529 DBG3(DBG_LIB
, " encrypted data: %B", &content
);
531 if (!encrypt_key(cert
, symmetricKey
, &protectedKey
))
533 DBG1(DBG_LIB
, " encrypting symmetric key failed");
534 chunk_clear(&symmetricKey
);
536 chunk_free(&content
);
539 chunk_clear(&symmetricKey
);
541 contentEncryptionAlgorithm
= asn1_wrap(ASN1_SEQUENCE
, "mm",
542 asn1_build_known_oid(alg_oid
),
543 asn1_wrap(ASN1_OCTET_STRING
, "m", iv
));
545 encryptedContentInfo
= asn1_wrap(ASN1_SEQUENCE
, "mmm",
546 asn1_build_known_oid(OID_PKCS7_DATA
),
547 contentEncryptionAlgorithm
,
548 asn1_wrap(ASN1_CONTEXT_S_0
, "m", content
));
550 recipientInfo
= asn1_wrap(ASN1_SEQUENCE
, "cmmm",
552 build_issuerAndSerialNumber(cert
),
553 asn1_algorithmIdentifier(OID_RSA_ENCRYPTION
),
554 asn1_wrap(ASN1_OCTET_STRING
, "m", protectedKey
));
556 this->encoding
= asn1_wrap(ASN1_SEQUENCE
, "mm",
557 asn1_build_known_oid(OID_PKCS7_ENVELOPED_DATA
),
558 asn1_wrap(ASN1_CONTEXT_C_0
, "m",
559 asn1_wrap(ASN1_SEQUENCE
, "cmm",
561 asn1_wrap(ASN1_SET
, "m", recipientInfo
),
562 encryptedContentInfo
)));
570 pkcs7_t
*pkcs7_enveloped_data_gen(container_type_t type
, va_list args
)
572 private_pkcs7_enveloped_data_t
*this;
573 chunk_t blob
= chunk_empty
;
574 encryption_algorithm_t alg
= ENCR_AES_CBC
;
575 certificate_t
*cert
= NULL
;
580 switch (va_arg(args
, builder_part_t
))
583 cert
= va_arg(args
, certificate_t
*);
585 case BUILD_ENCRYPTION_ALG
:
586 alg
= va_arg(args
, int);
589 key_size
= va_arg(args
, int);
592 blob
= va_arg(args
, chunk_t
);
601 if (blob
.len
&& cert
)
603 this = create_empty();
605 this->content
= chunk_clone(blob
);
606 if (generate(this, cert
, alg
, key_size
))
608 return &this->public;