1/* 2 * Copyright (c) 2008-2010 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 24#include <TargetConditionals.h> 25#if TARGET_OS_EMBEDDED 26 27#include <stdio.h> 28#include <unistd.h> 29#include <stdlib.h> 30#include <fcntl.h> 31#include <sys/stat.h> 32#include <sys/types.h> 33#include <stdint.h> 34#include <stdbool.h> 35#include <errno.h> 36#include <string.h> 37 38#include <CoreFoundation/CFData.h> 39#include <CoreFoundation/CFDictionary.h> 40#include <CoreFoundation/CFNumber.h> 41#include <CoreFoundation/CFString.h> 42#include <Security/SecImportExport.h> 43#include <Security/SecItem.h> 44#include <Security/SecCertificate.h> 45#include <Security/SecIdentity.h> 46#include <Security/SecTrust.h> 47#include <Security/SecInternal.h> 48#include <utilities/array_size.h> 49 50#include "SecurityCommands.h" 51#include "SecurityTool/print_cert.h" 52 53static void * 54read_file(const char * filename, size_t * data_length) 55{ 56 void * data = NULL; 57 int len = 0; 58 int fd = -1; 59 struct stat sb; 60 61 *data_length = 0; 62 if (stat(filename, &sb) < 0) 63 goto done; 64 if (sb.st_size > INT32_MAX) 65 goto done; 66 len = (uint32_t)sb.st_size; 67 if (len == 0) 68 goto done; 69 70 data = malloc(len); 71 if (data == NULL) 72 goto done; 73 74 fd = open(filename, O_RDONLY); 75 if (fd < 0) 76 goto done; 77 78 if (read(fd, data, len) != len) { 79 goto done; 80 } 81 done: 82 if (fd >= 0) 83 close(fd); 84 if (data) { 85 *data_length = len; 86 } 87 return (data); 88} 89 90static OSStatus 91add_cert_item(SecCertificateRef cert) 92{ 93 CFDictionaryRef dict; 94 OSStatus status; 95 96 dict = CFDictionaryCreate(NULL, 97 (const void * *)&kSecValueRef, 98 (const void * *)&cert, 1, 99 &kCFTypeDictionaryKeyCallBacks, 100 &kCFTypeDictionaryValueCallBacks); 101 status = SecItemAdd(dict, NULL); 102 CFReleaseNull(dict); 103 return (status); 104} 105 106static OSStatus 107remove_cert_item(SecCertificateRef cert) 108{ 109 CFDictionaryRef dict; 110 OSStatus status; 111 112 dict = CFDictionaryCreate(NULL, 113 (const void * *)&kSecValueRef, 114 (const void * *)&cert, 1, 115 &kCFTypeDictionaryKeyCallBacks, 116 &kCFTypeDictionaryValueCallBacks); 117 status = SecItemDelete(dict); 118 CFReleaseNull(dict); 119 if (status == errSecItemNotFound) 120 status = errSecSuccess; /* already gone, no problem */ 121 return (status); 122} 123 124static CFArrayRef 125PKCS12FileCreateArray(const char * filename, const char * password) 126{ 127 void * file_data = NULL; 128 size_t file_data_length; 129 CFArrayRef items = NULL; 130 CFDictionaryRef options = NULL; 131 CFDataRef pkcs12_data = NULL; 132 CFStringRef password_cf = NULL; 133 134 file_data = read_file(filename, &file_data_length); 135 if (file_data == NULL) { 136 int this_error = errno; 137 138 fprintf(stderr, "failed to read file '%s', %s\n", 139 filename, strerror(this_error)); 140 goto done; 141 } 142 pkcs12_data = CFDataCreate(NULL, file_data, file_data_length); 143 password_cf 144 = CFStringCreateWithCString(NULL, password, kCFStringEncodingUTF8); 145 146 options = CFDictionaryCreate(NULL, 147 (const void * *)&kSecImportExportPassphrase, 148 (const void * *)&password_cf, 1, 149 &kCFTypeDictionaryKeyCallBacks, 150 &kCFTypeDictionaryValueCallBacks); 151 if (SecPKCS12Import(pkcs12_data, options, &items) != 0) { 152 fprintf(stderr, "failed to import PKCS12 '%s'\n", 153 filename); 154 } 155 done: 156 if (file_data != NULL) { 157 free(file_data); 158 } 159 CFReleaseNull(pkcs12_data); 160 CFReleaseNull(password_cf); 161 CFReleaseNull(options); 162 return (items); 163} 164 165static void 166find_identity_using_handle(CFTypeRef identity_handle) 167{ 168 CFDictionaryRef dict; 169 CFTypeRef identity_ref; 170 const void * keys[] = { kSecClass, 171 kSecReturnRef, 172 kSecValuePersistentRef }; 173 const void * values[] = { kSecClassIdentity, 174 kCFBooleanTrue, 175 identity_handle }; 176 OSStatus status; 177 178 /* find the identity using the persistent handle */ 179 dict = CFDictionaryCreate(NULL, keys, values, 180 (array_size(keys)), 181 &kCFTypeDictionaryKeyCallBacks, 182 &kCFTypeDictionaryValueCallBacks); 183 status = SecItemCopyMatching(dict, &identity_ref); 184 CFReleaseNull(dict); 185 if (status != errSecSuccess) { 186 fprintf(stderr, "SecItemCopyMatching() failed %d\n", 187 (int)status); 188 } 189 else { 190 printf("Found identity:\n"); 191 fflush(stdout); 192 fflush(stderr); 193 CFShow(identity_ref); 194 CFReleaseNull(identity_ref); 195 } 196 return; 197} 198 199static bool 200PKCS12ArrayAddSecItems(CFArrayRef items, bool verbose) 201{ 202 CFIndex count; 203 CFIndex i; 204 bool success = TRUE; 205 206 count = CFArrayGetCount(items); 207 for (i = 0; i < count; i++) { 208 SecTrustRef trust_ref; 209 SecIdentityRef identity; 210 CFDictionaryRef item_dict = CFArrayGetValueAtIndex(items, 0); 211 OSStatus status; 212 213 /* add identity */ 214 identity = (SecIdentityRef)CFDictionaryGetValue(item_dict, kSecImportItemIdentity); 215 if (identity != NULL) { 216 if (verbose) { 217 SecCertificateRef cert = NULL; 218 SecIdentityCopyCertificate(identity, &cert); 219 print_cert(cert, false); 220 CFReleaseSafe(cert); 221 } 222 CFDictionaryRef dict; 223 CFTypeRef identity_handle = NULL; 224 const void * keys[] = { kSecReturnPersistentRef, 225 kSecValueRef }; 226 const void * values[] = { kCFBooleanTrue, 227 identity }; 228 dict = CFDictionaryCreate(NULL, 229 keys, values, 230 array_size(keys), 231 &kCFTypeDictionaryKeyCallBacks, 232 &kCFTypeDictionaryValueCallBacks); 233 status = SecItemAdd(dict, &identity_handle); 234 if (identity_handle != NULL) { 235 find_identity_using_handle(identity_handle); 236 } 237 CFReleaseNull(identity_handle); 238 if (status != errSecSuccess) { 239 fprintf(stderr, "SecItemAdd(identity) failed %d\n", 240 (int)status); 241 success = FALSE; 242 } 243 CFReleaseNull(dict); 244 } 245 246 /* add certs */ 247 trust_ref = (SecTrustRef)CFDictionaryGetValue(item_dict, kSecImportItemTrust); 248 if (trust_ref != NULL) { 249 CFIndex cert_count; 250 CFIndex cert_index; 251 252 cert_count = SecTrustGetCertificateCount(trust_ref); 253 for (cert_index = 1; cert_index < cert_count; cert_index++) { 254 SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust_ref, cert_index); 255 if (verbose) 256 print_cert(cert, false); 257 status = add_cert_item(cert); 258 if (status != errSecSuccess) { 259 fprintf(stderr, "add_cert_item %d failed %d\n", (int)cert_index, (int)status); 260 success = FALSE; 261 } 262 } 263 } 264 } 265 return (success); 266} 267 268static bool 269PKCS12ArrayRemoveSecItems(CFArrayRef items, bool verbose) 270{ 271 CFIndex count; 272 CFIndex i; 273 bool success = TRUE; 274 275 count = CFArrayGetCount(items); 276 for (i = 0; i < count; i++) { 277 CFTypeRef cert_chain; 278 SecIdentityRef identity; 279 CFDictionaryRef item_dict = CFArrayGetValueAtIndex(items, i); 280 OSStatus status; 281 282 /* remove identity */ 283 identity = (SecIdentityRef)CFDictionaryGetValue(item_dict, 284 kSecImportItemIdentity); 285 if (identity != NULL) { 286 if (verbose) { 287 SecCertificateRef cert = NULL; 288 SecIdentityCopyCertificate(identity, &cert); 289 print_cert(cert, false); 290 CFReleaseSafe(cert); 291 } 292 CFDictionaryRef dict; 293 294 dict = CFDictionaryCreate(NULL, 295 (const void * *)&kSecValueRef, 296 (const void * *)&identity, 1, 297 &kCFTypeDictionaryKeyCallBacks, 298 &kCFTypeDictionaryValueCallBacks); 299 status = SecItemDelete(dict); 300 if (status != errSecSuccess) { 301 fprintf(stderr, "SecItemDelete(identity) failed %d\n", 302 (int)status); 303 success = FALSE; 304 } 305 CFReleaseNull(dict); 306 } 307 /* remove cert chain */ 308 cert_chain = CFDictionaryGetValue(item_dict, kSecImportItemCertChain); 309 if (cert_chain != NULL) { 310 CFIndex cert_count; 311 CFIndex cert_index; 312 313 cert_count = CFArrayGetCount(cert_chain); 314 for (cert_index = 0; cert_index < cert_count; cert_index++) { 315 SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(cert_chain, cert_index); 316 if (verbose) 317 print_cert(cert, false); 318 status = remove_cert_item(cert); 319 if (status != errSecSuccess) { 320 fprintf(stderr, "remove_cert_item %d failed %d\n", (int)cert_index, (int)status); 321 success = FALSE; 322 } 323 } 324 } 325 } 326 return (success); 327} 328 329 330extern int pkcs12_util(int argc, char * const *argv) 331{ 332 CFArrayRef array; 333 const char * filename = NULL; 334 const char * passphrase = NULL; 335 bool delete = false; 336 bool verbose = false; 337 char ch; 338 339 while ((ch = getopt(argc, argv, "p:dv")) != -1) 340 { 341 switch (ch) 342 { 343 case 'p': 344 passphrase = optarg; 345 break; 346 case 'd': 347 delete = true; 348 break; 349 case 'v': 350 verbose = true; 351 break; 352 default: 353 return 2; /* Trigger usage message. */ 354 } 355 } 356 357 argc -= optind; 358 argv += optind; 359 360 if (argc != 1 || !passphrase) 361 return 2; /* Trigger usage message. */ 362 363 filename = argv[0]; 364 array = PKCS12FileCreateArray(filename, passphrase); 365 if (array == NULL) 366 return -1; 367 368 bool success = false; 369 if (delete) 370 success = PKCS12ArrayRemoveSecItems(array, verbose); 371 else 372 success = PKCS12ArrayAddSecItems(array, verbose); 373 374 CFReleaseNull(array); 375 376 return success ? 0 : -1; 377} 378 379#endif // TARGET_OS_EMBEDDED 380