1
2//
3//  si-68-secmatchissuer.c
4//  regressions
5//
6//  Created by Conrad Sauerwald on 6/18/12.
7//
8//
9#include <CoreFoundation/CoreFoundation.h>
10#include <Security/Security.h>
11#include <libDER/libDER.h>
12#include <libDER/DER_Decode.h>
13#include <libDER/asn1Types.h>
14#include <Security/SecCertificateInternal.h>
15#include <Security/SecCertificatePriv.h>
16#include <Security/SecIdentityPriv.h>
17#include <Security/SecItem.h>
18#include <Security/SecInternal.h>
19#include <utilities/array_size.h>
20
21#include "Security_regressions.h"
22#include <test/testcert.h>
23
24/*
25static OSStatus add_item_to_keychain(CFTypeRef item, CFDataRef * persistent_ref)
26{
27    const void *keys[] = { kSecValueRef, kSecReturnPersistentRef };
28    const void *vals[] = { item, kCFBooleanTrue };
29    CFDictionaryRef add_query = CFDictionaryCreate(NULL, keys, vals, array_size(keys), NULL, NULL);
30    OSStatus status = errSecAllocate;
31    if (add_query) {
32        status = SecItemAdd(add_query, (CFTypeRef *)persistent_ref);
33        CFRelease(add_query);
34    }
35    return status;
36}
37
38static OSStatus remove_item_from_keychain(CFTypeRef item, CFDataRef * persistent_ref)
39{
40    const void *keys[] = { kSecValueRef, kSecReturnPersistentRef };
41    const void *vals[] = { item, kCFBooleanTrue };
42    CFDictionaryRef add_query = CFDictionaryCreate(NULL, keys, vals, array_size(keys), NULL, NULL);
43    OSStatus status = errSecAllocate;
44    if (add_query) {
45        status = SecItemAdd(add_query, (CFTypeRef *)persistent_ref);
46        CFRelease(add_query);
47    }
48    return status;
49}
50*/
51
52static OSStatus add_item(CFTypeRef item)
53{
54    CFDictionaryRef add_query = CFDictionaryCreate(NULL, &kSecValueRef, &item, 1, NULL, NULL);
55    OSStatus status = SecItemAdd(add_query, NULL);
56    CFRelease(add_query);
57    return status;
58}
59
60static OSStatus remove_item(CFTypeRef item)
61{
62    CFDictionaryRef remove_query = CFDictionaryCreate(NULL, &kSecValueRef, &item, 1, NULL, NULL);
63    OSStatus status = SecItemDelete(remove_query);
64    CFRelease(remove_query);
65    return status;
66}
67
68static void tests(void)
69{
70
71// MARK: test SecDistinguishedNameCopyNormalizedContent
72
73    unsigned char example_dn[] = {
74        0x30, 0x4f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
75        0x02, 0x43, 0x5a, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x0a,
76        0x0c, 0x1e, 0x4d, 0x69, 0x6e, 0x69, 0x73, 0x74, 0x65, 0x72, 0x73, 0x74,
77        0x76, 0x6f, 0x20, 0x73, 0x70, 0x72, 0x61, 0x76, 0x65, 0x64, 0x6c, 0x6e,
78        0x6f, 0x73, 0x74, 0x69, 0x20, 0xc4, 0x8c, 0x52, 0x31, 0x17, 0x30, 0x15,
79        0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0e, 0x4d, 0x53, 0x70, 0x20, 0x52,
80        0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x30, 0x31
81    };
82    unsigned int example_dn_len = 81;
83
84    CFDataRef normalized_dn = NULL, dn = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, example_dn, example_dn_len, kCFAllocatorNull);
85    ok(dn, "got dn as data");
86    ok(normalized_dn = SecDistinguishedNameCopyNormalizedContent(dn), "convert to normalized form");
87    //CFShow(dn);
88    //CFShow(normalized_dn);
89    CFReleaseNull(dn);
90    CFReleaseNull(normalized_dn);
91
92// MARK: generate certificate hierarchy
93
94	SecKeyRef public_key = NULL, private_key = NULL;
95    ok_status(test_cert_generate_key(512, kSecAttrKeyTypeRSA, &private_key, &public_key), "generate keypair");
96	// make organization random uuid to avoid previous run to spoil the fun
97
98    CFUUIDRef UUID = CFUUIDCreate(kCFAllocatorDefault);
99    CFStringRef uuidString = CFUUIDCreateString(kCFAllocatorDefault, UUID);
100    CFStringRef root_authority_name = CFStringCreateWithFormat(kCFAllocatorDefault, 0, CFSTR("O=%@,CN=Root CA"), uuidString);
101    CFStringRef intermediate_authority_name = CFStringCreateWithFormat(kCFAllocatorDefault, 0, CFSTR("O=%@,CN=Intermediate CA"), uuidString);
102    CFStringRef leaf_name = CFStringCreateWithFormat(kCFAllocatorDefault, 0, CFSTR("O=%@,CN=Client"), uuidString);
103    CFRelease(uuidString);
104    CFRelease(UUID);
105
106    SecIdentityRef ca_identity =
107        test_cert_create_root_certificate(root_authority_name, public_key, private_key);
108    CFRelease(root_authority_name);
109
110    SecCertificateRef ca_cert = NULL;
111    SecIdentityCopyCertificate(ca_identity, &ca_cert);
112    //CFShow(ca_cert);
113
114	SecCertificateRef intermediate_cert =
115        test_cert_issue_certificate(ca_identity, public_key, intermediate_authority_name, 42, kSecKeyUsageKeyCertSign);
116    CFRelease(intermediate_authority_name);
117    SecIdentityRef intermediate_identity = SecIdentityCreate(kCFAllocatorDefault, intermediate_cert, private_key);
118
119    ok_status(add_item(intermediate_cert), "add intermediate");
120    //CFShow(intermediate_cert);
121
122	SecCertificateRef leaf_cert = test_cert_issue_certificate(intermediate_identity, public_key,
123          leaf_name, 4242, kSecKeyUsageDigitalSignature);
124    CFRelease(leaf_name);
125    SecIdentityRef leaf_identity = SecIdentityCreate(kCFAllocatorDefault, leaf_cert, private_key);
126
127    ok_status(add_item(leaf_identity), "add leaf");
128    //CFShow(leaf_cert);
129
130    // this is already canonical - see if we can get the raw one
131    CFDataRef issuer = SecCertificateGetNormalizedIssuerContent(intermediate_cert);
132    ok(CFDataGetLength(issuer) < 128, "max 127 bytes of content - or else you'll need to properly encode issuer sequence");
133    CFMutableDataRef canonical_issuer = CFDataCreateMutable(kCFAllocatorDefault, CFDataGetLength(issuer) + 2);
134    CFDataSetLength(canonical_issuer, CFDataGetLength(issuer) + 2);
135    uint8_t * ptr = CFDataGetMutableBytePtr(canonical_issuer);
136    memcpy(ptr+2, CFDataGetBytePtr(issuer), CFDataGetLength(issuer));
137    ptr[0] = 0x30;
138    ptr[1] = CFDataGetLength(issuer);
139
140    CFMutableArrayRef all_distinguished_names = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
141    CFArrayAppendValue(all_distinguished_names, canonical_issuer);
142
143    {
144        CFReleaseNull(canonical_issuer);
145        const void *keys[] = { kSecClass, kSecReturnRef, kSecMatchLimit, kSecMatchIssuers };
146        const void *vals[] = { kSecClassIdentity, kCFBooleanTrue, kSecMatchLimitAll, all_distinguished_names };
147        CFDictionaryRef all_identities_query = CFDictionaryCreate(kCFAllocatorDefault, keys, vals, array_size(keys), NULL, NULL);
148        CFTypeRef all_matching_identities = NULL;
149        ok_status(SecItemCopyMatching(all_identities_query, &all_matching_identities), "find all identities matching");
150        CFReleaseNull(all_identities_query);
151        ok(((CFArrayGetTypeID() == CFGetTypeID(all_matching_identities)) && (CFArrayGetCount(all_matching_identities) == 2)), "return 2");
152        //CFShow(all_matching_identities);
153    }
154
155    {
156        int limit = 0x7fff; // To regress-test <rdar://problem/14603111>
157        CFNumberRef cfLimit = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &limit);
158        const void *keys[] = { kSecClass, kSecReturnRef, kSecMatchLimit, kSecMatchIssuers };
159        const void *vals[] = { kSecClassCertificate, kCFBooleanTrue, cfLimit, all_distinguished_names };
160        CFDictionaryRef all_identities_query = CFDictionaryCreate(kCFAllocatorDefault, keys, vals, array_size(keys), NULL, NULL);
161        CFTypeRef all_matching_certificates = NULL;
162        ok_status(SecItemCopyMatching(all_identities_query, &all_matching_certificates), "find all certificates matching");
163        CFReleaseNull(all_identities_query);
164        ok(((CFArrayGetTypeID() == CFGetTypeID(all_matching_certificates)) && (CFArrayGetCount(all_matching_certificates) == 2)), "return 2");
165        //CFShow(all_matching_certificates);
166        CFReleaseSafe(cfLimit);
167    }
168
169    remove_item(leaf_identity);
170    CFRelease(leaf_identity);
171    CFRelease(leaf_cert);
172
173    remove_item(intermediate_cert);
174    CFRelease(intermediate_cert);
175    CFRelease(intermediate_identity);
176
177    CFRelease(ca_cert);
178    CFRelease(ca_identity);
179
180    CFRelease(public_key);
181    CFRelease(private_key);
182
183}
184
185int si_68_secmatchissuer(int argc, char *const *argv)
186{
187	plan_tests(10);
188
189	tests();
190
191	return 0;
192}
193