/ OSX / sec / Security / SecCMS.c
SecCMS.c
  1  /*
  2   * Copyright (c) 2008-2010,2012-2014 Apple Inc. All Rights Reserved.
  3   * 
  4   * @APPLE_LICENSE_HEADER_START@
  5   * 
  6   * This file contains Original Code and/or Modifications of Original Code
  7   * as defined in and that are subject to the Apple Public Source License
  8   * Version 2.0 (the 'License'). You may not use this file except in
  9   * compliance with the License. Please obtain a copy of the License at
 10   * http://www.opensource.apple.com/apsl/ and read it before using this
 11   * file.
 12   * 
 13   * The Original Code and all software distributed under the License are
 14   * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 15   * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 16   * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 17   * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 18   * Please see the License for the specific language governing rights and
 19   * limitations under the License.
 20   * 
 21   * @APPLE_LICENSE_HEADER_END@
 22   *
 23   */
 24  
 25  /*
 26   *  signed_data.c
 27   *  Security
 28   *
 29   *
 30   */
 31  #include <AssertMacros.h>
 32  
 33  #include <TargetConditionals.h>
 34  #if TARGET_OS_OSX
 35  #define ENABLE_CMS 0
 36  #else
 37  #define ENABLE_CMS 1
 38  #endif
 39  
 40  #if ENABLE_CMS
 41  #include <Security/SecBase.h>
 42  #include <Security/SecCmsMessage.h>
 43  #include <Security/SecCmsSignedData.h>
 44  #include <Security/SecCmsEnvelopedData.h>
 45  #include <Security/SecCmsContentInfo.h>
 46  #include <Security/SecCmsSignerInfo.h>
 47  #include <Security/SecCmsRecipientInfo.h>
 48  #include <Security/SecCmsEncoder.h>
 49  #include <Security/SecCmsDecoder.h>
 50  #include <Security/SecCmsDigestContext.h>
 51  #include <Security/cmstpriv.h>
 52  
 53  #include <CoreFoundation/CFData.h>
 54  
 55  #include <Security/SecInternal.h>
 56  #include <Security/SecBasePriv.h>
 57  #include <Security/SecCertificatePriv.h>
 58  
 59  #include <Security/SecCMS.h>
 60  #include <Security/SecTrustPriv.h>
 61  
 62  
 63  #include <security_asn1/secasn1.h>
 64  #include <security_asn1/secerr.h>
 65  #include <security_asn1/secport.h>
 66  #include <Security/SecAsn1Item.h>
 67  #include <security_smime/secoid.h>
 68  #include <security_smime/cmslocal.h>
 69  
 70  
 71  CFTypeRef kSecCMSSignDigest = CFSTR("kSecCMSSignDigest");
 72  CFTypeRef kSecCMSSignDetached = CFSTR("kSecCMSSignDetached");
 73  CFTypeRef kSecCMSCertChainMode = CFSTR("kSecCMSCertChainMode");
 74  CFTypeRef kSecCMSCertChainModeNone = CFSTR("0");
 75  CFTypeRef kSecCMSAdditionalCerts = CFSTR("kSecCMSAdditionalCerts");
 76  CFTypeRef kSecCMSSignedAttributes = CFSTR("kSecCMSSignedAttributes");
 77  CFTypeRef kSecCMSSignDate = CFSTR("kSecCMSSignDate");
 78  CFTypeRef kSecCMSAllCerts = CFSTR("kSecCMSAllCerts");
 79  CFTypeRef kSecCMSHashAgility = CFSTR("kSecCMSHashAgility");
 80  CFTypeRef kSecCMSHashAgilityV2 = CFSTR("kSecCMSHashAgilityV2");
 81  CFTypeRef kSecCMSExpirationDate = CFSTR("kSecCMSExpirationDate");
 82  
 83  CFTypeRef kSecCMSBulkEncryptionAlgorithm = CFSTR("kSecCMSBulkEncryptionAlgorithm");
 84  CFTypeRef kSecCMSEncryptionAlgorithmDESCBC = CFSTR("kSecCMSEncryptionAlgorithmDESCBC");
 85  CFTypeRef kSecCMSEncryptionAlgorithmAESCBC = CFSTR("kSecCMSEncryptionAlgorithmAESCBC");
 86  
 87  CFTypeRef kSecCMSSignHashAlgorithm = CFSTR("kSecCMSSignHashAlgorithm");
 88  CFTypeRef kSecCMSHashingAlgorithmMD5 = CFSTR("kSecCMSHashingAlgorithmMD5");
 89  CFTypeRef kSecCMSHashingAlgorithmSHA1 = CFSTR("kSecCMSHashingAlgorithmSHA1");
 90  CFTypeRef kSecCMSHashingAlgorithmSHA256 = CFSTR("kSecCMSHashingAlgorithmSHA256");
 91  CFTypeRef kSecCMSHashingAlgorithmSHA384 = CFSTR("kSecCMSHashingAlgorithmSHA384");
 92  CFTypeRef kSecCMSHashingAlgorithmSHA512 = CFSTR("kSecCMSHashingAlgorithmSHA512");
 93  
 94  OSStatus SecCMSCreateEnvelopedData(CFTypeRef recipient_or_cfarray_thereof, 
 95      CFDictionaryRef params, CFDataRef data, CFMutableDataRef enveloped_data)
 96  {
 97      SecCmsMessageRef cmsg = NULL;
 98      SecCmsContentInfoRef cinfo;
 99      SecCmsEnvelopedDataRef envd = NULL;
100      SECOidTag algorithmTag = SEC_OID_DES_EDE3_CBC;
101      int keySize = 192;
102      OSStatus status = errSecParam;
103      
104      if (params) {
105          CFStringRef algorithm_name = CFDictionaryGetValue(params, kSecCMSBulkEncryptionAlgorithm);
106          if (algorithm_name) {
107              if (CFEqual(kSecCMSEncryptionAlgorithmDESCBC, algorithm_name)) {
108                  algorithmTag = SEC_OID_DES_CBC;
109                  keySize = 64;
110              } else if (CFEqual(kSecCMSEncryptionAlgorithmAESCBC, algorithm_name)) {
111                  algorithmTag = SEC_OID_AES_128_CBC;
112                  keySize = 128;
113              }
114          }
115      }
116      
117      require(cmsg = SecCmsMessageCreate(), out);
118  	require(envd = SecCmsEnvelopedDataCreate(cmsg, algorithmTag, keySize), out);
119      require(cinfo = SecCmsMessageGetContentInfo(cmsg), out);
120      require_noerr(SecCmsContentInfoSetContentEnvelopedData(cinfo, envd), out);
121      require(cinfo = SecCmsEnvelopedDataGetContentInfo(envd), out);
122      require_noerr(SecCmsContentInfoSetContentData(cinfo, NULL, false), out);
123      // == wrapper of: require(SECSuccess == SecCmsContentInfoSetContent(cinfo, SEC_OID_PKCS7_DATA, NULL), out);
124      
125      if (CFGetTypeID(recipient_or_cfarray_thereof) == CFArrayGetTypeID()) {
126          CFIndex dex, numCerts = CFArrayGetCount(recipient_or_cfarray_thereof);
127          for(dex=0; dex<numCerts; dex++) {
128              SecCertificateRef recip = 
129                  (SecCertificateRef)CFArrayGetValueAtIndex(recipient_or_cfarray_thereof, dex);
130              SecCmsRecipientInfoRef rinfo;
131              require(rinfo = SecCmsRecipientInfoCreate(envd, recip), out);
132          }
133      } else if (CFGetTypeID(recipient_or_cfarray_thereof) == SecCertificateGetTypeID()) {
134              require(SecCmsRecipientInfoCreate(envd, (SecCertificateRef)recipient_or_cfarray_thereof), out);
135      } else
136          goto out;
137      
138      SecAsn1Item input = {};
139      if (data) {
140          input.Length = CFDataGetLength(data);
141          input.Data = (uint8_t*)CFDataGetBytePtr(data);
142      }
143      require_noerr(SecCmsMessageEncode(cmsg, (data && input.Length) ? &input : NULL, enveloped_data), out);
144      
145      status = errSecSuccess;
146  out:
147      if (cmsg) SecCmsMessageDestroy(cmsg);
148      return status;
149  }
150  
151  OSStatus SecCMSDecryptEnvelopedData(CFDataRef message, 
152      CFMutableDataRef data, SecCertificateRef *recipient)
153  {
154      SecCmsMessageRef cmsg = NULL;
155      SecCmsContentInfoRef cinfo;
156      SecCmsEnvelopedDataRef envd = NULL;
157      SecCertificateRef used_recipient = NULL;
158      OSStatus status = errSecParam;
159      
160      SecAsn1Item encoded_message = { CFDataGetLength(message), (uint8_t*)CFDataGetBytePtr(message) };
161      require_noerr_action_quiet(SecCmsMessageDecode(&encoded_message, NULL, NULL, NULL, NULL, NULL, NULL, &cmsg), 
162          out, status = errSecDecode);
163      require_quiet(cinfo = SecCmsMessageContentLevel(cmsg, 0), out);
164      require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo) == SEC_OID_PKCS7_ENVELOPED_DATA, out);
165      require_quiet(envd = (SecCmsEnvelopedDataRef)SecCmsContentInfoGetContent(cinfo), out);
166      SecCmsRecipientInfoRef *rinfo = envd->recipientInfos;
167      while (!used_recipient && *rinfo) {
168          used_recipient = (*rinfo)->cert;
169          rinfo++;
170      }
171      require_quiet(2 == SecCmsMessageContentLevelCount(cmsg), out);
172      require_quiet(cinfo = SecCmsMessageContentLevel(cmsg, 1), out);
173      require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo) == SEC_OID_PKCS7_DATA, out);
174      const SecAsn1Item *content = SecCmsMessageGetContent(cmsg);
175      if (content)
176          CFDataAppendBytes(data, content->Data, content->Length);
177      if (recipient) {
178          CFRetainSafe(used_recipient);
179          *recipient = used_recipient;
180      }
181      status = errSecSuccess;
182  out:
183      if (cmsg) SecCmsMessageDestroy(cmsg);
184      return status;
185  }
186  
187  static SecCmsAttribute *
188  make_attr(PLArenaPool *poolp, SecAsn1Item *type, SecAsn1Item *value, bool encoded)
189  {
190      SecAsn1Item * copiedvalue;
191      SecCmsAttribute *attr = (SecCmsAttribute *)PORT_ArenaZAlloc(poolp, sizeof(SecCmsAttribute));
192      if (attr == NULL)
193          goto loser;
194  
195      if (SECITEM_CopyItem(poolp, &(attr->type), type) != SECSuccess)
196          goto loser;
197  
198      if (value != NULL) {
199          if ((copiedvalue = SECITEM_AllocItem(poolp, NULL, value->Length)) == NULL)
200              goto loser;
201  
202          if (SECITEM_CopyItem(poolp, copiedvalue, value) != SECSuccess)
203              goto loser;
204  
205          if (SecCmsArrayAdd(poolp, (void ***)&(attr->values), (void *)copiedvalue) != SECSuccess)
206              goto loser;
207      }
208  
209      attr->encoded = encoded;
210      
211  loser:
212      return attr;
213  }
214  
215  static void
216  signerinfo_add_auth_attr(SecCmsSignerInfoRef signerinfo, /*SECOidTag oidtag*/
217      SecAsn1Item *oid, SecAsn1Item *value, bool encoded)
218  {
219      PLArenaPool *poolp  = signerinfo->signedData->contentInfo.cmsg->poolp;
220      PORT_Assert (poolp != NULL);
221      void *mark = PORT_ArenaMark (poolp);
222      
223      SecCmsAttribute *attr = make_attr(poolp, oid, value, encoded);
224      if (!attr || SecCmsAttributeArrayAddAttr(poolp, &(signerinfo->authAttr), attr) != SECSuccess)
225              goto loser;
226  
227      PORT_ArenaUnmark (poolp, mark);
228      return;
229  
230  loser:
231      PORT_Assert (mark != NULL);
232      PORT_ArenaRelease (poolp, mark);
233      return;
234  }
235  
236  static void sign_all_attributes(const void *key, const void *value, void *context)
237  {
238      SecAsn1Item oid = { CFDataGetLength(key), (uint8_t*)CFDataGetBytePtr(key) },
239              oid_value = { CFDataGetLength(value), (uint8_t*)CFDataGetBytePtr(value) };
240      
241      signerinfo_add_auth_attr((SecCmsSignerInfoRef)context, &oid, &oid_value, true);
242  }
243  
244  #if 0
245  static void enveloped_data_add_unprotected_attr(SecCmsEnvelopedDataRef envd,
246      SecAsn1Item *oid, SecAsn1Item *value, bool encoded)
247  {
248      PLArenaPool *poolp  = envd->contentInfo.cmsg->poolp;
249      PORT_Assert (poolp != NULL);
250      void *mark = PORT_ArenaMark (poolp);
251      SecCmsAttribute *attr = make_attr(poolp, oid, value, encoded);
252  
253      if (!attr || SecCmsAttributeArrayAddAttr(
254          poolp, 
255          &(envd->unprotectedAttr), attr) != SECSuccess)
256              goto loser;
257  
258      PORT_ArenaUnmark (poolp, mark);
259      return;
260  
261  loser:
262      PORT_Assert (mark != NULL);
263      PORT_ArenaRelease (poolp, mark);
264      return;
265  
266  }
267  #endif
268  
269  static OSStatus SecCMSSignDataOrDigestAndAttributes(SecIdentityRef identity, 
270      CFDataRef data, bool detached, bool data_is_digest, SECOidTag sign_algorithm,
271      CFMutableDataRef signed_data, CFDictionaryRef signed_attributes, SecCmsCertChainMode chainMode, CFArrayRef additional_certs)
272  {
273      SecCmsMessageRef cmsg = NULL;
274      SecCmsContentInfoRef cinfo;
275      SecCmsSignedDataRef sigd = NULL;
276      SecCmsSignerInfoRef signerinfo;
277      OSStatus status = errSecParam;
278      
279      require(!data_is_digest || detached /* if digest, must be detached */, out);
280  
281      require(cmsg = SecCmsMessageCreate(), out);
282      require(sigd = SecCmsSignedDataCreate(cmsg), out);
283      require(cinfo = SecCmsMessageGetContentInfo(cmsg), out);
284      require_noerr(SecCmsContentInfoSetContentSignedData(cinfo, sigd), out);
285      require(cinfo = SecCmsSignedDataGetContentInfo(sigd), out);
286      require_noerr(SecCmsContentInfoSetContentData(cinfo, NULL, detached), out);
287      require(signerinfo = SecCmsSignerInfoCreate(sigd, identity, sign_algorithm), out);
288      if (additional_certs)
289          require_noerr(SecCmsSignedDataAddCertList(sigd, additional_certs), out);
290      require_noerr(SecCmsSignerInfoIncludeCerts(signerinfo, chainMode, certUsageAnyCA), out);
291      require_noerr(SecCmsSignerInfoAddSigningTime(signerinfo, CFAbsoluteTimeGetCurrent()), out);
292  
293      if (signed_attributes)
294          CFDictionaryApplyFunction(signed_attributes, sign_all_attributes, signerinfo);
295      
296      SecAsn1Item input = {};
297      if (data) {
298          input.Length = CFDataGetLength(data);
299          input.Data = (uint8_t*)CFDataGetBytePtr(data);
300      }
301      if (data_is_digest) {
302          require_noerr(SecCmsSignedDataSetDigestValue(sigd, sign_algorithm, &input), out);
303          require_noerr(SecCmsMessageEncode(cmsg, NULL, signed_data), out);
304      }
305      else
306          require_noerr(SecCmsMessageEncode(cmsg, (data && input.Length) ? &input : NULL, signed_data), out);
307      
308      status = errSecSuccess;
309  out:
310      if (cmsg) SecCmsMessageDestroy(cmsg);
311      return status;
312  }
313  
314  OSStatus SecCMSSignDataAndAttributes(SecIdentityRef identity, CFDataRef data, bool detached, 
315      CFMutableDataRef signed_data, CFDictionaryRef signed_attributes)
316  {
317      return SecCMSSignDataOrDigestAndAttributes(identity, data, detached, false, SEC_OID_SHA1,
318          signed_data, signed_attributes, SecCmsCMCertChain, NULL);
319  }
320  
321  OSStatus SecCMSSignDigestAndAttributes(SecIdentityRef identity, CFDataRef digest, 
322      CFMutableDataRef signed_data, CFDictionaryRef signed_attributes)
323  {
324      return SecCMSSignDataOrDigestAndAttributes(identity, digest, true, true, SEC_OID_SHA1,
325          signed_data, signed_attributes, SecCmsCMCertChain, NULL);
326  }
327  
328  
329  OSStatus SecCMSCreateSignedData(SecIdentityRef identity, CFDataRef data,
330      CFDictionaryRef parameters, CFDictionaryRef signed_attributes,
331      CFMutableDataRef signed_data)
332  {
333      bool is_digest = false, is_detached = false;
334      CFStringRef algorithm_name = NULL;
335      SecCmsCertChainMode chain_mode = SecCmsCMCertChain;
336      CFArrayRef additional_certs = NULL;
337  
338      if (parameters) {
339          is_digest = CFDictionaryGetValueIfPresent(parameters, 
340                          kSecCMSSignDigest, NULL);
341          is_detached = CFDictionaryGetValueIfPresent(parameters, 
342                          kSecCMSSignDetached, NULL);
343          algorithm_name = CFDictionaryGetValue(parameters,
344                          kSecCMSSignHashAlgorithm);
345  
346          CFTypeRef chain_mode_param = CFDictionaryGetValue(parameters, kSecCMSCertChainMode);
347          if (chain_mode_param && (CFGetTypeID(chain_mode_param) == CFStringGetTypeID()))
348              chain_mode = CFStringGetIntValue(chain_mode_param);
349  
350          CFTypeRef additional_certs_param = CFDictionaryGetValue(parameters, kSecCMSAdditionalCerts);
351          if (additional_certs_param && (CFGetTypeID(additional_certs_param) == CFArrayGetTypeID()))
352              additional_certs = (CFArrayRef)additional_certs_param;
353      }
354      
355      SECOidTag algorithm = SEC_OID_SHA1;
356      if (algorithm_name) {
357          if (CFEqual(kSecCMSHashingAlgorithmSHA1, algorithm_name)) {
358              algorithm = SEC_OID_SHA1;
359          } else if (CFEqual(kSecCMSHashingAlgorithmSHA256, algorithm_name)) {
360              algorithm = SEC_OID_SHA256;
361          } else if (CFEqual(kSecCMSHashingAlgorithmSHA384, algorithm_name)) {
362              algorithm = SEC_OID_SHA384;
363          } else if (CFEqual(kSecCMSHashingAlgorithmSHA512, algorithm_name)) {
364              algorithm = SEC_OID_SHA512;
365          } else {
366              return errSecParam;
367          }
368      }
369      
370      return SecCMSSignDataOrDigestAndAttributes(identity, data, 
371          is_detached, is_digest, algorithm,
372          signed_data, signed_attributes, chain_mode, additional_certs);
373  }
374  
375  
376  static CFMutableArrayRef copy_signed_attribute_values(SecCmsAttribute *attr)
377  {
378      CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
379      SecAsn1Item **item = attr->values;
380      if (item) while (*item) {
381          CFDataRef asn1data = CFDataCreate(kCFAllocatorDefault, (*item)->Data, (*item)->Length);
382          if (asn1data) {
383              CFArrayAppendValue(array, asn1data);
384              CFRelease(asn1data);
385          }
386          item++;
387      }
388      return array;
389  }
390  
391  static OSStatus SecCMSVerifySignedData_internal(CFDataRef message, CFDataRef detached_contents,
392      CFTypeRef policy, SecTrustRef *trustref, CFArrayRef additional_certs,
393      CFDataRef *attached_contents, CFDictionaryRef *signed_attributes)
394  {
395      SecCmsMessageRef cmsg = NULL;
396      SecCmsContentInfoRef cinfo;
397      SecCmsSignedDataRef sigd = NULL;
398      OSStatus status = errSecParam;
399  
400      require(message, out);
401      SecAsn1Item encoded_message = { CFDataGetLength(message), (uint8_t*)CFDataGetBytePtr(message) };
402      require_noerr_action_quiet(SecCmsMessageDecode(&encoded_message, NULL, NULL, NULL, NULL, NULL, NULL, &cmsg), 
403          out, status = errSecDecode);
404      /* expected to be a signed data message at the top level */
405      require_quiet(cinfo = SecCmsMessageContentLevel(cmsg, 0), out);
406      require_quiet(SecCmsContentInfoGetContentTypeTag(cinfo) == SEC_OID_PKCS7_SIGNED_DATA, out);
407      require_quiet(sigd = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(cinfo), out);
408  
409      if (detached_contents)
410      {
411          require_quiet(!SecCmsSignedDataHasDigests(sigd), out);
412          SECAlgorithmID **digestalgs = SecCmsSignedDataGetDigestAlgs(sigd);
413          SecCmsDigestContextRef digcx = SecCmsDigestContextStartMultiple(digestalgs);
414          SecCmsDigestContextUpdate(digcx, CFDataGetBytePtr(detached_contents), CFDataGetLength(detached_contents));
415          SecCmsSignedDataSetDigestContext(sigd, digcx);
416          SecCmsDigestContextDestroy(digcx);
417      }
418  
419      if (additional_certs)
420          require_noerr_quiet(SecCmsSignedDataAddCertList(sigd, additional_certs), out);
421  
422      if (policy) { /* if no policy is given skip verification */
423          /* find out about signers */
424          int nsigners = SecCmsSignedDataSignerInfoCount(sigd);
425          require_quiet(nsigners == 1, out);
426          require_noerr_action_quiet(SecCmsSignedDataVerifySignerInfo(sigd, 0, NULL, policy, trustref), 
427              out, status = errSecAuthFailed);
428      }
429      
430  #if 0
431      if (nsigners > 1)
432          trustrefs = CFArrayCreateMutable(kCFAllocatorDefault, nsigners, &kCFTypeArrayCallBacks);
433          
434      int j;
435      for (j = 0; j < nsigners; j++)
436      {
437          SecTrustRef trustRef;
438          require_noerr_action_quiet(SecCmsSignedDataVerifySignerInfo(sigd, j, NULL, policy, &trustRef),
439              out, status = errSecAuthFailed);
440          if ((j == 0) && (nsigners == 1))
441              *trustref_or_cfarray_thereof = trustRef;
442          else {
443              CFArrayAppendValue(trustrefs, trustRef);
444              CFRelease(trustRef);
445          }
446      }
447      *trustref_or_cfarray_thereof = trustrefs;
448      trustrefs = NULL;
449  #endif
450  
451      status = errSecSuccess;
452  
453      if (attached_contents) {
454          const SecAsn1Item *content = SecCmsMessageGetContent(cmsg);
455          if (content)
456              *attached_contents = CFDataCreate(kCFAllocatorDefault, content->Data, content->Length);
457          else
458              *attached_contents = NULL;
459      }
460      
461      if (signed_attributes) {
462          CFMutableDictionaryRef attrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 
463              0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
464          require_quiet(attrs, out);
465          SecCmsAttribute **signed_attrs = sigd->signerInfos[0]->authAttr;
466          if (signed_attrs) while (*signed_attrs) {
467              CFDataRef type = CFDataCreate(kCFAllocatorDefault, (*signed_attrs)->type.Data, (*signed_attrs)->type.Length);
468              if (type) {
469                  CFMutableArrayRef attr = copy_signed_attribute_values(*signed_attrs);
470                  if (attr) {
471                      CFMutableArrayRef existing_attrs = (CFMutableArrayRef)CFDictionaryGetValue(attrs, type);
472                      if (existing_attrs) {
473                          CFIndex count = CFArrayGetCount(attr);
474                          if (count)
475                              CFArrayAppendArray(existing_attrs, attr, CFRangeMake(0, count));
476                      } else
477                          CFDictionarySetValue(attrs, type, attr);
478                      CFRelease(attr);
479                  }
480                  CFRelease(type);
481              }
482              signed_attrs++;
483          }
484          CFMutableArrayRef certs = NULL;
485          
486          SecAsn1Item **cert_datas = SecCmsSignedDataGetCertificateList(sigd);
487          certs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
488          SecAsn1Item *cert_data;
489          if (cert_datas) while ((cert_data = *cert_datas) != NULL) {
490              SecCertificateRef cert = SecCertificateCreateWithBytes(NULL, cert_data->Data, cert_data->Length);
491              if (cert) {
492                  CFArrayAppendValue(certs, cert);
493                  CFRelease(cert);
494              }
495              cert_datas++;
496          }
497          
498          CFDictionaryAddValue(attrs, kSecCMSAllCerts, certs);
499  
500          /* Add "cooked" values separately */
501          CFAbsoluteTime signing_time;
502          if (errSecSuccess == SecCmsSignerInfoGetSigningTime(sigd->signerInfos[0], &signing_time)) {
503                  CFDateRef signing_date = CFDateCreate(kCFAllocatorDefault, signing_time);
504              if (signing_date){
505                  CFDictionarySetValue(attrs, kSecCMSSignDate, signing_date);
506                  CFReleaseSafe(signing_date);
507              }
508          }
509  
510          CFDataRef hash_agility_value = NULL;
511          if (errSecSuccess == SecCmsSignerInfoGetAppleCodesigningHashAgility(sigd->signerInfos[0], &hash_agility_value)) {
512              if (hash_agility_value) {
513                  CFDictionarySetValue(attrs, kSecCMSHashAgility, hash_agility_value);
514              }
515          }
516  
517          CFDictionaryRef hash_agility_values = NULL;
518          if (errSecSuccess == SecCmsSignerInfoGetAppleCodesigningHashAgilityV2(sigd->signerInfos[0], &hash_agility_values)) {
519              if (hash_agility_values) {
520                  CFDictionarySetValue(attrs, kSecCMSHashAgilityV2, hash_agility_values);
521              }
522          }
523  
524          CFAbsoluteTime expiration_time;
525          if (errSecSuccess == SecCmsSignerInfoGetAppleExpirationTime(sigd->signerInfos[0], &expiration_time)) {
526              CFDateRef expiration_date = CFDateCreate(NULL, expiration_time);
527              if (expiration_date) {
528                  CFDictionarySetValue(attrs, kSecCMSExpirationDate, expiration_date);
529                  CFReleaseSafe(expiration_date);
530              }
531          }
532  
533          *signed_attributes = attrs;
534          CFReleaseSafe(certs);
535      }
536      
537      
538  out:
539      if (cmsg) SecCmsMessageDestroy(cmsg);
540      return status;
541  }
542  
543  OSStatus SecCMSVerifyCopyDataAndAttributes(CFDataRef message, CFDataRef detached_contents,
544      CFTypeRef policy, SecTrustRef *trustref,
545      CFDataRef *attached_contents, CFDictionaryRef *signed_attributes)
546  {
547      OSStatus status = SecCMSVerifySignedData_internal(message, detached_contents, policy, trustref, NULL, attached_contents, signed_attributes);
548      
549      return status;
550  }
551  
552  OSStatus SecCMSVerifySignedData(CFDataRef message, CFDataRef detached_contents,
553      CFTypeRef policy, SecTrustRef *trustref, CFArrayRef additional_certificates,
554      CFDataRef *attached_contents, CFDictionaryRef *message_attributes)
555  {
556      CFDictionaryRef signed_attributes = NULL;
557      OSStatus status = SecCMSVerifySignedData_internal(message, detached_contents, policy, trustref, additional_certificates, attached_contents, &signed_attributes);
558      if (!status && signed_attributes && message_attributes) {
559          *message_attributes = CFDictionaryCreate(kCFAllocatorDefault, &kSecCMSSignedAttributes, (const void **)&signed_attributes, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
560      }
561      CFReleaseSafe(signed_attributes);
562     
563      return status;
564  }
565  
566  OSStatus SecCMSVerify(CFDataRef message, CFDataRef detached_contents,
567      CFTypeRef policy, SecTrustRef *trustref,
568      CFDataRef *attached_contents) {
569          return SecCMSVerifySignedData_internal(message, detached_contents, policy, trustref, NULL, attached_contents, NULL);
570  }
571  
572  CFArrayRef SecCMSCertificatesOnlyMessageCopyCertificates(CFDataRef message) {
573      SecCmsMessageRef cmsg = NULL;
574      SecCmsContentInfoRef cinfo;
575      SecCmsSignedDataRef sigd = NULL;
576      CFMutableArrayRef certs = NULL;
577  
578      if (!message) {
579          return NULL;
580      }
581  
582      SecAsn1Item encoded_message = { CFDataGetLength(message), (uint8_t*)CFDataGetBytePtr(message) };
583      require_noerr_quiet(SecCmsMessageDecode(&encoded_message, NULL, NULL, NULL, NULL, NULL, NULL, &cmsg), out);
584      /* expected to be a signed data message at the top level */
585      require(cinfo = SecCmsMessageContentLevel(cmsg, 0), out);
586      require(SecCmsContentInfoGetContentTypeTag(cinfo) == SEC_OID_PKCS7_SIGNED_DATA, out);
587      require(sigd = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(cinfo), out);
588  
589      /* find out about signers */
590      int nsigners = SecCmsSignedDataSignerInfoCount(sigd);
591      require(nsigners == 0, out);
592  
593      SecAsn1Item **cert_datas = SecCmsSignedDataGetCertificateList(sigd);
594      certs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
595      SecAsn1Item *cert_data;
596      if (cert_datas) while ((cert_data = *cert_datas) != NULL) {
597          SecCertificateRef cert = SecCertificateCreateWithBytes(NULL, cert_data->Data, cert_data->Length);
598          if (cert) {
599              CFArrayAppendValue(certs, cert);
600              CFRelease(cert); 
601          }
602          cert_datas++;
603      }
604  
605  out:
606      if (cmsg) { SecCmsMessageDestroy(cmsg); }
607      if (certs && CFArrayGetCount(certs) < 1) {
608          CFReleaseNull(certs);
609      }
610  
611      return certs;
612  }
613  
614  
615  extern const SecAsn1Template SecCmsMessageTemplate[];
616  
617  CFDataRef SecCMSCreateCertificatesOnlyMessage(CFTypeRef cert_or_array_thereof) {
618      OSStatus status = errSecParam;
619      SecCmsMessageRef cmsg = NULL;
620      SecCmsContentInfoRef cinfo;
621      SecCmsSignedDataRef sigd = NULL;
622      CFMutableDataRef cert_only_signed_data = NULL;
623      CFArrayRef cert_array = NULL;
624      CFIndex cert_array_count = 0;
625      SecCertificateRef cert = NULL;
626      
627      require(cert_or_array_thereof, out);
628  
629      require(cmsg = SecCmsMessageCreate(), out);
630      require(sigd = SecCmsSignedDataCreate(cmsg), out);
631      require_noerr(SecCmsContentInfoSetContentData(&(sigd->contentInfo), NULL, PR_TRUE), out);
632      require(cinfo = SecCmsMessageGetContentInfo(cmsg), out);
633      require_noerr(SecCmsContentInfoSetContentSignedData(cinfo, sigd), out);
634      long version = SEC_CMS_SIGNED_DATA_VERSION_BASIC;
635      require(SEC_ASN1EncodeInteger(cmsg->poolp, &(sigd->version), version), out);
636      
637      if (CFGetTypeID(cert_or_array_thereof) == SecCertificateGetTypeID()) {
638          cert_array = CFArrayCreate(kCFAllocatorDefault, &cert_or_array_thereof, 1, &kCFTypeArrayCallBacks);
639      } else if (CFGetTypeID(cert_or_array_thereof) == CFArrayGetTypeID()) {
640          cert_array = CFArrayCreateCopy(kCFAllocatorDefault, (CFArrayRef)cert_or_array_thereof);
641      }
642  
643      require(cert_array, out);
644      cert_array_count = CFArrayGetCount(cert_array);
645      require(cert_array_count > 0, out);
646  
647      sigd->rawCerts = (SecAsn1Item * *)PORT_ArenaAlloc(cmsg->poolp, (cert_array_count + 1) * sizeof(SecAsn1Item *));
648      require(sigd->rawCerts, out);
649      CFIndex ix;
650      for (ix = 0; ix < cert_array_count; ix++) {
651          cert = (SecCertificateRef)CFArrayGetValueAtIndex(cert_array, ix);
652          require(cert, out);
653          
654          sigd->rawCerts[ix] = PORT_ArenaZAlloc(cmsg->poolp, sizeof(SecAsn1Item));
655          SecAsn1Item cert_data = { SecCertificateGetLength(cert),
656                                  (uint8_t *)SecCertificateGetBytePtr(cert) };
657          *(sigd->rawCerts[ix]) = cert_data;
658      }
659      sigd->rawCerts[ix] = NULL;
660  
661  	/* this is a SET OF, so we need to sort them guys - we have the DER already, though */
662      if (cert_array_count > 1)
663          SecCmsArraySort((void **)sigd->rawCerts, SecCmsUtilDERCompare, NULL, NULL);
664              
665      cert_only_signed_data = CFDataCreateMutable(kCFAllocatorDefault, 0);
666          SecAsn1Item cert_only_signed_data_item = {};
667          require_quiet(SEC_ASN1EncodeItem(cmsg->poolp, &cert_only_signed_data_item, 
668              cmsg, SecCmsMessageTemplate), out);
669      CFDataAppendBytes(cert_only_signed_data, cert_only_signed_data_item.Data, 
670          cert_only_signed_data_item.Length);
671      
672      status = errSecSuccess;
673  out:
674      CFReleaseSafe(cert_array);
675      if (status) CFReleaseSafe(cert_only_signed_data);
676      if (cmsg) SecCmsMessageDestroy(cmsg);
677      return cert_only_signed_data;
678  }
679  
680  CFDataRef SecCMSCreateCertificatesOnlyMessageIAP(SecCertificateRef cert)
681  {
682      static const uint8_t header[] = {
683          0x30, 0x82, 0x03, 0x6d, 0x06, 0x09, 0x2a, 0x86,
684          0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0,
685          0x82, 0x03, 0x5e, 0x30, 0x82, 0x03, 0x5a, 0x02,
686          0x01, 0x01, 0x31, 0x00, 0x30, 0x0b, 0x06, 0x09,
687          0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
688          0x01, 0xa0, 0x82, 0x03, 0x40
689      };
690  
691      static const uint8_t trailer[] = {
692          0xa1, 0x00, 0x31, 0x00
693      };
694  
695      CFMutableDataRef message = NULL;
696      CFDataRef certdata;
697      const uint8_t *certbytes;
698      CFIndex certlen;
699      uint8_t *messagebytes;
700      uint16_t messagelen;
701  
702      certdata = SecCertificateCopyData(cert);
703      require(certdata, out);
704  
705      certbytes = CFDataGetBytePtr(certdata);
706      certlen = CFDataGetLength(certdata);
707      require(certlen > UINT8_MAX, out);
708      require(certlen < UINT16_MAX, out);
709  
710      message = CFDataCreateMutable(kCFAllocatorDefault, 0);
711      require(message, out);
712  
713      CFDataAppendBytes(message, header, sizeof(header));
714      CFDataAppendBytes(message, certbytes, certlen);
715      CFDataAppendBytes(message, trailer, sizeof(trailer));
716  
717      messagebytes = CFDataGetMutableBytePtr(message);
718      messagelen = CFDataGetLength(message);
719  
720      messagelen -= 4;
721      messagebytes[2] = messagelen >> 8;
722      messagebytes[3] = messagelen & 0xFF;
723  
724      messagelen -= 15;
725      messagebytes[17] = messagelen >> 8;
726      messagebytes[18] = messagelen & 0xFF;
727  
728      messagelen -= 4;
729      messagebytes[21] = messagelen >> 8;
730      messagebytes[22] = messagelen & 0xFF;
731  
732      messagelen -= 26;
733      messagebytes[43] = messagelen >> 8;
734      messagebytes[44] = messagelen & 0xFF;
735  
736  out:
737      CFReleaseSafe(certdata);
738      return message;
739  }
740  
741  #endif /* ENABLE_CMS */
742