]>
Commit | Line | Data |
---|---|---|
d8f41ccd A |
1 | /* |
2 | * Copyright (c) 2003-2010,2012,2014 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 License. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | * | |
23 | * identity_prefs.c | |
24 | */ | |
25 | ||
26 | #include "identity_prefs.h" | |
27 | #include "identity_find.h" | |
28 | #include "keychain_utilities.h" | |
fa7225c8 | 29 | #include "security_tool.h" |
d8f41ccd A |
30 | |
31 | #include <stdio.h> | |
32 | #include <stdlib.h> | |
33 | #include <string.h> | |
34 | #include <unistd.h> | |
35 | #include <Security/cssmtype.h> | |
36 | #include <Security/SecCertificate.h> | |
37 | #include <Security/SecIdentity.h> | |
38 | #include <Security/SecIdentitySearch.h> | |
866f8763 | 39 | #include <Security/SecItem.h> |
d8f41ccd A |
40 | |
41 | // SecCertificateInferLabel, SecDigestGetData | |
42 | #include <Security/SecCertificatePriv.h> | |
43 | ||
44 | ||
45 | static int | |
46 | do_set_identity_preference(CFTypeRef keychainOrArray, | |
47 | const char *identity, | |
48 | const char *service, | |
49 | CSSM_KEYUSE keyUsage, | |
50 | const char *hash) | |
51 | { | |
52 | int result = 0; | |
53 | CFStringRef serviceRef = NULL; | |
54 | SecIdentityRef identityRef = NULL; | |
55 | ||
56 | // must have a service name | |
57 | if (!service) { | |
58 | return 2; | |
59 | } | |
60 | ||
61 | // find identity (if specified by name or hash) | |
62 | if (identity || hash) { | |
866f8763 | 63 | identityRef = CopyMatchingIdentity(keychainOrArray, identity, hash, keyUsage); |
d8f41ccd A |
64 | if (!identityRef) { |
65 | sec_error("No matching identity found for \"%s\"", (hash) ? hash : identity); | |
66 | result = 1; | |
67 | goto cleanup; | |
68 | } | |
69 | } | |
70 | ||
71 | // set the identity preference | |
72 | serviceRef = CFStringCreateWithCString(NULL, service, kCFStringEncodingUTF8); | |
73 | result = SecIdentitySetPreference(identityRef, serviceRef, keyUsage); | |
74 | ||
75 | cleanup: | |
76 | if (identityRef) | |
77 | CFRelease(identityRef); | |
78 | if (serviceRef) | |
79 | CFRelease(serviceRef); | |
80 | ||
81 | return result; | |
82 | } | |
83 | ||
866f8763 A |
84 | typedef struct { |
85 | int i; | |
86 | const char *name; | |
87 | } ctk_print_context; | |
88 | ||
89 | OSStatus ctk_dump_item(CFTypeRef item, ctk_print_context *ctx); | |
90 | ||
fa7225c8 | 91 | static int |
d8f41ccd A |
92 | do_get_identity_preference(const char *service, |
93 | CSSM_KEYUSE keyUsage, | |
94 | Boolean printName, | |
95 | Boolean printHash, | |
96 | Boolean pemFormat) | |
97 | { | |
98 | int result = 0; | |
99 | if (!service) { | |
100 | return 2; | |
101 | } | |
102 | CFStringRef serviceRef = CFStringCreateWithCString(NULL, service, kCFStringEncodingUTF8); | |
103 | SecCertificateRef certRef = NULL; | |
104 | SecIdentityRef identityRef = NULL; | |
105 | CSSM_DATA certData = { 0, NULL }; | |
106 | ||
107 | result = SecIdentityCopyPreference(serviceRef, keyUsage, NULL, &identityRef); | |
108 | if (result) { | |
109 | sec_perror("SecIdentityCopyPreference", result); | |
110 | goto cleanup; | |
111 | } | |
112 | result = SecIdentityCopyCertificate(identityRef, &certRef); | |
113 | if (result) { | |
114 | sec_perror("SecIdentityCopyCertificate", result); | |
115 | goto cleanup; | |
116 | } | |
117 | result = SecCertificateGetData(certRef, &certData); | |
118 | if (result) { | |
119 | sec_perror("SecCertificateGetData", result); | |
120 | goto cleanup; | |
121 | } | |
122 | ||
123 | if (printName) { | |
124 | char *nameBuf = NULL; | |
125 | CFStringRef nameRef = NULL; | |
126 | (void)SecCertificateCopyCommonName(certRef, &nameRef); | |
127 | CFIndex nameLen = (nameRef) ? CFStringGetLength(nameRef) : 0; | |
128 | if (nameLen > 0) { | |
129 | CFIndex bufLen = 1 + CFStringGetMaximumSizeForEncoding(nameLen, kCFStringEncodingUTF8); | |
130 | nameBuf = (char *)malloc(bufLen); | |
131 | if (!CFStringGetCString(nameRef, nameBuf, bufLen-1, kCFStringEncodingUTF8)) | |
132 | nameBuf[0]=0; | |
133 | } | |
134 | fprintf(stdout, "common name: \"%s\"\n", (nameBuf && nameBuf[0] != 0) ? nameBuf : "<NULL>"); | |
135 | if (nameBuf) | |
136 | free(nameBuf); | |
137 | safe_CFRelease(&nameRef); | |
138 | } | |
139 | ||
140 | if (printHash) { | |
141 | uint8 sha1_hash[20]; | |
142 | CSSM_DATA digest; | |
143 | digest.Length = sizeof(sha1_hash); | |
144 | digest.Data = sha1_hash; | |
145 | if (SecDigestGetData(CSSM_ALGID_SHA1, &digest, &certData) == CSSM_OK) { | |
146 | unsigned int i; | |
fa7225c8 | 147 | size_t len = digest.Length; |
d8f41ccd A |
148 | uint8 *cp = digest.Data; |
149 | fprintf(stdout, "SHA-1 hash: "); | |
150 | for(i=0; i<len; i++) { | |
151 | fprintf(stdout, "%02X", ((unsigned char *)cp)[i]); | |
152 | } | |
153 | fprintf(stdout, "\n"); | |
154 | } | |
155 | } | |
156 | ||
157 | if (pemFormat) | |
158 | { | |
159 | CSSM_DATA certData = { 0, NULL }; | |
160 | result = SecCertificateGetData(certRef, &certData); | |
161 | if (result) { | |
162 | sec_perror("SecCertificateGetData", result); | |
163 | goto cleanup; | |
164 | } | |
165 | ||
166 | print_buffer_pem(stdout, "CERTIFICATE", certData.Length, certData.Data); | |
167 | } | |
168 | else | |
169 | { | |
866f8763 A |
170 | CFTypeRef keys[] = { kSecValueRef, kSecReturnAttributes }; |
171 | CFTypeRef values[] = { certRef, kCFBooleanTrue }; | |
172 | CFDictionaryRef query = CFDictionaryCreate(kCFAllocatorDefault, keys, values, sizeof(keys) / sizeof(CFTypeRef), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
173 | CFDictionaryRef attributes = NULL; | |
174 | if (SecItemCopyMatching(query, (void *)&attributes) == errSecSuccess && CFDictionaryContainsKey(attributes, kSecAttrTokenID)) { | |
175 | ctk_print_context ctx = { 1, "certificate" }; | |
176 | ctk_dump_item(attributes, &ctx); | |
177 | } else | |
178 | print_keychain_item_attributes(stdout, (SecKeychainItemRef)certRef, FALSE, FALSE, FALSE, FALSE); | |
179 | ||
180 | CFRelease(query); | |
181 | if(attributes) | |
182 | CFRelease(attributes); | |
d8f41ccd A |
183 | } |
184 | ||
185 | cleanup: | |
186 | safe_CFRelease(&serviceRef); | |
187 | safe_CFRelease(&certRef); | |
188 | safe_CFRelease(&identityRef); | |
189 | ||
190 | return result; | |
191 | } | |
192 | ||
193 | int | |
194 | set_identity_preference(int argc, char * const *argv) | |
195 | { | |
196 | int ch, result = 0; | |
197 | char *identity = NULL, *service = NULL, *hash = NULL; | |
198 | CSSM_KEYUSE keyUsage = 0; | |
199 | CFTypeRef keychainOrArray = NULL; | |
200 | ||
201 | /* | |
202 | * " -n Specify no identity (clears existing preference for service)\n" | |
203 | * " -c Specify identity by common name of the certificate\n" | |
204 | * " -s Specify service (URI, email address, DNS host, or other name)\n" | |
205 | * " for which this identity is to be preferred\n" | |
206 | * " -u Specify key usage (optional)\n" | |
207 | * " -Z Specify identity by SHA-1 hash of certificate (optional)\n" | |
208 | */ | |
209 | ||
210 | while ((ch = getopt(argc, argv, "hnc:s:u:Z:")) != -1) | |
211 | { | |
212 | switch (ch) | |
213 | { | |
214 | case 'n': | |
215 | identity = NULL; | |
216 | break; | |
217 | case 'c': | |
218 | identity = optarg; | |
219 | break; | |
220 | case 's': | |
221 | service = optarg; | |
222 | break; | |
223 | case 'u': | |
224 | keyUsage = atoi(optarg); | |
225 | break; | |
226 | case 'Z': | |
227 | hash = optarg; | |
228 | break; | |
229 | case '?': | |
230 | default: | |
231 | result = 2; /* @@@ Return 2 triggers usage message. */ | |
232 | goto cleanup; | |
233 | } | |
234 | } | |
235 | ||
236 | argc -= optind; | |
237 | argv += optind; | |
238 | ||
239 | keychainOrArray = keychain_create_array(argc, argv); | |
240 | ||
241 | result = do_set_identity_preference(keychainOrArray, identity, service, keyUsage, hash); | |
242 | ||
243 | cleanup: | |
244 | safe_CFRelease(&keychainOrArray); | |
245 | ||
246 | return result; | |
247 | } | |
248 | ||
249 | int | |
250 | get_identity_preference(int argc, char * const *argv) | |
251 | { | |
252 | int ch, result = 0; | |
253 | char *service = NULL; | |
254 | Boolean printName = FALSE, printHash = FALSE, pemFormat = FALSE; | |
255 | CSSM_KEYUSE keyUsage = 0; | |
256 | ||
257 | /* | |
258 | * " -s Specify service (URI, email address, DNS host, or other name)\n" | |
259 | * " -u Specify key usage (optional)\n" | |
260 | * " -p Output identity certificate in pem format\n" | |
261 | * " -c Print common name of the preferred identity certificate (optional)\n" | |
262 | * " -Z Print SHA-1 hash of the preferred identity certificate (optional)\n" | |
263 | */ | |
264 | ||
265 | while ((ch = getopt(argc, argv, "hs:u:pcZ")) != -1) | |
266 | { | |
267 | switch (ch) | |
268 | { | |
269 | case 'c': | |
270 | printName = TRUE; | |
271 | break; | |
272 | case 'p': | |
273 | pemFormat = TRUE; | |
274 | break; | |
275 | case 's': | |
276 | service = optarg; | |
277 | break; | |
278 | case 'u': | |
279 | keyUsage = atoi(optarg); | |
280 | break; | |
281 | case 'Z': | |
282 | printHash = TRUE; | |
283 | break; | |
284 | case '?': | |
285 | default: | |
286 | result = 2; /* @@@ Return 2 triggers usage message. */ | |
287 | goto cleanup; | |
288 | } | |
289 | } | |
290 | ||
291 | result = do_get_identity_preference(service, keyUsage, printName, printHash, pemFormat); | |
292 | ||
293 | cleanup: | |
294 | ||
295 | return result; | |
296 | } | |
297 |