]> git.ipfire.org Git - people/ms/strongswan.git/blob - src/libstrongswan/plugins/pkcs7/pkcs7_enveloped_data.c
82d113decef35b0a329281524b14c63351ffee3e
[people/ms/strongswan.git] / src / libstrongswan / plugins / pkcs7 / pkcs7_enveloped_data.c
1 /*
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
8 *
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>.
13 *
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
17 * for more details.
18 */
19
20 #include "pkcs7_enveloped_data.h"
21
22 #include <asn1/asn1.h>
23 #include <asn1/asn1_parser.h>
24 #include <asn1/oid.h>
25 #include <credentials/certificates/x509.h>
26 #include <utils/debug.h>
27
28 typedef struct private_pkcs7_enveloped_data_t private_pkcs7_enveloped_data_t;
29
30 /**
31 * Private data of a PKCS#7 signed-data container.
32 */
33 struct private_pkcs7_enveloped_data_t {
34
35 /**
36 * Implements pkcs7_t.
37 */
38 pkcs7_t public;
39
40 /**
41 * Decrypted content
42 */
43 chunk_t content;
44
45 /**
46 * Encrypted and encoded PKCS#7 enveloped-data
47 */
48 chunk_t encoding;
49 };
50
51 /**
52 * ASN.1 definition of the PKCS#7 envelopedData type
53 */
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 }
71 };
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
81
82 /**
83 * Find a private key for issuerAndSerialNumber
84 */
85 static private_key_t *find_private(identification_t *issuer,
86 identification_t *serial)
87 {
88 enumerator_t *enumerator;
89 certificate_t *cert;
90 public_key_t *public;
91 private_key_t *private = NULL;
92 identification_t *id;
93 chunk_t fp;
94
95 enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
96 CERT_X509, KEY_RSA, serial, FALSE);
97 while (enumerator->enumerate(enumerator, &cert))
98 {
99 if (issuer->equals(issuer, cert->get_issuer(cert)))
100 {
101 public = cert->get_public_key(cert);
102 if (public)
103 {
104 if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &fp))
105 {
106 id = identification_create_from_encoding(ID_KEY_ID, fp);
107 private = lib->credmgr->get_private(lib->credmgr,
108 KEY_ANY, id, NULL);
109 id->destroy(id);
110 }
111 public->destroy(public);
112 }
113 }
114 if (private)
115 {
116 break;
117 }
118 }
119 enumerator->destroy(enumerator);
120 return private;
121 }
122
123 /**
124 * Decrypt content using a private key from "issuer"
125 */
126 static bool decrypt(private_key_t *private, chunk_t key, chunk_t iv, int oid,
127 chunk_t encrypted, chunk_t *plain)
128 {
129 encryption_algorithm_t alg;
130 chunk_t plain_key;
131 crypter_t *crypter;
132 size_t key_size;
133
134 alg = encryption_algorithm_from_oid(oid, &key_size);
135 if (alg == ENCR_UNDEFINED)
136 {
137 DBG1(DBG_LIB, "unsupported content encryption algorithm");
138 return FALSE;
139 }
140 if (!private->decrypt(private, ENCRYPT_RSA_PKCS1, key, &plain_key))
141 {
142 DBG1(DBG_LIB, "symmetric key could not be decrypted with rsa");
143 return FALSE;
144 }
145 crypter = lib->crypto->create_crypter(lib->crypto, alg, key_size / 8);
146 if (!crypter)
147 {
148 DBG1(DBG_LIB, "crypter %N-%d not available",
149 encryption_algorithm_names, alg, key_size);
150 free(plain_key.ptr);
151 return FALSE;
152 }
153 if (plain_key.len != crypter->get_key_size(crypter))
154 {
155 DBG1(DBG_LIB, "symmetric key length %d is wrong", plain_key.len);
156 free(plain_key.ptr);
157 crypter->destroy(crypter);
158 return FALSE;
159 }
160 if (iv.len != crypter->get_iv_size(crypter))
161 {
162 DBG1(DBG_LIB, "IV length %d is wrong", iv.len);
163 free(plain_key.ptr);
164 crypter->destroy(crypter);
165 return FALSE;
166 }
167 if (!crypter->set_key(crypter, plain_key) ||
168 !crypter->decrypt(crypter, encrypted, iv, plain))
169 {
170 free(plain_key.ptr);
171 crypter->destroy(crypter);
172 return FALSE;
173 }
174 DBG4(DBG_LIB, "decrypted content with padding: %B", plain);
175 free(plain_key.ptr);
176 crypter->destroy(crypter);
177 return TRUE;
178 }
179
180 /**
181 * Remove the padding from plain data
182 */
183 static bool remove_padding(private_pkcs7_enveloped_data_t *this)
184 {
185 u_char *pos = this->content.ptr + this->content.len - 1;
186 u_char pattern = *pos;
187 size_t padding = pattern;
188
189 if (padding > this->content.len)
190 {
191 DBG1(DBG_LIB, "padding greater than data length");
192 return FALSE;
193 }
194 this->content.len -= padding;
195
196 while (padding-- > 0)
197 {
198 if (*pos-- != pattern)
199 {
200 DBG1(DBG_LIB, "wrong padding pattern");
201 return FALSE;
202 }
203 }
204 return TRUE;
205 }
206
207 /**
208 * Parse and decrypt enveloped-data
209 */
210 static bool parse(private_pkcs7_enveloped_data_t *this, chunk_t content)
211 {
212 asn1_parser_t *parser;
213 chunk_t object;
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;
219
220 parser = asn1_parser_create(envelopedDataObjects, content);
221 parser->set_top_level(parser, 0);
222
223 while (parser->iterate(parser, &objectID, &object))
224 {
225 u_int level = parser->get_level(parser);
226
227 switch (objectID)
228 {
229 case PKCS7_VERSION:
230 version = object.len ? (int)*object.ptr : 0;
231 DBG2(DBG_LIB, " v%d", version);
232 if (version != 0)
233 {
234 DBG1(DBG_LIB, "envelopedData version is not 0");
235 goto end;
236 }
237 break;
238 case PKCS7_RECIPIENT_INFO_VERSION:
239 version = object.len ? (int)*object.ptr : 0;
240 DBG2(DBG_LIB, " v%d", version);
241 if (version != 0)
242 {
243 DBG1(DBG_LIB, "recipient info version is not 0");
244 goto end;
245 }
246 break;
247 case PKCS7_ISSUER:
248 if (!issuer)
249 {
250 issuer = identification_create_from_encoding(ID_DER_ASN1_DN,
251 object);
252 }
253 break;
254 case PKCS7_SERIAL_NUMBER:
255 if (!serial)
256 {
257 serial = identification_create_from_encoding(ID_KEY_ID,
258 object);
259 }
260 break;
261 case PKCS7_ENCRYPTION_ALG:
262 if (asn1_parse_algorithmIdentifier(object, level,
263 NULL) != OID_RSA_ENCRYPTION)
264 {
265 DBG1(DBG_LIB, "only rsa encryption supported");
266 goto end;
267 }
268 break;
269 case PKCS7_ENCRYPTED_KEY:
270 key = object;
271 break;
272 case PKCS7_CONTENT_TYPE:
273 if (asn1_known_oid(object) != OID_PKCS7_DATA)
274 {
275 DBG1(DBG_LIB, "encrypted content not of type pkcs7 data");
276 goto end;
277 }
278 break;
279 case PKCS7_CONTENT_ENC_ALGORITHM:
280 alg = asn1_parse_algorithmIdentifier(object, level, &iv);
281 if (!asn1_parse_simple_object(&iv, ASN1_OCTET_STRING,
282 level + 1, "IV"))
283 {
284 DBG1(DBG_LIB, "IV could not be parsed");
285 goto end;
286 }
287 break;
288 case PKCS7_ENCRYPTED_CONTENT:
289 encrypted = object;
290 break;
291 }
292 }
293 success = parser->success(parser);
294
295 end:
296 parser->destroy(parser);
297 if (!success)
298 {
299 goto failed;
300 }
301 success = FALSE;
302 if (!issuer)
303 {
304 goto failed;
305 }
306 private = find_private(issuer, serial);
307 if (!private)
308 {
309 DBG1(DBG_LIB, "no private key found to decrypt pkcs7");
310 goto failed;
311 }
312 if (!decrypt(private, key, iv, alg, encrypted, &this->content))
313 {
314 goto failed;
315 }
316 if (!remove_padding(this))
317 {
318 goto failed;
319 }
320
321 success = TRUE;
322 failed:
323 DESTROY_IF(issuer);
324 DESTROY_IF(serial);
325 DESTROY_IF(private);
326 return success;
327 }
328
329 METHOD(container_t, get_type, container_type_t,
330 private_pkcs7_enveloped_data_t *this)
331 {
332 return CONTAINER_PKCS7_ENVELOPED_DATA;
333 }
334
335 METHOD(container_t, create_signature_enumerator, enumerator_t*,
336 private_pkcs7_enveloped_data_t *this)
337 {
338 return enumerator_create_empty();
339 }
340
341 METHOD(container_t, get_data, bool,
342 private_pkcs7_enveloped_data_t *this, chunk_t *data)
343 {
344 if (this->content.len)
345 {
346 *data = chunk_clone(this->content);
347 return TRUE;
348 }
349 return FALSE;
350 }
351
352 METHOD(container_t, get_encoding, bool,
353 private_pkcs7_enveloped_data_t *this, chunk_t *data)
354 {
355 *data = chunk_clone(this->encoding);
356 return TRUE;
357 }
358
359 METHOD(container_t, destroy, void,
360 private_pkcs7_enveloped_data_t *this)
361 {
362 free(this->content.ptr);
363 free(this->encoding.ptr);
364 free(this);
365 }
366
367 /**
368 * Generic constructor
369 */
370 static private_pkcs7_enveloped_data_t* create_empty()
371 {
372 private_pkcs7_enveloped_data_t *this;
373
374 INIT(this,
375 .public = {
376 .container = {
377 .get_type = _get_type,
378 .create_signature_enumerator = _create_signature_enumerator,
379 .get_data = _get_data,
380 .get_encoding = _get_encoding,
381 .destroy = _destroy,
382 },
383 .create_cert_enumerator = (void*)enumerator_create_empty,
384 .get_attribute = (void*)return_false,
385 },
386 );
387
388 return this;
389 }
390
391 /**
392 * See header.
393 */
394 pkcs7_t *pkcs7_enveloped_data_load(chunk_t encoding, chunk_t content)
395 {
396 private_pkcs7_enveloped_data_t *this = create_empty();
397
398 this->encoding = chunk_clone(encoding);
399 if (!parse(this, content))
400 {
401 destroy(this);
402 return NULL;
403 }
404
405 return &this->public;
406 }
407
408 /**
409 * Allocate data with an RNG
410 */
411 static bool get_random(rng_quality_t quality, size_t size, chunk_t *out)
412 {
413 rng_t *rng;
414
415 rng = lib->crypto->create_rng(lib->crypto, quality);
416 if (!rng)
417 {
418 return FALSE;
419 }
420 if (!rng->allocate_bytes(rng, size, out))
421 {
422 rng->destroy(rng);
423 return FALSE;
424 }
425 rng->destroy(rng);
426 return TRUE;
427 }
428
429 /**
430 * Encrypt symmetric key using a public key from a certificate
431 */
432 static bool encrypt_key(certificate_t *cert, chunk_t in, chunk_t *out)
433 {
434 public_key_t *key;
435
436 key = cert->get_public_key(cert);
437 if (!key)
438 {
439 return FALSE;
440 }
441 if (!key->encrypt(key, ENCRYPT_RSA_PKCS1, in, out))
442 {
443 key->destroy(key);
444 return FALSE;
445 }
446 key->destroy(key);
447 return TRUE;
448 }
449
450 /**
451 * build a DER-encoded issuerAndSerialNumber object
452 */
453 static chunk_t build_issuerAndSerialNumber(certificate_t *cert)
454 {
455 identification_t *issuer = cert->get_issuer(cert);
456 chunk_t serial = chunk_empty;
457
458 if (cert->get_type(cert) == CERT_X509)
459 {
460 x509_t *x509 = (x509_t*)cert;
461 serial = x509->get_serial(x509);
462 }
463
464 return asn1_wrap(ASN1_SEQUENCE, "cm",
465 issuer->get_encoding(issuer),
466 asn1_integer("c", serial));
467 }
468
469 /**
470 * Generate a new PKCS#7 enveloped-data container
471 */
472 static bool generate(private_pkcs7_enveloped_data_t *this,
473 certificate_t *cert, encryption_algorithm_t alg, int key_size)
474 {
475 chunk_t contentEncryptionAlgorithm, encryptedContentInfo, recipientInfo;
476 chunk_t iv, symmetricKey, protectedKey, content;
477 crypter_t *crypter;
478 size_t bs, padding;
479 int alg_oid;
480
481 alg_oid = encryption_algorithm_to_oid(alg, key_size);
482 if (alg_oid == OID_UNKNOWN)
483 {
484 DBG1(DBG_LIB, " encryption algorithm %N not supported",
485 encryption_algorithm_names, alg);
486 return FALSE;
487 }
488 crypter = lib->crypto->create_crypter(lib->crypto, alg, key_size / 8);
489 if (crypter == NULL)
490 {
491 DBG1(DBG_LIB, " could not create crypter for algorithm %N",
492 encryption_algorithm_names, alg);
493 return FALSE;
494 }
495
496 if (!get_random(RNG_TRUE, crypter->get_key_size(crypter), &symmetricKey))
497 {
498 DBG1(DBG_LIB, " failed to allocate symmetric encryption key");
499 crypter->destroy(crypter);
500 return FALSE;
501 }
502 DBG4(DBG_LIB, " symmetric encryption key: %B", &symmetricKey);
503
504 if (!get_random(RNG_WEAK, crypter->get_iv_size(crypter), &iv))
505 {
506 DBG1(DBG_LIB, " failed to allocate initialization vector");
507 crypter->destroy(crypter);
508 return FALSE;
509 }
510 DBG4(DBG_LIB, " initialization vector: %B", &iv);
511
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);
518
519 /* symmetric inline encryption of content */
520 if (!crypter->set_key(crypter, symmetricKey) ||
521 !crypter->encrypt(crypter, content, iv, NULL))
522 {
523 crypter->destroy(crypter);
524 chunk_clear(&symmetricKey);
525 chunk_free(&iv);
526 return FALSE;
527 }
528 crypter->destroy(crypter);
529 DBG3(DBG_LIB, " encrypted data: %B", &content);
530
531 if (!encrypt_key(cert, symmetricKey, &protectedKey))
532 {
533 DBG1(DBG_LIB, " encrypting symmetric key failed");
534 chunk_clear(&symmetricKey);
535 chunk_free(&iv);
536 chunk_free(&content);
537 return FALSE;
538 }
539 chunk_clear(&symmetricKey);
540
541 contentEncryptionAlgorithm = asn1_wrap(ASN1_SEQUENCE, "mm",
542 asn1_build_known_oid(alg_oid),
543 asn1_wrap(ASN1_OCTET_STRING, "m", iv));
544
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));
549
550 recipientInfo = asn1_wrap(ASN1_SEQUENCE, "cmmm",
551 ASN1_INTEGER_0,
552 build_issuerAndSerialNumber(cert),
553 asn1_algorithmIdentifier(OID_RSA_ENCRYPTION),
554 asn1_wrap(ASN1_OCTET_STRING, "m", protectedKey));
555
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",
560 ASN1_INTEGER_0,
561 asn1_wrap(ASN1_SET, "m", recipientInfo),
562 encryptedContentInfo)));
563
564 return TRUE;
565 }
566
567 /**
568 * See header.
569 */
570 pkcs7_t *pkcs7_enveloped_data_gen(container_type_t type, va_list args)
571 {
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;
576 int key_size = 128;
577
578 while (TRUE)
579 {
580 switch (va_arg(args, builder_part_t))
581 {
582 case BUILD_CERT:
583 cert = va_arg(args, certificate_t*);
584 continue;
585 case BUILD_ENCRYPTION_ALG:
586 alg = va_arg(args, int);
587 continue;
588 case BUILD_KEY_SIZE:
589 key_size = va_arg(args, int);
590 continue;
591 case BUILD_BLOB:
592 blob = va_arg(args, chunk_t);
593 continue;
594 case BUILD_END:
595 break;
596 default:
597 return NULL;
598 }
599 break;
600 }
601 if (blob.len && cert)
602 {
603 this = create_empty();
604
605 this->content = chunk_clone(blob);
606 if (generate(this, cert, alg, key_size))
607 {
608 return &this->public;
609 }
610 destroy(this);
611 }
612 return NULL;
613 }