]> git.saurik.com Git - apple/security.git/blob - SecurityTool/identity_prefs.c
Security-58286.270.3.0.1.tar.gz
[apple/security.git] / SecurityTool / identity_prefs.c
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_tool.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 #include <Security/SecItem.h>
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 SHOW_USAGE_MESSAGE;
59 }
60
61 // find identity (if specified by name or hash)
62 if (identity || hash) {
63 identityRef = CopyMatchingIdentity(keychainOrArray, identity, hash, keyUsage);
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
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
91 static int
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 SHOW_USAGE_MESSAGE;
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;
147 size_t len = digest.Length;
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 {
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);
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 = SHOW_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