]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/regressions/kc-06-cert-search-email.m
Security-58286.51.6.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 }
107
108 // Create a trust reference, given policy and certificates
109 SecTrustRef trust=nil;
110 NSArray *certificates = [NSArray arrayWithObject:(__bridge id)certificate];
111 status = SecTrustCreateWithCertificates((CFArrayRef)certificates, policy, &trust);
112
113 SFCertificateData *sfCertData = [[SFCertificateData alloc] initWithCertificate:certificate trust:trust parse:NO];
114 const char *statusStr = [[sfCertData statusString] UTF8String];
115 // Skip the status string if the certificate is valid, but print it otherwise
116 if (statusStr && (strcmp(statusStr, "This certificate is valid") != 0))
117 fprintf(stdout, " (%s)", statusStr);
118 fprintf(stdout, "\n");
119 }
120
121 static BOOL certificateHasExpired(SecCertificateRef certificate)
122 {
123 SFCertificateData *sfCertData = [[SFCertificateData alloc] initWithCertificate:certificate trust:nil parse:NO];
124 BOOL result = [sfCertData expired];
125
126 return result;
127 }
128
129 static void doCertificateSearchForEmailAddress(SecKeychainRef kc, const char *emailAddr, bool showAll)
130 {
131 OSStatus status = errSecSuccess;
132
133 // Enumerate matching certificates
134 fprintf(stdout, "%s certificates matching \"%s\":\n", (showAll) ? "All" : "Valid", emailAddr);
135 SecKeychainSearchRef searchRef;
136 status = SecKeychainSearchCreateForCertificateByEmail(kc, emailAddr, &searchRef);
137 ok_status(status, "%s: SecKeychainSearchCreateForCertificateByEmail", testName);
138
139 SecCertificateRef preferredCert = nil;
140 CFStringRef emailStr = (emailAddr) ? CFStringCreateWithCStringNoCopy(NULL, emailAddr, kCFStringEncodingUTF8, kCFAllocatorNull) : NULL;
141
142 if (!status) {
143 SecKeychainItemRef itemRef=nil;
144 unsigned int i=0;
145 while (SecKeychainSearchCopyNext(searchRef, &itemRef)==noErr) {
146 if (showAll || !certificateHasExpired((SecCertificateRef)itemRef)) {
147 printCertificate((SecCertificateRef)itemRef, nil, ++i);
148 }
149
150 // Set this certificate as preferred for this email address
151 if(emailStr) {
152 ok_status(SecCertificateSetPreferred((SecCertificateRef)itemRef, emailStr, 0), "%s: SecCertificateSetPreferred", testName);
153 } else {
154 fail("No email for SecCertificateSetPreferred");
155 }
156
157 CFRelease(itemRef);
158 }
159 is(i, 1, "%s: Wrong number of certificates found", testName);
160
161 CFRelease(searchRef);
162 }
163
164 // Check that our certificate is new preferred
165 if(emailStr) {
166 status = SecCertificateCopyPreference(emailStr, (CSSM_KEYUSE) 0, &preferredCert);
167 } else {
168 status = errSecParam;
169 }
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 bool showAll = false;
181
182 plan_tests(7);
183 initializeKeychainTests(__FUNCTION__);
184
185 // Delete any existing preferences for our certificate, but don't test
186 // status since maybe it doesn't exist yet
187 CFMutableDictionaryRef q = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
188 CFDictionarySetValue(q, kSecClass, kSecClassGenericPassword);
189 q = addLabel(q, CFSTR("nobody_certificate@apple.com"));
190 SecItemDelete(q);
191
192
193 SecKeychainRef kc = getPopulatedTestKeychain();
194 addToSearchList(kc);
195
196 doCertificateSearchForEmailAddress(kc, "nobody_certificate@apple.com", showAll);
197
198 ok_status(SecKeychainDelete(kc), "%s: SecKeychainDelete", testName);
199 CFReleaseNull(kc);
200
201 deleteTestFiles();
202 return 0;
203 }