]> git.saurik.com Git - apple/security.git/blob - SecurityTool/identity_prefs.c
Security-57336.1.9.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.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