]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/regressions/kc-06-cert-search-email.m
Security-57740.31.2.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / regressions / kc-06-cert-search-email.m
1 /*
2 * Copyright (c) 2016 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 xLicense.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #import <Security/Security.h>
25 #import <Security/SecCertificatePriv.h>
26
27 #include "keychain_regressions.h"
28 #include "kc-helpers.h"
29 #include "kc-item-helpers.h"
30 #include "kc-key-helpers.h"
31
32 #import <Foundation/Foundation.h>
33
34 #include <Security/SecCertificate.h>
35 #include <Security/SecPolicyPriv.h>
36 #include <Security/SecPolicySearch.h>
37 #include <Security/SecIdentity.h>
38 #include <Security/SecIdentityPriv.h>
39 #include <Security/SecIdentitySearch.h>
40 #include <Security/SecIdentitySearchPriv.h>
41 #include <Security/SecTrust.h>
42 #include <Security/SecKeychain.h>
43 #include <Security/SecKeychainItem.h>
44 #include <Security/SecKeychainItemPriv.h>
45 #include <SecurityFoundation/SFCertificateData.h>
46 #include <Security/oidsalg.h>
47
48
49 static NSString* printDataAsHex(
50 const CSSM_DATA *d)
51 {
52 if (!d || !d->Data) return NULL;
53
54 unsigned int i;
55 CSSM_SIZE len = d->Length;
56 uint8 *cp = d->Data;
57 NSString *str = [NSString string];
58
59 for(i=0; i<len; i++) {
60 str = [str stringByAppendingFormat:@"%02X", ((unsigned char *)cp)[i]];
61 }
62 return str;
63 }
64
65 static NSString* printDigest(
66 CSSM_ALGORITHMS digestAlgorithm,
67 const CSSM_DATA* thingToDigest)
68 {
69 CSSM_RETURN crtn;
70 CSSM_DATA digest;
71 uint8 buf[64]; // we really only expect 16 or 20 byte digests, but...
72
73 digest.Data = buf;
74 digest.Length = sizeof(buf);
75 crtn = SecDigestGetData (digestAlgorithm, &digest, thingToDigest);
76
77 if (crtn || !digest.Length) return NULL;
78 return printDataAsHex(&digest);
79 }
80
81 static void printCertificate(SecCertificateRef certificate, SecPolicyRef policy, int ordinalValue)
82 {
83 CSSM_DATA certData = { 0, nil };
84 (void) SecCertificateGetData(certificate, &certData);
85 NSString *digestStr = printDigest(CSSM_ALGID_MD5, &certData);
86 const char *digest = [digestStr UTF8String];
87 fprintf(stdout, "%3d) %s", ordinalValue, (digest) ? digest : "!-- unable to get md5 digest --!");
88
89 CFStringRef label=nil;
90 OSStatus status = SecCertificateInferLabel(certificate, &label);
91 if (!status && label)
92 {
93 char buf[1024];
94 if (!CFStringGetCString(label, buf, 1024-1, kCFStringEncodingUTF8))
95 buf[0]=0;
96 fprintf(stdout, " \"%s\"", buf);
97 CFRelease(label);
98 }
99
100 // Default to X.509 Basic if no policy was specified
101 if (!policy) {
102 SecPolicySearchRef policySearch = NULL;
103 if (SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &policySearch)==noErr) {
104 SecPolicySearchCopyNext(policySearch, &policy);
105 }
106 [(id)policySearch release];
107 } else {
108 [(id)policy retain];
109 }
110
111 // Create a trust reference, given policy and certificates
112 SecTrustRef trust=nil;
113 NSArray *certificates = [NSArray arrayWithObject:(id)certificate];
114 status = SecTrustCreateWithCertificates((CFArrayRef)certificates, policy, &trust);
115
116 SFCertificateData *sfCertData = [[SFCertificateData alloc] initWithCertificate:certificate trust:trust parse:NO];
117 const char *statusStr = [[sfCertData statusString] UTF8String];
118 // Skip the status string if the certificate is valid, but print it otherwise
119 if (statusStr && (strcmp(statusStr, "This certificate is valid") != 0))
120 fprintf(stdout, " (%s)", statusStr);
121 fprintf(stdout, "\n");
122 [sfCertData release];
123
124 [(id)trust release];
125 [(id)policy release];
126 }
127
128 static BOOL certificateHasExpired(SecCertificateRef certificate)
129 {
130 SFCertificateData *sfCertData = [[SFCertificateData alloc] initWithCertificate:certificate trust:nil parse:NO];
131 BOOL result = [sfCertData expired];
132 [sfCertData release];
133
134 return result;
135 }
136
137 static void doCertificateSearchForEmailAddress(SecKeychainRef kc, const char *emailAddr, bool showAll)
138 {
139 OSStatus status = errSecSuccess;
140
141 // Enumerate matching certificates
142 fprintf(stdout, "%s certificates matching \"%s\":\n", (showAll) ? "All" : "Valid", emailAddr);
143 SecKeychainSearchRef searchRef;
144 status = SecKeychainSearchCreateForCertificateByEmail(kc, emailAddr, &searchRef);
145 ok_status(status, "%s: SecKeychainSearchCreateForCertificateByEmail", testName);
146
147 SecCertificateRef preferredCert = nil;
148 CFStringRef emailStr = (emailAddr) ? CFStringCreateWithCStringNoCopy(NULL, emailAddr, kCFStringEncodingUTF8, kCFAllocatorNull) : NULL;
149
150 if (!status) {
151 SecKeychainItemRef itemRef=nil;
152 unsigned int i=0;
153 while (SecKeychainSearchCopyNext(searchRef, &itemRef)==noErr) {
154 if (showAll || !certificateHasExpired((SecCertificateRef)itemRef)) {
155 printCertificate((SecCertificateRef)itemRef, nil, ++i);
156 }
157
158 // Set this certificate as preferred for this email address
159 ok_status(SecCertificateSetPreferred((SecCertificateRef)itemRef, emailStr, 0), "%s: SecCertificateSetPreferred", testName);
160
161 CFRelease(itemRef);
162 }
163 is(i, 1, "%s: Wrong number of certificates found", testName);
164
165 CFRelease(searchRef);
166 }
167
168 // Check that our certificate is new preferred
169 status = SecCertificateCopyPreference(emailStr, (CSSM_KEYUSE) 0, &preferredCert);
170 ok_status(status, "%s: SecCertificateCopyPreference", testName);
171
172 if (preferredCert)
173 CFRelease(preferredCert);
174 if (emailStr)
175 CFRelease(emailStr);
176 }
177
178 int kc_06_cert_search_email(int argc, char *const *argv)
179 {
180 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
181 unsigned int i;
182 const char *emailAddr = NULL;
183 bool showAll = false;
184
185 plan_tests(7);
186 initializeKeychainTests(__FUNCTION__);
187
188 // Delete any existing preferences for our certificate, but don't test
189 // status since maybe it doesn't exist yet
190 CFMutableDictionaryRef q = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
191 CFDictionarySetValue(q, kSecClass, kSecClassGenericPassword);
192 q = addLabel(q, CFSTR("nobody_certificate@apple.com"));
193 SecItemDelete(q);
194
195
196 SecKeychainRef kc = getPopulatedTestKeychain();
197 addToSearchList(kc);
198
199 doCertificateSearchForEmailAddress(kc, "nobody_certificate@apple.com", showAll);
200
201 ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", testName);
202 CFReleaseNull(kc);
203
204 deleteTestFiles();
205 [pool release];
206 return 0;
207 }