1/*
2 * Copyright (c) 2012-2014 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
25//
26//  si-68-secmatchissuer.c
27//  regressions
28//
29//
30//
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>
42
43#include "Security_regressions.h"
44#include <test/testcert.h>
45
46/*
47static OSStatus add_item_to_keychain(CFTypeRef item, CFDataRef * persistent_ref)
48{
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;
53    if (add_query) {
54        status = SecItemAdd(add_query, (CFTypeRef *)persistent_ref);
55        CFRelease(add_query);
56    }
57    return status;
58}
59
60static OSStatus remove_item_from_keychain(CFTypeRef item, CFDataRef * persistent_ref)
61{
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;
66    if (add_query) {
67        status = SecItemAdd(add_query, (CFTypeRef *)persistent_ref);
68        CFRelease(add_query);
69    }
70    return status;
71}
72*/
73
74static OSStatus add_item(CFTypeRef item)
75{
76    CFDictionaryRef add_query = CFDictionaryCreate(NULL, &kSecValueRef, &item, 1, NULL, NULL);
77    OSStatus status = SecItemAdd(add_query, NULL);
78    CFRelease(add_query);
79    return status;
80}
81
82static OSStatus remove_item(CFTypeRef item)
83{
84    CFDictionaryRef remove_query = CFDictionaryCreate(NULL, &kSecValueRef, &item, 1, NULL, NULL);
85    OSStatus status = SecItemDelete(remove_query);
86    CFRelease(remove_query);
87    return status;
88}
89
90static void tests(void)
91{
92
93// MARK: test SecDistinguishedNameCopyNormalizedContent
94
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
103    };
104    unsigned int example_dn_len = 81;
105
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");
109    //CFShow(dn);
110    //CFShow(normalized_dn);
111    CFReleaseNull(dn);
112    CFReleaseNull(normalized_dn);
113
114// MARK: generate certificate hierarchy
115
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
119
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);
126    CFRelease(UUID);
127
128    SecIdentityRef ca_identity =
129        test_cert_create_root_certificate(root_authority_name, public_key, private_key);
130    CFRelease(root_authority_name);
131
132    SecCertificateRef ca_cert = NULL;
133    SecIdentityCopyCertificate(ca_identity, &ca_cert);
134    //CFShow(ca_cert);
135
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);
140
141    ok_status(add_item(intermediate_cert), "add intermediate");
142    //CFShow(intermediate_cert);
143
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);
148
149    ok_status(add_item(leaf_identity), "add leaf");
150    //CFShow(leaf_cert);
151
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));
159    ptr[0] = 0x30;
160    ptr[1] = CFDataGetLength(issuer);
161
162    CFMutableArrayRef all_distinguished_names = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
163    CFArrayAppendValue(all_distinguished_names, canonical_issuer);
164
165    {
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);
175    }
176
177    {
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);
189    }
190
191    remove_item(leaf_identity);
192    CFRelease(leaf_identity);
193    CFRelease(leaf_cert);
194
195    remove_item(intermediate_cert);
196    CFRelease(intermediate_cert);
197    CFRelease(intermediate_identity);
198
199    CFRelease(ca_cert);
200    CFRelease(ca_identity);
201
202    CFRelease(public_key);
203    CFRelease(private_key);
204
205}
206
207int si_68_secmatchissuer(int argc, char *const *argv)
208{
209	plan_tests(10);
210
211	tests();
212
213	return 0;
214}
215