]> git.saurik.com Git - apple/security.git/blobdiff - SecurityTool/sharedTool/pkcs12_util.c
Security-59306.11.20.tar.gz
[apple/security.git] / SecurityTool / sharedTool / pkcs12_util.c
diff --git a/SecurityTool/sharedTool/pkcs12_util.c b/SecurityTool/sharedTool/pkcs12_util.c
new file mode 100644 (file)
index 0000000..1831dd6
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+ * 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