--- /dev/null
+/*
+ * Copyright (c) 2008-2010,2013-2014 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <TargetConditionals.h>
+#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+
+#include <CoreFoundation/CFData.h>
+#include <CoreFoundation/CFDictionary.h>
+#include <CoreFoundation/CFNumber.h>
+#include <CoreFoundation/CFString.h>
+#include <Security/SecImportExport.h>
+#include <Security/SecItem.h>
+#include <Security/SecCertificate.h>
+#include <Security/SecIdentity.h>
+#include <Security/SecTrust.h>
+#include <Security/SecInternal.h>
+#include <utilities/array_size.h>
+
+#include "SecurityCommands.h"
+#include "SecurityTool/sharedTool/print_cert.h"
+
+static void *
+read_file(const char * filename, size_t * data_length)
+{
+ void * data = NULL;
+ int len = 0;
+ int fd = -1;
+ struct stat sb;
+
+ *data_length = 0;
+ if (stat(filename, &sb) < 0)
+ goto done;
+ if (sb.st_size > INT32_MAX)
+ goto done;
+ len = (uint32_t)sb.st_size;
+ if (len == 0)
+ goto done;
+
+ data = malloc(len);
+ if (data == NULL)
+ goto done;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ goto done;
+
+ if (read(fd, data, len) != len) {
+ goto done;
+ }
+ done:
+ if (fd >= 0)
+ close(fd);
+ if (data) {
+ *data_length = len;
+ }
+ return (data);
+}
+
+static OSStatus
+add_cert_item(SecCertificateRef cert)
+{
+ CFDictionaryRef dict;
+ OSStatus status;
+
+ dict = CFDictionaryCreate(NULL,
+ (const void * *)&kSecValueRef,
+ (const void * *)&cert, 1,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ status = SecItemAdd(dict, NULL);
+ CFReleaseNull(dict);
+ return (status);
+}
+
+static OSStatus
+remove_cert_item(SecCertificateRef cert)
+{
+ CFDictionaryRef dict;
+ OSStatus status;
+
+ dict = CFDictionaryCreate(NULL,
+ (const void * *)&kSecValueRef,
+ (const void * *)&cert, 1,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ status = SecItemDelete(dict);
+ CFReleaseNull(dict);
+ if (status == errSecItemNotFound)
+ status = errSecSuccess; /* already gone, no problem */
+ return (status);
+}
+
+static CFArrayRef
+PKCS12FileCreateArray(const char * filename, const char * password)
+{
+ void * file_data = NULL;
+ size_t file_data_length;
+ CFArrayRef items = NULL;
+ CFDictionaryRef options = NULL;
+ CFDataRef pkcs12_data = NULL;
+ CFStringRef password_cf = NULL;
+
+ file_data = read_file(filename, &file_data_length);
+ if (file_data == NULL) {
+ int this_error = errno;
+
+ fprintf(stderr, "failed to read file '%s', %s\n",
+ filename, strerror(this_error));
+ goto done;
+ }
+ pkcs12_data = CFDataCreate(NULL, file_data, file_data_length);
+ password_cf
+ = CFStringCreateWithCString(NULL, password, kCFStringEncodingUTF8);
+
+ options = CFDictionaryCreate(NULL,
+ (const void * *)&kSecImportExportPassphrase,
+ (const void * *)&password_cf, 1,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ if (SecPKCS12Import(pkcs12_data, options, &items) != 0) {
+ fprintf(stderr, "failed to import PKCS12 '%s'\n",
+ filename);
+ }
+ done:
+ if (file_data != NULL) {
+ free(file_data);
+ }
+ CFReleaseNull(pkcs12_data);
+ CFReleaseNull(password_cf);
+ CFReleaseNull(options);
+ return (items);
+}
+
+static void
+find_identity_using_handle(CFTypeRef identity_handle)
+{
+ CFDictionaryRef dict;
+ CFTypeRef identity_ref;
+ const void * keys[] = { kSecClass,
+ kSecReturnRef,
+ kSecValuePersistentRef };
+ const void * values[] = { kSecClassIdentity,
+ kCFBooleanTrue,
+ identity_handle };
+ OSStatus status;
+
+ /* find the identity using the persistent handle */
+ dict = CFDictionaryCreate(NULL, keys, values,
+ (array_size(keys)),
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ status = SecItemCopyMatching(dict, &identity_ref);
+ CFReleaseNull(dict);
+ if (status != errSecSuccess) {
+ fprintf(stderr, "SecItemCopyMatching() failed %d\n",
+ (int)status);
+ }
+ else {
+ printf("Found identity:\n");
+ fflush(stdout);
+ fflush(stderr);
+ CFShow(identity_ref);
+ CFReleaseNull(identity_ref);
+ }
+ return;
+}
+
+static bool
+PKCS12ArrayAddSecItems(CFArrayRef items, bool verbose)
+{
+ CFIndex count;
+ CFIndex i;
+ bool success = TRUE;
+
+ count = CFArrayGetCount(items);
+ for (i = 0; i < count; i++) {
+ SecTrustRef trust_ref;
+ SecIdentityRef identity;
+ CFDictionaryRef item_dict = CFArrayGetValueAtIndex(items, 0);
+ OSStatus status;
+
+ /* add identity */
+ identity = (SecIdentityRef)CFDictionaryGetValue(item_dict, kSecImportItemIdentity);
+ if (identity != NULL) {
+ if (verbose) {
+ SecCertificateRef cert = NULL;
+ SecIdentityCopyCertificate(identity, &cert);
+ print_cert(cert, false);
+ CFReleaseSafe(cert);
+ }
+ CFDictionaryRef dict;
+ CFTypeRef identity_handle = NULL;
+ const void * keys[] = { kSecReturnPersistentRef,
+ kSecValueRef };
+ const void * values[] = { kCFBooleanTrue,
+ identity };
+ dict = CFDictionaryCreate(NULL,
+ keys, values,
+ array_size(keys),
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ status = SecItemAdd(dict, &identity_handle);
+ if (identity_handle != NULL) {
+ find_identity_using_handle(identity_handle);
+ }
+ CFReleaseNull(identity_handle);
+ if (status != errSecSuccess) {
+ fprintf(stderr, "SecItemAdd(identity) failed %d\n",
+ (int)status);
+ success = FALSE;
+ }
+ CFReleaseNull(dict);
+ }
+
+ /* add certs */
+ trust_ref = (SecTrustRef)CFDictionaryGetValue(item_dict, kSecImportItemTrust);
+ if (trust_ref != NULL) {
+ CFIndex cert_count;
+ CFIndex cert_index;
+
+ cert_count = SecTrustGetCertificateCount(trust_ref);
+ for (cert_index = 1; cert_index < cert_count; cert_index++) {
+ SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust_ref, cert_index);
+ if (verbose)
+ print_cert(cert, false);
+ status = add_cert_item(cert);
+ if (status != errSecSuccess) {
+ fprintf(stderr, "add_cert_item %d failed %d\n", (int)cert_index, (int)status);
+ success = FALSE;
+ }
+ }
+ }
+ }
+ return (success);
+}
+
+static bool
+PKCS12ArrayRemoveSecItems(CFArrayRef items, bool verbose)
+{
+ CFIndex count;
+ CFIndex i;
+ bool success = TRUE;
+
+ count = CFArrayGetCount(items);
+ for (i = 0; i < count; i++) {
+ CFTypeRef cert_chain;
+ SecIdentityRef identity;
+ CFDictionaryRef item_dict = CFArrayGetValueAtIndex(items, i);
+ OSStatus status;
+
+ /* remove identity */
+ identity = (SecIdentityRef)CFDictionaryGetValue(item_dict,
+ kSecImportItemIdentity);
+ if (identity != NULL) {
+ if (verbose) {
+ SecCertificateRef cert = NULL;
+ SecIdentityCopyCertificate(identity, &cert);
+ print_cert(cert, false);
+ CFReleaseSafe(cert);
+ }
+ CFDictionaryRef dict;
+
+ dict = CFDictionaryCreate(NULL,
+ (const void * *)&kSecValueRef,
+ (const void * *)&identity, 1,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ status = SecItemDelete(dict);
+ if (status != errSecSuccess) {
+ fprintf(stderr, "SecItemDelete(identity) failed %d\n",
+ (int)status);
+ success = FALSE;
+ }
+ CFReleaseNull(dict);
+ }
+ /* remove cert chain */
+ cert_chain = CFDictionaryGetValue(item_dict, kSecImportItemCertChain);
+ if (cert_chain != NULL) {
+ CFIndex cert_count;
+ CFIndex cert_index;
+
+ cert_count = CFArrayGetCount(cert_chain);
+ for (cert_index = 0; cert_index < cert_count; cert_index++) {
+ SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(cert_chain, cert_index);
+ if (verbose)
+ print_cert(cert, false);
+ status = remove_cert_item(cert);
+ if (status != errSecSuccess) {
+ fprintf(stderr, "remove_cert_item %d failed %d\n", (int)cert_index, (int)status);
+ success = FALSE;
+ }
+ }
+ }
+ }
+ return (success);
+}
+
+
+extern int pkcs12_util(int argc, char * const *argv)
+{
+ CFArrayRef array;
+ const char * filename = NULL;
+ const char * passphrase = NULL;
+ bool delete = false;
+ bool verbose = false;
+ char ch;
+
+ while ((ch = getopt(argc, argv, "p:dv")) != -1)
+ {
+ switch (ch)
+ {
+ case 'p':
+ passphrase = optarg;
+ break;
+ case 'd':
+ delete = true;
+ break;
+ case 'v':
+ verbose = true;
+ break;
+ default:
+ return SHOW_USAGE_MESSAGE;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 1 || !passphrase)
+ return SHOW_USAGE_MESSAGE;
+
+ filename = argv[0];
+ array = PKCS12FileCreateArray(filename, passphrase);
+ if (array == NULL)
+ return -1;
+
+ bool success = false;
+ if (delete)
+ success = PKCS12ArrayRemoveSecItems(array, verbose);
+ else
+ success = PKCS12ArrayAddSecItems(array, verbose);
+
+ CFReleaseNull(array);
+
+ return success ? 0 : -1;
+}
+
+#endif // TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR