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