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