SecImportExport.c
1 /* 2 * Copyright (c) 2007-2008,2012-2013 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 <Security/SecBase.h> 25 #include <Security/SecBasePriv.h> 26 #include <Security/SecItem.h> 27 #include <Security/SecRSAKey.h> 28 #include <Security/SecECKey.h> 29 #include <Security/SecCertificate.h> 30 #include <Security/SecIdentityPriv.h> 31 #include <Security/SecPolicy.h> 32 #include <Security/SecTrust.h> 33 #include <Security/SecInternal.h> 34 #include <libDER/oids.h> 35 36 #include <AssertMacros.h> 37 38 #include "p12import.h" 39 #include <Security/SecImportExportPriv.h> 40 41 #if !TARGET_OS_OSX 42 const CFStringRef kSecImportExportPassphrase = CFSTR("passphrase"); 43 const CFStringRef kSecImportItemLabel = CFSTR("label"); 44 const CFStringRef kSecImportItemKeyID = CFSTR("keyid"); 45 const CFStringRef kSecImportItemTrust = CFSTR("trust"); 46 const CFStringRef kSecImportItemCertChain = CFSTR("chain"); 47 const CFStringRef kSecImportItemIdentity = CFSTR("identity"); 48 #endif 49 50 typedef struct { 51 CFMutableArrayRef certs; 52 p12_error *status; 53 } collect_certs_context; 54 55 56 static void collect_certs(const void *key, const void *value, void *context) 57 { 58 if (!CFDictionaryContainsKey(value, CFSTR("key"))) { 59 CFDataRef cert_bytes = CFDictionaryGetValue(value, CFSTR("cert")); 60 if (!cert_bytes) 61 return; 62 collect_certs_context *a_collect_certs_context = (collect_certs_context *)context; 63 SecCertificateRef cert = 64 SecCertificateCreateWithData(kCFAllocatorDefault, cert_bytes); 65 if (!cert) { 66 *a_collect_certs_context->status = p12_decodeErr; 67 return; 68 } 69 CFMutableArrayRef cert_array = a_collect_certs_context->certs; 70 CFArrayAppendValue(cert_array, cert); 71 CFRelease(cert); 72 } 73 } 74 75 typedef struct { 76 CFMutableArrayRef identities; 77 CFArrayRef certs; 78 p12_error *status; 79 } build_trust_chains_context; 80 81 static void build_trust_chains(const void *key, const void *value, 82 void *context) 83 { 84 CFMutableDictionaryRef identity_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 85 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 86 SecKeyRef private_key = NULL; 87 SecCertificateRef cert = NULL; 88 SecIdentityRef identity = NULL; 89 SecPolicyRef policy = NULL; 90 CFMutableArrayRef cert_chain = NULL, eval_chain = NULL; 91 SecTrustRef trust = NULL; 92 build_trust_chains_context * a_build_trust_chains_context = (build_trust_chains_context*)context; 93 94 CFDataRef key_bytes = CFDictionaryGetValue(value, CFSTR("key")); 95 require(key_bytes, out); 96 CFDataRef cert_bytes = CFDictionaryGetValue(value, CFSTR("cert")); 97 require(cert_bytes, out); 98 CFDataRef algoid_bytes = CFDictionaryGetValue(value, CFSTR("algid")); 99 100 101 DERItem algorithm = { (DERByte *)CFDataGetBytePtr(algoid_bytes), CFDataGetLength(algoid_bytes) }; 102 if (DEROidCompare(&oidEcPubKey, &algorithm)) { 103 require (private_key = SecKeyCreateECPrivateKey(kCFAllocatorDefault, 104 CFDataGetBytePtr(key_bytes), CFDataGetLength(key_bytes), 105 kSecKeyEncodingPkcs1), out); 106 } else if (DEROidCompare(&oidRsa, &algorithm)) { 107 require (private_key = SecKeyCreateRSAPrivateKey(kCFAllocatorDefault, 108 CFDataGetBytePtr(key_bytes), CFDataGetLength(key_bytes), 109 kSecKeyEncodingPkcs1), out); 110 } else { 111 *a_build_trust_chains_context->status = p12_decodeErr; 112 goto out; 113 } 114 115 require_action(cert = SecCertificateCreateWithData(kCFAllocatorDefault, cert_bytes), out, 116 *a_build_trust_chains_context->status = p12_decodeErr); 117 require_action(identity = SecIdentityCreate(kCFAllocatorDefault, cert, private_key), out, 118 *a_build_trust_chains_context->status = p12_decodeErr); 119 CFDictionarySetValue(identity_dict, kSecImportItemIdentity, identity); 120 121 eval_chain = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 122 require(eval_chain, out); 123 CFArrayAppendValue(eval_chain, cert); 124 CFRange all_certs = { 0, CFArrayGetCount(a_build_trust_chains_context->certs) }; 125 CFArrayAppendArray(eval_chain, a_build_trust_chains_context->certs, all_certs); 126 require(policy = SecPolicyCreateBasicX509(), out); 127 SecTrustResultType result; 128 SecTrustCreateWithCertificates(eval_chain, policy, &trust); 129 require(trust, out); 130 SecTrustEvaluate(trust, &result); 131 CFDictionarySetValue(identity_dict, kSecImportItemTrust, trust); 132 133 require(cert_chain = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks), out); 134 CFIndex cert_chain_length = SecTrustGetCertificateCount(trust); 135 int i; 136 for (i = 0; i < cert_chain_length; i++) 137 CFArrayAppendValue(cert_chain, SecTrustGetCertificateAtIndex(trust, i)); 138 CFDictionarySetValue(identity_dict, kSecImportItemCertChain, cert_chain); 139 140 CFArrayAppendValue(a_build_trust_chains_context->identities, identity_dict); 141 out: 142 CFReleaseSafe(identity_dict); 143 CFReleaseSafe(identity); 144 CFReleaseSafe(private_key); 145 CFReleaseSafe(cert); 146 CFReleaseSafe(policy); 147 CFReleaseSafe(cert_chain); 148 CFReleaseSafe(eval_chain); 149 CFReleaseSafe(trust); 150 } 151 152 #if TARGET_OS_OSX 153 OSStatus SecPKCS12Import_ios(CFDataRef pkcs12_data, CFDictionaryRef options, CFArrayRef *items) 154 #else 155 OSStatus SecPKCS12Import(CFDataRef pkcs12_data, CFDictionaryRef options, CFArrayRef *items) 156 #endif 157 { 158 pkcs12_context context = {}; 159 SecAsn1CoderCreate(&context.coder); 160 if (options) 161 context.passphrase = CFDictionaryGetValue(options, kSecImportExportPassphrase); 162 context.items = CFDictionaryCreateMutable(kCFAllocatorDefault, 163 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 164 p12_error status = p12decode(&context, pkcs12_data); 165 if (!status) { 166 CFMutableArrayRef certs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 167 collect_certs_context a_collect_certs_context = { certs, &status }; 168 CFDictionaryApplyFunction(context.items, collect_certs, &a_collect_certs_context); 169 170 if (!status) { 171 CFMutableArrayRef identities = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 172 build_trust_chains_context a_build_trust_chains_context = { identities, certs, &status }; 173 CFDictionaryApplyFunction(context.items, build_trust_chains, &a_build_trust_chains_context); 174 CFReleaseSafe(certs); 175 176 /* ignoring certs that weren't picked up as part of the certchain for found keys */ 177 *items = identities; 178 } 179 } 180 181 CFReleaseSafe(context.items); 182 SecAsn1CoderRelease(context.coder); 183 184 switch (status) { 185 case p12_noErr: return errSecSuccess; 186 case p12_passwordErr: return errSecAuthFailed; 187 case p12_decodeErr: return errSecDecode; 188 default: return errSecInternal; 189 }; 190 return errSecSuccess; 191 } 192