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