3 // si-68-secmatchissuer.c
6 // Created by Conrad Sauerwald on 6/18/12.
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>
21 #include "Security_regressions.h"
22 #include <test/testcert.h>
25 static OSStatus add_item_to_keychain(CFTypeRef item, CFDataRef * persistent_ref)
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;
32 status = SecItemAdd(add_query, (CFTypeRef *)persistent_ref);
38 static OSStatus remove_item_from_keychain(CFTypeRef item, CFDataRef * persistent_ref)
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;
45 status = SecItemAdd(add_query, (CFTypeRef *)persistent_ref);
52 static OSStatus
add_item(CFTypeRef item
)
54 CFDictionaryRef add_query
= CFDictionaryCreate(NULL
, &kSecValueRef
, &item
, 1, NULL
, NULL
);
55 OSStatus status
= SecItemAdd(add_query
, NULL
);
60 static OSStatus
remove_item(CFTypeRef item
)
62 CFDictionaryRef remove_query
= CFDictionaryCreate(NULL
, &kSecValueRef
, &item
, 1, NULL
, NULL
);
63 OSStatus status
= SecItemDelete(remove_query
);
64 CFRelease(remove_query
);
68 static void tests(void)
71 // MARK: test SecDistinguishedNameCopyNormalizedContent
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
82 unsigned int example_dn_len
= 81;
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");
88 //CFShow(normalized_dn);
90 CFReleaseNull(normalized_dn
);
92 // MARK: generate certificate hierarchy
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
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
);
106 SecIdentityRef ca_identity
=
107 test_cert_create_root_certificate(root_authority_name
, public_key
, private_key
);
108 CFRelease(root_authority_name
);
110 SecCertificateRef ca_cert
= NULL
;
111 SecIdentityCopyCertificate(ca_identity
, &ca_cert
);
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
);
119 ok_status(add_item(intermediate_cert
), "add intermediate");
120 //CFShow(intermediate_cert);
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
);
127 ok_status(add_item(leaf_identity
), "add leaf");
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
));
138 ptr
[1] = CFDataGetLength(issuer
);
140 CFMutableArrayRef all_distinguished_names
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
141 CFArrayAppendValue(all_distinguished_names
, canonical_issuer
);
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);
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
);
169 remove_item(leaf_identity
);
170 CFRelease(leaf_identity
);
171 CFRelease(leaf_cert
);
173 remove_item(intermediate_cert
);
174 CFRelease(intermediate_cert
);
175 CFRelease(intermediate_identity
);
178 CFRelease(ca_identity
);
180 CFRelease(public_key
);
181 CFRelease(private_key
);
185 int si_68_secmatchissuer(int argc
, char *const *argv
)