+++ /dev/null
-/*
- * Copyright (c) 1999-2001,2005-2008,2010-2012 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@
- */
-
-/*
- * sslKeychain.c - Apple Keychain routines
- */
-
-#include "ssl.h"
-#include "sslContext.h"
-#include "sslMemory.h"
-
-#include "sslCrypto.h"
-#ifdef USE_CDSA_CRYPTO
-#include <Security/Security.h>
-#else
-#include <Security/SecBase.h>
-#include <Security/SecCertificate.h>
-#include <Security/SecIdentity.h>
-#include <Security/SecPolicy.h>
-#include <Security/SecTrust.h>
-#endif /* !USE_CDSA_CRYPTO */
-#include "utilities/SecCFRelease.h"
-
-#include "sslDebug.h"
-#include "sslKeychain.h"
-#include "sslUtils.h"
-#include <string.h>
-#include <assert.h>
-
-#if TARGET_OS_IPHONE
-#include "utilities/SecCFRelease.h"
-#endif
-
-#ifdef USE_SSLCERTIFICATE
-
-/*
- * Given an array of certs (as SecIdentityRefs, specified by caller
- * in SSLSetCertificate or SSLSetEncryptionCertificate) and a
- * destination SSLCertificate:
- *
- * -- free destCerts if we have any
- * -- Get raw cert data, convert to array of SSLCertificates in *destCert
- * -- validate cert chain
- * -- get pub, priv keys from certRef[0], store in *pubKey, *privKey
- */
-
-/* Convert a SecCertificateRef to an SSLCertificate * */
-static OSStatus secCertToSslCert(
- SSLContext *ctx,
- SecCertificateRef certRef,
- SSLCertificate **sslCert)
-{
- CSSM_DATA certData; // struct is transient, referent owned by
- // Sec layer
- OSStatus ortn;
- SSLCertificate *thisSslCert = NULL;
-
- ortn = SecCertificateGetData(certRef, &certData);
- if(ortn) {
- sslErrorLog("SecCertificateGetData() returned %d\n", (int)ortn);
- return ortn;
- }
-
- thisSslCert = (SSLCertificate *)sslMalloc(sizeof(SSLCertificate));
- if(thisSslCert == NULL) {
- return errSecAllocate;
- }
- if(SSLAllocBuffer(&thisSslCert->derCert, certData.Length,
- ctx)) {
- return errSecAllocate;
- }
- memcpy(thisSslCert->derCert.data, certData.Data, certData.Length);
- thisSslCert->derCert.length = certData.Length;
- *sslCert = thisSslCert;
- return errSecSuccess;
-}
-
-/*
- * Determine the basic signing algorithm, without the digest, component, of
- * a cert. The returned algorithm will be RSA, DSA, or ECDSA.
- */
-static OSStatus sslCertSignerAlg(
- SecCertificateRef certRef,
- CSSM_ALGORITHMS *signerAlg)
-{
- OSStatus ortn;
- CSSM_DATA_PTR fieldPtr;
- CSSM_X509_ALGORITHM_IDENTIFIER *algId;
- CSSM_ALGORITHMS sigAlg;
-
- /*
- * Extract the full signature algorithm OID
- */
- *signerAlg = CSSM_ALGID_NONE;
- ortn = SecCertificateCopyFirstFieldValue(certRef,
- &CSSMOID_X509V1SignatureAlgorithm,
- &fieldPtr);
- if(ortn) {
- return ortn;
- }
- if(fieldPtr->Length != sizeof(CSSM_X509_ALGORITHM_IDENTIFIER)) {
- sslErrorLog("sslCertSignerAlg() length error\n");
- ortn = errSSLCrypto;
- goto errOut;
- }
- algId = (CSSM_X509_ALGORITHM_IDENTIFIER *)fieldPtr->Data;
- if(!cssmOidToAlg(&algId->algorithm, &sigAlg)) {
- /* Only way this could happen is if we're given a bad cert */
- sslErrorLog("sslCertSignerAlg() bad sigAlg OID\n");
- ortn = errSecParam;
- goto errOut;
- }
-
- /*
- * OK we have the full signature algorithm as a CSSM_ALGORITHMS.
- * Extract the core signature alg.
- */
- switch(sigAlg) {
- case CSSM_ALGID_RSA:
- case CSSM_ALGID_MD2WithRSA:
- case CSSM_ALGID_MD5WithRSA:
- case CSSM_ALGID_SHA1WithRSA:
- case CSSM_ALGID_SHA224WithRSA:
- case CSSM_ALGID_SHA256WithRSA:
- case CSSM_ALGID_SHA384WithRSA:
- case CSSM_ALGID_SHA512WithRSA:
- *signerAlg = CSSM_ALGID_RSA;
- break;
- case CSSM_ALGID_SHA1WithECDSA:
- case CSSM_ALGID_SHA224WithECDSA:
- case CSSM_ALGID_SHA256WithECDSA:
- case CSSM_ALGID_SHA384WithECDSA:
- case CSSM_ALGID_SHA512WithECDSA:
- case CSSM_ALGID_ECDSA:
- case CSSM_ALGID_ECDSA_SPECIFIED:
- *signerAlg = CSSM_ALGID_ECDSA;
- break;
- case CSSM_ALGID_DSA:
- case CSSM_ALGID_SHA1WithDSA:
- *signerAlg = CSSM_ALGID_DSA;
- break;
- default:
- sslErrorLog("sslCertSignerAlg() unknown sigAlg\n");
- ortn = errSecParam;
- break;
- }
-errOut:
- SecCertificateReleaseFirstFieldValue(certRef,
- &CSSMOID_X509V1SignatureAlgorithm, fieldPtr);
- return ortn;
-}
-
-OSStatus
-parseIncomingCerts(
- SSLContext *ctx,
- CFArrayRef certs,
- SSLCertificate **destCert, /* &ctx->{localCert,encryptCert} */
- CSSM_KEY_PTR *pubKey, /* &ctx->signingPubKey, etc. */
- SecKeyRef *privKeyRef, /* &ctx->signingPrivKeyRef, etc. */
- CSSM_ALGORITHMS *signerAlg) /* optional */
-{
- CFIndex numCerts;
- CFIndex cert;
- SSLCertificate *certChain = NULL;
- SSLCertificate *thisSslCert;
- OSStatus ortn;
- SecIdentityRef identity;
- SecCertificateRef certRef;
- SecKeyRef keyRef;
- CSSM_DATA certData;
- CSSM_CL_HANDLE clHand; // carefully derive from a SecCertificateRef
- CSSM_RETURN crtn;
- CSSM_KEY_PTR *pubKey;
- SecKeyRef *privKeyRef;
-
- assert(ctx != NULL);
- assert(destCert != NULL); /* though its referent may be NULL */
- assert(sslPubKey != NULL);
- assert(sslPrivKeyRef != NULL);
-
- pubKey = &sslPubKey->key;
- privKeyRef = &sslPrivKey->key;
-
- sslDeleteCertificateChain(*destCert, ctx);
- *destCert = NULL;
- *pubKey = NULL;
- *privKeyRef = NULL;
-
- if(certs == NULL) {
- sslErrorLog("parseIncomingCerts: NULL incoming cert array\n");
- return errSSLBadCert;
- }
- numCerts = CFArrayGetCount(certs);
- if(numCerts == 0) {
- sslErrorLog("parseIncomingCerts: empty incoming cert array\n");
- return errSSLBadCert;
- }
-
- /*
- * Certs[0] is an SecIdentityRef from which we extract subject cert,
- * privKeyRef, pubKey.
- *
- * 1. ensure the first element is a SecIdentityRef.
- */
- identity = (SecIdentityRef)CFArrayGetValueAtIndex(certs, 0);
- if(identity == NULL) {
- sslErrorLog("parseIncomingCerts: bad cert array (1)\n");
- return errSecParam;
- }
- if(CFGetTypeID(identity) != SecIdentityGetTypeID()) {
- sslErrorLog("parseIncomingCerts: bad cert array (2)\n");
- return errSecParam;
- }
-
- /*
- * 2. Extract cert, keys and convert to local format.
- */
- ortn = SecIdentityCopyCertificate(identity, &certRef);
- if(ortn) {
- sslErrorLog("parseIncomingCerts: bad cert array (3)\n");
- return ortn;
- }
- ortn = secCertToSslCert(ctx, certRef, &thisSslCert);
- if(ortn) {
- sslErrorLog("parseIncomingCerts: bad cert array (4)\n");
- return ortn;
- }
- /* enqueue onto head of cert chain */
- thisSslCert->next = certChain;
- certChain = thisSslCert;
-
- if(signerAlg != NULL) {
- ortn = sslCertSignerAlg(certRef, signerAlg);
- if(ortn) {
- return ortn;
- }
- }
-
- /* fetch private key from identity */
- ortn = SecIdentityCopyPrivateKey(identity, &keyRef);
- if(ortn) {
- sslErrorLog("parseIncomingCerts: SecIdentityCopyPrivateKey err %d\n",
- (int)ortn);
- return ortn;
- }
- *privKeyRef = keyRef;
-
- /* obtain public key from cert */
- ortn = SecCertificateGetCLHandle(certRef, &clHand);
- if(ortn) {
- sslErrorLog("parseIncomingCerts: SecCertificateGetCLHandle err %d\n",
- (int)ortn);
- return ortn;
- }
- certData.Data = thisSslCert->derCert.data;
- certData.Length = thisSslCert->derCert.length;
- crtn = CSSM_CL_CertGetKeyInfo(clHand, &certData, pubKey);
- if(crtn) {
- sslErrorLog("parseIncomingCerts: CSSM_CL_CertGetKeyInfo err\n");
- return (OSStatus)crtn;
- }
-
- /* OK, that's the subject cert. Fetch optional remaining certs. */
- /*
- * Convert: CFArray of SecCertificateRefs --> chain of SSLCertificates.
- * Incoming certs have root last; SSLCertificate chain has root
- * first.
- */
- for(cert=1; cert<numCerts; cert++) {
- certRef = (SecCertificateRef)CFArrayGetValueAtIndex(certs, cert);
- if(certRef == NULL) {
- sslErrorLog("parseIncomingCerts: bad cert array (5)\n");
- return errSecParam;
- }
- if(CFGetTypeID(certRef) != SecCertificateGetTypeID()) {
- sslErrorLog("parseIncomingCerts: bad cert array (6)\n");
- return errSecParam;
- }
-
- /* Extract cert, convert to local format.
- */
- ortn = secCertToSslCert(ctx, certRef, &thisSslCert);
- if(ortn) {
- sslErrorLog("parseIncomingCerts: bad cert array (7)\n");
- return ortn;
- }
- /* enqueue onto head of cert chain */
- thisSslCert->next = certChain;
- certChain = thisSslCert;
- }
-
- /* SUCCESS */
- *destCert = certChain;
- return errSecSuccess;
-
- /* free certChain, everything in it, other vars, return ortn */
- sslDeleteCertificateChain(certChain, ctx);
- /* FIXME - anything else? */
- return ortn;
-}
-
-#else /* !USE_SSLCERTIFICATE */
-
-OSStatus
-parseIncomingCerts(
- SSLContext *ctx,
- CFArrayRef certs,
- CFArrayRef *destCertChain, /* &ctx->{localCertChain,encryptCertChain} */
- SSLPubKey **sslPubKey, /* &ctx->signingPubKey, etc. */
- SSLPrivKey **sslPrivKey, /* &ctx->signingPrivKeyRef, etc. */
- CFIndex *signerAlg) /* optional */
-{
- OSStatus ortn;
- CFIndex ix, numCerts;
- SecIdentityRef identity;
- CFMutableArrayRef certChain = NULL; /* Retained */
- SecCertificateRef leafCert = NULL; /* Retained */
- SecKeyRef pubKey = NULL; /* Retained */
- SecKeyRef privKey = NULL; /* Retained */
- SecTrustRef trust = NULL; /* Retained */
-
- assert(ctx != NULL);
- assert(destCertChain != NULL); /* though its referent may be NULL */
- assert(sslPubKey != NULL);
- assert(sslPrivKey != NULL);
-
- if (certs == NULL) {
- sslErrorLog("parseIncomingCerts: NULL incoming cert array\n");
- ortn = errSSLBadCert;
- goto errOut;
- }
- numCerts = CFArrayGetCount(certs);
- if (numCerts == 0) {
- sslErrorLog("parseIncomingCerts: empty incoming cert array\n");
- ortn = errSSLBadCert;
- goto errOut;
- }
-
- /*
- * Certs[0] is an SecIdentityRef from which we extract subject cert,
- * privKey, pubKey.
- *
- * 1. ensure the first element is a SecIdentityRef.
- */
- identity = (SecIdentityRef)CFArrayGetValueAtIndex(certs, 0);
- if (identity == NULL) {
- sslErrorLog("parseIncomingCerts: bad cert array (1)\n");
- ortn = errSecParam;
- goto errOut;
- }
- if (CFGetTypeID(identity) != SecIdentityGetTypeID()) {
- sslErrorLog("parseIncomingCerts: bad cert array (2)\n");
- ortn = errSecParam;
- goto errOut;
- }
-
- /*
- * 2. Extract cert, keys and convert to local format.
- */
- ortn = SecIdentityCopyCertificate(identity, &leafCert);
- if (ortn) {
- sslErrorLog("parseIncomingCerts: bad cert array (3)\n");
- goto errOut;
- }
-
- /* Fetch private key from identity */
- ortn = SecIdentityCopyPrivateKey(identity, &privKey);
- if (ortn) {
- sslErrorLog("parseIncomingCerts: SecIdentityCopyPrivateKey err %d\n",
- (int)ortn);
- goto errOut;
- }
-
- /* Convert the input array of SecIdentityRef at the start to an array of
- all certificates. */
- certChain = CFArrayCreateMutable(kCFAllocatorDefault, numCerts,
- &kCFTypeArrayCallBacks);
- if (!certChain) {
- ortn = errSecAllocate;
- goto errOut;
- }
- CFArrayAppendValue(certChain, leafCert);
- for (ix = 1; ix < numCerts; ++ix) {
- SecCertificateRef intermediate =
- (SecCertificateRef)CFArrayGetValueAtIndex(certs, ix);
- if (intermediate == NULL) {
- sslErrorLog("parseIncomingCerts: bad cert array (5)\n");
- ortn = errSecParam;
- goto errOut;
- }
- if (CFGetTypeID(intermediate) != SecCertificateGetTypeID()) {
- sslErrorLog("parseIncomingCerts: bad cert array (6)\n");
- ortn = errSecParam;
- goto errOut;
- }
-
- CFArrayAppendValue(certChain, intermediate);
- }
-
- /* Obtain public key from cert */
-#if TARGET_OS_IPHONE
- ortn = SecTrustCreateWithCertificates(certChain, NULL, &trust);
-#else
- {
- SecPolicyRef policy = SecPolicyCreateBasicX509();
- ortn = SecTrustCreateWithCertificates(certChain, policy, &trust);
- CFReleaseSafe(policy);
- if (!ortn) {
- /* We are only interested in getting the public key from the leaf
- * cert here, so for best performance, don't try to build a chain
- * or search any keychains.
- */
- CFArrayRef emptyArray = CFArrayCreate(NULL, NULL, 0, NULL);
- (void)SecTrustSetAnchorCertificates(trust, emptyArray);
- (void)SecTrustSetKeychains(trust, emptyArray);
- CFReleaseSafe(emptyArray);
- }
- }
-#endif
- if (ortn) {
- sslErrorLog("parseIncomingCerts: SecTrustCreateWithCertificates err %d\n",
- (int)ortn);
- goto errOut;
- }
-
-
-#if !TARGET_OS_IPHONE
- /* This is not required on iOS, but still required on osx */
- SecTrustResultType trustResult;
- ortn = SecTrustEvaluate(trust, &trustResult);
- if (ortn) {
- sslErrorLog("parseIncomingCerts: SecTrustEvaluate err %d\n",
- (int)ortn);
- goto errOut;
- }
-#endif
-
-
- pubKey = SecTrustCopyPublicKey(trust);
- if (!pubKey) {
- /* We parsed the private key succesfully but could not get the public key: return an error */
- sslErrorLog("parseIncomingCerts: SecTrustCopyPublicKey failed\n");
- ortn = errSecParam;
- goto errOut;
- }
-
- /* SUCCESS */
-errOut:
- CFReleaseSafe(trust);
- CFReleaseSafe(leafCert);
- CFReleaseSafe(*destCertChain);
- sslFreePubKey(sslPubKey);
- sslFreePrivKey(sslPrivKey);
-
- if (ortn) {
- CFReleaseSafe(certChain);
- CFReleaseSafe(pubKey);
- CFReleaseSafe(privKey);
-
- *destCertChain = NULL;
- } else {
- *destCertChain = certChain;
- *sslPubKey = (SSLPubKey*)pubKey;
- *sslPrivKey = (SSLPrivKey*)privKey;
- }
-
- return ortn;
-}
-#endif /* !USE_SSLCERTIFICATE */