2 * Copyright (c) 2003-2010,2012,2014-2019 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 #include "identity_prefs.h"
27 #include "identity_find.h"
28 #include "keychain_utilities.h"
29 #include "security_tool.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 #include <CommonCrypto/CommonDigest.h>
42 // SecCertificateInferLabel, SecDigestGetData
43 #include <Security/SecCertificatePriv.h>
46 do_set_identity_preference(CFTypeRef keychainOrArray
,
53 CFStringRef serviceRef
= NULL
;
54 SecIdentityRef identityRef
= NULL
;
56 // must have a service name
58 return SHOW_USAGE_MESSAGE
;
61 // find identity (if specified by name or hash)
62 if (identity
|| hash
) {
63 identityRef
= CopyMatchingIdentity(keychainOrArray
, identity
, hash
, keyUsage
);
65 sec_error("No matching identity found for \"%s\"", (hash
) ? hash
: identity
);
71 // set the identity preference
72 serviceRef
= CFStringCreateWithCString(NULL
, service
, kCFStringEncodingUTF8
);
73 result
= SecIdentitySetPreference(identityRef
, serviceRef
, keyUsage
);
77 CFRelease(identityRef
);
79 CFRelease(serviceRef
);
89 OSStatus
ctk_dump_item(CFTypeRef item
, ctk_print_context
*ctx
);
92 do_get_identity_preference(const char *service
,
100 return SHOW_USAGE_MESSAGE
;
102 CFStringRef serviceRef
= CFStringCreateWithCString(NULL
, service
, kCFStringEncodingUTF8
);
103 SecCertificateRef certRef
= NULL
;
104 SecIdentityRef identityRef
= NULL
;
105 CSSM_DATA certData
= { 0, NULL
};
107 result
= SecIdentityCopyPreference(serviceRef
, keyUsage
, NULL
, &identityRef
);
109 sec_perror("SecIdentityCopyPreference", result
);
112 result
= SecIdentityCopyCertificate(identityRef
, &certRef
);
114 sec_perror("SecIdentityCopyCertificate", result
);
117 result
= SecCertificateGetData(certRef
, &certData
);
119 sec_perror("SecCertificateGetData", result
);
124 char *nameBuf
= NULL
;
125 CFStringRef nameRef
= NULL
;
126 (void)SecCertificateCopyCommonName(certRef
, &nameRef
);
127 CFIndex nameLen
= (nameRef
) ? CFStringGetLength(nameRef
) : 0;
129 CFIndex bufLen
= 1 + CFStringGetMaximumSizeForEncoding(nameLen
, kCFStringEncodingUTF8
);
130 nameBuf
= (char *)malloc(bufLen
);
131 if (!CFStringGetCString(nameRef
, nameBuf
, bufLen
-1, kCFStringEncodingUTF8
))
134 fprintf(stdout
, "common name: \"%s\"\n", (nameBuf
&& nameBuf
[0] != 0) ? nameBuf
: "<NULL>");
137 safe_CFRelease(&nameRef
);
141 uint8_t digest
[CC_SHA256_DIGEST_LENGTH
];
143 if (certData
.Data
!= NULL
&& certData
.Length
> 0) {
144 // print SHA-256 hash value
145 CC_SHA256(certData
.Data
, (CC_LONG
)certData
.Length
, digest
);
146 fprintf(stdout
, "SHA-256 hash: ");
147 for (i
=0; i
<CC_SHA256_DIGEST_LENGTH
; i
++) {
148 fprintf(stdout
, "%02X", ((unsigned char *)digest
)[i
]);
150 fprintf(stdout
, "\n");
151 // print SHA-1 hash value for compatibility
152 CC_SHA1(certData
.Data
, (CC_LONG
)certData
.Length
, digest
);
153 fprintf(stdout
, "SHA-1 hash: ");
154 for (i
=0; i
<CC_SHA1_DIGEST_LENGTH
; i
++) {
155 fprintf(stdout
, "%02X", ((unsigned char *)digest
)[i
]);
157 fprintf(stdout
, "\n");
163 CSSM_DATA certData
= { 0, NULL
};
164 result
= SecCertificateGetData(certRef
, &certData
);
166 sec_perror("SecCertificateGetData", result
);
170 print_buffer_pem(stdout
, "CERTIFICATE", certData
.Length
, certData
.Data
);
174 CFTypeRef keys
[] = { kSecValueRef
, kSecReturnAttributes
};
175 CFTypeRef values
[] = { certRef
, kCFBooleanTrue
};
176 CFDictionaryRef query
= CFDictionaryCreate(kCFAllocatorDefault
, keys
, values
, sizeof(keys
) / sizeof(CFTypeRef
), &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
177 CFDictionaryRef attributes
= NULL
;
178 if (SecItemCopyMatching(query
, (void *)&attributes
) == errSecSuccess
&& CFDictionaryContainsKey(attributes
, kSecAttrTokenID
)) {
179 ctk_print_context ctx
= { 1, "certificate" };
180 ctk_dump_item(attributes
, &ctx
);
182 print_keychain_item_attributes(stdout
, (SecKeychainItemRef
)certRef
, FALSE
, FALSE
, FALSE
, FALSE
);
186 CFRelease(attributes
);
190 safe_CFRelease(&serviceRef
);
191 safe_CFRelease(&certRef
);
192 safe_CFRelease(&identityRef
);
198 set_identity_preference(int argc
, char * const *argv
)
201 char *identity
= NULL
, *service
= NULL
, *hash
= NULL
;
202 CSSM_KEYUSE keyUsage
= 0;
203 CFTypeRef keychainOrArray
= NULL
;
206 * " -n Specify no identity (clears existing preference for service)\n"
207 * " -c Specify identity by common name of the certificate\n"
208 * " -s Specify service (URI, email address, DNS host, or other name)\n"
209 * " for which this identity is to be preferred\n"
210 * " -u Specify key usage (optional)\n"
211 * " -Z Specify identity by SHA-256 (or SHA-1) hash of certificate (optional)\n"
214 while ((ch
= getopt(argc
, argv
, "hnc:s:u:Z:")) != -1)
228 keyUsage
= atoi(optarg
);
235 result
= SHOW_USAGE_MESSAGE
;
243 keychainOrArray
= keychain_create_array(argc
, argv
);
245 result
= do_set_identity_preference(keychainOrArray
, identity
, service
, keyUsage
, hash
);
248 safe_CFRelease(&keychainOrArray
);
254 get_identity_preference(int argc
, char * const *argv
)
257 char *service
= NULL
;
258 Boolean printName
= FALSE
, printHash
= FALSE
, pemFormat
= FALSE
;
259 CSSM_KEYUSE keyUsage
= 0;
262 * " -s Specify service (URI, email address, DNS host, or other name)\n"
263 * " -u Specify key usage (optional)\n"
264 * " -p Output identity certificate in pem format\n"
265 * " -c Print common name of the preferred identity certificate (optional)\n"
266 * " -Z Print SHA-256 (or SHA-1) hash of the preferred identity certificate (optional)\n"
269 while ((ch
= getopt(argc
, argv
, "hs:u:pcZ")) != -1)
283 keyUsage
= atoi(optarg
);
290 result
= 2; /* @@@ Return 2 triggers usage message. */
295 result
= do_get_identity_preference(service
, keyUsage
, printName
, printHash
, pemFormat
);