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