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