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