]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/Regressions/secitem/si-35-cms-expiration-time.m
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / sec / Security / Regressions / secitem / si-35-cms-expiration-time.m
1 /*
2 * Copyright (c) 2018 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 #include <AssertMacros.h>
25 #import <Foundation/Foundation.h>
26
27 #include <Security/SecIdentity.h>
28 #include <Security/SecCMS.h>
29 #include <Security/CMSEncoder.h>
30 #include <Security/CMSDecoder.h>
31 #include <Security/CMSPrivate.h>
32
33 #include <utilities/SecCFWrappers.h>
34
35 #if TARGET_OS_OSX
36 #include <Security/SecKeychain.h>
37 #include <Security/SecImportExport.h>
38 #include <Security/CMSPrivate.h>
39 #endif
40
41 #include "shared_regressions.h"
42
43 #include "si-35-cms-expiration-time.h"
44
45 /* MARK: SecCMS tests */
46 static void SecCMS_positive_tests(void) {
47 SecPolicyRef policy = NULL;
48 SecTrustRef trust = NULL;
49 CFDictionaryRef tmpAttrs = NULL;
50 NSDictionary* attrs = nil;
51 NSData *expirationDateOid = nil, *unparsedExpirationDate = nil;
52 NSArray *attrValues = nil;
53 NSDate *expirationDate = nil, *expectedDate = [NSDate dateWithTimeIntervalSinceReferenceDate: 599400000.0];
54
55 NSData *message = [NSData dataWithBytes:_css_gen_expiration_time length:sizeof(_css_gen_expiration_time)];
56 NSData *content = [NSData dataWithBytes:_css_content length:sizeof(_css_content)];
57 policy = SecPolicyCreateBasicX509();
58
59 /* verify a valid message and copy out attributes */
60 ok_status(SecCMSVerifyCopyDataAndAttributes((__bridge CFDataRef)message, (__bridge CFDataRef)content, policy, &trust, NULL, &tmpAttrs),
61 "Failed to verify valid CMS message and get out attributes");
62 require_action(attrs = CFBridgingRelease(tmpAttrs), exit, fail("Failed to copy attributes"));
63
64 /* verify we can get the parsed expiration date attribute out */
65 uint8_t appleExpirationDateOid[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x63, 0x64, 0x9, 0x3 };
66 expirationDateOid = [NSData dataWithBytes:appleExpirationDateOid length:sizeof(appleExpirationDateOid)];
67 attrValues = attrs[expirationDateOid];
68 is([attrValues count], (size_t)1, "Wrong number of attribute values");
69 require_action(unparsedExpirationDate = attrValues[0], exit, fail("Failed to get expiration date attribute value"));
70 uint8_t expectedUTCData[] = { 0x31, 0x39, 0x31, 0x32, 0x33, 0x30, 0x31, 0x32, 0x30, 0x30, 0x30, 0x30, 0x5a };
71 is([unparsedExpirationDate isEqualToData:[NSData dataWithBytes:expectedUTCData length:sizeof(expectedUTCData)]], true, "Failed to get correct expiration date");
72
73 /* verify we can get the "cooked" expiration data out */
74 ok(expirationDate = attrs[(__bridge NSString*)kSecCMSExpirationDate], "Failed to get pre-parsed expiration date from attributes");
75 is([expirationDate isEqualToDate:expectedDate], true, "Failed to get correct expiration date");
76
77 exit:
78 CFReleaseNull(policy);
79 CFReleaseNull(trust);
80 }
81
82 static void SecCMS_negative_date_changed(void) {
83 SecPolicyRef policy = NULL;
84 SecTrustRef trust = NULL;
85
86 NSMutableData *invalid_message = [NSMutableData dataWithBytes:_css_gen_expiration_time length:sizeof(_css_gen_expiration_time)];
87 [invalid_message resetBytesInRange:NSMakeRange(3980, 1)]; // reset byte in expiration date attribute of _css_gen_expiration_time
88 NSData *content = [NSData dataWithBytes:_css_content length:sizeof(_css_content)];
89 policy = SecPolicyCreateBasicX509();
90
91 /* Verify message with expiration date changed fails*/
92 is(SecCMSVerifyCopyDataAndAttributes((__bridge CFDataRef)invalid_message, (__bridge CFDataRef)content, policy, &trust, NULL, NULL),
93 errSecAuthFailed, "Failed to verify valid CMS message and get out attributes");
94
95 CFReleaseNull(policy);
96 CFReleaseNull(trust);
97 }
98
99 static void SecCMS_negative_missing_date(void) {
100 SecPolicyRef policy = NULL;
101 SecTrustRef trust = NULL;
102 CFDictionaryRef tmpAttrs = NULL;
103 NSDictionary *attrs = nil;
104 NSData *expirationDateOid = nil;
105
106 NSData *message = [NSData dataWithBytes:_no_expiration_attr length:sizeof(_no_expiration_attr)];
107 policy = SecPolicyCreateBasicX509();
108
109 /* verify a message with no expiration date */
110 ok_status(SecCMSVerifyCopyDataAndAttributes((__bridge CFDataRef)message, NULL, policy, &trust, NULL, &tmpAttrs),
111 "Failed to verify valid CMS message and get out attributes");
112 require_action(attrs = CFBridgingRelease(tmpAttrs), exit, fail("Failed to copy attributes"));
113
114 /* verify we can't get the expiration date out */
115 uint8_t appleExpirationDateOid[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x63, 0x64, 0x9, 0x3 };
116 expirationDateOid = [NSData dataWithBytes:appleExpirationDateOid length:sizeof(appleExpirationDateOid)];
117 is(attrs[expirationDateOid], NULL, "Got an expiration date attribute from message with no expiration date");
118 is(attrs[(__bridge NSString*)kSecCMSExpirationDate], NULL, "Got an expiration date attribute from message with no expiration date");
119
120 exit:
121 CFReleaseNull(policy);
122 CFReleaseNull(trust);
123 }
124
125 static void SecCMS_tests(void) {
126 SecCMS_positive_tests();
127 SecCMS_negative_date_changed();
128 SecCMS_negative_missing_date();
129 }
130
131 /* MARK: CMSEncoder tests */
132 static void CMSEncoder_tests(SecIdentityRef identity) {
133 CMSEncoderRef encoder = NULL;
134 CMSDecoderRef decoder = NULL;
135 CFDataRef message = NULL;
136
137 /* Create encoder */
138 require_noerr_action(CMSEncoderCreate(&encoder), exit, fail("Failed to create CMS encoder"));
139 require_noerr_action(CMSEncoderSetSignerAlgorithm(encoder, kCMSEncoderDigestAlgorithmSHA256), exit,
140 fail("Failed to set digest algorithm to SHA256"));
141
142 /* Set identity as signer */
143 require_noerr_action(CMSEncoderAddSigners(encoder, identity), exit, fail("Failed to add signer identity"));
144
145 /* Add signing time attribute for 6 June 2018 */
146 require_noerr_action(CMSEncoderAddSignedAttributes(encoder, kCMSAttrSigningTime), exit,
147 fail("Failed to set signing time flag"));
148 require_noerr_action(CMSEncoderSetSigningTime(encoder, 550000000.0), exit, fail("Failed to set signing time"));
149
150 /* Add expiration date attribute for 30 September 2018 */
151 ok_status(CMSEncoderAddSignedAttributes(encoder, kCMSAttrAppleExpirationTime),
152 "Set expiration date flag");
153 ok_status(CMSEncoderSetAppleExpirationTime(encoder, 560000000.0), "Set Expiration time");
154
155 /* Load content */
156 require_noerr_action(CMSEncoderSetHasDetachedContent(encoder, true), exit, fail("Failed to set detached content"));
157 require_noerr_action(CMSEncoderUpdateContent(encoder, _css_content, sizeof(_css_content)), exit, fail("Failed to set content"));
158
159 /* output cms message */
160 ok_status(CMSEncoderCopyEncodedContent(encoder, &message), "Finish encoding and output message");
161 isnt(message, NULL, "Encoded message exists");
162
163 /* decode message */
164 require_noerr_action(CMSDecoderCreate(&decoder), exit, fail("Create CMS decoder"));
165 require_noerr_action(CMSDecoderUpdateMessage(decoder, CFDataGetBytePtr(message),
166 CFDataGetLength(message)), exit,
167 fail("Update decoder with CMS message"));
168 require_noerr_action(CMSDecoderSetDetachedContent(decoder, (__bridge CFDataRef)[NSData dataWithBytes:_css_content
169 length:sizeof(_css_content)]),
170 exit, fail("Set detached content"));
171 ok_status(CMSDecoderFinalizeMessage(decoder), "Finalize decoder");
172
173 exit:
174 CFReleaseNull(encoder);
175 CFReleaseNull(message);
176 CFReleaseNull(decoder);
177 }
178
179 /* MARK: CMSDecoder tests */
180 static void CMSDecoder_positive_tests(void) {
181 CMSDecoderRef decoder = NULL;
182 SecPolicyRef policy = NULL;
183 SecTrustRef trust = NULL;
184 CMSSignerStatus signerStatus;
185 NSData *_css_contentData = nil;
186 CFAbsoluteTime expirationTime = 0;
187 NSDate *expirationDate = nil, *expectedDate = [NSDate dateWithTimeIntervalSinceReferenceDate: 599400000.0];
188
189 /* Create decoder and decode */
190 require_noerr_action(CMSDecoderCreate(&decoder), exit, fail("Failed to create CMS decoder"));
191 require_noerr_action(CMSDecoderUpdateMessage(decoder, _css_gen_expiration_time, sizeof(_css_gen_expiration_time)), exit,
192 fail("Failed to update decoder with CMS message"));
193 _css_contentData = [NSData dataWithBytes:_css_content length:sizeof(_css_content)];
194 require_noerr_action(CMSDecoderSetDetachedContent(decoder, (__bridge CFDataRef)_css_contentData), exit,
195 fail("Failed to set detached _css_content"));
196 ok_status(CMSDecoderFinalizeMessage(decoder), "Finalize decoder");
197
198 /* Get signer status */
199 require_action(policy = SecPolicyCreateBasicX509(), exit, fail("Failed to Create policy"));
200 ok_status(CMSDecoderCopySignerStatus(decoder, 0, policy, false, &signerStatus, &trust, NULL),
201 "Copy Signer status");
202 is(signerStatus, kCMSSignerValid, "Valid signature");
203
204 /* Get Expiration Time Attribute value */
205 ok_status(CMSDecoderCopySignerAppleExpirationTime(decoder, 0, &expirationTime),
206 "Got expiration time from message with no expiration attribute");
207 expirationDate = [NSDate dateWithTimeIntervalSinceReferenceDate:expirationTime];
208 is([expirationDate isEqualToDate:expectedDate], true, "Got wrong expiration time"); // 31 December 2019 12:00:00 Zulu
209
210 exit:
211 CFReleaseNull(decoder);
212 CFReleaseNull(policy);
213 CFReleaseNull(trust);
214 }
215
216 static void CMSDecoder_negative_date_changed(void) {
217 CMSDecoderRef decoder = NULL;
218 SecPolicyRef policy = NULL;
219 SecTrustRef trust = NULL;
220 CMSSignerStatus signerStatus;
221 NSData *_css_contentData = nil;
222 NSMutableData *invalid_message = nil;
223
224 /* Create decoder and decode */
225 invalid_message = [NSMutableData dataWithBytes:_css_gen_expiration_time length:sizeof(_css_gen_expiration_time)];
226 [invalid_message resetBytesInRange:NSMakeRange(3980, 1)]; // reset byte in expiration date attribute of _css_gen_expiration_time
227 require_noerr_action(CMSDecoderCreate(&decoder), exit, fail("Failed to create CMS decoder"));
228 require_noerr_action(CMSDecoderUpdateMessage(decoder, [invalid_message bytes], [invalid_message length]), exit,
229 fail("Failed to update decoder with CMS message"));
230 _css_contentData = [NSData dataWithBytes:_css_content length:sizeof(_css_content)];
231 require_noerr_action(CMSDecoderSetDetachedContent(decoder, (__bridge CFDataRef)_css_contentData), exit,
232 fail("Failed to set detached _css_content"));
233 ok_status(CMSDecoderFinalizeMessage(decoder), "Finalize decoder");
234
235 /* Get signer status */
236 require_action(policy = SecPolicyCreateBasicX509(), exit, fail("Failed to Create policy"));
237 ok_status(CMSDecoderCopySignerStatus(decoder, 0, policy, false, &signerStatus, &trust, NULL),
238 "Copy Signer status");
239 is(signerStatus, kCMSSignerInvalidSignature, "Valid signature");
240
241 exit:
242 CFReleaseNull(decoder);
243 CFReleaseNull(policy);
244 CFReleaseNull(trust);
245 }
246
247 static void CMSDecoder_negative_missing_date(void) {
248 CMSDecoderRef decoder = NULL;
249 SecPolicyRef policy = NULL;
250 SecTrustRef trust = NULL;
251 CMSSignerStatus signerStatus;
252 CFAbsoluteTime expirationTime = 0.0;
253
254 /* Create decoder and decode */
255 require_noerr_action(CMSDecoderCreate(&decoder), exit, fail("Failed to create CMS decoder"));
256 require_noerr_action(CMSDecoderUpdateMessage(decoder, _no_expiration_attr, sizeof(_no_expiration_attr)), exit,
257 fail("Failed to update decoder with CMS message"));
258 ok_status(CMSDecoderFinalizeMessage(decoder), "Finalize decoder");
259
260 /* Get signer status */
261 require_action(policy = SecPolicyCreateBasicX509(), exit, fail("Failed to Create policy"));
262 ok_status(CMSDecoderCopySignerStatus(decoder, 0, policy, false, &signerStatus, &trust, NULL),
263 "Copy Signer status");
264 is(signerStatus, kCMSSignerValid, "Valid signature");
265
266 /* Get Expiration Time Attribute value */
267 is(CMSDecoderCopySignerAppleExpirationTime(decoder, 0, &expirationTime), -1,
268 "Got expiration time from message with no expiration attribute");
269
270 exit:
271 CFReleaseNull(decoder);
272 CFReleaseNull(policy);
273 CFReleaseNull(trust);
274 }
275
276 static void CMSDecoder_tests(void) {
277 CMSDecoder_positive_tests();
278 CMSDecoder_negative_date_changed();
279 CMSDecoder_negative_missing_date();
280 }
281
282 static bool setup_keychain(const uint8_t *p12, size_t p12_len, SecIdentityRef *identity) {
283 CFArrayRef tmp_imported_items = NULL;
284 NSArray *imported_items = nil;
285
286 NSDictionary *options = @{ (__bridge NSString *)kSecImportExportPassphrase : @"password" };
287 NSData *p12Data = [NSData dataWithBytes:signing_identity_p12 length:sizeof(signing_identity_p12)];
288 require_noerr_action(SecPKCS12Import((__bridge CFDataRef)p12Data, (__bridge CFDictionaryRef)options,
289 &tmp_imported_items), exit,
290 fail("Failed to import identity"));
291 imported_items = CFBridgingRelease(tmp_imported_items);
292 require_noerr_action([imported_items count] == 0 &&
293 [imported_items[0] isKindOfClass:[NSDictionary class]], exit,
294 fail("Wrong imported items output"));
295 *identity = (SecIdentityRef)CFBridgingRetain(imported_items[0][(__bridge NSString*)kSecImportItemIdentity]);
296 require_action(*identity, exit, fail("Failed to get identity"));
297
298 return true;
299
300 exit:
301 return false;
302 }
303
304 static void cleanup_keychain(SecIdentityRef identity) {
305 #if TARGET_OS_OSX
306 // SecPKCS12Import adds the items to the keychain on macOS
307 NSDictionary *query = @{ (__bridge NSString*)kSecValueRef : (__bridge id)identity };
308 ok_status(SecItemDelete((__bridge CFDictionaryRef)query), "failed to remove identity from keychain");
309 #else
310 pass("skip test on iOS");
311 #endif
312 CFReleaseNull(identity);
313 }
314
315 int si_35_cms_expiration_time(int argc, char *const *argv) {
316 plan_tests(5+1+3+5+5+3+4+1);
317
318 SecIdentityRef identity = NULL;
319
320 if (setup_keychain(signing_identity_p12 , sizeof(signing_identity_p12), &identity)) {
321 SecCMS_tests();
322 CMSEncoder_tests(identity);
323 CMSDecoder_tests();
324 cleanup_keychain(identity);
325 }
326
327 return 0;
328 }