Esempio n. 1
0
/* We have an iOS-style SecTrustRef, but we need to return a CDSA-based SecKeyRef.
 */
SecKeyRef SecTrustCopyPublicKey(SecTrustRef trust)
{
	SecKeyRef pubKey = NULL;
	SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, 0);
	(void) SecCertificateCopyPublicKey(certificate, &pubKey);
	return pubKey;
}
Esempio n. 2
0
SecCertificateRef AppleCryptoNative_X509ChainGetCertificateAtIndex(SecTrustRef chain, int64_t index)
{
    if (chain == NULL || index < 0)
        return NULL;

    return SecTrustGetCertificateAtIndex(chain, index);
}
static carray * mailstream_low_cfstream_get_certificate_chain(mailstream_low * s)
{
#if HAVE_CFNETWORK
  struct mailstream_cfstream_data * cfstream_data;
  unsigned int i;
  carray * result;
  
  cfstream_data = (struct mailstream_cfstream_data *) s->data;
  SecTrustRef secTrust = (SecTrustRef)CFReadStreamCopyProperty(cfstream_data->readStream, kCFStreamPropertySSLPeerTrust);
  if (secTrust == NULL)
    return NULL;
  
  CFIndex count = SecTrustGetCertificateCount(secTrust);
  
  result = carray_new(4);
  for(i = 0 ; i < count ; i ++) {
    SecCertificateRef cert = (SecCertificateRef) SecTrustGetCertificateAtIndex(secTrust, i);
    CFDataRef data = SecCertificateCopyData(cert);
    CFIndex length = CFDataGetLength(data);
    const UInt8 * bytes = CFDataGetBytePtr(data);
    MMAPString * str = mmap_string_sized_new(length);
    mmap_string_append_len(str, (char*) bytes, length);
    carray_add(result, str, NULL);
    CFRelease(data);
  }
  
  CFRelease(secTrust);
  
  return result;
#else
  return NULL;
#endif
}
Esempio n. 4
0
static int stransport_certificate(git_cert **out, git_stream *stream)
{
	stransport_stream *st = (stransport_stream *) stream;
	SecTrustRef trust = NULL;
	SecCertificateRef sec_cert;
	OSStatus ret;

	if ((ret = SSLCopyPeerTrust(st->ctx, &trust)) != noErr)
		return stransport_error(ret);

	sec_cert = SecTrustGetCertificateAtIndex(trust, 0);
	st->der_data = SecCertificateCopyData(sec_cert);
	CFRelease(trust);

	if (st->der_data == NULL) {
		giterr_set(GITERR_SSL, "retrieved invalid certificate data");
		return -1;
	}

	st->cert_info.parent.cert_type = GIT_CERT_X509;
	st->cert_info.data = (void *) CFDataGetBytePtr(st->der_data);
	st->cert_info.len = CFDataGetLength(st->der_data);

	*out = (git_cert *)&st->cert_info;
	return 0;
}
static void build_trust_chains(const void *key, const void *value, 
    void *context)
{
    CFMutableDictionaryRef identity_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 
        0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    SecKeyRef private_key = NULL;
    SecCertificateRef cert = NULL;
    SecIdentityRef identity = NULL;
    SecPolicyRef policy = NULL;
    CFMutableArrayRef cert_chain = NULL, eval_chain = NULL;
    SecTrustRef trust = NULL;
    build_trust_chains_context * a_build_trust_chains_context = (build_trust_chains_context*)context;

    CFDataRef key_bytes = CFDictionaryGetValue(value, CFSTR("key"));
    require(key_bytes, out);
    CFDataRef cert_bytes = CFDictionaryGetValue(value, CFSTR("cert"));
    require(cert_bytes, out);

    /* p12import only passes up rsa keys */
    require (private_key = SecKeyCreateRSAPrivateKey(kCFAllocatorDefault, 
        CFDataGetBytePtr(key_bytes), CFDataGetLength(key_bytes),
        kSecKeyEncodingPkcs1), out);
    require(cert = SecCertificateCreateWithData(kCFAllocatorDefault, cert_bytes), out);
    require(identity = SecIdentityCreate(kCFAllocatorDefault, cert, private_key), out);
    CFDictionarySetValue(identity_dict, kSecImportItemIdentity, identity);
    
    eval_chain = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
    require(eval_chain, out);
    CFArrayAppendValue(eval_chain, cert);
    CFRange all_certs = { 0, CFArrayGetCount(a_build_trust_chains_context->certs) };
    CFArrayAppendArray(eval_chain, a_build_trust_chains_context->certs, all_certs);
    require(policy = SecPolicyCreateBasicX509(), out);
    SecTrustResultType result;
    SecTrustCreateWithCertificates(eval_chain, policy, &trust);
    require(trust, out);
    SecTrustEvaluate(trust, &result);
    CFDictionarySetValue(identity_dict, kSecImportItemTrust, trust);
    
    require(cert_chain = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks), out);
    CFIndex cert_chain_length = SecTrustGetCertificateCount(trust);
    int i;
    for (i = 0; i < cert_chain_length; i++)
        CFArrayAppendValue(cert_chain, SecTrustGetCertificateAtIndex(trust, i));
    CFDictionarySetValue(identity_dict, kSecImportItemCertChain, cert_chain);
    
    CFArrayAppendValue(a_build_trust_chains_context->identities, identity_dict);
out:
    CFReleaseSafe(identity_dict);
    CFReleaseSafe(identity);
    CFReleaseSafe(private_key);
    CFReleaseSafe(cert);
    CFReleaseSafe(policy);
    CFReleaseSafe(cert_chain);
    CFReleaseSafe(eval_chain);
    CFReleaseSafe(trust);
}
Esempio n. 6
0
CFArrayRef SecTrustCopyProperties(SecTrustRef trust) {
    /* OS X creates a completely different structure with one dictionary for each certificate */
    CFIndex ix, count = SecTrustGetCertificateCount(trust);

    CFMutableArrayRef properties = CFArrayCreateMutable(kCFAllocatorDefault, count,
                                                        &kCFTypeArrayCallBacks);

    for (ix = 0; ix < count; ix++) {
        CFMutableDictionaryRef certDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
                                                                    &kCFTypeDictionaryValueCallBacks);
        /* Populate the certificate title */
        SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, ix);
        if (cert) {
            CFStringRef subjectSummary = SecCertificateCopySubjectSummary(cert);
            if (subjectSummary) {
                CFDictionaryAddValue(certDict, kSecPropertyTypeTitle, subjectSummary);
                CFRelease(subjectSummary);
            }
        }

        /* Populate a revocation reason if the cert was revoked */
        unsigned int numStatusCodes;
        CSSM_RETURN *statusCodes = NULL;
        statusCodes = copyCssmStatusCodes(trust, (uint32_t)ix, &numStatusCodes);
        if (statusCodes) {
            int32_t reason = statusCodes[numStatusCodes];  // stored at end of status codes array
            if (reason > 0) {
                CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason);
                if (cfreason) {
                    CFDictionarySetValue(certDict, kSecTrustRevocationReason, cfreason);
                    CFRelease(cfreason);
                }
            }
            free(statusCodes);
        }

        /* Populate the error in the leaf dictionary */
        if (ix == 0) {
            OSStatus error = errSecSuccess;
            (void)SecTrustGetCssmResultCode(trust, &error);
            CFStringRef errorStr = SecCopyErrorMessageString(error, NULL);
            if (errorStr) {
                CFDictionarySetValue(certDict, kSecPropertyTypeError, errorStr);
                CFRelease(errorStr);
            }
        }

        CFArrayAppendValue(properties, certDict);
        CFRelease(certDict);
    }

    return properties;
}
Esempio n. 7
0
// Return the constructed certificate chain for this trust reference,
// making output certificates pointer-equivalent to any provided input
// certificates (where possible) for legacy behavioral compatibility.
// Caller must release this array.
//
CFArrayRef SecTrustCopyConstructedChain(SecTrustRef trust)
{
	CFMutableArrayRef certChain = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
	CFIndex idx, count = SecTrustGetCertificateCount(trust);
	for (idx=0; idx < count; idx++) {
		SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, idx);
		if (certificate) {
			CFArrayAppendValue(certChain, certificate);
		}
	}
	// <rdar://24393060>
	// Some callers make the assumption that the certificates in
	// this chain are pointer-equivalent to ones they passed to the
	// SecTrustCreateWithCertificates function. We'll maintain that
	// behavior here for compatibility.
	//
	CFArrayRef inputCertArray = SecTrustCopyInputCertificates(trust);
	CFArrayRef inputAnchorArray = SecTrustCopyInputAnchors(trust);
	CFIndex inputCertIdx, inputCertCount = (inputCertArray) ? CFArrayGetCount(inputCertArray) : 0;
	CFIndex inputAnchorIdx, inputAnchorCount = (inputAnchorArray) ? CFArrayGetCount(inputAnchorArray) : 0;
	for (idx=0; idx < count; idx++) {
		SecCertificateRef tmpCert = (SecCertificateRef) CFArrayGetValueAtIndex(certChain, idx);
		if (tmpCert) {
			SecCertificateRef matchCert = NULL;
			for (inputCertIdx=0; inputCertIdx < inputCertCount && !matchCert; inputCertIdx++) {
				SecCertificateRef inputCert = (SecCertificateRef) CFArrayGetValueAtIndex(inputCertArray, inputCertIdx);
				if (inputCert && CFEqual(inputCert, tmpCert)) {
					matchCert = inputCert;
				}
			}
			for (inputAnchorIdx=0; inputAnchorIdx < inputAnchorCount && !matchCert; inputAnchorIdx++) {
				SecCertificateRef inputAnchor = (SecCertificateRef) CFArrayGetValueAtIndex(inputAnchorArray, inputAnchorIdx);
				if (inputAnchor && CFEqual(inputAnchor, tmpCert)) {
					matchCert = inputAnchor;
				}
			}
			if (matchCert) {
				CFArraySetValueAtIndex(certChain, idx, matchCert);
			}
		}
	}
	if (inputCertArray) {
		CFRelease(inputCertArray);
	}
	if (inputAnchorArray) {
		CFRelease(inputAnchorArray);
	}
	return certChain;
}
static OSStatus
_EAPSecIdentityCreateCertificateTrustChain(SecIdentityRef identity,
					   CFArrayRef * ret_chain)
{
    SecCertificateRef		cert = NULL;
    CFArrayRef 			certs;
    SecPolicyRef		policy = NULL;
    OSStatus			status;
    SecTrustRef 		trust = NULL;
    SecTrustResultType 		trust_result;

    *ret_chain = NULL;
    ok(policy = SecPolicyCreateBasicX509(), "SecPolicyCreateBasicX509");
    ok_status(status = SecIdentityCopyCertificate(identity, &cert), "SecIdentityCopyCertificate");
    certs = CFArrayCreate(NULL, (const void **)&cert,
			  1, &kCFTypeArrayCallBacks);
    CFReleaseNull(cert);
    ok_status(status = SecTrustCreateWithCertificates(certs, policy, &trust),
        "SecTrustCreateWithCertificates");
    CFReleaseNull(certs);
    ok_status(status = SecTrustEvaluate(trust, &trust_result), "SecTrustEvaluate");
    {
	CFMutableArrayRef	array;
	CFIndex			count = SecTrustGetCertificateCount(trust);
	CFIndex			i;

	isnt(count, 0, "SecTrustGetCertificateCount is nonzero");
	array = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks);
	for (i = 0; i < count; i++) {
	    SecCertificateRef	s;

	    s = SecTrustGetCertificateAtIndex(trust, i);
	    CFArrayAppendValue(array, s);
	}
	*ret_chain = array;
    }

    CFReleaseNull(trust);
    CFReleaseNull(policy);
    return (status);
}
Esempio n. 9
0
static CURLcode
darwinssl_connect_step3(struct connectdata *conn,
                        int sockindex)
{
  struct SessionHandle *data = conn->data;
  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
  CFStringRef server_cert_summary;
  char server_cert_summary_c[128];
  CFArrayRef server_certs;
  SecCertificateRef server_cert;
  OSStatus err;
  CFIndex i, count;
  SecTrustRef trust;

  /* There is no step 3!
   * Well, okay, if verbose mode is on, let's print the details of the
   * server certificates. */
#if defined(__MAC_10_7) || defined(__IPHONE_5_0)
  if(SecTrustGetCertificateCount != NULL) {
#pragma unused(server_certs)
    err = SSLCopyPeerTrust(connssl->ssl_ctx, &trust);
    if(err == noErr) {
      count = SecTrustGetCertificateCount(trust);
      for(i = 0L ; i < count ; i++) {
        server_cert = SecTrustGetCertificateAtIndex(trust, i);
        server_cert_summary = SecCertificateCopySubjectSummary(server_cert);
        memset(server_cert_summary_c, 0, 128);
        if(CFStringGetCString(server_cert_summary,
                              server_cert_summary_c,
                              128,
                              kCFStringEncodingUTF8)) {
          infof(data, "Server certificate: %s\n", server_cert_summary_c);
        }
        CFRelease(server_cert_summary);
      }
      CFRelease(trust);
    }
  }
  else {
#elif TARGET_OS_EMBEDDED == 0
#pragma unused(trust)
  err = SSLCopyPeerCertificates(connssl->ssl_ctx, &server_certs);
  if(err == noErr) {
    count = CFArrayGetCount(server_certs);
    for(i = 0L ; i < count ; i++) {
      server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs, i);

      server_cert_summary = SecCertificateCopySubjectSummary(server_cert);
      memset(server_cert_summary_c, 0, 128);
      if(CFStringGetCString(server_cert_summary,
                            server_cert_summary_c,
                            128,
                            kCFStringEncodingUTF8)) {
        infof(data, "Server certificate: %s\n", server_cert_summary_c);
      }
      CFRelease(server_cert_summary);
    }
    CFRelease(server_certs);
  }
#endif /* defined(__MAC_10_7) || defined(__IPHONE_5_0) */
#if defined(__MAC_10_7) || defined(__IPHONE_5_0)
  }
#endif /* defined(__MAC_10_7) || defined(__IPHONE_5_0) */

  connssl->connecting_state = ssl_connect_done;
  return CURLE_OK;
}
Esempio n. 10
0
static int st_validateServerCertificate (vlc_tls_t *session, const char *hostname) {

    int result = -1;
    vlc_tls_sys_t *sys = session->sys;
    SecCertificateRef leaf_cert = NULL;

    SecTrustRef trust = NULL;
    OSStatus ret = SSLCopyPeerTrust (sys->p_context, &trust);
    if (ret != noErr || trust == NULL) {
        msg_Err(session, "error getting certifictate chain");
        return -1;
    }

    CFStringRef cfHostname = CFStringCreateWithCString(kCFAllocatorDefault,
                             hostname,
                             kCFStringEncodingUTF8);


    /* enable default root / anchor certificates */
    ret = SecTrustSetAnchorCertificates (trust, NULL);
    if (ret != noErr) {
        msg_Err(session, "error setting anchor certificates");
        result = -1;
        goto out;
    }

    SecTrustResultType trust_eval_result = 0;

    ret = SecTrustEvaluate(trust, &trust_eval_result);
    if(ret != noErr) {
        msg_Err(session, "error calling SecTrustEvaluate");
        result = -1;
        goto out;
    }

    switch (trust_eval_result) {
    case kSecTrustResultUnspecified:
    case kSecTrustResultProceed:
        msg_Dbg(session, "cerfificate verification successful, result is %d", trust_eval_result);
        result = 0;
        goto out;

    case kSecTrustResultRecoverableTrustFailure:
    case kSecTrustResultDeny:
    default:
        msg_Warn(session, "cerfificate verification failed, result is %d", trust_eval_result);
    }

    /* get leaf certificate */
    /* SSLCopyPeerCertificates is only available on OSX 10.5 or later */
#if !TARGET_OS_IPHONE
    CFArrayRef cert_chain = NULL;
    ret = SSLCopyPeerCertificates (sys->p_context, &cert_chain);
    if (ret != noErr || !cert_chain) {
        result = -1;
        goto out;
    }

    if (CFArrayGetCount (cert_chain) == 0) {
        CFRelease (cert_chain);
        result = -1;
        goto out;
    }

    leaf_cert = (SecCertificateRef)CFArrayGetValueAtIndex (cert_chain, 0);
    CFRetain (leaf_cert);
    CFRelease (cert_chain);
#else
    /* SecTrustGetCertificateAtIndex is only available on 10.7 or iOS */
    if (SecTrustGetCertificateCount (trust) == 0) {
        result = -1;
        goto out;
    }

    leaf_cert = SecTrustGetCertificateAtIndex (trust, 0);
    CFRetain (leaf_cert);
#endif


    /* check if leaf already accepted */
    CFIndex max = CFArrayGetCount (sys->p_cred->whitelist);
    for (CFIndex i = 0; i < max; ++i) {
        CFDictionaryRef dict = CFArrayGetValueAtIndex (sys->p_cred->whitelist, i);
        CFStringRef knownHost = (CFStringRef)CFDictionaryGetValue (dict, cfKeyHost);
        SecCertificateRef knownCert = (SecCertificateRef)CFDictionaryGetValue (dict, cfKeyCertificate);

        if (!knownHost || !knownCert)
            continue;

        if (CFEqual (knownHost, cfHostname) && CFEqual (knownCert, leaf_cert)) {
            msg_Warn(session, "certificate already accepted, continuing");
            result = 0;
            goto out;
        }
    }

    /* We do not show more certificate details yet because there is no proper API to get
       a summary of the certificate. SecCertificateCopySubjectSummary is the only method
       available on iOS and 10.6. More promising API functions such as
       SecCertificateCopyLongDescription also print out the subject only, more or less.
       But only showing the certificate subject is of no real help for the user.
       We could use SecCertificateCopyValues, but then we need to parse all OID values for
       ourself. This is too mad for just printing information the user will never check
       anyway.
     */

    const char *msg = N_("You attempted to reach %s. "
                         "However the security certificate presented by the server "
                         "is unknown and could not be authenticated by any trusted "
                         "Certification Authority. "
                         "This problem may be caused by a configuration error "
                         "or an attempt to breach your security or your privacy.\n\n"
                         "If in doubt, abort now.\n");
    int answer = dialog_Question (session, _("Insecure site"), vlc_gettext (msg),
                                  _("Abort"), _("Accept certificate temporarily"), NULL, hostname);

    if(answer == 2) {
        msg_Warn(session, "Proceeding despite of failed certificate validation");

        /* save leaf certificate in whitelist */
        const void *keys[] = {cfKeyHost, cfKeyCertificate};
        const void *values[] = {cfHostname, leaf_cert};
        CFDictionaryRef dict = CFDictionaryCreate (kCFAllocatorDefault,
                               keys, values, 2,
                               &kCFTypeDictionaryKeyCallBacks,
                               &kCFTypeDictionaryValueCallBacks);
        if(!dict) {
            msg_Err (session, "error creating dict");
            result = -1;
            goto out;
        }

        CFArrayAppendValue (sys->p_cred->whitelist, dict);
        CFRelease (dict);

        result = 0;
        goto out;

    } else {
        result = -1;
        goto out;
    }

out:
    CFRelease (trust);

    if (cfHostname)
        CFRelease (cfHostname);
    if (leaf_cert)
        CFRelease (leaf_cert);

    return result;
}
Esempio n. 11
0
static CURLcode
darwinssl_connect_step3(struct connectdata *conn,
                        int sockindex)
{
  struct SessionHandle *data = conn->data;
  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
  CFStringRef server_cert_summary;
  char server_cert_summary_c[128];
  CFArrayRef server_certs;
  SecCertificateRef server_cert;
  OSStatus err;
  CFIndex i, count;
  SecTrustRef trust;

  /* There is no step 3!
   * Well, okay, if verbose mode is on, let's print the details of the
   * server certificates. */
#if defined(__MAC_10_7) || defined(__IPHONE_5_0)
#if (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)
#pragma unused(server_certs)
  err = SSLCopyPeerTrust(connssl->ssl_ctx, &trust);
  if(err == noErr) {
    count = SecTrustGetCertificateCount(trust);
    for(i = 0L ; i < count ; i++) {
      server_cert = SecTrustGetCertificateAtIndex(trust, i);
      server_cert_summary = SecCertificateCopySubjectSummary(server_cert);
      memset(server_cert_summary_c, 0, 128);
      if(CFStringGetCString(server_cert_summary,
                            server_cert_summary_c,
                            128,
                            kCFStringEncodingUTF8)) {
        infof(data, "Server certificate: %s\n", server_cert_summary_c);
      }
      CFRelease(server_cert_summary);
    }
    CFRelease(trust);
  }
#else
  /* SSLCopyPeerCertificates() is deprecated as of Mountain Lion.
     The function SecTrustGetCertificateAtIndex() is officially present
     in Lion, but it is unfortunately also present in Snow Leopard as
     private API and doesn't work as expected. So we have to look for
     a different symbol to make sure this code is only executed under
     Lion or later. */
  if(SecTrustEvaluateAsync != NULL) {
#pragma unused(server_certs)
    err = SSLCopyPeerTrust(connssl->ssl_ctx, &trust);
    if(err == noErr) {
      count = SecTrustGetCertificateCount(trust);
      for(i = 0L ; i < count ; i++) {
        server_cert = SecTrustGetCertificateAtIndex(trust, i);
        server_cert_summary =
          SecCertificateCopyLongDescription(NULL, server_cert, NULL);
        memset(server_cert_summary_c, 0, 128);
        if(CFStringGetCString(server_cert_summary,
                              server_cert_summary_c,
                              128,
                              kCFStringEncodingUTF8)) {
          infof(data, "Server certificate: %s\n", server_cert_summary_c);
        }
        CFRelease(server_cert_summary);
      }
      CFRelease(trust);
    }
  }
  else {
    err = SSLCopyPeerCertificates(connssl->ssl_ctx, &server_certs);
    if(err == noErr) {
      count = CFArrayGetCount(server_certs);
      for(i = 0L ; i < count ; i++) {
        server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs,
                                                                i);

        server_cert_summary = SecCertificateCopySubjectSummary(server_cert);
        memset(server_cert_summary_c, 0, 128);
        if(CFStringGetCString(server_cert_summary,
                              server_cert_summary_c,
                              128,
                              kCFStringEncodingUTF8)) {
          infof(data, "Server certificate: %s\n", server_cert_summary_c);
        }
        CFRelease(server_cert_summary);
      }
      CFRelease(server_certs);
    }
  }
#endif /* (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE) */
#else
#pragma unused(trust)
  err = SSLCopyPeerCertificates(connssl->ssl_ctx, &server_certs);
  if(err == noErr) {
    count = CFArrayGetCount(server_certs);
    for(i = 0L ; i < count ; i++) {
      server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs, i);

      server_cert_summary = SecCertificateCopySubjectSummary(server_cert);
      memset(server_cert_summary_c, 0, 128);
      if(CFStringGetCString(server_cert_summary,
                            server_cert_summary_c,
                            128,
                            kCFStringEncodingUTF8)) {
        infof(data, "Server certificate: %s\n", server_cert_summary_c);
      }
      CFRelease(server_cert_summary);
    }
    CFRelease(server_certs);
  }
#endif /* defined(__MAC_10_7) || defined(__IPHONE_5_0) */

  connssl->connecting_state = ssl_connect_done;
  return CURLE_OK;
}
Esempio n. 12
0
//
// Here is where backward compatibility gets ugly. CSSM_TP_APPLE_EVIDENCE_INFO does not exist
// in the unified SecTrust world. Unfortunately, some clients are still calling legacy APIs
// (e.g. SecTrustGetResult) and grubbing through the info for StatusBits and StatusCodes.
// SecTrustGetEvidenceInfo builds the legacy evidence info structure as needed, and returns
// a pointer to it. The evidence data is allocated here and set in the _legacy_* fields
// of the TSecTrust; the trust object subsequently owns it. The returned pointer is expected
// to be valid for the lifetime of the SecTrustRef, or until the trust parameters are changed,
// which would force re-evaluation.
//
static CSSM_TP_APPLE_EVIDENCE_INFO *
SecTrustGetEvidenceInfo(SecTrustRef trust)
{
	TSecTrust *secTrust = (TSecTrust *)trust;
	if (!secTrust) {
		return NULL;
	}
	if (secTrust->_trustResult != kSecTrustResultInvalid &&
		secTrust->_legacy_info_array) {
		// we've already got valid evidence info, return it now.
		return (CSSM_TP_APPLE_EVIDENCE_INFO *)secTrust->_legacy_info_array;
	}

	// Getting the count implicitly evaluates the chain if necessary.
	CFIndex idx, count = SecTrustGetCertificateCount(trust);
	CFArrayRef inputCertArray = SecTrustCopyInputCertificates(trust);
	CFArrayRef inputAnchorArray = SecTrustCopyInputAnchors(trust);
	CFIndex inputCertIdx, inputCertCount = (inputCertArray) ? CFArrayGetCount(inputCertArray) : 0;
	CFIndex inputAnchorIdx, inputAnchorCount = (inputAnchorArray) ? CFArrayGetCount(inputAnchorArray) : 0;

	CSSM_TP_APPLE_EVIDENCE_INFO *infoArray = (CSSM_TP_APPLE_EVIDENCE_INFO *)calloc(count, sizeof(CSSM_TP_APPLE_EVIDENCE_INFO));
	CSSM_RETURN *statusArray = NULL;
	unsigned int numStatusCodes = 0;

	// Set status codes for each certificate in the constructed chain
	for (idx=0; idx < count; idx++) {
		SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, idx);
		if (!cert) {
			continue;
		}
		CSSM_TP_APPLE_EVIDENCE_INFO *evInfo = &infoArray[idx];

		/* first the booleans (StatusBits flags) */
		CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
		if (secTrust->_verifyDate) {
			now = CFDateGetAbsoluteTime(secTrust->_verifyDate);
		}
		CFAbsoluteTime na = SecCertificateNotValidAfter(cert);
		if (na < now) {
			evInfo->StatusBits |= CSSM_CERT_STATUS_EXPIRED;
		}
		CFAbsoluteTime nb = SecCertificateNotValidBefore(cert);
		if (nb > now) {
			evInfo->StatusBits |= CSSM_CERT_STATUS_NOT_VALID_YET;
		}
		for (inputAnchorIdx=0; inputAnchorIdx < inputAnchorCount; inputAnchorIdx++) {
			SecCertificateRef inputAnchor = (SecCertificateRef) CFArrayGetValueAtIndex(inputAnchorArray, inputAnchorIdx);
			if (inputAnchor && CFEqual(inputAnchor, cert)) {
				evInfo->StatusBits |= CSSM_CERT_STATUS_IS_IN_ANCHORS;
				break;
			}
		}
		for (inputCertIdx=0; inputCertIdx < inputCertCount; inputCertIdx++) {
			SecCertificateRef inputCert = (SecCertificateRef) CFArrayGetValueAtIndex(inputCertArray, inputCertIdx);
			if (inputCert && CFEqual(inputCert, cert)) {
				evInfo->StatusBits |= CSSM_CERT_STATUS_IS_IN_INPUT_CERTS;
				break;
			}
		}

		/* See if there are trust settings for this certificate. */
		CFStringRef hashStr = SecTrustSettingsCertHashStrFromCert(cert);
		bool foundMatch = false;
		bool foundAny = false;
		CSSM_RETURN *errors = NULL;
		uint32 errorCount = 0;
		OSStatus status = 0;
		SecTrustSettingsDomain foundDomain = kSecTrustSettingsDomainUser;
		SecTrustSettingsResult foundResult = kSecTrustSettingsResultInvalid;
		bool isSelfSigned = false;
		if ((count - 1) == idx) {
			// Only the last cert in the chain needs to be considered
			Boolean selfSigned;
			status = SecCertificateIsSelfSigned(cert, &selfSigned);
			isSelfSigned = (status) ? false : ((selfSigned) ? true : false);
			if (isSelfSigned) {
				evInfo->StatusBits |= CSSM_CERT_STATUS_IS_ROOT;
			}
		}
		// STU: rdar://25554967
		// %%% need to get policyOID, policyString, and keyUsage here!

		status = SecTrustSettingsEvaluateCert(
				hashStr,		/* certHashStr */
				NULL,			/* policyOID (optional) */
				NULL,			/* policyString (optional) */
				0,				/* policyStringLen */
				0,				/* keyUsage */
				isSelfSigned,	/* isRootCert */
				&foundDomain,	/* foundDomain */
				&errors,		/* allowedErrors -- MUST FREE */
				&errorCount,	/* numAllowedErrors */
				&foundResult,	/* resultType */
				&foundMatch,	/* foundMatchingEntry */
				&foundAny);		/* foundAnyEntry */

		if (status == errSecSuccess) {
			if (foundMatch) {
				switch (foundResult) {
					case kSecTrustSettingsResultTrustRoot:
					case kSecTrustSettingsResultTrustAsRoot:
						/* these two can be disambiguated by IS_ROOT */
						evInfo->StatusBits |= CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST;
						break;
					case kSecTrustSettingsResultDeny:
						evInfo->StatusBits |= CSSM_CERT_STATUS_TRUST_SETTINGS_DENY;
						break;
					case kSecTrustSettingsResultUnspecified:
					case kSecTrustSettingsResultInvalid:
					default:
						break;
				}
			}
		}
		if (errors) {
			free(errors);
		}
		if (hashStr) {
			CFRelease(hashStr);
		}

		unsigned int numCodes=0;
		CSSM_RETURN *statusCodes = copyCssmStatusCodes(trust, (unsigned int)idx, &numCodes);
		if (statusCodes) {
			// Realloc space for these status codes at end of our status codes block.
			// Two important things to note:
			// 1. the actual length is numCodes+1 because copyCssmStatusCodes
			// allocates one more element at the end for the CrlReason value.
			// 2. realloc may cause the pointer to move, which means we will
			// need to fix up the StatusCodes fields after we're done with this loop.
			unsigned int totalStatusCodes = numStatusCodes + numCodes + 1;
			statusArray = (CSSM_RETURN *)realloc(statusArray, totalStatusCodes * sizeof(CSSM_RETURN));
			evInfo->StatusCodes = &statusArray[numStatusCodes];
			evInfo->NumStatusCodes = numCodes;
			// Copy the new codes (plus one) into place
			for (unsigned int cpix = 0; cpix <= numCodes; cpix++) {
				evInfo->StatusCodes[cpix] = statusCodes[cpix];
			}
			numStatusCodes = totalStatusCodes;
			free(statusCodes);
		}

		if(evInfo->StatusBits & (CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST |
								 CSSM_CERT_STATUS_TRUST_SETTINGS_DENY |
								 CSSM_CERT_STATUS_TRUST_SETTINGS_IGNORED_ERROR)) {
			/* Something noteworthy happened involving TrustSettings */
			uint32 whichDomain = 0;
			switch(foundDomain) {
				case kSecTrustSettingsDomainUser:
					whichDomain = CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_USER;
					break;
				case kSecTrustSettingsDomainAdmin:
					whichDomain = CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_ADMIN;
					break;
				case kSecTrustSettingsDomainSystem:
					whichDomain = CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_SYSTEM;
					break;
			}
			evInfo->StatusBits |= whichDomain;
		}

		/* index into raw cert group or AnchorCerts depending on IS_IN_ANCHORS */
		//evInfo->Index = certInfo->index();
		/* nonzero if cert came from a DLDB */
		//evInfo->DlDbHandle = certInfo->dlDbHandle();
		//evInfo->UniqueRecord = certInfo->uniqueRecord();
	}

	// Now that all the status codes have been allocated in a contiguous block,
	// refresh the StatusCodes pointer in each array element.
	numStatusCodes = 0;
	for (idx=0; idx < count; idx++) {
		CSSM_TP_APPLE_EVIDENCE_INFO *evInfo = &infoArray[idx];
		evInfo->StatusCodes = &statusArray[numStatusCodes];
		numStatusCodes += evInfo->NumStatusCodes + 1;
	}

	secTrust->_legacy_info_array = infoArray;
	secTrust->_legacy_status_array = statusArray;

	if (inputCertArray) {
		CFRelease(inputCertArray);
	}
	if (inputAnchorArray) {
		CFRelease(inputAnchorArray);
	}

	return (CSSM_TP_APPLE_EVIDENCE_INFO *)secTrust->_legacy_info_array;
}
Esempio n. 13
0
static carray * mailstream_low_cfstream_get_certificate_chain(mailstream_low * s)
{
#if HAVE_CFNETWORK
  struct mailstream_cfstream_data * cfstream_data;
  unsigned int i;
  carray * result;
  CFArrayRef certs;
  CFIndex count;
  
  cfstream_data = (struct mailstream_cfstream_data *) s->data;
    
  SecTrustRef secTrust = (SecTrustRef)CFReadStreamCopyProperty(cfstream_data->readStream, kCFStreamPropertySSLPeerTrust);
  if (secTrust) {
      // SecTrustEvaluate() needs to be called before SecTrustGetCertificateCount() in Mac OS X <= 10.8
      SecTrustEvaluate(secTrust, NULL);
      count = SecTrustGetCertificateCount(secTrust);
      result = carray_new(4);
      for(i = 0 ; i < count ; i ++) {
          SecCertificateRef cert = (SecCertificateRef) SecTrustGetCertificateAtIndex(secTrust, i);
          CFDataRef data = SecCertificateCopyData(cert);
          if (data == NULL) {
            carray_free(result);
            CFRelease(secTrust);
            return NULL;
          }
          CFIndex length = CFDataGetLength(data);
          const UInt8 * bytes = CFDataGetBytePtr(data);
          MMAPString * str = mmap_string_sized_new(length);
          mmap_string_append_len(str, (char*) bytes, length);
          carray_add(result, str, NULL);
          CFRelease(data);
      }
      CFRelease(secTrust);
  }
  else {
      certs = CFReadStreamCopyProperty(cfstream_data->readStream, kCFStreamPropertySSLPeerCertificates);
      if (certs) {
          count = CFArrayGetCount(certs);
          result = carray_new(4);
          for(i = 0 ; i < count ; i ++) {
              SecCertificateRef cert = (SecCertificateRef) CFArrayGetValueAtIndex(certs, i);
              CFDataRef data = SecCertificateCopyData(cert);
              if (data == NULL) {
                carray_free(result);
                CFRelease(certs);
                return NULL;
              }
              CFIndex length = CFDataGetLength(data);
              const UInt8 * bytes = CFDataGetBytePtr(data);
              MMAPString * str = mmap_string_sized_new(length);
              mmap_string_append_len(str, (char*) bytes, length);
              carray_add(result, str, NULL);
              CFRelease(data);
          }
          CFRelease(certs);
      }
      else {
          return NULL;
      }
  }
    
  return result;
#else
  return NULL;
#endif
}
Esempio n. 14
0
static bool isSoftwareUpdateDevelopment(SecTrustRef trust) {
    bool isPolicy = false, isEKU = false;
    CFArrayRef policies = NULL;

    /* Policy used to evaluate was SWUpdateSigning */
    SecTrustCopyPolicies(trust, &policies);
    if (policies) {
        SecPolicyRef swUpdatePolicy = SecPolicyCreateAppleSWUpdateSigning();
        if (swUpdatePolicy && CFArrayContainsValue(policies, CFRangeMake(0, CFArrayGetCount(policies)),
                                                   swUpdatePolicy)) {
            isPolicy = true;
        }
        if (swUpdatePolicy) { CFRelease(swUpdatePolicy); }
        CFRelease(policies);
    }
    if (!isPolicy) {
        return false;
    }

    /* Only error was EKU on the leaf */
    CFArrayRef details = SecTrustCopyFilteredDetails(trust);
    CFIndex ix, count = CFArrayGetCount(details);
    bool hasDisqualifyingError = false;
    for (ix = 0; ix < count; ix++) {
        CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix);
        if (ix == 0) { // Leaf
            if (CFDictionaryGetCount(detail) != 1 || // One error
                CFDictionaryGetValue(detail, CFSTR("ExtendedKeyUsage")) != kCFBooleanFalse) { // kSecPolicyCheckExtendedKeyUsage
                hasDisqualifyingError = true;
                break;
            }
        } else {
            if (CFDictionaryGetCount(detail) > 0) { // No errors on other certs
                hasDisqualifyingError = true;
                break;
            }
        }
    }
    CFReleaseSafe(details);
    if (hasDisqualifyingError) {
        return false;
    }

    /* EKU on the leaf is the Apple Development Code Signing OID */
    SecCertificateRef leaf = SecTrustGetCertificateAtIndex(trust, 0);
    CSSM_DATA *fieldValue = NULL;
    if (errSecSuccess != SecCertificateCopyFirstFieldValue(leaf, &CSSMOID_ExtendedKeyUsage, &fieldValue)) {
        return false;
    }
    if (fieldValue && fieldValue->Data && fieldValue->Length == sizeof(CSSM_X509_EXTENSION)) {
        const CSSM_X509_EXTENSION *ext = (const CSSM_X509_EXTENSION *)fieldValue->Data;
        if (ext->format == CSSM_X509_DATAFORMAT_PARSED) {
            const CE_ExtendedKeyUsage *ekus = (const CE_ExtendedKeyUsage *)ext->value.parsedValue;
            if (ekus && (ekus->numPurposes == 1) && ekus->purposes[0].Data &&
                (ekus->purposes[0].Length == CSSMOID_APPLE_EKU_CODE_SIGNING_DEV.Length) &&
                (memcmp(ekus->purposes[0].Data, CSSMOID_APPLE_EKU_CODE_SIGNING_DEV.Data,
                        ekus->purposes[0].Length) == 0)) {
                isEKU = true;
            }
        }
    }
    SecCertificateReleaseFirstFieldValue(leaf, &CSSMOID_ExtendedKeyUsage, fieldValue);
    return isEKU;
}
Esempio n. 15
0
static void
filter_exception(const void *key, const void *value, void *context)
{
	SecExceptionFilterContext *ctx = (SecExceptionFilterContext *)context;
	if (!ctx) { return; }

	SecTrustOptionFlags options = ctx->flags;
	CFMutableDictionaryRef filteredException = ctx->filteredException;
	CFStringRef keystr = (CFStringRef)key;

	if (ctx->oldException && CFDictionaryContainsKey(ctx->oldException, key)) {
		// Keep existing exception in filtered dictionary, regardless of options
		CFDictionaryAddValue(filteredException, key, CFDictionaryGetValue(ctx->oldException, key));
		return;
	}

	bool allowed = false;

	if (CFEqual(keystr, CFSTR("SHA1Digest"))) {
		allowed = true; // this key is informational and always permitted
	}
	else if (CFEqual(keystr, CFSTR("NotValidBefore"))) {
		allowed = ((options & kSecTrustOptionAllowExpired) != 0);
	}
	else if (CFEqual(keystr, CFSTR("ValidLeaf"))) {
		allowed = ((options & kSecTrustOptionAllowExpired) != 0);
	}
	else if (CFEqual(keystr, CFSTR("ValidIntermediates"))) {
		allowed = ((options & kSecTrustOptionAllowExpired) != 0);
	}
	else if (CFEqual(keystr, CFSTR("ValidRoot"))) {
        if (((options & kSecTrustOptionAllowExpired) != 0) ||
            ((options & kSecTrustOptionAllowExpiredRoot) != 0)) {
            allowed = true;
        }
	}
	else if (CFEqual(keystr, CFSTR("AnchorTrusted"))) {
		bool implicitAnchors = ((options & kSecTrustOptionImplicitAnchors) != 0);
		// Implicit anchors option only filters exceptions for self-signed certs
		if (implicitAnchors && ctx->trustRef &&
		    (ctx->certIX < SecTrustGetCertificateCount(ctx->trustRef))) {
			Boolean isSelfSigned = false;
			SecCertificateRef cert = SecTrustGetCertificateAtIndex(ctx->trustRef, ctx->certIX);
			if (cert && (errSecSuccess == SecCertificateIsSelfSigned(cert, &isSelfSigned)) &&
			    isSelfSigned) {
				allowed = true;
			}
		}
	}
	else if (CFEqual(keystr, CFSTR("KeyUsage")) ||
	         CFEqual(keystr, CFSTR("ExtendedKeyUsage")) ||
	         CFEqual(keystr, CFSTR("BasicConstraints")) ||
	         CFEqual(keystr, CFSTR("NonEmptySubject")) ||
	         CFEqual(keystr, CFSTR("IdLinkage"))) {
		// Cannot override these exceptions
		allowed = false;
	}
	else {
		// Unhandled exceptions should not be overridden,
		// but we want to know which ones we're missing
		char *cstr = CFStringToCString(keystr);
		syslog(LOG_ERR, "Unfiltered exception: %s", (cstr) ? cstr : "<NULL>");
		if (cstr) { free(cstr); }
		allowed = false;
	}

	if (allowed) {
		CFDictionaryAddValue(filteredException, key, value);
	}
}
Esempio n. 16
0
/*
 * Verify a chain of DER-encoded certs.
 */
static OSStatus sslVerifyCertChain(
	SSLContext				*ctx)
{
	OSStatus status;
	SecTrustRef trust = NULL;

    /* renegotiate - start with a new SecTrustRef */
    CFReleaseNull(ctx->peerSecTrust);

    /* on failure, we always return trust==NULL, so we don't check the returned status here */
    sslCreateSecTrust(ctx, &trust);

    if(trust==NULL) {
        if(ctx->protocolSide == kSSLClientSide) {
            /* No cert chain is always a trust failure on the server side */
            status = errSSLXCertChainInvalid;
            sslErrorLog("***Error: NULL server cert chain\n");
        } else {
            /* No cert chain on the client side is ok unless using kAlwaysAuthenticate */
            if(ctx->clientAuth == kAlwaysAuthenticate) {
                sslErrorLog("***Error: NULL client cert chain\n");
                status = errSSLXCertChainInvalid;
            } else {
                status = noErr;
            }
        }
        goto errOut;
    }


	if (!ctx->enableCertVerify) {
		/* trivial case, this is caller's responsibility */
		status = errSecSuccess;
		goto errOut;
	}

	SecTrustResultType secTrustResult;
	require_noerr(status = SecTrustEvaluate(trust, &secTrustResult), errOut);
	switch (secTrustResult) {
        case kSecTrustResultUnspecified:
            /* cert chain valid, no special UserTrust assignments */
        case kSecTrustResultProceed:
            /* cert chain valid AND user explicitly trusts this */
            status = errSecSuccess;
            break;
        case kSecTrustResultDeny:
        case kSecTrustResultConfirm:
        case kSecTrustResultRecoverableTrustFailure:
        default:
            if(ctx->allowAnyRoot) {
                sslErrorLog("***Warning: accepting unverified cert chain\n");
                status = errSecSuccess;
            }
            else {
#if !TARGET_OS_IPHONE
				/*
				 * If the caller provided a list of trusted leaf certs, check them here
				 */
                if(ctx->trustedLeafCerts) {
                    if (sslGetMatchingCertInArray(SecTrustGetCertificateAtIndex(trust, 0),
                                                  ctx->trustedLeafCerts)) {
                        status = errSecSuccess;
                        goto errOut;
                    }
                }
#endif
				status = errSSLXCertChainInvalid;
            }
            /* Do we really need to return things like:
                   errSSLNoRootCert
                   errSSLUnknownRootCert
                   errSSLCertExpired
                   errSSLCertNotYetValid
                   errSSLHostNameMismatch
               for our client to see what went wrong, or should we just always
               return
                   errSSLXCertChainInvalid
               when something is wrong? */
            break;
	}

errOut:
	ctx->peerSecTrust = trust;

	return status;
}
/*
 * Convert a keychain name (which may be NULL) into the CFArrayRef required
 * by SSLSetCertificate. This is a bare-bones example of this operation,
 * since it requires and assumes that there is exactly one SecIdentity
 * in the keychain - i.e., there is exactly one matching cert/private key 
 * pair. A real world server would probably search a keychain for a SecIdentity 
 * matching some specific criteria. 
 */
CFArrayRef getSslCerts( 
	const char			*kcName,				// may be NULL, i.e., use default
	bool                encryptOnly,
	bool                completeCertChain,
	const char			*anchorFile,			// optional trusted anchor
	SecKeychainRef		*pKcRef)				// RETURNED
{
#if 0
	SecKeychainRef 		kcRef = nil;
	OSStatus			ortn;
	
	*pKcRef = nil;
	
	/* pick a keychain */
	if(kcName) {
		ortn = SecKeychainOpen(kcName, &kcRef);
		if(ortn) {
			printf("SecKeychainOpen returned %d.\n", (int)ortn);
			printf("Cannot open keychain at %s. Aborting.\n", kcName);
			return NULL;
		}
	}
	else {
		/* use default keychain */
		ortn = SecKeychainCopyDefault(&kcRef);
		if(ortn) {
			printf("SecKeychainCopyDefault returned %d; aborting.\n", (int)ortn);
			return nil;
		}
	}
	*pKcRef = kcRef;
	return sslKcRefToCertArray(kcRef, encryptOnly, completeCertChain, anchorFile);
#else
	SecCertificateRef cert = NULL;
	SecIdentityRef identity = NULL;
	CFMutableArrayRef certificates = NULL, result = NULL;
	CFMutableDictionaryRef certQuery = NULL, keyQuery = NULL, keyResult = NULL;
	SecTrustRef trust = NULL;
	SecKeyRef key = NULL;
	CFTypeRef pkdigest = NULL;

	// Find the first private key in the keychain and return both it's
	// attributes and a ref to it.
	require(keyQuery = CFDictionaryCreateMutable(NULL, 0, NULL, NULL), errOut);
	CFDictionaryAddValue(keyQuery, kSecClass, kSecClassKey);
	CFDictionaryAddValue(keyQuery, kSecAttrKeyClass, kSecAttrKeyClassPrivate);
	CFDictionaryAddValue(keyQuery, kSecReturnRef, kCFBooleanTrue);
	CFDictionaryAddValue(keyQuery, kSecReturnAttributes, kCFBooleanTrue);
	require_noerr(SecItemCopyMatching(keyQuery, (CFTypeRef *)&keyResult),
		errOut);
	require(key = (SecKeyRef)CFDictionaryGetValue(keyResult, kSecValueRef),
		errOut);
	require(pkdigest = CFDictionaryGetValue(keyResult, kSecAttrApplicationLabel),
		errOut);

	// Find the first certificate that has the same public key hash as the
	// returned private key and return it as a ref.
	require(certQuery = CFDictionaryCreateMutable(NULL, 0, NULL, NULL), errOut);
	CFDictionaryAddValue(certQuery, kSecClass, kSecClassCertificate);
	CFDictionaryAddValue(certQuery, kSecAttrPublicKeyHash, pkdigest);
	CFDictionaryAddValue(certQuery, kSecReturnRef, kCFBooleanTrue);
	require_noerr(SecItemCopyMatching(certQuery, (CFTypeRef *)&cert), errOut);

	// Create an identity from the key and certificate.
	require(identity = SecIdentityCreate(NULL, cert, key), errOut);

	// Build a (partial) certificate chain from cert
	require(certificates = CFArrayCreateMutable(NULL, 0,
		&kCFTypeArrayCallBacks), errOut);
	CFArrayAppendValue(certificates, cert);
	require_noerr(SecTrustCreateWithCertificates(certificates, NULL, &trust),
		errOut);
	SecTrustResultType tresult;
	require_noerr(SecTrustEvaluate(trust, &tresult), errOut);

	CFIndex certCount, ix;
	// We need at least 1 certificate
	require(certCount = SecTrustGetCertificateCount(trust), errOut);

	// Build a result where element 0 is the identity and the other elements
	// are the certs in the chain starting at the first intermediate up to the
	// anchor, if we found one, or as far as we were able to build the chain
	// if not.
	require(result = CFArrayCreateMutable(NULL, certCount, &kCFTypeArrayCallBacks),
		errOut);

	// We are commited to returning a result now, so do not use require below
	// this line without setting result to NULL again.
	CFArrayAppendValue(result, identity);
	for (ix = 1; ix < certCount; ++ix) {
		CFArrayAppendValue(result, SecTrustGetCertificateAtIndex(trust, ix));
	}

errOut:
	CFReleaseSafe(trust);
	CFReleaseSafe(certificates);
	CFReleaseSafe(identity);
	CFReleaseSafe(cert);
	CFReleaseSafe(certQuery);
	CFReleaseSafe(keyResult);
	CFReleaseSafe(keyQuery);

    return result;
#endif
}
/* Test basic add delete update copy matching stuff. */
static void tests(void)
{
    SecTrustRef trust;
	SecCertificateRef cert0, cert1;
	isnt(cert0 = SecCertificateCreateWithBytes(NULL, _c0, sizeof(_c0)),
		NULL, "create cert0");
	isnt(cert1 = SecCertificateCreateWithBytes(NULL, _c1, sizeof(_c1)),
		NULL, "create cert1");
	const void *v_certs[] = {
		cert0,
		cert1
	};
    SecPolicyRef policy = SecPolicyCreateSSL(false, NULL);
    CFArrayRef certs = CFArrayCreate(NULL, v_certs,
		array_size(v_certs), NULL);

    /* SecTrustCreateWithCertificates using single cert. */
    ok_status(SecTrustCreateWithCertificates(cert0, policy, &trust),
        "create trust with single cert0");
    is(SecTrustGetCertificateCount(trust), 1, "cert count is 1");
    is(SecTrustGetCertificateAtIndex(trust, 0), cert0, "cert 0 is leaf");
    CFReleaseNull(trust);

    /* SecTrustCreateWithCertificates failures. */
    is_status(SecTrustCreateWithCertificates(kCFBooleanTrue, policy, &trust),
        errSecParam, "create trust with boolean instead of cert");
    is_status(SecTrustCreateWithCertificates(cert0, kCFBooleanTrue, &trust),
        errSecParam, "create trust with boolean instead of policy");

    /* SecTrustCreateWithCertificates using array of certs. */
    ok_status(SecTrustCreateWithCertificates(certs, policy, &trust), "create trust");
    /* NOTE: prior to <rdar://11810677 SecTrustGetCertificateCount would return 1 at this point.
     * Now, however, we do an implicit SecTrustEvaluate to build the chain if it has not yet been
     * evaluated, so we now expect the full chain length.
     */
    is(SecTrustGetCertificateCount(trust), 3, "cert count is 3");
    is(SecTrustGetCertificateAtIndex(trust, 0), cert0, "cert 0 is leaf");

	/* Jan 1st 2006. */
	CFDateRef date = CFDateCreate(NULL, 157680000.0);
    ok_status(SecTrustSetVerifyDate(trust, date), "set date");

    is(SecTrustGetVerifyTime(trust), 157680000.0, "get date");

	SecTrustResultType trustResult;

SKIP: {
#ifdef NO_SERVER
    skip("Can't fail to connect to securityd in NO_SERVER mode", 4, false);
#endif
    // Test Restore OS environment
    SecServerSetMachServiceName("com.apple.security.doesn't-exist");
    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust without securityd running");
    is_status(trustResult, kSecTrustResultInvalid, "trustResult is kSecTrustResultInvalid");
	is(SecTrustGetCertificateCount(trust), 1, "cert count is 1 without securityd running");
    SecKeyRef pubKey = NULL;
    ok(pubKey = SecTrustCopyPublicKey(trust), "copy public key without securityd running");
    CFReleaseNull(pubKey);
    SecServerSetMachServiceName(NULL);
    // End of Restore OS environment tests
}

    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
    is_status(trustResult, kSecTrustResultUnspecified,
		"trustResult is kSecTrustResultUnspecified");

	is(SecTrustGetCertificateCount(trust), 3, "cert count is 3");

	CFDataRef c0_serial = CFDataCreate(NULL, _c0_serial, sizeof(_c0_serial));
	CFDataRef serial;
	ok(serial = SecCertificateCopySerialNumber(cert0), "copy cert0 serial");
	ok(CFEqual(c0_serial, serial), "serial matches");

    CFArrayRef anchors = CFArrayCreate(NULL, (const void **)&cert1, 1, &kCFTypeArrayCallBacks);
    ok_status(SecTrustSetAnchorCertificates(trust, anchors), "set anchors");
    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
    is_status(trustResult, kSecTrustResultUnspecified,
		"trust is kSecTrustResultUnspecified");
	is(SecTrustGetCertificateCount(trust), 2, "cert count is 2");

	CFReleaseSafe(anchors);
    anchors = CFArrayCreate(NULL, NULL, 0, NULL);
    ok_status(SecTrustSetAnchorCertificates(trust, anchors), "set empty anchors list");
    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
    is_status(trustResult, kSecTrustResultRecoverableTrustFailure,
		"trust is kSecTrustResultRecoverableTrustFailure");

	ok_status(SecTrustSetAnchorCertificatesOnly(trust, false), "trust passed in anchors and system anchors");
    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
    is_status(trustResult, kSecTrustResultUnspecified,
		"trust is kSecTrustResultUnspecified");

	ok_status(SecTrustSetAnchorCertificatesOnly(trust, true), "only trust passed in anchors (default)");
    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
    is_status(trustResult, kSecTrustResultRecoverableTrustFailure,
		"trust is kSecTrustResultRecoverableTrustFailure");

    /* Test cert_1 intermididate from the keychain. */
    CFReleaseSafe(trust);
    ok_status(SecTrustCreateWithCertificates(cert0, policy, &trust),
              "create trust with single cert0");
    ok_status(SecTrustSetVerifyDate(trust, date), "set date");

    // Add cert1
    CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
        kSecClass, kSecClassCertificate, kSecValueRef, cert1, NULL);
    ok_status(SecItemAdd(query, NULL), "add cert1 to keychain");
    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
    // Cleanup added cert1.
    ok_status(SecItemDelete(query), "remove cert1 from keychain");
    CFReleaseSafe(query);
    is_status(trustResult, kSecTrustResultUnspecified,
              "trust is kSecTrustResultUnspecified");
	is(SecTrustGetCertificateCount(trust), 3, "cert count is 3");

    /* Set certs to be the xedge2 leaf. */
	CFReleaseSafe(certs);
	const void *cert_xedge2;
	isnt(cert_xedge2 = SecCertificateCreateWithBytes(NULL, xedge2_certificate,
        sizeof(xedge2_certificate)), NULL, "create cert_xedge2");
    certs = CFArrayCreate(NULL, &cert_xedge2, 1, NULL);

	CFReleaseSafe(trust);
	CFReleaseSafe(policy);
	CFReleaseSafe(date);
    bool server = true;
    policy = SecPolicyCreateSSL(server, CFSTR("xedge2.apple.com"));
    ok_status(SecTrustCreateWithCertificates(certs, policy, &trust),
        "create trust for ssl server xedge2.apple.com");
    /* Jan 1st 2009. */
    date = CFDateCreate(NULL, 252288000.0);
    ok_status(SecTrustSetVerifyDate(trust, date), "set xedge2 trust date to Jan 1st 2009");
    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate xedge2 trust");
    is_status(trustResult, kSecTrustResultUnspecified,
		"trust is kSecTrustResultUnspecified");

	CFReleaseSafe(trust);
	CFReleaseSafe(policy);
    server = false;
    policy = SecPolicyCreateSSL(server, CFSTR("xedge2.apple.com"));
    ok_status(SecTrustCreateWithCertificates(certs, policy, &trust),
        "create trust for ssl client xedge2.apple.com");
    ok_status(SecTrustSetVerifyDate(trust, date), "set xedge2 trust date to Jan 1st 2009");
    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate xedge2 trust");
    is_status(trustResult, kSecTrustResultRecoverableTrustFailure,
		"trust is kSecTrustResultRecoverableTrustFailure");

	CFReleaseSafe(trust);
	CFReleaseSafe(policy);
    server = true;
    policy = SecPolicyCreateIPSec(server, CFSTR("xedge2.apple.com"));
    ok_status(SecTrustCreateWithCertificates(certs, policy, &trust),
        "create trust for ip server xedge2.apple.com");
    ok_status(SecTrustSetVerifyDate(trust, date), "set xedge2 trust date to Jan 1st 2009");
    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate xedge2 trust");
#if 0
    /* Although this shouldn't be a valid ipsec cert, since we no longer
       check for ekus in the ipsec policy it is. */
    is_status(trustResult, kSecTrustResultRecoverableTrustFailure,
		"trust is kSecTrustResultRecoverableTrustFailure");
#else
    is_status(trustResult, kSecTrustResultUnspecified,
		"trust is kSecTrustResultUnspecified");
#endif

	CFReleaseSafe(trust);
	CFReleaseSafe(policy);
    server = true;
    policy = SecPolicyCreateSSL(server, CFSTR("nowhere.com"));
    ok_status(SecTrustCreateWithCertificates(certs, policy, &trust),
        "create trust for ssl server nowhere.com");
    SecPolicyRef replacementPolicy = SecPolicyCreateSSL(server, CFSTR("xedge2.apple.com"));
    SecTrustSetPolicies(trust, replacementPolicy);
    CFReleaseSafe(replacementPolicy);
    ok_status(SecTrustSetVerifyDate(trust, date), "set xedge2 trust date to Jan 1st 2009");
    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate xedge2 trust");
    is_status(trustResult, kSecTrustResultUnspecified,
		"trust is kSecTrustResultUnspecified");

	CFReleaseSafe(trust);
	CFReleaseSafe(policy);
    server = true;
    policy = SecPolicyCreateSSL(server, CFSTR("nowhere.com"));
    ok_status(SecTrustCreateWithCertificates(certs, policy, &trust),
        "create trust for ssl server nowhere.com");
    SecPolicyRef replacementPolicy2 = SecPolicyCreateSSL(server, CFSTR("xedge2.apple.com"));
    CFArrayRef replacementPolicies = CFArrayCreate(kCFAllocatorDefault, (CFTypeRef*)&replacementPolicy2, 1, &kCFTypeArrayCallBacks);
    SecTrustSetPolicies(trust, replacementPolicies);
    CFReleaseSafe(replacementPolicy2);
    CFReleaseSafe(replacementPolicies);
    ok_status(SecTrustSetVerifyDate(trust, date), "set xedge2 trust date to Jan 1st 2009");
    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate xedge2 trust");
    is_status(trustResult, kSecTrustResultUnspecified,
		"trust is kSecTrustResultUnspecified");

    /* Test self signed ssl cert with cert itself set as anchor. */
	CFReleaseSafe(trust);
	CFReleaseSafe(policy);
	CFReleaseSafe(certs);
	CFReleaseSafe(date);
	const void *garthc2;
    server = true;
	isnt(garthc2 = SecCertificateCreateWithBytes(NULL, garthc2_certificate,
        sizeof(garthc2_certificate)), NULL, "create garthc2");
    certs = CFArrayCreate(NULL, &garthc2, 1, NULL);
    policy = SecPolicyCreateSSL(server, CFSTR("garthc2.apple.com"));
    ok_status(SecTrustCreateWithCertificates(certs, policy, &trust),
        "create trust for ip server garthc2.apple.com");
    date = CFDateCreate(NULL, 269568000.0);
    ok_status(SecTrustSetVerifyDate(trust, date),
        "set garthc2 trust date to Aug 2009");
    ok_status(SecTrustSetAnchorCertificates(trust, certs),
        "set garthc2 as anchor");
    ok_status(SecTrustEvaluate(trust, &trustResult),
        "evaluate self signed cert with cert as anchor");
    is_status(trustResult, kSecTrustResultUnspecified,
		"trust is kSecTrustResultUnspecified");

	CFReleaseSafe(garthc2);
	CFReleaseSafe(cert_xedge2);
	CFReleaseSafe(anchors);
	CFReleaseSafe(trust);
	CFReleaseSafe(serial);
	CFReleaseSafe(c0_serial);
	CFReleaseSafe(policy);
	CFReleaseSafe(certs);
	CFReleaseSafe(cert0);
	CFReleaseSafe(cert1);
	CFReleaseSafe(date);
    
    /* Test prt_forest_fi */
    const void *prt_forest_fi;
    isnt(prt_forest_fi = SecCertificateCreateWithBytes(NULL, prt_forest_fi_certificate,
						 sizeof(prt_forest_fi_certificate)), NULL, "create prt_forest_fi");
    isnt(certs = CFArrayCreate(NULL, &prt_forest_fi, 1, NULL), NULL, "failed to create cert array");
    policy = SecPolicyCreateSSL(false, CFSTR("owa.prt-forest.fi"));
    ok_status(SecTrustCreateWithCertificates(certs, policy, &trust),
	      "create trust for ip client owa.prt-forest.fi");
    date = CFDateCreate(NULL, 391578321.0);
    ok_status(SecTrustSetVerifyDate(trust, date),
	      "set owa.prt-forest.fi trust date to May 2013");
    
    SecKeyRef pubkey = SecTrustCopyPublicKey(trust);
    is(pubkey, NULL, "pubkey returned");
    
	CFReleaseSafe(certs);
    CFReleaseNull(prt_forest_fi);
    CFReleaseNull(policy);
    CFReleaseNull(trust);
    CFReleaseNull(pubkey);
    CFReleaseNull(date);

}