]> git.saurik.com Git - apple/security.git/blob - libsecurity_smime/lib/CMSDecoder.c
Security-58286.200.222.tar.gz
[apple/security.git] / libsecurity_smime / lib / CMSDecoder.c
1 /*
2 * Copyright (c) 2006-2016 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 * CMSDecoder.c - Interface for decoding CMS messages.
26 */
27
28 #include "CMSDecoder.h"
29 #include "CMSUtils.h"
30
31 #include <Security/SecCmsDecoder.h>
32 #include <Security/SecCmsEnvelopedData.h>
33 #include <Security/SecCmsMessage.h>
34 #include <Security/SecCmsSignedData.h>
35 #include <Security/SecCmsSignerInfo.h>
36 #include <Security/SecCmsContentInfo.h>
37 #include <Security/SecCmsDigestContext.h>
38 #include <Security/SecCertificate.h>
39 #include <Security/SecCertificatePriv.h>
40 #include <Security/SecSMIME.h>
41 #include <Security/oidsattr.h>
42 #include <Security/SecTrustPriv.h>
43 #include <utilities/SecAppleAnchorPriv.h>
44 #include <CoreFoundation/CFRuntime.h>
45 #include <pthread.h>
46 #include <syslog.h>
47 #include <AssertMacros.h>
48
49 #pragma mark --- Private types and definitions ---
50
51 /*
52 * Decoder state.
53 */
54 typedef enum {
55 DS_Init, /* between CMSDecoderCreate and CMSDecoderUpdateMessage */
56 DS_Updating, /* between first CMSDecoderUpdateMessage and CMSDecoderFinalizeMessage */
57 DS_Final /* CMSDecoderFinalizeMessage has been called */
58 } CMSDecoderState;
59
60 /*
61 * Caller's CMSDecoderRef points to one of these.
62 */
63 struct _CMSDecoder {
64 CFRuntimeBase base;
65 CMSDecoderState decState;
66 SecCmsDecoderRef decoder;
67 CFDataRef detachedContent;
68
69 /*
70 * The following are valid (and quiescent) after CMSDecoderFinalizeMessage().
71 */
72 SecCmsMessageRef cmsMsg;
73 Boolean wasEncrypted; /* valid after CMSDecoderFinalizeMessage() */
74 SecCmsSignedDataRef signedData; /* if there is one... */
75 /* only non-NULL if we found a signedData */
76 size_t numSigners;
77 SecAsn1Oid *eContentType;
78 /* etc. */
79 };
80
81 static void cmsDecoderInit(CFTypeRef dec);
82 static void cmsDecoderFinalize(CFTypeRef dec);
83
84 static CFRuntimeClass cmsDecoderRuntimeClass =
85 {
86 0, /* version */
87 "CMSDecoder",
88 cmsDecoderInit,
89 NULL, /* copy */
90 cmsDecoderFinalize,
91 NULL, /* equal - just use pointer equality */
92 NULL, /* hash, ditto */
93 NULL, /* copyFormattingDesc */
94 NULL /* copyDebugDesc */
95 };
96
97 #pragma mark --- Private Routines ---
98
99 static CFTypeID cmsDecoderTypeID = _kCFRuntimeNotATypeID;
100
101 /* one time only class init, called via pthread_once() in CMSDecoderGetTypeID() */
102 static void cmsDecoderClassInitialize(void)
103 {
104 cmsDecoderTypeID =
105 _CFRuntimeRegisterClass((const CFRuntimeClass * const)&cmsDecoderRuntimeClass);
106 }
107
108 /* init called out from _CFRuntimeCreateInstance() */
109 static void cmsDecoderInit(CFTypeRef dec)
110 {
111 char *start = ((char *)dec) + sizeof(CFRuntimeBase);
112 memset(start, 0, sizeof(struct _CMSDecoder) - sizeof(CFRuntimeBase));
113 }
114
115 /*
116 * Dispose of a CMSDecoder. Called out from CFRelease().
117 */
118 static void cmsDecoderFinalize(
119 CFTypeRef dec)
120 {
121 CMSDecoderRef cmsDecoder = (CMSDecoderRef)dec;
122 if(cmsDecoder == NULL) {
123 return;
124 }
125 if(cmsDecoder->decoder != NULL) {
126 /*
127 * Normally this gets freed in SecCmsDecoderFinish - this is
128 * an error case. Unlike Finish, this calls SecCmsMessageDestroy.
129 */
130 SecCmsDecoderDestroy(cmsDecoder->decoder);
131 cmsDecoder->cmsMsg = NULL;
132 }
133 CFRELEASE(cmsDecoder->detachedContent);
134 if(cmsDecoder->cmsMsg != NULL) {
135 SecCmsMessageDestroy(cmsDecoder->cmsMsg);
136 cmsDecoder->cmsMsg = NULL;
137 }
138 }
139
140
141 /*
142 * Given detached content and a valid (decoded) SignedData, digest the detached
143 * content. This occurs at the later of {CMSDecoderFinalizeMessage() finding a
144 * SignedData when already have detachedContent, or CMSDecoderSetDetachedContent()
145 * when we already have a SignedData).
146 */
147 static OSStatus cmsDigestDetachedContent(
148 CMSDecoderRef cmsDecoder)
149 {
150 ASSERT((cmsDecoder->signedData != NULL) && (cmsDecoder->detachedContent != NULL));
151
152 SECAlgorithmID **digestAlgorithms = SecCmsSignedDataGetDigestAlgs(cmsDecoder->signedData);
153 if(digestAlgorithms == NULL) {
154 return errSecUnknownFormat;
155 }
156 SecCmsDigestContextRef digcx = SecCmsDigestContextStartMultiple(digestAlgorithms);
157 if(digcx == NULL) {
158 return errSecAllocate;
159 }
160
161 SecCmsDigestContextUpdate(digcx, CFDataGetBytePtr(cmsDecoder->detachedContent),
162 CFDataGetLength(cmsDecoder->detachedContent));
163 OSStatus ortn = SecCmsSignedDataSetDigestContext(cmsDecoder->signedData, digcx);
164 SecCmsDigestContextDestroy(digcx);
165
166 if(ortn) {
167 ortn = cmsRtnToOSStatus(ortn);
168 CSSM_PERROR("SecCmsSignedDataSetDigestContext", ortn);
169 return ortn;
170 }
171
172 return ortn;
173 }
174
175 #pragma mark --- Start of Public API ---
176
177 CFTypeID CMSDecoderGetTypeID(void)
178 {
179 static pthread_once_t once = PTHREAD_ONCE_INIT;
180
181 if(cmsDecoderTypeID == _kCFRuntimeNotATypeID) {
182 pthread_once(&once, &cmsDecoderClassInitialize);
183 }
184 return cmsDecoderTypeID;
185 }
186
187 /*
188 * Create a CMSDecoder. Result must eventually be freed via CFRelease().
189 */
190 OSStatus CMSDecoderCreate(
191 CMSDecoderRef *cmsDecoderOut) /* RETURNED */
192 {
193 CMSDecoderRef cmsDecoder = NULL;
194
195 uint32_t extra = sizeof(*cmsDecoder) - sizeof(cmsDecoder->base);
196 cmsDecoder = (CMSDecoderRef)_CFRuntimeCreateInstance(NULL, CMSDecoderGetTypeID(),
197 extra, NULL);
198 if(cmsDecoder == NULL) {
199 return errSecAllocate;
200 }
201 cmsDecoder->decState = DS_Init;
202 *cmsDecoderOut = cmsDecoder;
203 return errSecSuccess;
204 }
205
206 /*
207 * Feed raw bytes of the message to be decoded into the decoder. Can be called
208 * multiple times.
209 */
210 OSStatus CMSDecoderUpdateMessage(
211 CMSDecoderRef cmsDecoder,
212 const void *msgBytes,
213 size_t msgBytesLen)
214 {
215 if(cmsDecoder == NULL) {
216 return errSecParam;
217 }
218
219 OSStatus ortn;
220 switch(cmsDecoder->decState) {
221 case DS_Init:
222 /* First time through; set up */
223 ASSERT(cmsDecoder->decoder == NULL);
224 ASSERT(cmsDecoder->arena == NULL);
225 ortn = SecCmsDecoderCreate(NULL, NULL, NULL, NULL, NULL, NULL, &cmsDecoder->decoder);
226 if(ortn) {
227 ortn = cmsRtnToOSStatus(ortn);
228 CSSM_PERROR("SecCmsDecoderCreate", ortn);
229 return ortn;
230 }
231 cmsDecoder->decState = DS_Updating;
232 break;
233
234 case DS_Updating:
235 ASSERT(cmsDecoder->decoder != NULL);
236 break;
237
238 case DS_Final:
239 /* Too late for another update */
240 return errSecParam;
241
242 default:
243 dprintf("CMSDecoderUpdateMessage: bad decState\n");
244 return errSecInternalComponent;
245 }
246
247 /* FIXME - CFIndex same size as size_t on 64bit? */
248 ortn = SecCmsDecoderUpdate(cmsDecoder->decoder, msgBytes, (CFIndex)msgBytesLen);
249 if(ortn) {
250 ortn = cmsRtnToOSStatusDefault(ortn, errSecUnknownFormat);
251 CSSM_PERROR("SecCmsDecoderUpdate", ortn);
252 }
253 return ortn;
254 }
255
256 /*
257 * Indicate that no more CMSDecoderUpdateMessage() calls are forthcoming;
258 * finish decoding the message. We parse the message as best we can, up to
259 * but not including verifying individual signerInfos.
260 */
261 OSStatus CMSDecoderFinalizeMessage(
262 CMSDecoderRef cmsDecoder)
263 {
264 if(cmsDecoder == NULL) {
265 return errSecParam;
266 }
267 if(cmsDecoder->decState != DS_Updating) {
268 return errSecParam;
269 }
270 ASSERT(cmsDecoder->decoder != NULL);
271 OSStatus ortn = SecCmsDecoderFinish(cmsDecoder->decoder, &cmsDecoder->cmsMsg);
272 cmsDecoder->decState = DS_Final;
273
274 /* SecCmsDecoderFinish destroyed the decoder even on failure */
275 cmsDecoder->decoder = NULL;
276
277 if(ortn) {
278 ortn = cmsRtnToOSStatusDefault(ortn, errSecUnknownFormat);
279 CSSM_PERROR("SecCmsDecoderFinish", ortn);
280 return ortn;
281 }
282
283 ASSERT(cmsDecoder->cmsMsg != NULL);
284 cmsDecoder->wasEncrypted = SecCmsMessageIsEncrypted(cmsDecoder->cmsMsg);
285
286 /* Look for a SignedData */
287 int numContentInfos = SecCmsMessageContentLevelCount(cmsDecoder->cmsMsg);
288 int dex;
289 for(dex=0; dex<numContentInfos; dex++) {
290 SecCmsContentInfoRef ci = SecCmsMessageContentLevel(cmsDecoder->cmsMsg, dex);
291 SECOidTag tag = SecCmsContentInfoGetContentTypeTag(ci);
292 switch(tag) {
293 case SEC_OID_PKCS7_SIGNED_DATA:
294 cmsDecoder->signedData =
295 (SecCmsSignedDataRef)SecCmsContentInfoGetContent(ci);
296 /* dig down one more layer for eContentType */
297 ci = SecCmsSignedDataGetContentInfo(cmsDecoder->signedData);
298 cmsDecoder->eContentType = SecCmsContentInfoGetContentTypeOID(ci);
299 break;
300 default:
301 break;
302 }
303 if(cmsDecoder->signedData != NULL) {
304 break;
305 }
306
307 }
308
309 /* minimal processing of optional signedData... */
310 if(cmsDecoder->signedData != NULL) {
311 cmsDecoder->numSigners = (size_t)
312 SecCmsSignedDataSignerInfoCount(cmsDecoder->signedData);
313 if(cmsDecoder->detachedContent != NULL) {
314 /* time to calculate digests from detached content */
315 ortn = cmsDigestDetachedContent(cmsDecoder);
316 }
317 }
318 return ortn;
319 }
320
321 /*
322 * A signed CMS message optionally includes the data which was signed. If the
323 * message does not include the signed data, caller specifies the signed data
324 * (the "detached content") here.
325 *
326 * This can be called either before or after the actual decoding of the message
327 * (via CMSDecoderUpdateMessage() and CMSDecoderFinalizeMessage()); the only
328 * restriction is that, if detached content is required, this function must
329 * be called befoere successfully ascertaining the signature status via
330 * CMSDecoderCopySignerStatus().
331 */
332 OSStatus CMSDecoderSetDetachedContent(
333 CMSDecoderRef cmsDecoder,
334 CFDataRef detachedContent)
335 {
336 if((cmsDecoder == NULL) || (detachedContent == NULL)) {
337 return errSecParam;
338 }
339 cmsDecoder->detachedContent = detachedContent;
340 CFRetain(detachedContent);
341
342 if(cmsDecoder->signedData != NULL) {
343 /* time to calculate digests from detached content */
344 ASSERT(cmsDecoder->decState == DS_Final);
345 return cmsDigestDetachedContent(cmsDecoder);
346 }
347 return errSecSuccess;
348 }
349
350 /*
351 * Obtain the detached content specified in CMSDecoderSetDetachedContent().
352 * Returns a NULL detachedContent if no detached content has been specified.
353 * Caller must CFRelease() the result.
354 */
355 OSStatus CMSDecoderCopyDetachedContent(
356 CMSDecoderRef cmsDecoder,
357 CFDataRef *detachedContent) /* RETURNED */
358 {
359 if((cmsDecoder == NULL) || (detachedContent == NULL)) {
360 return errSecParam;
361 }
362 if(cmsDecoder->detachedContent != NULL) {
363 CFRetain(cmsDecoder->detachedContent);
364 }
365 *detachedContent = cmsDecoder->detachedContent;
366 return errSecSuccess;
367 }
368
369 /*
370 * Obtain the number of signers of a message. A result of zero indicates that
371 * the message was not signed.
372 */
373 OSStatus CMSDecoderGetNumSigners(
374 CMSDecoderRef cmsDecoder,
375 size_t *numSigners) /* RETURNED */
376 {
377 if((cmsDecoder == NULL) || (numSigners == NULL)) {
378 return errSecParam;
379 }
380 if(cmsDecoder->decState != DS_Final) {
381 return errSecParam;
382 }
383 *numSigners = cmsDecoder->numSigners;
384 return errSecSuccess;
385 }
386
387 /*
388 * Obtain the status of a CMS message's signature. A CMS message can
389 * be signed my multiple signers; this function returns the status
390 * associated with signer 'n' as indicated by the signerIndex parameter.
391 */
392 OSStatus CMSDecoderCopySignerStatus(
393 CMSDecoderRef cmsDecoder,
394 size_t signerIndex,
395 CFTypeRef policyOrArray,
396 Boolean evaluateSecTrust,
397 CMSSignerStatus *signerStatus, /* optional; RETURNED */
398 SecTrustRef *secTrust, /* optional; RETURNED */
399 OSStatus *certVerifyResultCode) /* optional; RETURNED */
400 {
401 if((cmsDecoder == NULL) || (cmsDecoder->decState != DS_Final) || (!policyOrArray)) {
402 return errSecParam;
403 }
404
405 /* initialize return values */
406 if(signerStatus) {
407 *signerStatus = kCMSSignerUnsigned;
408 }
409 if(secTrust) {
410 *secTrust = NULL;
411 }
412 if(certVerifyResultCode) {
413 *certVerifyResultCode = 0;
414 }
415
416 if(cmsDecoder->signedData == NULL) {
417 *signerStatus = kCMSSignerUnsigned; /* redundant, I know, but explicit */
418 return errSecSuccess;
419 }
420 ASSERT(cmsDecoder->numSigners > 0);
421 if(signerIndex >= cmsDecoder->numSigners) {
422 *signerStatus = kCMSSignerInvalidIndex;
423 return errSecSuccess;
424 }
425 if(!SecCmsSignedDataHasDigests(cmsDecoder->signedData)) {
426 *signerStatus = kCMSSignerNeedsDetachedContent;
427 return errSecSuccess;
428 }
429
430 /*
431 * OK, we should be able to verify this signerInfo.
432 * I think we have to do the SecCmsSignedDataVerifySignerInfo first
433 * in order get all the cert pieces into place before returning them
434 * to the caller.
435 */
436 SecTrustRef theTrust = NULL;
437 OSStatus vfyRtn = SecCmsSignedDataVerifySignerInfo(cmsDecoder->signedData,
438 (int)signerIndex,
439 NULL,
440 policyOrArray,
441 &theTrust);
442
443 #if SECTRUST_VERBOSE_DEBUG
444 syslog(LOG_ERR, "CMSDecoderCopySignerStatus: SecCmsSignedDataVerifySignerInfo returned %d", (int)vfyRtn);
445 if (policyOrArray) CFShow(policyOrArray);
446 if (theTrust) CFShow(theTrust);
447 #endif
448
449 /* Subsequent errors to errOut: */
450
451 /*
452 * NOTE the smime lib did NOT evaluate that SecTrust - it only does
453 * SecTrustEvaluate() if we don't ask for a copy.
454 *
455 * FIXME deal with multitudes of status returns here...for now, proceed with
456 * obtaining components the caller wants and assume that a nonzero vfyRtn
457 * means "bad signature".
458 */
459 OSStatus ortn = errSecSuccess;
460 SecTrustResultType secTrustResult;
461 OSStatus evalRtn, verifyStatus = errSecSuccess;
462
463 if(secTrust != NULL) {
464 *secTrust = theTrust;
465 /* we'll release our reference at the end */
466 if (theTrust)
467 CFRetain(theTrust);
468 }
469 SecCmsSignerInfoRef signerInfo =
470 SecCmsSignedDataGetSignerInfo(cmsDecoder->signedData, (int)signerIndex);
471 if(signerInfo == NULL) {
472 /* should never happen */
473 ASSERT(0);
474 dprintf("CMSDecoderCopySignerStatus: no signerInfo\n");
475 ortn = errSecInternalComponent;
476 goto errOut;
477 }
478
479 /* now do the actual cert verify */
480 if(evaluateSecTrust) {
481 evalRtn = SecTrustEvaluate(theTrust, &secTrustResult);
482 if(evalRtn) {
483 /* should never happen */
484 CSSM_PERROR("SecTrustEvaluate", evalRtn);
485 dprintf("CMSDecoderCopySignerStatus: SecTrustEvaluate error\n");
486 ortn = errSecInternalComponent;
487 goto errOut;
488 }
489 switch(secTrustResult) {
490 case kSecTrustResultUnspecified:
491 /* cert chain valid, no special UserTrust assignments */
492 case kSecTrustResultProceed:
493 /* cert chain valid AND user explicitly trusts this */
494 break;
495 case kSecTrustResultDeny:
496 verifyStatus = errSecTrustSettingDeny;
497 break;
498 default:
499 {
500 verifyStatus = errSecNotTrusted;
501 break;
502 }
503 } /* switch(secTrustResult) */
504 } /* evaluateSecTrust true */
505 if(certVerifyResultCode != NULL) {
506 *certVerifyResultCode = verifyStatus;
507 }
508
509 /* cook up global status based on vfyRtn and tpVfyStatus */
510 if(signerStatus != NULL) {
511 if((vfyRtn == errSecSuccess) && (verifyStatus == errSecSuccess)) {
512 *signerStatus = kCMSSignerValid;
513 }
514 else if(vfyRtn != errSecSuccess) {
515 /* this could mean other things, but for now... */
516 *signerStatus = kCMSSignerInvalidSignature;
517 }
518 else {
519 *signerStatus = kCMSSignerInvalidCert;
520 }
521 }
522 errOut:
523 CFRELEASE(theTrust);
524 return ortn;
525 }
526
527 /*
528 * Obtain the email address of signer 'signerIndex' of a CMS message, if
529 * present.
530 *
531 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
532 */
533 OSStatus CMSDecoderCopySignerEmailAddress(
534 CMSDecoderRef cmsDecoder,
535 size_t signerIndex,
536 CFStringRef *signerEmailAddress) /* RETURNED */
537 {
538 if((cmsDecoder == NULL) ||
539 (signerEmailAddress == NULL) ||
540 (cmsDecoder->signedData == NULL) || /* not signed */
541 (signerIndex >= cmsDecoder->numSigners) || /* index out of range */
542 (cmsDecoder->decState != DS_Final)) {
543 return errSecParam;
544 }
545
546 SecCmsSignerInfoRef signerInfo =
547 SecCmsSignedDataGetSignerInfo(cmsDecoder->signedData, (int)signerIndex);
548 if(signerInfo == NULL) {
549 /* should never happen */
550 ASSERT(0);
551 dprintf("CMSDecoderCopySignerEmailAddress: no signerInfo\n");
552 return errSecInternalComponent;
553 }
554
555 /*
556 * This is leaking memory in libsecurityKeychain per Radar 4412699.
557 */
558 *signerEmailAddress = SecCmsSignerInfoGetSignerEmailAddress(signerInfo);
559 return errSecSuccess;
560 }
561
562 /*
563 * Obtain the certificate of signer 'signerIndex' of a CMS message, if
564 * present.
565 *
566 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
567 */
568 OSStatus CMSDecoderCopySignerCert(
569 CMSDecoderRef cmsDecoder,
570 size_t signerIndex,
571 SecCertificateRef *signerCert) /* RETURNED */
572 {
573 if((cmsDecoder == NULL) ||
574 (signerCert == NULL) ||
575 (cmsDecoder->signedData == NULL) || /* not signed */
576 (signerIndex >= cmsDecoder->numSigners) || /* index out of range */
577 (cmsDecoder->decState != DS_Final)) {
578 return errSecParam;
579 }
580
581 SecCmsSignerInfoRef signerInfo =
582 SecCmsSignedDataGetSignerInfo(cmsDecoder->signedData, (int)signerIndex);
583 if(signerInfo == NULL) {
584 /* should never happen */
585 ASSERT(0);
586 dprintf("CMSDecoderCopySignerCertificate: no signerInfo\n");
587 return errSecInternalComponent;
588 }
589 *signerCert = SecCmsSignerInfoGetSigningCertificate(signerInfo, NULL);
590 /* libsecurity_smime does NOT retain that */
591 if(*signerCert == NULL) {
592 /* should never happen */
593 ASSERT(0);
594 dprintf("CMSDecoderCopySignerCertificate: no signerCert\n");
595 return errSecInternalComponent;
596 }
597 CFRetain(*signerCert);
598 return errSecSuccess;
599 }
600
601 /*
602 * Determine whether a CMS message was encrypted, and if so, whether we were
603 * able to decrypt it.
604 */
605 OSStatus CMSDecoderIsContentEncrypted(
606 CMSDecoderRef cmsDecoder,
607 Boolean *wasEncrypted)
608 {
609 if((cmsDecoder == NULL) || (wasEncrypted == NULL)) {
610 return errSecParam;
611 }
612 if(cmsDecoder->decState != DS_Final) {
613 return errSecParam;
614 }
615 *wasEncrypted = cmsDecoder->wasEncrypted;
616 return errSecSuccess;
617 }
618
619 /*
620 * Obtain the eContentType OID for a SignedData's EncapsulatedContentType, if
621 * present.
622 */
623 OSStatus CMSDecoderCopyEncapsulatedContentType(
624 CMSDecoderRef cmsDecoder,
625 CFDataRef *eContentType) /* RETURNED */
626 {
627 if((cmsDecoder == NULL) || (eContentType == NULL)) {
628 return errSecParam;
629 }
630 if(cmsDecoder->decState != DS_Final) {
631 return errSecParam;
632 }
633 if(cmsDecoder->signedData == NULL) {
634 *eContentType = NULL;
635 }
636 else {
637 SecAsn1Oid *ecOid = cmsDecoder->eContentType;
638 *eContentType = CFDataCreate(NULL, ecOid->Data, ecOid->Length);
639 }
640 return errSecSuccess;
641 }
642
643 /*
644 * Obtain an array of all of the certificates in a message. Elements of the
645 * returned array are SecCertificateRefs. The caller must CFRelease the returned
646 * array.
647 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
648 */
649 OSStatus CMSDecoderCopyAllCerts(
650 CMSDecoderRef cmsDecoder,
651 CFArrayRef *certs) /* RETURNED */
652 {
653 if((cmsDecoder == NULL) || (certs == NULL)) {
654 return errSecParam;
655 }
656 if(cmsDecoder->decState != DS_Final) {
657 return errSecParam;
658 }
659 if(cmsDecoder->signedData == NULL) {
660 /* message wasn't signed */
661 *certs = NULL;
662 return errSecSuccess;
663 }
664
665 /* NULL_terminated array of CSSM_DATA ptrs */
666 SecAsn1Item **cssmCerts = SecCmsSignedDataGetCertificateList(cmsDecoder->signedData);
667 if((cssmCerts == NULL) || (*cssmCerts == NULL)) {
668 *certs = NULL;
669 return errSecSuccess;
670 }
671
672 CFMutableArrayRef allCerts = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
673 SecAsn1Item **cssmCert;
674 for(cssmCert=cssmCerts; *cssmCert!=NULL; cssmCert++) {
675 SecCertificateRef cfCert = SecCertificateCreateWithBytes(NULL, (*cssmCert)->Data, (*cssmCert)->Length);
676 if(!cfCert) {
677 CFRelease(allCerts);
678 return errSecDecode;
679 }
680 CFArrayAppendValue(allCerts, cfCert);
681 /* the array holds the only needed refcount */
682 CFRelease(cfCert);
683 }
684 *certs = allCerts;
685 return errSecSuccess;
686 }
687
688 /*
689 * Obtain the actual message content (payload), if any. If the message was
690 * signed with detached content this will return NULL.
691 * Caller must CFRelease the result.
692 */
693 OSStatus CMSDecoderCopyContent(
694 CMSDecoderRef cmsDecoder,
695 CFDataRef *content) /* RETURNED */
696 {
697 if((cmsDecoder == NULL) || (content == NULL)) {
698 return errSecParam;
699 }
700 if(cmsDecoder->decState != DS_Final) {
701 return errSecParam;
702 }
703 if(cmsDecoder->cmsMsg == NULL) {
704 /* Hmmm....looks like the finalize call failed */
705 return errSecParam;
706 }
707 const SecAsn1Item *odata = SecCmsMessageGetContent(cmsDecoder->cmsMsg);
708 if((odata == NULL) || (odata->Length == 0)) {
709 /* i.e., detached content */
710 *content = NULL;
711 return errSecSuccess;
712 }
713 *content = CFDataCreate(NULL, (const UInt8 *)odata->Data, odata->Length);
714 return errSecSuccess;
715 }
716
717 #pragma mark --- SPI declared in CMSPrivate.h ---
718
719 /*
720 * Obtain the SecCmsMessageRef associated with a CMSDecoderRef. Intended
721 * to be called after decoding the message (i.e., after
722 * CMSDecoderFinalizeMessage() to gain finer access to the contents of the
723 * SecCmsMessageRef than is otherwise available via the CMSDecoder interface.
724 * Returns a NULL SecCmsMessageRef if CMSDecoderFinalizeMessage() has not been
725 * called.
726 *
727 * The CMSDecoder retains ownership of the returned SecCmsMessageRef.
728 */
729 OSStatus CMSDecoderGetCmsMessage(
730 CMSDecoderRef cmsDecoder,
731 SecCmsMessageRef *cmsMessage) /* RETURNED */
732 {
733 if((cmsDecoder == NULL) || (cmsMessage == NULL)) {
734 return errSecParam;
735 }
736 /* any state, whether we have a msg or not is OK */
737 *cmsMessage = cmsDecoder->cmsMsg;
738 return errSecSuccess;
739 }
740
741 /*
742 * Optionally specify a SecCmsDecoderRef to use with a CMSDecoderRef.
743 * If this is called, it must be called before the first call to
744 * CMSDecoderUpdateMessage(). The CMSDecoderRef takes ownership of the
745 * incoming SecCmsDecoderRef.
746 */
747 OSStatus CMSDecoderSetDecoder(
748 CMSDecoderRef cmsDecoder,
749 SecCmsDecoderRef decoder)
750 {
751 if((cmsDecoder == NULL) || (decoder == NULL)) {
752 return errSecParam;
753 }
754 switch(cmsDecoder->decState) {
755 case DS_Init:
756 ASSERT(cmsDecoder->decoder == NULL);
757 cmsDecoder->decoder = decoder;
758 cmsDecoder->decState = DS_Updating;
759 return errSecSuccess;
760 case DS_Updating:
761 case DS_Final:
762 return errSecParam;
763 }
764 return errSecSuccess;
765 }
766
767 /*
768 * Obtain the SecCmsDecoderRef associated with a CMSDecoderRef.
769 * Returns a NULL SecCmsDecoderRef if neither CMSDecoderSetDecoder() nor
770 * CMSDecoderUpdateMessage() has been called.
771 * The CMSDecoderRef retains ownership of the SecCmsDecoderRef.
772 */
773 OSStatus CMSDecoderGetDecoder(
774 CMSDecoderRef cmsDecoder,
775 SecCmsDecoderRef *decoder) /* RETURNED */
776 {
777 if((cmsDecoder == NULL) || (decoder == NULL)) {
778 return errSecParam;
779 }
780 /* any state, whether we have a decoder or not is OK */
781 *decoder = cmsDecoder->decoder;
782 return errSecSuccess;
783 }
784
785 /*
786 * Obtain the signing time of signer 'signerIndex' of a CMS message, if
787 * present. This is an unauthenticate time, although it is part of the
788 * signed attributes of the message.
789 *
790 * Returns errSecParam if the CMS message was not signed or if signerIndex
791 * is greater than the number of signers of the message minus one.
792 *
793 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
794 */
795 OSStatus CMSDecoderCopySignerSigningTime(
796 CMSDecoderRef cmsDecoder,
797 size_t signerIndex, /* usually 0 */
798 CFAbsoluteTime *signingTime) /* RETURNED */
799 {
800 OSStatus status = errSecParam;
801 SecCmsMessageRef cmsg;
802 SecCmsSignedDataRef signedData = NULL;
803 int numContentInfos = 0;
804
805 require(cmsDecoder && signingTime, xit);
806 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder, &cmsg), xit);
807 numContentInfos = SecCmsMessageContentLevelCount(cmsg);
808 for (int dex = 0; !signedData && dex < numContentInfos; dex++)
809 {
810 SecCmsContentInfoRef ci = SecCmsMessageContentLevel(cmsg, dex);
811 SECOidTag tag = SecCmsContentInfoGetContentTypeTag(ci);
812 if (tag == SEC_OID_PKCS7_SIGNED_DATA)
813 if ((signedData = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(ci))) {
814 SecCmsSignerInfoRef signerInfo = SecCmsSignedDataGetSignerInfo(signedData, (int)signerIndex);
815 if (signerInfo)
816 {
817 status = SecCmsSignerInfoGetSigningTime(signerInfo, signingTime);
818 break;
819 }
820 }
821 }
822 xit:
823 return status;
824 }
825
826 #if TIMESTAMPING_SUPPORTED
827 /*
828 * Obtain the timestamp of signer 'signerIndex' of a CMS message, if
829 * present. This timestamp is an authenticated timestamp provided by
830 * a timestamping authority.
831 *
832 * Returns errSecParam if the CMS message was not signed or if signerIndex
833 * is greater than the number of signers of the message minus one.
834 *
835 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
836 */
837
838 OSStatus CMSDecoderCopySignerTimestamp(
839 CMSDecoderRef cmsDecoder,
840 size_t signerIndex, /* usually 0 */
841 CFAbsoluteTime *timestamp) /* RETURNED */
842 {
843 return CMSDecoderCopySignerTimestampWithPolicy(cmsDecoder, NULL, signerIndex, timestamp);
844 }
845
846 OSStatus CMSDecoderCopySignerTimestampWithPolicy(
847 CMSDecoderRef cmsDecoder,
848 CFTypeRef timeStampPolicy,
849 size_t signerIndex, /* usually 0 */
850 CFAbsoluteTime *timestamp) /* RETURNED */
851 {
852 OSStatus status = errSecParam;
853 SecCmsMessageRef cmsg;
854 SecCmsSignedDataRef signedData = NULL;
855 int numContentInfos = 0;
856
857 require(cmsDecoder && timestamp, xit);
858 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder, &cmsg), xit);
859 numContentInfos = SecCmsMessageContentLevelCount(cmsg);
860 for (int dex = 0; !signedData && dex < numContentInfos; dex++)
861 {
862 SecCmsContentInfoRef ci = SecCmsMessageContentLevel(cmsg, dex);
863 SECOidTag tag = SecCmsContentInfoGetContentTypeTag(ci);
864 if (tag == SEC_OID_PKCS7_SIGNED_DATA)
865 if ((signedData = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(ci))) {
866 SecCmsSignerInfoRef signerInfo = SecCmsSignedDataGetSignerInfo(signedData, (int)signerIndex);
867 if (signerInfo)
868 {
869 status = SecCmsSignerInfoGetTimestampTimeWithPolicy(signerInfo, timeStampPolicy, timestamp);
870 break;
871 }
872 }
873 }
874
875 xit:
876 return status;
877 }
878
879 /*
880 * Obtain an array of the certificates in a timestamp response. Elements of the
881 * returned array are SecCertificateRefs. The caller must CFRelease the returned
882 * array. This timestamp is an authenticated timestamp provided by
883 * a timestamping authority.
884 *
885 * Returns errSecParam if the CMS message was not signed or if signerIndex
886 * is greater than the number of signers of the message minus one. It returns
887 * errSecItemNotFound if no certificates were found.
888 *
889 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
890 */
891 OSStatus CMSDecoderCopySignerTimestampCertificates(
892 CMSDecoderRef cmsDecoder,
893 size_t signerIndex, /* usually 0 */
894 CFArrayRef *certificateRefs) /* RETURNED */
895 {
896 OSStatus status = errSecParam;
897 SecCmsMessageRef cmsg = NULL;
898 SecCmsSignedDataRef signedData = NULL;
899 int numContentInfos = 0;
900 CFIndex tsn = 0;
901 bool good = false;
902
903 require(cmsDecoder && certificateRefs, xit);
904 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder, &cmsg), xit);
905 numContentInfos = SecCmsMessageContentLevelCount(cmsg);
906 for (int dex = 0; !signedData && dex < numContentInfos; dex++)
907 {
908 SecCmsContentInfoRef ci = SecCmsMessageContentLevel(cmsg, dex);
909 SECOidTag tag = SecCmsContentInfoGetContentTypeTag(ci);
910 if (tag == SEC_OID_PKCS7_SIGNED_DATA)
911 if ((signedData = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(ci))) {
912 SecCmsSignerInfoRef signerInfo = SecCmsSignedDataGetSignerInfo(signedData, (int)signerIndex);
913 if (signerInfo)
914 {
915 CFArrayRef certList = SecCmsSignerInfoGetTimestampCertList(signerInfo);
916 require_action(certList, xit, status = errSecItemNotFound);
917 CFMutableArrayRef certs = CFArrayCreateMutableCopy(kCFAllocatorDefault, CFArrayGetCount(certList), certList);
918
919 if(certs){
920 //reorder certificates:
921 tsn = CFArrayGetCount(certs);
922 good = tsn > 0 && SecIsAppleTrustAnchor((SecCertificateRef)CFArrayGetValueAtIndex(certs, tsn-1), 0);
923
924 if ( good == false )
925 {
926 //change TS certificate ordering.
927 for (CFIndex n = 0; n < tsn; n++)
928 {
929 SecCertificateRef tsRoot = (SecCertificateRef)CFArrayGetValueAtIndex(certs, n);
930 if (tsRoot)
931 if ((good = SecIsAppleTrustAnchor(tsRoot, 0))) {
932 CFArrayExchangeValuesAtIndices(certs, n, tsn-1);
933 break;
934 }
935 }
936 }
937
938 *certificateRefs = CFArrayCreateCopy(kCFAllocatorDefault, certs);
939 CFRelease(certs);
940 status = errSecSuccess;
941 }
942 break;
943 }
944 }
945 }
946
947
948 xit:
949 return status;
950 }
951 #endif
952
953 /*
954 * Obtain the Hash Agility attribute value of signer 'signerIndex'
955 * of a CMS message, if present.
956 *
957 * Returns errSecParam if the CMS message was not signed or if signerIndex
958 * is greater than the number of signers of the message minus one.
959 *
960 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
961 */
962 OSStatus CMSDecoderCopySignerAppleCodesigningHashAgility(
963 CMSDecoderRef cmsDecoder,
964 size_t signerIndex, /* usually 0 */
965 CFDataRef CF_RETURNS_RETAINED *hashAgilityAttrValue) /* RETURNED */
966 {
967 OSStatus status = errSecParam;
968 SecCmsMessageRef cmsg;
969 SecCmsSignedDataRef signedData = NULL;
970 int numContentInfos = 0;
971 CFDataRef returnedValue = NULL;
972
973 require(cmsDecoder && hashAgilityAttrValue, exit);
974 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder, &cmsg), exit);
975 numContentInfos = SecCmsMessageContentLevelCount(cmsg);
976 for (int dex = 0; !signedData && dex < numContentInfos; dex++)
977 {
978 SecCmsContentInfoRef ci = SecCmsMessageContentLevel(cmsg, dex);
979 SECOidTag tag = SecCmsContentInfoGetContentTypeTag(ci);
980 if (tag == SEC_OID_PKCS7_SIGNED_DATA)
981 if ((signedData = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(ci))) {
982 SecCmsSignerInfoRef signerInfo = SecCmsSignedDataGetSignerInfo(signedData, (int)signerIndex);
983 if (signerInfo)
984 {
985 status = SecCmsSignerInfoGetAppleCodesigningHashAgility(signerInfo, &returnedValue);
986 break;
987 }
988 }
989 }
990 exit:
991 if (status == errSecSuccess && returnedValue) {
992 *hashAgilityAttrValue = (CFDataRef) CFRetain(returnedValue);
993 } else {
994 *hashAgilityAttrValue = NULL;
995 }
996 return status;
997 }
998
999 /*
1000 * Obtain the Hash Agility V2 attribute value of signer 'signerIndex'
1001 * of a CMS message, if present.
1002 *
1003 * Returns errSecParam if the CMS message was not signed or if signerIndex
1004 * is greater than the number of signers of the message minus one.
1005 *
1006 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
1007 */
1008 OSStatus CMSDecoderCopySignerAppleCodesigningHashAgilityV2(
1009 CMSDecoderRef cmsDecoder,
1010 size_t signerIndex, /* usually 0 */
1011 CFDictionaryRef CF_RETURNS_RETAINED *hashAgilityV2AttrValues) /* RETURNED */
1012 {
1013 OSStatus status = errSecParam;
1014 SecCmsMessageRef cmsg;
1015 SecCmsSignedDataRef signedData = NULL;
1016 int numContentInfos = 0;
1017 CFDictionaryRef returnedValue = NULL;
1018
1019 require(cmsDecoder && hashAgilityV2AttrValues, exit);
1020 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder, &cmsg), exit);
1021 numContentInfos = SecCmsMessageContentLevelCount(cmsg);
1022 for (int dex = 0; !signedData && dex < numContentInfos; dex++)
1023 {
1024 SecCmsContentInfoRef ci = SecCmsMessageContentLevel(cmsg, dex);
1025 SECOidTag tag = SecCmsContentInfoGetContentTypeTag(ci);
1026 if (tag == SEC_OID_PKCS7_SIGNED_DATA)
1027 if ((signedData = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(ci))) {
1028 SecCmsSignerInfoRef signerInfo = SecCmsSignedDataGetSignerInfo(signedData, (int)signerIndex);
1029 if (signerInfo)
1030 {
1031 status = SecCmsSignerInfoGetAppleCodesigningHashAgilityV2(signerInfo, &returnedValue);
1032 break;
1033 }
1034 }
1035 }
1036 exit:
1037 if (status == errSecSuccess && returnedValue) {
1038 *hashAgilityV2AttrValues = (CFDictionaryRef) CFRetain(returnedValue);
1039 } else {
1040 *hashAgilityV2AttrValues = NULL;
1041 }
1042 return status;
1043 }
1044
1045 /*
1046 * Obtain the expiration time of signer 'signerIndex' of a CMS message, if
1047 * present. This is part of the signed attributes of the message.
1048 *
1049 * Returns errSecParam if the CMS message was not signed or if signerIndex
1050 * is greater than the number of signers of the message minus one.
1051 *
1052 * This cannot be called until after CMSDecoderFinalizeMessage() is called.
1053 */
1054 OSStatus CMSDecoderCopySignerAppleExpirationTime(
1055 CMSDecoderRef cmsDecoder,
1056 size_t signerIndex,
1057 CFAbsoluteTime *expirationTime) /* RETURNED */
1058 {
1059 OSStatus status = errSecParam;
1060 SecCmsMessageRef cmsg = NULL;
1061 int numContentInfos = 0;
1062 SecCmsSignedDataRef signedData = NULL;
1063
1064 require(cmsDecoder && expirationTime, xit);
1065 require_noerr(CMSDecoderGetCmsMessage(cmsDecoder, &cmsg), xit);
1066 numContentInfos = SecCmsMessageContentLevelCount(cmsg);
1067 for (int dex = 0; !signedData && dex < numContentInfos; dex++) {
1068 SecCmsContentInfoRef ci = SecCmsMessageContentLevel(cmsg, dex);
1069 SECOidTag tag = SecCmsContentInfoGetContentTypeTag(ci);
1070 if (tag == SEC_OID_PKCS7_SIGNED_DATA) {
1071 if ((signedData = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(ci))) {
1072 SecCmsSignerInfoRef signerInfo = SecCmsSignedDataGetSignerInfo(signedData, (int)signerIndex);
1073 if (signerInfo) {
1074 status = SecCmsSignerInfoGetAppleExpirationTime(signerInfo, expirationTime);
1075 break;
1076 }
1077 }
1078 }
1079 }
1080 xit:
1081 return status;
1082 }