2 * Copyright (c) 2018 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 #include "shared_regressions.h"
26 #import <AssertMacros.h>
27 #import <Foundation/Foundation.h>
29 #import <Security/CMSDecoder.h>
30 #import <Security/CMSEncoder.h>
31 #import <Security/SecTrust.h>
32 #include <utilities/SecCFRelease.h>
34 #include <sys/socket.h>
35 #include <sys/types.h>
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
41 #include <Security/CMSPrivate.h>
42 #include <Security/tsaSupport.h>
45 #import "si-34-cms-timestamp.h"
46 #import "si-cms-hash-agility-data.h" // for signing_identity_p12, hash agility attribute data
48 static CMSSignerStatus test_verify_timestamp(NSData *content, NSData *message) {
49 CMSDecoderRef decoder = NULL;
50 SecPolicyRef policy = NULL;
51 SecTrustRef trust = NULL;
52 CMSSignerStatus signerStatus = kCMSSignerUnsigned;
54 /* Create decoder and decode */
55 require_noerr_action(CMSDecoderCreate(&decoder), fail, fail("Failed to create CMS decoder"));
56 require_noerr_action(CMSDecoderUpdateMessage(decoder, [message bytes], [message length]), fail,
57 fail("Failed to update decoder with CMS message"));
58 require_noerr_action(CMSDecoderSetDetachedContent(decoder, (__bridge CFDataRef)content), fail,
59 fail("Failed to set detached content"));
60 require_noerr_action(CMSDecoderFinalizeMessage(decoder), fail, fail("Failed to finalize decoder"));
62 /* Get signer status */
63 require_action(policy = SecPolicyCreateBasicX509(), fail, fail("Failed to Create policy"));
64 require_noerr_action(CMSDecoderCopySignerStatus(decoder, 0, policy, false, &signerStatus, &trust, NULL),
65 fail, fail("Failed to copy Signer status"));
68 CFReleaseNull(decoder);
69 CFReleaseNull(policy);
74 static void test_matching_messageImprint(void) {
75 /* If the timestamp is invalid, SecCmsSignerInfoVerifyUnAuthAttrs will fail, so the signer status will be
76 * kCMSSignerInvalidSignature. */
77 CMSSignerStatus expected_mismatch_result = kCMSSignerInvalidSignature;
78 #if !TIMESTAMPING_SUPPORTED
79 expected_mismatch_result = kCMSSignerValid;
82 is(test_verify_timestamp([NSData dataWithBytes:_developer_id_data length:sizeof(_developer_id_data)],
83 [NSData dataWithBytes:_developer_id_sig length:sizeof(_developer_id_sig)]),
84 kCMSSignerValid, "failed to verify good timestamped signature");
85 is(test_verify_timestamp([NSData dataWithBytes:_mismatched_content length:sizeof(_mismatched_content)],
86 [NSData dataWithBytes:_mismatched_timestamp length:sizeof(_mismatched_timestamp)]),
87 expected_mismatch_result, "successful verification of bad timestamped signature");
90 static void test_create_timestamp(void) {
91 CFArrayRef tmp_imported_items = NULL;
92 NSArray *imported_items = nil;
93 SecIdentityRef identity = nil;
94 CMSEncoderRef encoder = NULL;
95 CMSDecoderRef decoder = NULL;
96 CFDataRef message = NULL;
97 NSDictionary *attrValues = nil;
100 NSDictionary *options = @{ (__bridge NSString *)kSecImportExportPassphrase : @"password" };
101 NSData *p12Data = [NSData dataWithBytes:signing_identity_p12 length:sizeof(signing_identity_p12)];
102 require_noerr_action(SecPKCS12Import((__bridge CFDataRef)p12Data, (__bridge CFDictionaryRef)options,
103 &tmp_imported_items), exit,
104 fail("Failed to import identity"));
105 imported_items = CFBridgingRelease(tmp_imported_items);
106 require_noerr_action([imported_items count] == 0 &&
107 [imported_items[0] isKindOfClass:[NSDictionary class]], exit,
108 fail("Wrong imported items output"));
109 identity = (SecIdentityRef)CFBridgingRetain(imported_items[0][(__bridge NSString*)kSecImportItemIdentity]);
110 require_action(identity, exit, fail("Failed to get identity"));
113 require_noerr_action(CMSEncoderCreate(&encoder), exit, fail("Failed to create CMS encoder"));
114 require_noerr_action(CMSEncoderSetSignerAlgorithm(encoder, kCMSEncoderDigestAlgorithmSHA256), exit,
115 fail("Failed to set digest algorithm to SHA256"));
117 /* Set identity as signer */
118 require_noerr_action(CMSEncoderAddSigners(encoder, identity), exit, fail("Failed to add signer identity"));
120 /* Add hash agility attribute */
121 require_noerr_action(CMSEncoderAddSignedAttributes(encoder, kCMSAttrAppleCodesigningHashAgility), exit,
122 fail("Set hash agility flag"));
123 require_noerr_action(CMSEncoderSetAppleCodesigningHashAgility(encoder, (__bridge CFDataRef)[NSData dataWithBytes:attribute
124 length:sizeof(attribute)]),
125 exit, fail("Set hash agility data"));
127 /* Add hash agility v2 attribute */
128 attrValues = @{ @(SEC_OID_SHA1) : [NSData dataWithBytes:_attributev2 length:20],
129 @(SEC_OID_SHA256) : [NSData dataWithBytes:(_attributev2 + 32) length:32],
131 require_noerr_action(CMSEncoderAddSignedAttributes(encoder, kCMSAttrAppleCodesigningHashAgilityV2), exit,
132 fail("Set hash agility flag"));
133 require_noerr_action(CMSEncoderSetAppleCodesigningHashAgilityV2(encoder, (__bridge CFDictionaryRef)attrValues), exit,
134 fail("Set hash agility data"));
136 #if TIMESTAMPING_SUPPORTED
137 /* Set timestamp context */
138 CmsMessageSetTSAContext(encoder, SecCmsTSAGetDefaultContext(NULL));
142 require_noerr_action(CMSEncoderSetHasDetachedContent(encoder, true), exit, fail("Failed to set detached content"));
143 require_noerr_action(CMSEncoderUpdateContent(encoder, content, sizeof(content)), exit, fail("Failed to set content"));
145 /* output cms message */
146 ok_status(CMSEncoderCopyEncodedContent(encoder, &message), "Finish encoding and output message");
147 isnt(message, NULL, "Encoded message exists");
150 require_noerr_action(CMSDecoderCreate(&decoder), exit, fail("Create CMS decoder"));
151 require_noerr_action(CMSDecoderUpdateMessage(decoder, CFDataGetBytePtr(message),
152 CFDataGetLength(message)), exit,
153 fail("Update decoder with CMS message"));
154 require_noerr_action(CMSDecoderSetDetachedContent(decoder, (__bridge CFDataRef)[NSData dataWithBytes:content
155 length:sizeof(content)]),
156 exit, fail("Set detached content"));
157 ok_status(CMSDecoderFinalizeMessage(decoder), "Finalize decoder");
160 CFReleaseNull(encoder);
161 CFReleaseNull(decoder);
162 CFReleaseNull(message);
164 // SecPKCS12Import adds the items to the keychain on macOS
165 NSDictionary *query = @{ (__bridge NSString*)kSecValueRef : (__bridge id)identity };
166 ok_status(SecItemDelete((__bridge CFDictionaryRef)query), "failed to remove identity from keychain");
168 pass("skip test on iOS");
170 CFReleaseNull(identity);
173 static int ping_host(char *host_name){
175 struct sockaddr_in pin;
176 struct hostent *nlp_host;
183 //tries 5 times then give up
184 while ((nlp_host=gethostbyname(host_name))==0 && retries--){
185 printf("Resolve Error! (%s) %d\n", host_name, h_errno);
192 bzero(&pin,sizeof(pin));
193 pin.sin_family=AF_INET;
194 pin.sin_addr.s_addr=htonl(INADDR_ANY);
195 pin.sin_addr.s_addr=((struct in_addr *)(nlp_host->h_addr))->s_addr;
196 pin.sin_port=htons(port);
198 sd=socket(AF_INET,SOCK_STREAM,0);
200 if (connect(sd,(struct sockaddr*)&pin,sizeof(pin))==-1){
201 printf("connect error! (%s) %d\n", host_name, errno);
211 int si_34_cms_timestamp(int argc, char * const *argv) {
214 test_matching_messageImprint();
216 if (!ping_host("timestamp.apple.com")) {
217 printf("Accessing timestamp.apple.com failed, check the network!\n");
220 test_create_timestamp();