Coverage Report

Created: 2026-06-30 06:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/strongswan/src/libstrongswan/plugins/openssl/openssl_pkcs7.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2012 Martin Willi
3
 *
4
 * Copyright (C) secunet Security Networks AG
5
 *
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>.
10
 *
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
14
 * for more details.
15
 */
16
17
#include <openssl/opensslv.h>
18
#include <openssl/opensslconf.h>
19
20
#if OPENSSL_VERSION_NUMBER >= 0x0090807fL
21
#ifndef OPENSSL_NO_CMS
22
23
#include "openssl_pkcs7.h"
24
#include "openssl_util.h"
25
26
#include <library.h>
27
#include <utils/debug.h>
28
#include <asn1/oid.h>
29
#include <credentials/sets/mem_cred.h>
30
31
#include <openssl/cms.h>
32
33
#if OPENSSL_VERSION_NUMBER < 0x10100000L
34
#define X509_ATTRIBUTE_get0_object(attr) ({ (attr)->object; })
35
#endif
36
37
typedef struct private_openssl_pkcs7_t private_openssl_pkcs7_t;
38
39
/**
40
 * Private data of an openssl_pkcs7_t object.
41
 */
42
struct private_openssl_pkcs7_t {
43
44
  /**
45
   * Public pkcs7_t interface.
46
   */
47
  pkcs7_t public;
48
49
  /**
50
   * Type of this container
51
   */
52
  container_type_t type;
53
54
  /**
55
   * OpenSSL CMS structure
56
   */
57
  CMS_ContentInfo *cms;
58
};
59
60
/**
61
 * OpenSSL does not allow us to read the signature to verify it with our own
62
 * crypto API. We define the internal CMS_SignerInfo structure here to get it.
63
 */
64
struct CMS_SignerInfo_st {
65
  long version;
66
  void *sid;
67
  X509_ALGOR *digestAlgorithm;
68
  STACK_OF(X509_ATTRIBUTE) *signedAttrs;
69
  X509_ALGOR *signatureAlgorithm;
70
  ASN1_OCTET_STRING *signature;
71
  /* and more... */
72
};
73
74
/**
75
 * And we also need access to the wrappend CMS_KeyTransRecipientInfo to
76
 * read the encrypted key
77
 */
78
struct CMS_KeyTransRecipientInfo_st {
79
  long version;
80
  void *rid;
81
  X509_ALGOR *keyEncryptionAlgorithm;
82
  ASN1_OCTET_STRING *encryptedKey;
83
};
84
85
struct CMS_RecipientInfo_st {
86
  int type;
87
  struct CMS_KeyTransRecipientInfo_st *ktri;
88
  /* and more in union... */
89
};
90
91
struct CMS_EncryptedContentInfo_st {
92
  ASN1_OBJECT *contentType;
93
  X509_ALGOR *contentEncryptionAlgorithm;
94
  ASN1_OCTET_STRING *encryptedContent;
95
  /* and more... */
96
};
97
98
struct CMS_EnvelopedData_st {
99
  long version;
100
  void *originatorInfo;
101
  STACK_OF(CMS_RecipientInfo) *recipientInfos;
102
  struct CMS_EncryptedContentInfo_st *encryptedContentInfo;
103
  /* and more... */
104
};
105
106
struct CMS_ContentInfo_st {
107
  ASN1_OBJECT *contentType;
108
  struct CMS_EnvelopedData_st *envelopedData;
109
  /* and more in union... */
110
};
111
112
/**
113
 * We can't include asn1.h, declare function prototypes directly
114
 */
115
chunk_t asn1_wrap(int, const char *mode, ...);
116
int asn1_unwrap(chunk_t*, chunk_t*);
117
118
/**
119
 * Enumerator over certificates
120
 */
121
typedef struct {
122
  /** implements enumerator_t */
123
  enumerator_t public;
124
  /** Stack of X509 certificates */
125
  STACK_OF(X509) *certs;
126
  /** current enumerator position in certificates */
127
  int i;
128
  /** currently enumerating certificate_t */
129
  certificate_t *cert;
130
} cert_enumerator_t;
131
132
METHOD(enumerator_t, cert_destroy, void,
133
  cert_enumerator_t *this)
134
0
{
135
0
  DESTROY_IF(this->cert);
136
0
  free(this);
137
0
}
138
139
METHOD(enumerator_t, cert_enumerate, bool,
140
  cert_enumerator_t *this, va_list args)
141
0
{
142
0
  certificate_t **out;
143
144
0
  VA_ARGS_VGET(args, out);
145
146
0
  if (!this->certs)
147
0
  {
148
0
    return FALSE;
149
0
  }
150
0
  while (this->i < sk_X509_num(this->certs))
151
0
  {
152
0
    chunk_t encoding;
153
0
    X509 *x509;
154
155
    /* clean up previous round */
156
0
    DESTROY_IF(this->cert);
157
0
    this->cert = NULL;
158
159
0
    x509 = sk_X509_value(this->certs, this->i++);
160
0
    encoding = openssl_i2chunk(X509, x509);
161
0
    this->cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
162
0
                    BUILD_BLOB_ASN1_DER, encoding,
163
0
                    BUILD_END);
164
0
    free(encoding.ptr);
165
0
    if (!this->cert)
166
0
    {
167
0
      continue;
168
0
    }
169
0
    *out = this->cert;
170
0
    return TRUE;
171
0
  }
172
0
  return FALSE;
173
0
}
174
175
METHOD(pkcs7_t, create_cert_enumerator, enumerator_t*,
176
  private_openssl_pkcs7_t *this)
177
0
{
178
0
  cert_enumerator_t *enumerator;
179
180
0
  if (this->type == CONTAINER_PKCS7_SIGNED_DATA)
181
0
  {
182
0
    INIT(enumerator,
183
0
      .public = {
184
0
        .enumerate = enumerator_enumerate_default,
185
0
        .venumerate = _cert_enumerate,
186
0
        .destroy = _cert_destroy,
187
0
      },
188
0
      .certs = CMS_get1_certs(this->cms),
189
0
    );
190
0
    return &enumerator->public;
191
0
  }
192
0
  return enumerator_create_empty();
193
0
}
194
195
/**
196
 * Enumerator for signatures
197
 */
198
typedef struct {
199
  /** implements enumerator_t */
200
  enumerator_t public;
201
  /** Stack of signerinfos */
202
  STACK_OF(CMS_SignerInfo) *signers;
203
  /** current enumerator position in signers */
204
  int i;
205
  /** currently enumerating auth config */
206
  auth_cfg_t *auth;
207
  /** full CMS */
208
  CMS_ContentInfo *cms;
209
  /** credential set containing wrapped certificates */
210
  mem_cred_t *creds;
211
} signature_enumerator_t;
212
213
/**
214
 * Verify signerInfo signature
215
 */
216
static auth_cfg_t *verify_signature(CMS_SignerInfo *si,
217
                  signature_params_t *sig_alg)
218
0
{
219
0
  enumerator_t *enumerator;
220
0
  public_key_t *key;
221
0
  certificate_t *cert;
222
0
  auth_cfg_t *auth, *found = NULL;
223
0
  identification_t *issuer, *serial;
224
0
  chunk_t attrs = chunk_empty, sig, attr;
225
0
  X509_NAME *name;
226
0
  ASN1_INTEGER *snr;
227
0
  int i;
228
229
0
  if (CMS_SignerInfo_get0_signer_id(si, NULL, &name, &snr) != 1)
230
0
  {
231
0
    return NULL;
232
0
  }
233
0
  issuer = openssl_x509_name2id(name);
234
0
  if (!issuer)
235
0
  {
236
0
    return NULL;
237
0
  }
238
0
  serial = identification_create_from_encoding(
239
0
                  ID_KEY_ID, openssl_asn1_str2chunk(snr));
240
241
  /* reconstruct DER encoded attributes to verify signature */
242
0
  for (i = 0; i < CMS_signed_get_attr_count(si); i++)
243
0
  {
244
0
    attr = openssl_i2chunk(X509_ATTRIBUTE, CMS_signed_get_attr(si, i));
245
0
    attrs = chunk_cat("mm", attrs, attr);
246
0
  }
247
  /* wrap in a ASN1_SET */
248
0
  attrs = asn1_wrap(0x31, "m", attrs);
249
250
  /* TODO: find a better way to access and verify the signature */
251
0
  sig = openssl_asn1_str2chunk(si->signature);
252
0
  enumerator = lib->credmgr->create_trusted_enumerator(lib->credmgr,
253
0
                key_type_from_signature_scheme(sig_alg->scheme),
254
0
                serial, FALSE);
255
0
  while (enumerator->enumerate(enumerator, &cert, &auth))
256
0
  {
257
0
    if (issuer->equals(issuer, cert->get_issuer(cert)))
258
0
    {
259
0
      key = cert->get_public_key(cert);
260
0
      if (key)
261
0
      {
262
0
        if (key->verify(key, sig_alg->scheme, sig_alg->params,
263
0
                attrs, sig))
264
0
        {
265
0
          found = auth->clone(auth);
266
0
          key->destroy(key);
267
0
          break;
268
0
        }
269
0
        key->destroy(key);
270
0
      }
271
0
    }
272
0
  }
273
0
  enumerator->destroy(enumerator);
274
0
  issuer->destroy(issuer);
275
0
  serial->destroy(serial);
276
0
  free(attrs.ptr);
277
278
0
  return found;
279
0
}
280
281
/**
282
 * Verify the message digest in the signerInfo attributes
283
 */
284
static bool verify_digest(CMS_ContentInfo *cms, CMS_SignerInfo *si, int hash_oid)
285
0
{
286
0
  const ASN1_OCTET_STRING *os;
287
0
  ASN1_OCTET_STRING **osp;
288
0
  hash_algorithm_t hash_alg;
289
0
  chunk_t digest, content, hash;
290
0
  hasher_t *hasher;
291
292
0
  os = CMS_signed_get0_data_by_OBJ(si,
293
0
        OBJ_nid2obj(NID_pkcs9_messageDigest), -3, V_ASN1_OCTET_STRING);
294
0
  if (!os)
295
0
  {
296
0
    return FALSE;
297
0
  }
298
0
  digest = openssl_asn1_str2chunk(os);
299
0
  osp = CMS_get0_content(cms);
300
0
  if (!osp)
301
0
  {
302
0
    return FALSE;
303
0
  }
304
0
  content = openssl_asn1_str2chunk(*osp);
305
306
0
  hash_alg = hasher_algorithm_from_oid(hash_oid);
307
0
  hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
308
0
  if (!hasher)
309
0
  {
310
0
    DBG1(DBG_LIB, "hash algorithm %N not supported",
311
0
       hash_algorithm_names, hash_alg);
312
0
    return FALSE;
313
0
  }
314
0
  if (!hasher->allocate_hash(hasher, content, &hash))
315
0
  {
316
0
    hasher->destroy(hasher);
317
0
    return FALSE;
318
0
  }
319
0
  hasher->destroy(hasher);
320
321
0
  if (!chunk_equals_const(digest, hash))
322
0
  {
323
0
    free(hash.ptr);
324
0
    DBG1(DBG_LIB, "invalid messageDigest");
325
0
    return FALSE;
326
0
  }
327
0
  free(hash.ptr);
328
0
  return TRUE;
329
0
}
330
331
METHOD(enumerator_t, signature_enumerate, bool,
332
  signature_enumerator_t *this, va_list args)
333
0
{
334
0
  auth_cfg_t **out;
335
336
0
  VA_ARGS_VGET(args, out);
337
338
0
  if (!this->signers)
339
0
  {
340
0
    return FALSE;
341
0
  }
342
0
  while (this->i < sk_CMS_SignerInfo_num(this->signers))
343
0
  {
344
0
    CMS_SignerInfo *si;
345
0
    X509_ALGOR *digest, *sig;
346
0
    signature_params_t sig_alg = {};
347
0
    chunk_t sig_scheme;
348
0
    int hash_oid;
349
350
    /* clean up previous round */
351
0
    DESTROY_IF(this->auth);
352
0
    this->auth = NULL;
353
354
0
    si = sk_CMS_SignerInfo_value(this->signers, this->i++);
355
356
0
    CMS_SignerInfo_get0_algs(si, NULL, NULL, &digest, &sig);
357
0
    hash_oid = openssl_asn1_known_oid(digest->algorithm);
358
0
    if (openssl_asn1_known_oid(sig->algorithm) == OID_RSA_ENCRYPTION)
359
0
    {
360
      /* derive the signature scheme from the digest algorithm
361
       * for the classic PKCS#7 RSA mechanism */
362
0
      sig_alg.scheme = signature_scheme_from_oid(hash_oid);
363
0
    }
364
0
    else
365
0
    {
366
0
      sig_scheme = openssl_i2chunk(X509_ALGOR, sig);
367
0
      if (!signature_params_parse(sig_scheme, 0, &sig_alg))
368
0
      {
369
0
        free(sig_scheme.ptr);
370
0
        continue;
371
0
      }
372
0
      free(sig_scheme.ptr);
373
0
    }
374
0
    this->auth = verify_signature(si, &sig_alg);
375
0
    signature_params_clear(&sig_alg);
376
0
    if (!this->auth)
377
0
    {
378
0
      DBG1(DBG_LIB, "unable to verify pkcs7 attributes signature");
379
0
      continue;
380
0
    }
381
0
    if (!verify_digest(this->cms, si, hash_oid))
382
0
    {
383
0
      continue;
384
0
    }
385
0
    *out = this->auth;
386
0
    return TRUE;
387
0
  }
388
0
  return FALSE;
389
0
}
390
391
METHOD(enumerator_t, signature_destroy, void,
392
  signature_enumerator_t *this)
393
0
{
394
0
  lib->credmgr->remove_local_set(lib->credmgr, &this->creds->set);
395
0
  this->creds->destroy(this->creds);
396
0
  DESTROY_IF(this->auth);
397
0
  free(this);
398
0
}
399
400
METHOD(container_t, create_signature_enumerator, enumerator_t*,
401
  private_openssl_pkcs7_t *this)
402
0
{
403
0
  signature_enumerator_t *enumerator;
404
405
0
  if (this->type == CONTAINER_PKCS7_SIGNED_DATA)
406
0
  {
407
0
    enumerator_t *certs;
408
0
    certificate_t *cert;
409
410
0
    INIT(enumerator,
411
0
      .public = {
412
0
        .enumerate = enumerator_enumerate_default,
413
0
        .venumerate = _signature_enumerate,
414
0
        .destroy = _signature_destroy,
415
0
      },
416
0
      .cms = this->cms,
417
0
      .signers = CMS_get0_SignerInfos(this->cms),
418
0
      .creds = mem_cred_create(),
419
0
    );
420
421
    /* make available wrapped certs during signature checking */
422
0
    certs = create_cert_enumerator(this);
423
0
    while (certs->enumerate(certs, &cert))
424
0
    {
425
0
      enumerator->creds->add_cert(enumerator->creds, FALSE,
426
0
                    cert->get_ref(cert));
427
0
    }
428
0
    certs->destroy(certs);
429
430
0
    lib->credmgr->add_local_set(lib->credmgr, &enumerator->creds->set,
431
0
                  FALSE);
432
433
0
    return &enumerator->public;
434
0
  }
435
0
  return enumerator_create_empty();
436
0
}
437
438
439
METHOD(container_t, get_type, container_type_t,
440
  private_openssl_pkcs7_t *this)
441
0
{
442
0
  return this->type;
443
0
}
444
445
METHOD(pkcs7_t, get_attribute, bool,
446
  private_openssl_pkcs7_t *this, int oid,
447
  enumerator_t *enumerator, chunk_t *value)
448
0
{
449
0
  signature_enumerator_t *e;
450
0
  CMS_SignerInfo *si;
451
0
  X509_ATTRIBUTE *attr;
452
0
  const ASN1_TYPE *type;
453
0
  chunk_t chunk, wrapped;
454
0
  int i;
455
456
0
  e = (signature_enumerator_t*)enumerator;
457
0
  if (e->i <= 0)
458
0
  {
459
0
    return FALSE;
460
0
  }
461
462
  /* "i" gets incremented after enumerate(), hence read from previous */
463
0
  si = sk_CMS_SignerInfo_value(e->signers, e->i - 1);
464
0
  for (i = 0; i < CMS_signed_get_attr_count(si); i++)
465
0
  {
466
0
    attr = CMS_signed_get_attr(si, i);
467
0
    if (X509_ATTRIBUTE_count(attr) == 1 &&
468
0
      openssl_asn1_known_oid(X509_ATTRIBUTE_get0_object(attr)) == oid)
469
0
    {
470
      /* get first value in SET */
471
0
      type = X509_ATTRIBUTE_get0_type(attr, 0);
472
0
#if OPENSSL_VERSION_NUMBER < 0x30000000L
473
0
      chunk = wrapped = openssl_i2chunk(ASN1_TYPE, (ASN1_TYPE*)type);
474
#else
475
      chunk = wrapped = openssl_i2chunk(ASN1_TYPE, type);
476
#endif
477
0
      if (asn1_unwrap(&chunk, &chunk) != 0x100 /* ASN1_INVALID */)
478
0
      {
479
0
        *value = chunk_clone(chunk);
480
0
        free(wrapped.ptr);
481
0
        return TRUE;
482
0
      }
483
0
      free(wrapped.ptr);
484
0
    }
485
0
  }
486
0
  return FALSE;
487
0
}
488
489
/**
490
 * Find a private key for issuerAndSerialNumber
491
 */
492
static private_key_t *find_private(identification_t *issuer,
493
                   identification_t *serial)
494
0
{
495
0
  enumerator_t *enumerator;
496
0
  certificate_t *cert;
497
0
  public_key_t *public;
498
0
  private_key_t *private = NULL;
499
0
  identification_t *id;
500
0
  chunk_t fp;
501
502
0
  enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
503
0
                      CERT_X509, KEY_RSA, serial, FALSE);
504
0
  while (enumerator->enumerate(enumerator, &cert))
505
0
  {
506
0
    if (issuer->equals(issuer, cert->get_issuer(cert)))
507
0
    {
508
0
      public = cert->get_public_key(cert);
509
0
      if (public)
510
0
      {
511
0
        if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &fp))
512
0
        {
513
0
          id = identification_create_from_encoding(ID_KEY_ID, fp);
514
0
          private = lib->credmgr->get_private(lib->credmgr,
515
0
                            KEY_ANY, id, NULL);
516
0
          id->destroy(id);
517
0
        }
518
0
        public->destroy(public);
519
0
      }
520
0
    }
521
0
    if (private)
522
0
    {
523
0
      break;
524
0
    }
525
0
  }
526
0
  enumerator->destroy(enumerator);
527
0
  return private;
528
0
}
529
530
/**
531
 * Decrypt enveloped-data with a decrypted symmetric key
532
 */
533
static bool decrypt_symmetric(private_openssl_pkcs7_t *this, chunk_t key,
534
                chunk_t encrypted, chunk_t *plain)
535
0
{
536
0
  encryption_algorithm_t encr;
537
0
  X509_ALGOR *alg;
538
0
  crypter_t *crypter;
539
0
  chunk_t iv;
540
0
  size_t key_size;
541
542
  /* read encryption algorithm from internal structures; TODO fixup */
543
0
  alg = this->cms->envelopedData->encryptedContentInfo->
544
0
                        contentEncryptionAlgorithm;
545
0
  encr = encryption_algorithm_from_oid(openssl_asn1_known_oid(alg->algorithm),
546
0
                     &key_size);
547
0
  if (alg->parameter->type != V_ASN1_OCTET_STRING)
548
0
  {
549
0
    return FALSE;
550
0
  }
551
0
  iv = openssl_asn1_str2chunk(alg->parameter->value.octet_string);
552
553
0
  crypter = lib->crypto->create_crypter(lib->crypto, encr, key_size / 8);
554
0
  if (!crypter)
555
0
  {
556
0
    DBG1(DBG_LIB, "crypter %N-%d not available",
557
0
       encryption_algorithm_names, alg, key_size);
558
0
    return FALSE;
559
0
  }
560
0
  if (key.len != crypter->get_key_size(crypter))
561
0
  {
562
0
    DBG1(DBG_LIB, "symmetric key length is wrong");
563
0
    crypter->destroy(crypter);
564
0
    return FALSE;
565
0
  }
566
0
  if (iv.len != crypter->get_iv_size(crypter))
567
0
  {
568
0
    DBG1(DBG_LIB, "IV length is wrong");
569
0
    crypter->destroy(crypter);
570
0
    return FALSE;
571
0
  }
572
0
  if (!crypter->set_key(crypter, key) ||
573
0
    !crypter->decrypt(crypter, encrypted, iv, plain))
574
0
  {
575
0
    crypter->destroy(crypter);
576
0
    return FALSE;
577
0
  }
578
0
  crypter->destroy(crypter);
579
0
  return TRUE;
580
0
}
581
582
/**
583
 * Remove enveloped-data PKCS#7 padding from plain data
584
 */
585
static bool remove_padding(chunk_t *data)
586
0
{
587
0
  u_char *pos;
588
0
  u_char pattern;
589
0
  size_t padding;
590
591
0
  if (!data->len)
592
0
  {
593
0
    return FALSE;
594
0
  }
595
0
  pos = data->ptr + data->len - 1;
596
0
  padding = pattern = *pos;
597
598
0
  if (padding > data->len)
599
0
  {
600
0
    DBG1(DBG_LIB, "padding greater than data length");
601
0
    return FALSE;
602
0
  }
603
0
  data->len -= padding;
604
605
0
  while (padding-- > 0)
606
0
  {
607
0
    if (*pos-- != pattern)
608
0
    {
609
0
      DBG1(DBG_LIB, "wrong padding pattern");
610
0
      return FALSE;
611
0
    }
612
0
  }
613
0
  return TRUE;
614
0
}
615
616
/**
617
 * Decrypt PKCS#7 enveloped-data
618
 */
619
static bool decrypt(private_openssl_pkcs7_t *this,
620
          chunk_t encrypted, chunk_t *plain)
621
0
{
622
0
  STACK_OF(CMS_RecipientInfo) *ris;
623
0
  CMS_RecipientInfo *ri;
624
0
  chunk_t chunk, key = chunk_empty;
625
0
  int i;
626
627
0
  ris = CMS_get0_RecipientInfos(this->cms);
628
0
  for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++)
629
0
  {
630
0
    ri = sk_CMS_RecipientInfo_value(ris, i);
631
0
    if (CMS_RecipientInfo_type(ri) == CMS_RECIPINFO_TRANS)
632
0
    {
633
0
      identification_t *serial, *issuer;
634
0
      private_key_t *private;
635
0
      X509_ALGOR *alg;
636
0
      X509_NAME *name;
637
0
      ASN1_INTEGER *sn;
638
0
      u_char zero = 0;
639
0
      int oid;
640
641
0
      if (CMS_RecipientInfo_ktri_get0_algs(ri, NULL, NULL, &alg) == 1 &&
642
0
        CMS_RecipientInfo_ktri_get0_signer_id(ri, NULL, &name, &sn) == 1)
643
0
      {
644
0
        oid = openssl_asn1_known_oid(alg->algorithm);
645
0
        if (oid != OID_RSA_ENCRYPTION)
646
0
        {
647
0
          DBG1(DBG_LIB, "only RSA encryption supported in PKCS#7");
648
0
          continue;
649
0
        }
650
0
        issuer = openssl_x509_name2id(name);
651
0
        if (!issuer)
652
0
        {
653
0
          continue;
654
0
        }
655
0
        chunk = openssl_asn1_str2chunk(sn);
656
0
        if (chunk.len && chunk.ptr[0] & 0x80)
657
0
        { /* if MSB is set, append a zero to make it non-negative */
658
0
          chunk = chunk_cata("cc", chunk_from_thing(zero), chunk);
659
0
        }
660
0
        serial = identification_create_from_encoding(ID_KEY_ID, chunk);
661
0
        private = find_private(issuer, serial);
662
0
        issuer->destroy(issuer);
663
0
        serial->destroy(serial);
664
665
0
        if (private)
666
0
        {
667
          /* get encryptedKey from internal structure; TODO fixup */
668
0
          chunk = openssl_asn1_str2chunk(ri->ktri->encryptedKey);
669
0
          if (private->decrypt(private, ENCRYPT_RSA_PKCS1, NULL,
670
0
                     chunk, &key))
671
0
          {
672
0
            private->destroy(private);
673
0
            break;
674
0
          }
675
0
          private->destroy(private);
676
0
        }
677
0
      }
678
0
    }
679
0
  }
680
0
  if (!key.len)
681
0
  {
682
0
    DBG1(DBG_LIB, "no private key found to decrypt PKCS#7");
683
0
    return FALSE;
684
0
  }
685
0
  if (!decrypt_symmetric(this, key, encrypted, plain))
686
0
  {
687
0
    chunk_clear(&key);
688
0
    return FALSE;
689
0
  }
690
0
  chunk_clear(&key);
691
0
  if (!remove_padding(plain))
692
0
  {
693
0
    free(plain->ptr);
694
0
    return FALSE;
695
0
  }
696
0
  return TRUE;
697
0
}
698
699
METHOD(container_t, get_data, bool,
700
  private_openssl_pkcs7_t *this, chunk_t *data)
701
0
{
702
0
  ASN1_OCTET_STRING **os;
703
0
  chunk_t chunk;
704
705
0
  os = CMS_get0_content(this->cms);
706
0
  if (os)
707
0
  {
708
0
    chunk = openssl_asn1_str2chunk(*os);
709
0
    switch (this->type)
710
0
    {
711
0
      case CONTAINER_PKCS7_DATA:
712
0
      case CONTAINER_PKCS7_SIGNED_DATA:
713
0
        *data = chunk_clone(chunk);
714
0
        return TRUE;
715
0
      case CONTAINER_PKCS7_ENVELOPED_DATA:
716
0
        return decrypt(this, chunk, data);
717
0
      default:
718
0
        break;
719
0
    }
720
0
  }
721
0
  return FALSE;
722
0
}
723
724
METHOD(container_t, get_encoding, bool,
725
  private_openssl_pkcs7_t *this, chunk_t *data)
726
0
{
727
0
  return FALSE;
728
0
}
729
730
METHOD(container_t, destroy, void,
731
  private_openssl_pkcs7_t *this)
732
0
{
733
0
  CMS_ContentInfo_free(this->cms);
734
0
  free(this);
735
0
}
736
737
/**
738
 * Generic constructor
739
 */
740
static private_openssl_pkcs7_t* create_empty()
741
0
{
742
0
  private_openssl_pkcs7_t *this;
743
744
0
  INIT(this,
745
0
    .public = {
746
0
      .container = {
747
0
        .get_type = _get_type,
748
0
        .create_signature_enumerator = _create_signature_enumerator,
749
0
        .get_data = _get_data,
750
0
        .get_encoding = _get_encoding,
751
0
        .destroy = _destroy,
752
0
      },
753
0
      .get_attribute = _get_attribute,
754
0
      .create_cert_enumerator = _create_cert_enumerator,
755
0
    },
756
0
  );
757
758
0
  return this;
759
0
}
760
761
/**
762
 * Parse a PKCS#7 container
763
 */
764
static bool parse(private_openssl_pkcs7_t *this, chunk_t blob)
765
0
{
766
0
  BIO *bio;
767
768
0
  bio = BIO_new_mem_buf(blob.ptr, blob.len);
769
0
  this->cms = d2i_CMS_bio(bio, NULL);
770
0
  BIO_free(bio);
771
772
0
  if (!this->cms)
773
0
  {
774
0
    return FALSE;
775
0
  }
776
0
  switch (openssl_asn1_known_oid((ASN1_OBJECT*)CMS_get0_type(this->cms)))
777
0
  {
778
0
    case OID_PKCS7_DATA:
779
0
      this->type = CONTAINER_PKCS7_DATA;
780
0
      break;
781
0
    case OID_PKCS7_SIGNED_DATA:
782
0
      this->type = CONTAINER_PKCS7_SIGNED_DATA;
783
0
      break;
784
0
    case OID_PKCS7_ENVELOPED_DATA:
785
0
      this->type = CONTAINER_PKCS7_ENVELOPED_DATA;
786
0
      break;
787
0
    default:
788
0
      return FALSE;
789
0
  }
790
791
0
  return TRUE;
792
0
}
793
794
/**
795
 * See header
796
 */
797
pkcs7_t *openssl_pkcs7_load(container_type_t type, va_list args)
798
0
{
799
0
  chunk_t blob = chunk_empty;
800
0
  private_openssl_pkcs7_t *this;
801
802
0
  while (TRUE)
803
0
  {
804
0
    switch (va_arg(args, builder_part_t))
805
0
    {
806
0
      case BUILD_BLOB_ASN1_DER:
807
0
        blob = va_arg(args, chunk_t);
808
0
        continue;
809
0
      case BUILD_END:
810
0
        break;
811
0
      default:
812
0
        return NULL;
813
0
    }
814
0
    break;
815
0
  }
816
0
  if (blob.len)
817
0
  {
818
0
    this = create_empty();
819
0
    if (parse(this, blob))
820
0
    {
821
0
      return &this->public;
822
0
    }
823
0
    destroy(this);
824
0
  }
825
0
  return NULL;
826
0
}
827
828
#endif /* OPENSSL_NO_CMS */
829
#endif /* OPENSSL_VERSION_NUMBER */