/ OSX / sec / Security / SecImportExport.c
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