]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_cms/lib/CMSDecoder.cpp
a6fb2688d59f524e97190d29f63f3d31125844de
[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 if (ci) {
315 cmsDecoder->eContentType = SecCmsContentInfoGetContentTypeOID(ci);
316 }
317 break;
318 default:
319 break;
320 }
321 if(cmsDecoder->signedData != NULL) {
322 break;
323 }
324
325 }
326
327 /* minimal processing of optional signedData... */
328 if(cmsDecoder->signedData != NULL) {
329 cmsDecoder->numSigners = (size_t)
330 SecCmsSignedDataSignerInfoCount(cmsDecoder->signedData);
331 if(cmsDecoder->detachedContent != NULL) {
332 /* time to calculate digests from detached content */
333 ortn = cmsDigestDetachedContent(cmsDecoder);
334 }
335 }
336 return ortn;
337 }
338
339 /*
340 * A signed CMS message optionally includes the data which was signed. If the
341 * message does not include the signed data, caller specifies the signed data
342 * (the "detached content") here.
343 *
344 * This can be called either before or after the actual decoding of the message
345 * (via CMSDecoderUpdateMessage() and CMSDecoderFinalizeMessage()); the only
346 * restriction is that, if detached content is required, this function must
347 * be called befoere successfully ascertaining the signature status via
348 * CMSDecoderCopySignerStatus().
349 */
350 OSStatus CMSDecoderSetDetachedContent(
351 CMSDecoderRef cmsDecoder,
352 CFDataRef detachedContent)
353 {
354 if((cmsDecoder == NULL) || (detachedContent == NULL)) {
355 return errSecParam;
356 }
357 cmsDecoder->detachedContent = detachedContent;
358 CFRetain(detachedContent);
359
360 if(cmsDecoder->signedData != NULL) {
361 /* time to calculate digests from detached content */
362 ASSERT(cmsDecoder->decState == DS_Final);
363 return cmsDigestDetachedContent(cmsDecoder);
364 }
365 return errSecSuccess;
366 }
367
368 /*
369 * Obtain the detached content specified in CMSDecoderSetDetachedContent().
370 * Returns a NULL detachedContent if no detached content has been specified.
371 * Caller must CFRelease() the result.
372 */
373 OSStatus CMSDecoderCopyDetachedContent(
374 CMSDecoderRef cmsDecoder,
375 CFDataRef *detachedContent) /* RETURNED */
376 {
377 if((cmsDecoder == NULL) || (detachedContent == NULL)) {
378 return errSecParam;
379 }
380 if(cmsDecoder->detachedContent != NULL) {
381 CFRetain(cmsDecoder->detachedContent);
382 }
383 *detachedContent = cmsDecoder->detachedContent;
384 return errSecSuccess;
385 }
386
387 /*
388 * Beginning in 10.12, this function stopped affecting the behavior of the
389 * CMS Decoder. Its only use was in SecTrustSetKeychains which is a no-op.
390 * Please discontinue use.
391 */
392 OSStatus CMSDecoderSetSearchKeychain(
393 CMSDecoderRef cmsDecoder,
394 CFTypeRef keychainOrArray)
395 {
396 return errSecSuccess;
397 }
398
399 /*
400 * Obtain the number of signers of a message. A result of zero indicates that
401 * the message was not signed.
402 */
403 OSStatus CMSDecoderGetNumSigners(
404 CMSDecoderRef cmsDecoder,
405 size_t *numSigners) /* RETURNED */
406 {
407 if((cmsDecoder == NULL) || (numSigners == NULL)) {
408 return errSecParam;
409 }
410 if(cmsDecoder->decState != DS_Final) {
411 return errSecParam;
412 }
413 *numSigners = cmsDecoder->numSigners;
414 return errSecSuccess;
415 }
416
417 /*
418 * Obtain the status of a CMS message's signature. A CMS message can
419 * be signed my multiple signers; this function returns the status
420 * associated with signer 'n' as indicated by the signerIndex parameter.
421 */
422 OSStatus CMSDecoderCopySignerStatus(
423 CMSDecoderRef cmsDecoder,
424 size_t signerIndex,
425 CFTypeRef policyOrArray,
426 Boolean evaluateSecTrust,
427 CMSSignerStatus *signerStatus, /* optional; RETURNED */
428 SecTrustRef *secTrust, /* optional; RETURNED */
429 OSStatus *certVerifyResultCode) /* optional; RETURNED */
430 {
431 if((cmsDecoder == NULL) || (cmsDecoder->decState != DS_Final) || (!policyOrArray)) {
432 return errSecParam;
433 }
434
435 /* initialize return values */
436 if(signerStatus) {
437 *signerStatus = kCMSSignerUnsigned;
438 }
439 if(secTrust) {
440 *secTrust = NULL;
441 }
442 if(certVerifyResultCode) {
443 *certVerifyResultCode = 0;
444 }
445
446 if(cmsDecoder->signedData == NULL) {
447 *signerStatus = kCMSSignerUnsigned; /* redundant, I know, but explicit */
448 return errSecSuccess;
449 }
450 ASSERT(cmsDecoder->numSigners > 0);
451 if(signerIndex >= cmsDecoder->numSigners) {
452 *signerStatus = kCMSSignerInvalidIndex;
453 return errSecSuccess;
454 }
455 if(!SecCmsSignedDataHasDigests(cmsDecoder->signedData)) {
456 *signerStatus = kCMSSignerNeedsDetachedContent;
457 return errSecSuccess;
458 }
459
460 /*
461 * OK, we should be able to verify this signerInfo.
462 * I think we have to do the SecCmsSignedDataVerifySignerInfo first
463 * in order get all the cert pieces into place before returning them
464 * to the caller.
465 */
466 SecTrustRef theTrust = NULL;
467 OSStatus vfyRtn = SecCmsSignedDataVerifySignerInfo(cmsDecoder->signedData,
468 (int)signerIndex,
469 NULL,
470 policyOrArray,
471 &theTrust);
472
473 #if SECTRUST_VERBOSE_DEBUG
474 syslog(LOG_ERR, "CMSDecoderCopySignerStatus: SecCmsSignedDataVerifySignerInfo returned %d", (int)vfyRtn);
475 if (policyOrArray) CFShow(policyOrArray);
476 if (theTrust) CFShow(theTrust);
477 #endif
478
479 /* Subsequent errors to errOut: */
480
481 /*
482 * NOTE the smime lib did NOT evaluate that SecTrust - it only does
483 * SecTrustEvaluate() if we don't ask for a copy.
484 *
485 * FIXME deal with multitudes of status returns here...for now, proceed with
486 * obtaining components the caller wants and assume that a nonzero vfyRtn
487 * means "bad signature".
488 */
489 OSStatus ortn = errSecSuccess;
490 SecTrustResultType secTrustResult;
491 CSSM_RETURN tpVfyStatus = CSSM_OK;
492 OSStatus evalRtn;
493
494 if(secTrust != NULL) {
495 *secTrust = theTrust;
496 /* we'll release our reference at the end */
497 if (theTrust)
498 CFRetain(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 }