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@
25 #include <AssertMacros.h>
26 #import <XCTest/XCTest.h>
27 #include <Security/SecCertificatePriv.h>
28 #include <Security/SecPolicyPriv.h>
29 #include <Security/SecTrustPriv.h>
30 #include "OSX/utilities/SecCFWrappers.h"
31 #include <Security/SecTrustSettings.h>
32 #include <Security/SecTrustSettingsPriv.h>
33 #include "OSX/sec/Security/SecFramework.h"
34 #include "OSX/utilities/SecCFWrappers.h"
35 #include "trust/trustd/OTATrustUtilities.h"
38 #include <utilities/SecCFRelease.h>
39 #include "../TestMacroConversions.h"
40 #include "TrustFrameworkTestCase.h"
42 #include "CertificateInterfaceTests_data.h"
44 @interface CertificateInterfaceTests : TrustFrameworkTestCase
48 @implementation CertificateInterfaceTests
50 - (void)testCTInterfaces {
51 SecCertificateRef certF = NULL;
53 CFDataRef precertTBS = NULL;
54 CFArrayRef proofs = NULL;
55 CFDataRef spkiDigest = NULL;
57 isnt(certF = SecCertificateCreateWithBytes(NULL, serverF_cert_der, sizeof(serverF_cert_der)), NULL, "create certF");
59 isnt(precertTBS = SecCertificateCopyPrecertTBS(certF), NULL, "copy precertTBS");
60 XCTAssertEqualObjects((__bridge NSData *)precertTBS, [NSData dataWithBytes:serverF_pre_cert_der length:sizeof(serverF_pre_cert_der)],
61 "Pre-cert TBS for serverF incorrect");
63 isnt(spkiDigest = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(certF), NULL, "copy SPKI digest");
64 XCTAssertEqualObjects((__bridge NSData *)spkiDigest, [NSData dataWithBytes:serverF_SPKI_hash length:sizeof(serverF_SPKI_hash)],
65 "SPKI digest for serverF incorrect");
67 isnt(proofs = SecCertificateCopySignedCertificateTimestamps(certF), NULL, "copy SCTs");
68 NSArray *expectedProofs = @[[NSData dataWithBytes:serverF_sct length:sizeof(serverF_sct)]];
69 XCTAssertEqualObjects((__bridge NSArray*)proofs, expectedProofs , "SCT array for serverF incorrect");
72 CFReleaseSafe(precertTBS);
73 CFReleaseSafe(proofs);
74 CFReleaseSafe(spkiDigest);
77 - (void)testCreation {
78 SecCertificateRef cert0 = NULL, cert2 = NULL, cert4 = NULL;
79 isnt(cert0 = SecCertificateCreateWithBytes(NULL, _c0, sizeof(_c0)),
80 NULL, "create cert0");
82 CFDataRef cert2Data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
83 _c2, sizeof(_c2), kCFAllocatorNull);
84 isnt(cert2 = SecCertificateCreateWithData(kCFAllocatorDefault, cert2Data),
85 NULL, "create cert2");
86 CFReleaseNull(cert2Data);
88 CFDataRef cert4data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
89 pem, sizeof(pem), kCFAllocatorNull);
90 ok(cert4 = SecCertificateCreateWithPEM(NULL, cert4data), "create cert from pem");
93 (void)SecRandomCopyBytes(kSecRandomDefault, sizeof(random), random);
94 NSData *randomData = [[NSData alloc] initWithBytes:random length:sizeof(random)];
95 XCTAssert(NULL == SecCertificateCreateWithPEM(NULL, (__bridge CFDataRef)randomData));
97 CFReleaseNull(cert4data);
100 CFReleaseNull(cert4);
103 - (void)testSelfSignedCA {
104 SecCertificateRef cert0 = NULL, cert1 = NULL, cert5 = NULL;
105 isnt(cert0 = SecCertificateCreateWithBytes(NULL, _c0, sizeof(_c0)),
106 NULL, "create cert0");
107 isnt(cert1 = SecCertificateCreateWithBytes(NULL, _c1, sizeof(_c1)),
108 NULL, "create cert1");
109 isnt(cert5 = SecCertificateCreateWithBytes(NULL, _elektron_v1_cert_der,
110 sizeof(_elektron_v1_cert_der)), NULL, "create cert5");
112 ok(SecCertificateIsSelfSignedCA(cert0), "cert0 is CA");
113 ok(!SecCertificateIsSelfSignedCA(cert1), "cert1 is not CA");
114 ok(SecCertificateIsSelfSignedCA(cert5), "cert5 is v1 CA");
116 CFReleaseNull(cert0);
117 CFReleaseNull(cert1);
118 CFReleaseNull(cert5);
121 - (void)testSummary {
122 SecCertificateRef cert1 = NULL, cert3 = NULL, cert4 = NULL;
123 CFStringRef subjectSummary = NULL, issuerSummary = NULL;
125 isnt(cert1 = SecCertificateCreateWithBytes(NULL, _c1, sizeof(_c1)),
126 NULL, "create cert1");
127 isnt(cert3 = SecCertificateCreateWithBytes(NULL, _phased_c3, sizeof(_phased_c3)),
128 NULL, "create cert3");
130 CFDataRef cert4data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
131 pem, sizeof(pem), kCFAllocatorNull);
132 ok(cert4 = SecCertificateCreateWithPEM(NULL, cert4data), "create cert from pem");
133 CFReleaseNull(cert4data);
135 isnt(subjectSummary = SecCertificateCopySubjectSummary(cert1), NULL,
136 "cert1 has a subject summary");
137 isnt(issuerSummary = SecCertificateCopyIssuerSummary(cert1), NULL,
138 "cert1 has an issuer summary");
140 ok(subjectSummary && CFEqual(subjectSummary, CFSTR("www.verisign.com/CPS Incorp.by Ref. LIABILITY LTD.(c)97 VeriSign, VeriSign International Server CA - Class 3, VeriSign, Inc.")),
141 "subject summary is \"www.verisign.com/CPS Incorp.by Ref. LIABILITY LTD.(c)97 VeriSign, VeriSign International Server CA - Class 3, VeriSign, Inc.\"");
142 ok(issuerSummary && CFEqual(issuerSummary,
143 CFSTR("Class 3 Public Primary Certification Authority")),
144 "issuer summary is \"Class 3 Public Primary Certification Authority\"");
145 CFReleaseNull(subjectSummary);
147 isnt(subjectSummary = SecCertificateCopySubjectSummary(cert3), NULL,
148 "cert3 has a subject summary");
149 /* @@@ this caused a double free without an extra retain in obtainSummaryFromX501Name():
150 summary->description = string = copyDERThingDescription(kCFAllocatorDefault, value, true); */
151 CFReleaseNull(subjectSummary);
153 isnt(subjectSummary = SecCertificateCopySubjectSummary(cert4), NULL,
154 "cert4 has a subject summary");
155 ok(subjectSummary && CFEqual(subjectSummary, CFSTR("S5L8900 Secure Boot")),
156 "cert4 is S5L8900 Secure Boot");
158 CFReleaseNull(subjectSummary);
159 CFReleaseNull(issuerSummary);
160 CFReleaseNull(cert1);
161 CFReleaseNull(cert3);
162 CFReleaseNull(cert4);
165 - (void)testNTPrincipalName {
166 SecCertificateRef cert2 = NULL;
167 CFArrayRef ntPrincipalNames = NULL;
169 isnt(cert2 = SecCertificateCreateWithBytes(NULL, _c2, sizeof(_c2)),
170 NULL, "create cert2");
172 ok(ntPrincipalNames = SecCertificateCopyNTPrincipalNames(cert2),
173 "SecCertificateCopyNTPrincipalNames");
174 is(CFArrayGetCount(ntPrincipalNames), 1, "we got 1 princialname back");
175 CFStringRef principal = (CFStringRef)CFArrayGetValueAtIndex(ntPrincipalNames, 0);
176 ok(CFEqual(principal, CFSTR("kmm6b@Virginia.EDU")),
177 "first principal is kmm6b@Virginia.EDU");
178 CFReleaseNull(ntPrincipalNames);
179 CFReleaseNull(cert2);
182 - (void)testDescription {
183 CFStringRef desc = NULL;
184 SecCertificateRef cert4 = NULL;
186 CFDataRef cert4data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
187 pem, sizeof(pem), kCFAllocatorNull);
188 ok(cert4 = SecCertificateCreateWithPEM(NULL, cert4data), "create cert from pem");
189 CFReleaseNull(cert4data);
191 ok(desc = CFCopyDescription(cert4), "cert4 CFCopyDescription works");
193 CFReleaseNull(cert4);
197 SecCertificateRef cert0 = NULL;
198 isnt(cert0 = SecCertificateCreateWithBytes(NULL, _c0, sizeof(_c0)),
199 NULL, "create cert0");
200 CFDataRef spki1Hash = SecCertificateCopySubjectPublicKeyInfoSHA1Digest(cert0);
201 isnt(spki1Hash, NULL, "cert0 has a SHA-1 subject public key info hash");
202 CFReleaseSafe(spki1Hash);
204 CFDataRef spki2Hash = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(cert0);
205 isnt(spki2Hash, NULL, "cert0 has a SHA-256 subject public key info hash");
206 CFReleaseSafe(spki2Hash);
207 CFReleaseNull(cert0);
210 - (void)testCommonName {
211 SecCertificateRef cert = NULL;
212 CFStringRef commonName = NULL;
214 XCTAssert(cert = SecCertificateCreateWithBytes(NULL, two_common_names, sizeof(two_common_names)), "failed to create cert");
215 XCTAssertEqual(errSecSuccess, SecCertificateCopyCommonName(cert, &commonName),
216 "failed to copy common names");
217 is(CFStringCompare(commonName, CFSTR("certxauthsplit"), 0), kCFCompareEqualTo, "copy common name got the wrong name");
219 CFReleaseSafe(commonName);
223 - (void)testCopyEmailAddresses {
224 SecCertificateRef cert = SecCertificateCreateWithBytes(NULL, mail_google_com, sizeof (mail_google_com));
225 CFArrayRef array = NULL;
226 CFStringRef name = NULL;
228 ok_status(SecCertificateCopyCommonName(cert, &name), "Failed to get common name from cert");
229 ok(name, "Failed to get common name");
230 ok(CFEqual(name, CFSTR("mail.google.com")), "Got wrong common name");
232 ok_status(SecCertificateCopyEmailAddresses (cert, &array), "Failed to get email addresses from cert");
233 ok(array, "Failed to get email address array");
234 is(CFArrayGetCount(array), 0, "Found unexpected email addresses");
238 CFReleaseNull(array);
241 - (void)testCopyExtensionValue {
242 SecCertificateRef cert = SecCertificateCreateWithBytes(NULL, mail_google_com, sizeof(mail_google_com));
243 CFDataRef extension = NULL, expected = NULL, oid = NULL;
244 bool critical = false;
246 /* parameter fails */
247 is(extension = SecCertificateCopyExtensionValue(NULL, CFSTR("1.2.3.4"), &critical), NULL,
248 "NULL cert input succeeded");
249 is(extension = SecCertificateCopyExtensionValue(cert, NULL, &critical), NULL,
250 "NULL OID input succeeded");
252 /* Extension not present */
253 is(extension = SecCertificateCopyExtensionValue(cert, CFSTR("1.2.3.4"), &critical), NULL,
254 "Got extension value for non-present extension OID");
256 /* Using decimal OID, extension present and critical */
257 isnt(extension = SecCertificateCopyExtensionValue(cert, CFSTR("2.5.29.19"), &critical), NULL,
258 "Failed to get extension for present extension OID");
259 is(critical, true, "Got wrong criticality for critical extension");
260 uint8_t basic_constraints_value[2] = { 0x30, 0x00 };
261 expected = CFDataCreate(NULL, basic_constraints_value, sizeof(basic_constraints_value));
262 ok(CFEqual(extension, expected), "Got wrong extension value for basic constraints");
263 CFReleaseNull(extension);
264 CFReleaseNull(expected);
266 /* Using binary OID, extension present and non critical */
267 uint8_t eku_oid[3] = { 0x55, 0x01d, 0x25 };
268 oid = CFDataCreate(NULL, eku_oid, sizeof(eku_oid));
269 isnt(extension = SecCertificateCopyExtensionValue(cert, oid, &critical), NULL,
270 "Failed to get extension for present extension OID");
271 is(critical, false, "Got wrong criticality for non-critical extension");
272 uint8_t eku_value[] = {
273 0x30, 0x1f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06,
274 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x04,
277 expected = CFDataCreate(NULL, eku_value, sizeof(eku_value));
278 ok(CFEqual(extension, expected), "Got wrong extension value for extended key usage");
280 CFReleaseNull(extension);
281 CFReleaseNull(expected);
283 /* No critical output */
284 isnt(extension = SecCertificateCopyExtensionValue(cert, CFSTR("2.5.29.19"), NULL), NULL,
285 "Failed to get extension for present extension OID");
286 CFReleaseNull(extension);
288 /* messed up binary OIDs */
289 is(extension = SecCertificateCopyExtensionValue(cert, CFSTR("abcd"), NULL), NULL,
291 is(extension = SecCertificateCopyExtensionValue(cert, CFSTR("8.1.1.2"), NULL), NULL,
293 is(extension = SecCertificateCopyExtensionValue(cert, CFSTR("10.1.1.1"), NULL), NULL,
294 "longer bad first arc");
295 is(extension = SecCertificateCopyExtensionValue(cert, CFSTR(""), NULL), NULL,
297 is(extension = SecCertificateCopyExtensionValue(cert, CFSTR("1.2.1099511627776."), NULL), NULL,
298 "six byte component");
303 - (void)testCopySerialNumber {
304 SecCertificateRef cert1 = NULL;
305 CFDataRef c1_serial = NULL, serial = NULL;
307 isnt(cert1 = SecCertificateCreateWithBytes(NULL, _c1, sizeof(_c1)),
308 NULL, "create cert1");
310 c1_serial = CFDataCreate(NULL, _c1_serial, sizeof(_c1_serial));
311 CFErrorRef error = NULL;
312 ok(serial = SecCertificateCopySerialNumberData(cert1, &error), "copy cert1 serial");
313 CFReleaseNull(error);
314 ok(CFEqual(c1_serial, serial), "serial matches");
316 CFReleaseNull(serial);
317 CFReleaseNull(c1_serial);
318 CFReleaseNull(cert1);
321 #if !TARGET_OS_BRIDGE // bridgeOS doesn't have a CT log list
322 -(void)testCopyTrustedCTLogs {
323 __block CFDictionaryRef trustedLogs = NULL;
324 __block int matched = 0;
326 require_action(trustedLogs = SecCertificateCopyTrustedCTLogs(),
327 errOut, fail("failed to copy trusted CT logs"));
328 /* look for some known CT log ids to ensure functionality */
329 for (int ix = 0; ix < CTLOG_KEYID_COUNT; ix++) {
330 CFDataRef logIDData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, _ctlogids[ix], CTLOG_KEYID_LENGTH, kCFAllocatorNull);
331 NSString *logIDKey = [(__bridge NSData *)logIDData base64EncodedStringWithOptions:0];
332 CFDictionaryRef logData = CFDictionaryGetValue(trustedLogs, (__bridge CFStringRef)logIDKey);
336 CFReleaseSafe(logIDData);
338 require_action(matched > 0,
339 errOut, fail("failed to match known CT log ids"));
341 CFReleaseSafe(trustedLogs);
343 #endif // !TARGET_OS_BRIDGE
345 #if !TARGET_OS_BRIDGE // bridgeOS doesn't have a CT log list
346 -(void)testCopyCTLogForKeyID {
348 /* look for some known CT log ids to ensure functionality */
349 for (int ix = 0; ix < CTLOG_KEYID_COUNT; ix++) {
350 CFDataRef logIDData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, _ctlogids[ix], CTLOG_KEYID_LENGTH, kCFAllocatorNull);
351 CFDictionaryRef logDict = NULL;
352 const void *operator = NULL;
353 require_action(logDict = SecCertificateCopyCTLogForKeyID(logIDData),
354 errContinue, fail("failed to match CT log"));
355 require_action(isDictionary(logDict),
356 errContinue, fail("returned CT log is not a dictionary"));
357 require_action(CFDictionaryGetValueIfPresent(logDict, CFSTR("operator"), &operator),
358 errContinue, fail("operator value is not present"));
359 require_action(isString(operator),
360 errContinue, fail("operator value is not a string"));
365 CFReleaseNull(logDict);
366 CFReleaseNull(logIDData);
368 require_action(matched > 0,
369 errOut, fail("failed to match known CT log ids"));
373 #endif // !TARGET_OS_BRIDGE
375 - (void)testDeveloperIdDate {
376 SecCertificateRef old_devid = SecCertificateCreateWithBytes(NULL, _old_developer_cert, sizeof(_old_developer_cert));
377 SecCertificateRef new_devid = SecCertificateCreateWithBytes(NULL, _new_developer_cert, sizeof(_new_developer_cert));
379 CFErrorRef error = NULL;
381 is(SecCertificateGetDeveloperIDDate(old_devid, &time, &error), false, "old Developer ID cert returned date");
382 is(CFErrorGetCode(error), errSecMissingRequiredExtension, "old Developer ID cert failed with wrong error code");
383 CFReleaseNull(error);
385 ok(SecCertificateGetDeveloperIDDate(new_devid, &time, &error), "new developer ID cert failed to copy date");
386 is(time, 573436800.0, "date in certificate wasn't 2019-03-05 00:00:00Z");
388 CFReleaseNull(old_devid);
389 CFReleaseNull(new_devid);
392 - (void)testSecFrameworkIsDNSName {
393 const char *valid_names[] = {
395 "127.0.0.1.example.com",
398 "example.xn--3hcrj9c",
399 "example.xn--80ao21a",
402 const char *invalid_names[] = {
403 /* Error: All-numeric TLD. */
406 /* Error: Label begins with a hyphen. */
408 /* Error: Label ends with a hyphen. */
410 /* Error: TLD begins with a hyphen. */
412 /* Error: TLD ends with a hyphen. */
414 /* Error: Label has invalid characters. */
419 for (i = 0; i < sizeof(valid_names) / sizeof(valid_names[0]); i++) {
420 CFStringRef name = CFStringCreateWithCString(NULL, valid_names[i], kCFStringEncodingUTF8);
421 XCTAssertTrue(name != NULL);
422 XCTAssertTrue(SecFrameworkIsDNSName(name), "Valid host name '%s' failed to be parsed as such.", valid_names[i]);
426 for (i = 0; i < sizeof(invalid_names) / sizeof(invalid_names[0]); i++) {
427 CFStringRef name = CFStringCreateWithCString(NULL, invalid_names[i], kCFStringEncodingUTF8);
428 XCTAssertTrue(name != NULL);
429 XCTAssertFalse(SecFrameworkIsDNSName(name), "Invalid host name '%s' failed to be parsed as such.", invalid_names[i]);
434 - (void)testSecFrameworkIsIPAddress {
435 const char *valid_addrs[] = {
436 "127.0.0.1", /* localhost IPv4 */
437 "162.159.36.1", /* WAN IPv4 */
438 "::", /* all-zeros IPv6 address */
439 "::1", /* localhost IPv6, leading zero expansion */
440 "cafe:feed:face::1", /* inline zero expansion */
441 "cafe:FEED:FACE::", /* trailing zero expansion */
442 "2606:4700:4700::1111", /* compressed */
443 "2606:4700:4700:0:0:0:0:1111", /* uncompressed */
444 "[2606:4700:4700:0:0:0:0:1111]", /* literal form (for URLs) */
447 const char *invalid_addrs[] = {
448 "apple.com.1", /* invalid characters */
449 "284.321.1.1", /* IPv4 octet values > 255 */
450 "192.168.254.0/24", /* CIDR notation; not for SAN values */
451 "2606:4700:4700::1111::1" /* multiple IPv6 expansions */
452 "[2606:4700:4700:[0:0:0:0]:1111]", /* too many brackets */
453 "...1", /* not enough fields for IPv4 */
454 "23.45.56.67.78", /* too many fields */
455 ":1", /* not enough fields for IPv6 */
456 "100:90:80:70:60:50:40:30:20:10", /* too many fields */
457 "2600:f00000000d::1", /* invalid IPv6 octet value */
458 "cov:fefe::1", /* invalid characters */
462 for (i = 0; i < sizeof(valid_addrs) / sizeof(valid_addrs[0]); i++) {
463 CFStringRef addr = CFStringCreateWithCString(NULL, valid_addrs[i], kCFStringEncodingUTF8);
464 XCTAssertTrue(addr != NULL);
465 XCTAssertTrue(SecFrameworkIsIPAddress(addr), "Valid IP address '%s' failed to be parsed as such.", valid_addrs[i]);
469 for (i = 0; i < sizeof(invalid_addrs) / sizeof(invalid_addrs[0]); i++) {
470 CFStringRef addr = CFStringCreateWithCString(NULL, invalid_addrs[i], kCFStringEncodingUTF8);
471 XCTAssertTrue(addr != NULL);
472 XCTAssertFalse(SecFrameworkIsIPAddress(addr), "Invalid IP address '%s' failed to be parsed as such.", invalid_addrs[i]);
477 - (void)testSecFrameworkCopyIPAddressData {
478 unsigned char ipv4_data[4] = {
479 0xA2, 0x9F, 0x84, 0x35 };
480 unsigned char ipv6_data[16] = {
481 0x26, 0x06, 0x47, 0x00, 0x47, 0x00, 0x00, 0x00,
482 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11 };
484 CFDataRef data4 = NULL, result4 = NULL;
485 CFDataRef data6 = NULL, result6 = NULL;
487 data4 = CFDataCreate(NULL, ipv4_data, sizeof(ipv4_data));
488 XCTAssertTrue(data4 != NULL);
489 result4 = SecFrameworkCopyIPAddressData(CFSTR("162.159.132.53"));
490 XCTAssertTrue(result4 != NULL);
491 XCTAssertTrue(CFEqual(result4, data4));
495 data6 = CFDataCreate(NULL, ipv6_data, sizeof(ipv6_data));
496 XCTAssertTrue(data6 != NULL);
497 result6 = SecFrameworkCopyIPAddressData(CFSTR("2606:4700:4700::1111"));
498 XCTAssertTrue(result6 != NULL);
499 XCTAssertTrue(CFEqual(result6, data6));