2 * Copyright (c) 2012-2014 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@
26 // si-68-secmatchissuer.c
31 #include <CoreFoundation/CoreFoundation.h>
32 #include <Security/Security.h>
33 #include <libDER/libDER.h>
34 #include <libDER/DER_Decode.h>
35 #include <libDER/asn1Types.h>
36 #include <Security/SecCertificateInternal.h>
37 #include <Security/SecCertificatePriv.h>
38 #include <Security/SecIdentityPriv.h>
39 #include <Security/SecItem.h>
40 #include <Security/SecInternal.h>
41 #include <utilities/array_size.h>
43 #include "Security_regressions.h"
44 #include <test/testcert.h>
47 static OSStatus add_item_to_keychain(CFTypeRef item, CFDataRef * persistent_ref)
49 const void *keys[] = { kSecValueRef, kSecReturnPersistentRef };
50 const void *vals[] = { item, kCFBooleanTrue };
51 CFDictionaryRef add_query = CFDictionaryCreate(NULL, keys, vals, array_size(keys), NULL, NULL);
52 OSStatus status = errSecAllocate;
54 status = SecItemAdd(add_query, (CFTypeRef *)persistent_ref);
60 static OSStatus remove_item_from_keychain(CFTypeRef item, CFDataRef * persistent_ref)
62 const void *keys[] = { kSecValueRef, kSecReturnPersistentRef };
63 const void *vals[] = { item, kCFBooleanTrue };
64 CFDictionaryRef add_query = CFDictionaryCreate(NULL, keys, vals, array_size(keys), NULL, NULL);
65 OSStatus status = errSecAllocate;
67 status = SecItemAdd(add_query, (CFTypeRef *)persistent_ref);
74 static OSStatus
add_item(CFTypeRef item
)
76 CFDictionaryRef add_query
= CFDictionaryCreate(NULL
, (const void **)&kSecValueRef
, &item
, 1, NULL
, NULL
);
77 OSStatus status
= SecItemAdd(add_query
, NULL
);
82 static OSStatus
remove_item(CFTypeRef item
)
84 CFDictionaryRef remove_query
= CFDictionaryCreate(NULL
, (const void **)&kSecValueRef
, &item
, 1, NULL
, NULL
);
85 OSStatus status
= SecItemDelete(remove_query
);
86 CFRelease(remove_query
);
90 static void tests(void)
93 // MARK: test SecDistinguishedNameCopyNormalizedContent
95 unsigned char example_dn
[] = {
96 0x30, 0x4f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
97 0x02, 0x43, 0x5a, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x0a,
98 0x0c, 0x1e, 0x4d, 0x69, 0x6e, 0x69, 0x73, 0x74, 0x65, 0x72, 0x73, 0x74,
99 0x76, 0x6f, 0x20, 0x73, 0x70, 0x72, 0x61, 0x76, 0x65, 0x64, 0x6c, 0x6e,
100 0x6f, 0x73, 0x74, 0x69, 0x20, 0xc4, 0x8c, 0x52, 0x31, 0x17, 0x30, 0x15,
101 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0e, 0x4d, 0x53, 0x70, 0x20, 0x52,
102 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x30, 0x31
104 unsigned int example_dn_len
= 81;
106 CFDataRef normalized_dn
= NULL
, dn
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, example_dn
, example_dn_len
, kCFAllocatorNull
);
107 ok(dn
, "got dn as data");
108 ok(normalized_dn
= SecDistinguishedNameCopyNormalizedContent(dn
), "convert to normalized form");
110 //CFShow(normalized_dn);
112 CFReleaseNull(normalized_dn
);
114 // MARK: generate certificate hierarchy
116 SecKeyRef public_key
= NULL
, private_key
= NULL
;
117 ok_status(test_cert_generate_key(512, kSecAttrKeyTypeRSA
, &private_key
, &public_key
), "generate keypair");
118 // make organization random uuid to avoid previous run to spoil the fun
120 CFUUIDRef UUID
= CFUUIDCreate(kCFAllocatorDefault
);
121 CFStringRef uuidString
= CFUUIDCreateString(kCFAllocatorDefault
, UUID
);
122 CFStringRef root_authority_name
= CFStringCreateWithFormat(kCFAllocatorDefault
, 0, CFSTR("O=%@,CN=Root CA"), uuidString
);
123 CFStringRef intermediate_authority_name
= CFStringCreateWithFormat(kCFAllocatorDefault
, 0, CFSTR("O=%@,CN=Intermediate CA"), uuidString
);
124 CFStringRef leaf_name
= CFStringCreateWithFormat(kCFAllocatorDefault
, 0, CFSTR("O=%@,CN=Client"), uuidString
);
125 CFRelease(uuidString
);
128 SecIdentityRef ca_identity
=
129 test_cert_create_root_certificate(root_authority_name
, public_key
, private_key
);
130 CFRelease(root_authority_name
);
132 SecCertificateRef ca_cert
= NULL
;
133 SecIdentityCopyCertificate(ca_identity
, &ca_cert
);
136 SecCertificateRef intermediate_cert
=
137 test_cert_issue_certificate(ca_identity
, public_key
, intermediate_authority_name
, 42, kSecKeyUsageKeyCertSign
);
138 CFRelease(intermediate_authority_name
);
139 SecIdentityRef intermediate_identity
= SecIdentityCreate(kCFAllocatorDefault
, intermediate_cert
, private_key
);
141 ok_status(add_item(intermediate_cert
), "add intermediate");
142 //CFShow(intermediate_cert);
144 SecCertificateRef leaf_cert
= test_cert_issue_certificate(intermediate_identity
, public_key
,
145 leaf_name
, 4242, kSecKeyUsageDigitalSignature
);
146 CFRelease(leaf_name
);
147 SecIdentityRef leaf_identity
= SecIdentityCreate(kCFAllocatorDefault
, leaf_cert
, private_key
);
149 ok_status(add_item(leaf_identity
), "add leaf");
152 // this is already canonical - see if we can get the raw one
153 CFDataRef issuer
= SecCertificateGetNormalizedIssuerContent(intermediate_cert
);
154 ok(CFDataGetLength(issuer
) < 128, "max 127 bytes of content - or else you'll need to properly encode issuer sequence");
155 CFMutableDataRef canonical_issuer
= CFDataCreateMutable(kCFAllocatorDefault
, CFDataGetLength(issuer
) + 2);
156 CFDataSetLength(canonical_issuer
, CFDataGetLength(issuer
) + 2);
157 uint8_t * ptr
= CFDataGetMutableBytePtr(canonical_issuer
);
158 memcpy(ptr
+2, CFDataGetBytePtr(issuer
), CFDataGetLength(issuer
));
160 ptr
[1] = CFDataGetLength(issuer
);
162 CFMutableArrayRef all_distinguished_names
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
163 CFArrayAppendValue(all_distinguished_names
, canonical_issuer
);
166 CFReleaseNull(canonical_issuer
);
167 const void *keys
[] = { kSecClass
, kSecReturnRef
, kSecMatchLimit
, kSecMatchIssuers
};
168 const void *vals
[] = { kSecClassIdentity
, kCFBooleanTrue
, kSecMatchLimitAll
, all_distinguished_names
};
169 CFDictionaryRef all_identities_query
= CFDictionaryCreate(kCFAllocatorDefault
, keys
, vals
, array_size(keys
), NULL
, NULL
);
170 CFTypeRef all_matching_identities
= NULL
;
171 ok_status(SecItemCopyMatching(all_identities_query
, &all_matching_identities
), "find all identities matching");
172 CFReleaseNull(all_identities_query
);
173 ok(((CFArrayGetTypeID() == CFGetTypeID(all_matching_identities
)) && (CFArrayGetCount(all_matching_identities
) == 2)), "return 2");
174 //CFShow(all_matching_identities);
178 int limit
= 0x7fff; // To regress-test <rdar://problem/14603111>
179 CFNumberRef cfLimit
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberIntType
, &limit
);
180 const void *keys
[] = { kSecClass
, kSecReturnRef
, kSecMatchLimit
, kSecMatchIssuers
};
181 const void *vals
[] = { kSecClassCertificate
, kCFBooleanTrue
, cfLimit
, all_distinguished_names
};
182 CFDictionaryRef all_identities_query
= CFDictionaryCreate(kCFAllocatorDefault
, keys
, vals
, array_size(keys
), NULL
, NULL
);
183 CFTypeRef all_matching_certificates
= NULL
;
184 ok_status(SecItemCopyMatching(all_identities_query
, &all_matching_certificates
), "find all certificates matching");
185 CFReleaseNull(all_identities_query
);
186 ok(((CFArrayGetTypeID() == CFGetTypeID(all_matching_certificates
)) && (CFArrayGetCount(all_matching_certificates
) == 2)), "return 2");
187 //CFShow(all_matching_certificates);
188 CFReleaseSafe(cfLimit
);
191 remove_item(leaf_identity
);
192 CFRelease(leaf_identity
);
193 CFRelease(leaf_cert
);
195 remove_item(intermediate_cert
);
196 CFRelease(intermediate_cert
);
197 CFRelease(intermediate_identity
);
200 CFRelease(ca_identity
);
202 CFRelease(public_key
);
203 CFRelease(private_key
);
207 int si_68_secmatchissuer(int argc
, char *const *argv
)