2 * Copyright (c) 2015-2017 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 #import <AssertMacros.h>
25 #include <Foundation/Foundation.h>
27 #include <regressions/test/testmore.h>
28 #include <Security/SecBase.h>
29 #include <utilities/SecCFRelease.h>
30 #include <Security/CMSEncoder.h>
31 #include <Security/SecImportExport.h>
32 #include <Security/CMSPrivate.h>
33 #include <Security/SecCertificatePriv.h>
34 #include <Security/SecTrust.h>
35 #include <Security/SecPolicy.h>
36 #include <Security/SecKeychain.h>
37 #include <Security/SecIdentity.h>
39 #include "cms-hashagility-test.h"
41 #define TMP_KEYCHAIN_PATH "/tmp/cms_signer.keychain"
44 static void encode_test(void)
46 CMSEncoderRef encoder = NULL;
47 CFDataRef attributeData = NULL, message = NULL, p12Data = NULL;
48 CFArrayRef imported_items = NULL;
49 SecIdentityRef identity = NULL;
50 SecKeychainRef keychain = NULL;
51 SecExternalFormat sef = kSecFormatPKCS12;
52 SecItemImportExportKeyParameters keyParams = {
53 .passphrase = CFSTR("password")
57 ok_status(CMSEncoderCreate(&encoder), "Create CMS encoder");
58 ok_status(CMSEncoderSetSignerAlgorithm(encoder, kCMSEncoderDigestAlgorithmSHA256),
59 "Set digest algorithm to SHA256");
61 /* Load identity and set as signer */
62 unlink(TMP_KEYCHAIN_PATH);
63 ok_status(SecKeychainCreate(TMP_KEYCHAIN_PATH, 8, "password", false, NULL, &keychain),
64 "Create keychain for identity");
65 ok(p12Data = CFDataCreate(NULL, signing_identity_p12, sizeof(signing_identity_p12)),
67 ok_status(SecItemImport(p12Data, NULL, &sef, NULL, 0, &keyParams, keychain, &imported_items),
69 is(CFArrayGetCount(imported_items),1,"Imported 1 items");
70 is(CFGetTypeID(CFArrayGetValueAtIndex(imported_items, 0)), SecIdentityGetTypeID(),
71 "Got back an identity");
72 ok(identity = (SecIdentityRef) CFRetainSafe(CFArrayGetValueAtIndex(imported_items, 0)),
74 ok_status(CMSEncoderAddSigners(encoder, identity), "Set Signer identity");
76 /* Add signing time attribute for 3 November 2015 */
77 ok_status(CMSEncoderAddSignedAttributes(encoder, kCMSAttrSigningTime),
78 "Set signing time flag");
79 ok_status(CMSEncoderSetSigningTime(encoder, 468295000.0), "Set Signing time");
81 /* Add hash agility attribute */
82 ok_status(CMSEncoderAddSignedAttributes(encoder, kCMSAttrAppleCodesigningHashAgility),
83 "Set hash agility flag");
84 ok(attributeData = CFDataCreate(NULL, attribute, sizeof(attribute)),
85 "Create atttribute object");
86 ok_status(CMSEncoderSetAppleCodesigningHashAgility(encoder, attributeData),
87 "Set hash agility data");
90 ok_status(CMSEncoderSetHasDetachedContent(encoder, true), "Set detached content");
91 ok_status(CMSEncoderUpdateContent(encoder, content, sizeof(content)), "Set content");
93 /* output cms message */
94 ok_status(CMSEncoderCopyEncodedContent(encoder, &message), "Finish encoding and output message");
97 CMSDecoderRef decoder = NULL;
98 CFDataRef contentData = NULL;
99 isnt(message, NULL, "Encoded message exists");
100 ok_status(CMSDecoderCreate(&decoder), "Create CMS decoder");
101 ok_status(CMSDecoderUpdateMessage(decoder, CFDataGetBytePtr(message), CFDataGetLength(message)),
102 "Update decoder with CMS message");
103 ok(contentData = CFDataCreate(NULL, content, sizeof(content)), "Create detached content");
104 ok_status(CMSDecoderSetDetachedContent(decoder, contentData), "Set detached content");
105 ok_status(CMSDecoderFinalizeMessage(decoder), "Finalize decoder");
108 ok_status(SecKeychainDelete(keychain), "Delete temporary keychain");
110 CFReleaseNull(encoder);
111 CFReleaseNull(keychain);
112 CFReleaseNull(p12Data);
113 CFReleaseNull(imported_items);
114 CFReleaseNull(identity);
115 CFReleaseNull(attributeData);
116 CFReleaseNull(message);
117 CFReleaseNull(decoder);
118 CFReleaseNull(contentData);
121 static void decode_positive_test(void)
123 CMSDecoderRef decoder = NULL;
124 CFDataRef contentData = NULL, attrValue = NULL;
125 SecPolicyRef policy = NULL;
126 SecTrustRef trust = NULL;
127 CMSSignerStatus signerStatus;
128 CFAbsoluteTime signingTime = 0.0;
130 /* Create decoder and decode */
131 ok_status(CMSDecoderCreate(&decoder), "Create CMS decoder");
132 ok_status(CMSDecoderUpdateMessage(decoder, valid_message, sizeof(valid_message)),
133 "Update decoder with CMS message");
134 ok(contentData = CFDataCreate(NULL, content, sizeof(content)), "Create detached content");
135 ok_status(CMSDecoderSetDetachedContent(decoder, contentData), "Set detached content");
136 ok_status(CMSDecoderFinalizeMessage(decoder), "Finalize decoder");
138 /* Get signer status */
139 ok(policy = SecPolicyCreateBasicX509(), "Create policy");
140 ok_status(CMSDecoderCopySignerStatus(decoder, 0, policy, false, &signerStatus, &trust, NULL),
141 "Copy Signer status");
142 is(signerStatus, kCMSSignerValid, "Valid signature");
144 /* Get Hash Agility Attribute value */
145 ok_status(CMSDecoderCopySignerAppleCodesigningHashAgility(decoder, 0, &attrValue),
146 "Copy hash agility attribute value");
147 is(CFDataGetLength(attrValue), sizeof(attribute), "Decoded attribute size");
148 is(memcmp(attribute, CFDataGetBytePtr(attrValue), sizeof(attribute)), 0,
149 "Decoded value same as input value");
151 /* Get Signing Time Attribute value */
152 ok_status(CMSDecoderCopySignerSigningTime(decoder, 0, &signingTime),
153 "Copy signing time attribute value");
154 is(signingTime, 468295000.0, "Decoded date same as input date");
156 CFReleaseNull(decoder);
157 CFReleaseNull(contentData);
158 CFReleaseNull(policy);
159 CFReleaseNull(trust);
160 CFReleaseNull(attrValue);
163 static void decode_negative_test(void)
165 CMSDecoderRef decoder = NULL;
166 CFDataRef contentData = NULL;
167 SecPolicyRef policy = NULL;
168 SecTrustRef trust = NULL;
169 CMSSignerStatus signerStatus;
171 /* Create decoder and decode */
172 ok_status(CMSDecoderCreate(&decoder), "Create CMS decoder");
173 ok_status(CMSDecoderUpdateMessage(decoder, invalid_message, sizeof(invalid_message)),
174 "Update decoder with CMS message");
175 ok(contentData = CFDataCreate(NULL, content, sizeof(content)), "Create detached content");
176 ok_status(CMSDecoderSetDetachedContent(decoder, contentData), "Set detached content");
177 ok_status(CMSDecoderFinalizeMessage(decoder), "Finalize decoder");
179 /* Get signer status */
180 ok(policy = SecPolicyCreateBasicX509(), "Create policy");
181 ok_status(CMSDecoderCopySignerStatus(decoder, 0, policy, false, &signerStatus, &trust, NULL),
182 "Copy Signer status");
183 is(signerStatus, kCMSSignerInvalidSignature, "Invalid signature");
185 CFReleaseNull(decoder);
186 CFReleaseNull(contentData);
187 CFReleaseNull(policy);
188 CFReleaseNull(trust);
191 static void decode_no_attr_test(void)
193 CMSDecoderRef decoder = NULL;
194 CFDataRef contentData = NULL, attrValue = NULL;
195 SecPolicyRef policy = NULL;
196 SecTrustRef trust = NULL;
197 CMSSignerStatus signerStatus;
199 /* Create decoder and decode */
200 ok_status(CMSDecoderCreate(&decoder), "Create CMS decoder");
201 ok_status(CMSDecoderUpdateMessage(decoder, valid_no_attr, sizeof(valid_no_attr)),
202 "Update decoder with CMS message");
203 ok(contentData = CFDataCreate(NULL, content, sizeof(content)), "Create detached content");
204 ok_status(CMSDecoderSetDetachedContent(decoder, contentData), "Set detached content");
205 ok_status(CMSDecoderFinalizeMessage(decoder), "Finalize decoder");
207 /* Get signer status */
208 ok(policy = SecPolicyCreateBasicX509(), "Create policy");
209 ok_status(CMSDecoderCopySignerStatus(decoder, 0, policy, false, &signerStatus, &trust, NULL),
210 "Copy Signer status");
211 is(signerStatus, kCMSSignerValid, "Valid signature");
213 /* Get Hash Agility Attribute value */
214 ok_status(CMSDecoderCopySignerAppleCodesigningHashAgility(decoder, 0, &attrValue),
215 "Copy empty hash agility attribute value");
216 is(attrValue, NULL, "NULL attribute value");
218 CFReleaseNull(decoder);
219 CFReleaseNull(contentData);
220 CFReleaseNull(policy);
221 CFReleaseNull(trust);
222 CFReleaseNull(attrValue);
225 static void macOS_shim_tests(void) {
227 decode_positive_test();
228 decode_negative_test();
229 decode_no_attr_test();
232 static void encode_V2_test(void) {
233 CMSEncoderRef encoder = NULL;
234 CMSDecoderRef decoder = NULL;
235 NSData *p12Data = nil;
236 CFArrayRef tmp_imported_items = NULL;
237 NSArray *imported_items = nil;
238 SecIdentityRef identity = NULL;
239 CFDataRef message = NULL;
240 NSDictionary *attrValues = nil, *options = @{ (__bridge NSString *)kSecImportExportPassphrase : @"password" };
243 require_noerr_string(CMSEncoderCreate(&encoder), exit, "Failed to create CMS encoder");
244 require_noerr_string(CMSEncoderSetSignerAlgorithm(encoder, kCMSEncoderDigestAlgorithmSHA256), exit,
245 "Failed to set digest algorithm to SHA256");
247 /* Load identity and set as signer */
248 p12Data = [NSData dataWithBytes:signing_identity_p12 length:sizeof(signing_identity_p12)];
249 require_noerr_string(SecPKCS12Import((__bridge CFDataRef)p12Data, (__bridge CFDictionaryRef)options,
250 &tmp_imported_items), exit,
251 "Failed to import identity");
252 imported_items = CFBridgingRelease(tmp_imported_items);
253 require_noerr_string([imported_items count] == 0 &&
254 [imported_items[0] isKindOfClass:[NSDictionary class]], exit,
255 "Wrong imported items output");
256 identity = (SecIdentityRef)CFBridgingRetain(imported_items[0][(__bridge NSString*)kSecImportItemIdentity]);
257 require_string(identity, exit, "Failed to get identity");
258 require_noerr_string(CMSEncoderAddSigners(encoder, identity), exit, "Failed to add signer identity");
260 /* Add signing time attribute for 26 October 2017 */
261 require_noerr_string(CMSEncoderAddSignedAttributes(encoder, kCMSAttrSigningTime), exit,
262 "Failed to set signing time flag");
263 require_noerr_string(CMSEncoderSetSigningTime(encoder, 530700000.0), exit, "Failed to set signing time");
265 /* Add hash agility attribute */
266 attrValues = @{ @(SEC_OID_SHA1) : [NSData dataWithBytes:_attributev2 length:20],
267 @(SEC_OID_SHA256) : [NSData dataWithBytes:(_attributev2 + 32) length:32],
269 ok_status(CMSEncoderAddSignedAttributes(encoder, kCMSAttrAppleCodesigningHashAgilityV2),
270 "Set hash agility flag");
271 ok_status(CMSEncoderSetAppleCodesigningHashAgilityV2(encoder, (__bridge CFDictionaryRef)attrValues),
272 "Set hash agility data");
275 require_noerr_string(CMSEncoderSetHasDetachedContent(encoder, true), exit, "Failed to set detached content");
276 require_noerr_string(CMSEncoderUpdateContent(encoder, content, sizeof(content)), exit, "Failed to set content");
278 /* output cms message */
279 ok_status(CMSEncoderCopyEncodedContent(encoder, &message), "Finish encoding and output message");
280 isnt(message, NULL, "Encoded message exists");
283 require_noerr_string(CMSDecoderCreate(&decoder), exit, "Create CMS decoder");
284 require_noerr_string(CMSDecoderUpdateMessage(decoder, CFDataGetBytePtr(message),
285 CFDataGetLength(message)), exit,
286 "Update decoder with CMS message");
287 require_noerr_string(CMSDecoderSetDetachedContent(decoder, (__bridge CFDataRef)[NSData dataWithBytes:content
288 length:sizeof(content)]),
289 exit, "Set detached content");
290 ok_status(CMSDecoderFinalizeMessage(decoder), "Finalize decoder");
293 CFReleaseNull(encoder);
294 CFReleaseNull(identity);
295 CFReleaseNull(message);
296 CFReleaseNull(decoder);
299 /* macOS shim test - decode positive */
300 static void decode_V2_positive_test(void) {
301 CMSDecoderRef decoder = NULL;
302 SecPolicyRef policy = NULL;
303 SecTrustRef trust = NULL;
304 CMSSignerStatus signerStatus;
305 NSData *contentData = nil;
306 CFDictionaryRef tmpAttrValue = NULL;
307 NSDictionary *attrValue = nil;
309 /* Create decoder and decode */
310 require_noerr_string(CMSDecoderCreate(&decoder), exit, "Failed to create CMS decoder");
311 require_noerr_string(CMSDecoderUpdateMessage(decoder, _V2_valid_message, sizeof(_V2_valid_message)), exit,
312 "Failed to update decoder with CMS message");
313 contentData = [NSData dataWithBytes:content length:sizeof(content)];
314 require_noerr_string(CMSDecoderSetDetachedContent(decoder, (__bridge CFDataRef)contentData), exit,
315 "Failed to set detached content");
316 ok_status(CMSDecoderFinalizeMessage(decoder), "Finalize decoder");
318 /* Get signer status */
319 require_string(policy = SecPolicyCreateBasicX509(), exit, "Failed to Create policy");
320 ok_status(CMSDecoderCopySignerStatus(decoder, 0, policy, false, &signerStatus, &trust, NULL),
321 "Copy Signer status");
322 is(signerStatus, kCMSSignerValid, "Valid signature");
324 /* Get Hash Agility Attribute value */
325 ok_status(CMSDecoderCopySignerAppleCodesigningHashAgilityV2(decoder, 0, &tmpAttrValue),
326 "Copy hash agility attribute value");
327 attrValue = CFBridgingRelease(tmpAttrValue);
328 ok([attrValue[@(SEC_OID_SHA1)] isEqualToData:[NSData dataWithBytes:_attributev2 length:20]],
329 "Got wrong SHA1 agility value");
330 ok([attrValue[@(SEC_OID_SHA256)] isEqualToData:[NSData dataWithBytes:(_attributev2+32) length:32]],
331 "Got wrong SHA256 agility value");
334 CFReleaseNull(decoder);
335 CFReleaseNull(policy);
336 CFReleaseNull(trust);
339 /* macOS shim test - decode negative */
340 static void decode_V2_negative_test(void) {
341 CMSDecoderRef decoder = NULL;
342 SecPolicyRef policy = NULL;
343 SecTrustRef trust = NULL;
344 CMSSignerStatus signerStatus;
345 NSData *contentData = nil;
346 NSMutableData *invalid_message = nil;
348 /* Create decoder and decode */
349 invalid_message = [NSMutableData dataWithBytes:_V2_valid_message length:sizeof(_V2_valid_message)];
350 [invalid_message resetBytesInRange:NSMakeRange(2110, 1)]; /* reset byte in hash agility attribute */
351 require_noerr_string(CMSDecoderCreate(&decoder), exit, "Failed to create CMS decoder");
352 require_noerr_string(CMSDecoderUpdateMessage(decoder, [invalid_message bytes], [invalid_message length]), exit,
353 "Failed to update decoder with CMS message");
354 contentData = [NSData dataWithBytes:content length:sizeof(content)];
355 require_noerr_string(CMSDecoderSetDetachedContent(decoder, (__bridge CFDataRef)contentData), exit,
356 "Failed to set detached content");
357 ok_status(CMSDecoderFinalizeMessage(decoder), "Finalize decoder");
359 /* Get signer status */
360 require_string(policy = SecPolicyCreateBasicX509(), exit, "Failed to Create policy");
361 ok_status(CMSDecoderCopySignerStatus(decoder, 0, policy, false, &signerStatus, &trust, NULL),
362 "Copy Signer status");
363 is(signerStatus, kCMSSignerInvalidSignature, "Valid signature");
366 CFReleaseNull(decoder);
367 CFReleaseNull(policy);
368 CFReleaseNull(trust);
371 /* macOS shim test - no attribute */
372 static void decodeV2_no_attr_test(void) {
373 CMSDecoderRef decoder = NULL;
374 SecPolicyRef policy = NULL;
375 SecTrustRef trust = NULL;
376 CMSSignerStatus signerStatus;
377 NSData *contentData = nil;
378 CFDictionaryRef attrValue = NULL;
380 /* Create decoder and decode */
381 require_noerr_string(CMSDecoderCreate(&decoder), exit, "Failed to create CMS decoder");
382 require_noerr_string(CMSDecoderUpdateMessage(decoder, valid_message, sizeof(valid_message)), exit,
383 "Failed to update decoder with CMS message");
384 contentData = [NSData dataWithBytes:content length:sizeof(content)];
385 require_noerr_string(CMSDecoderSetDetachedContent(decoder, (__bridge CFDataRef)contentData), exit,
386 "Failed to set detached content");
387 ok_status(CMSDecoderFinalizeMessage(decoder), "Finalize decoder");
389 /* Get signer status */
390 require_string(policy = SecPolicyCreateBasicX509(), exit, "Failed to Create policy");
391 ok_status(CMSDecoderCopySignerStatus(decoder, 0, policy, false, &signerStatus, &trust, NULL),
392 "Copy Signer status");
393 is(signerStatus, kCMSSignerValid, "Valid signature");
395 /* Get Hash Agility Attribute value */
396 ok_status(CMSDecoderCopySignerAppleCodesigningHashAgilityV2(decoder, 0, &attrValue),
397 "Copy hash agility attribute value");
398 is(attrValue, NULL, "NULL attribute value");
401 CFReleaseNull(decoder);
402 CFReleaseNull(policy);
403 CFReleaseNull(trust);
404 CFReleaseNull(attrValue);
407 static void macOS_shim_V2_tests(void) {
409 decode_V2_positive_test();
410 decode_V2_negative_test();
411 decodeV2_no_attr_test();
414 int cms_hash_agility_test(int argc, char *const *argv)
419 macOS_shim_V2_tests();