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
);