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