/* 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, CFSTR("store.apple.com"));
    CFArrayRef certs = CFArrayCreate(NULL, v_certs,
		array_size(v_certs), NULL);
    ok_status(SecTrustCreateWithCertificates(certs, policy, &trust), "create trust");
	/* Jan 1st 2006. */
	CFDateRef date = CFDateCreate(NULL, 157680000.0);
    ok_status(SecTrustSetVerifyDate(trust, date), "set date");

	SecTrustResultType trustResult;
    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
    is_status(trustResult, kSecTrustResultUnspecified,
		"trust is kSecTrustResultUnspecified");
    CFDataRef exceptions;
    ok(exceptions = SecTrustCopyExceptions(trust), "create an exceptions");
    ok(SecTrustSetExceptions(trust, exceptions), "set exceptions");
    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
    is_status(trustResult, kSecTrustResultProceed, "trust is kSecTrustResultProceed");

	CFReleaseSafe(trust);
	CFReleaseSafe(policy);
    policy = SecPolicyCreateSSL(false, CFSTR("badstore.apple.com"));
    ok_status(SecTrustCreateWithCertificates(certs, policy, &trust), "create trust with hostname mismatch");
    ok_status(SecTrustSetVerifyDate(trust, date), "set date");
    ok(SecTrustSetExceptions(trust, exceptions), "set old exceptions");
    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
    is_status(trustResult, kSecTrustResultRecoverableTrustFailure, "trust is kSecTrustResultRecoverableTrustFailure");
	CFReleaseSafe(exceptions);
    ok(exceptions = SecTrustCopyExceptions(trust), "create a new exceptions");
    ok(SecTrustSetExceptions(trust, exceptions), "set exceptions");
    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
    is_status(trustResult, kSecTrustResultProceed, "trust is kSecTrustResultProceed");

	CFReleaseSafe(trust);
    ok_status(SecTrustCreateWithCertificates(certs, policy, &trust), "create trust");
    ok_status(SecTrustSetVerifyDate(trust, date), "set date");
    ok(SecTrustSetExceptions(trust, exceptions), "set exceptions");
    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
    is_status(trustResult, kSecTrustResultProceed, "trust is kSecTrustResultProceed");
    CFArrayRef anchors = CFArrayCreate(kCFAllocatorDefault, NULL, 0, &kCFTypeArrayCallBacks);
    ok_status(SecTrustSetAnchorCertificates(trust, anchors), "set empty anchor 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, kSecTrustResultProceed, "trust is now kSecTrustResultProceed");

	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 again");

	CFReleaseSafe(exceptions);
    ok(exceptions = SecTrustCopyExceptions(trust), "create a new exceptions");
    ok(SecTrustSetExceptions(trust, exceptions), "set exceptions");
    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
    is_status(trustResult, kSecTrustResultProceed, "trust is kSecTrustResultProceed");
	CFReleaseSafe(date);
	date = CFDateCreate(NULL, 667680000.0);
    ok_status(SecTrustSetVerifyDate(trust, date), "set date to far future so certs are expired");
    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
    is_status(trustResult, kSecTrustResultRecoverableTrustFailure, "trust is kSecTrustResultRecoverableTrustFailure");

	CFReleaseSafe(anchors);
	CFReleaseSafe(exceptions);
	CFReleaseSafe(trust);
	CFReleaseSafe(policy);
	CFReleaseSafe(certs);
	CFReleaseSafe(cert0);
	CFReleaseSafe(cert1);
	CFReleaseSafe(date);
}
Esempio n. 2
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;
  
  cfstream_data = (struct mailstream_cfstream_data *) s->data;
  SecTrustRef secTrust = (SecTrustRef)CFReadStreamCopyProperty(cfstream_data->readStream, kCFStreamPropertySSLPeerTrust);
  if (secTrust == NULL)
    return NULL;
  
  // SecTrustEvaluate() needs to be called before SecTrustGetCertificateCount() in Mac OS X <= 10.8
  SecTrustEvaluate(secTrust, 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. 3
0
/*
 * Given a SecCertificateRef cert, obtain its public key as a SSLPubKey.
 * Caller must sslFreePubKey and free the SSLPubKey itself.
 */
extern OSStatus sslCopyPeerPubKey(
	SSLContext 				*ctx,
	SSLPubKey               **pubKey)
{
    OSStatus status = noErr;

    check(pubKey);
    check(ctx->peerSecTrust);

    if (!ctx->enableCertVerify) {
        SecTrustResultType result;
        require_noerr(status = SecTrustEvaluate(ctx->peerSecTrust, &result),
            errOut);
	}

    SecKeyRef key = SecTrustCopyPublicKey(ctx->peerSecTrust);
    if (!key) {
		sslErrorLog("sslCopyPeerPubKey: %s, ctx->peerSecTrust=%p\n",
			"SecTrustCopyPublicKey failed", (uintptr_t)ctx->peerSecTrust);
		return errSSLBadCert;
	}
    *pubKey = (SSLPubKey*)key;

errOut:
	if (status) {
		sslErrorLog("sslCopyPeerPubKey: error %d\n", status);
	}
	return status;
}
bool verify_X509_cert_chain(const std::vector<std::string> &certChain, const std::string &hostName)
{
    // Build up CFArrayRef with all the certificates.
    // All this code is basically just to get into the correct structures for the Apple APIs.
    // Copies are avoided whenever possible.
    std::vector<cf_ref<SecCertificateRef>> certs;
    for(const auto & certBuf : certChain)
    {
        cf_ref<CFDataRef> certDataRef = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
                                                                   reinterpret_cast<const unsigned char*>(certBuf.c_str()),
                                                                   certBuf.size(),
                                                                   kCFAllocatorNull);
        if(certDataRef.get() == nullptr)
        {
            return false;
        }

        cf_ref<SecCertificateRef> certObj = SecCertificateCreateWithData(nullptr, certDataRef.get());
        if(certObj.get() == nullptr)
        {
            return false;
        }
        certs.push_back(std::move(certObj));
    }
    cf_ref<CFArrayRef> certsArray = CFArrayCreate(kCFAllocatorDefault, const_cast<const void **>(reinterpret_cast<void **>(&certs[0])), certs.size(), nullptr);
    if(certsArray.get() == nullptr)
    {
        return false;
    }

    // Create trust management object with certificates and SSL policy.
    // Note: SecTrustCreateWithCertificates expects the certificate to be
    // verified is the first element.
    cf_ref<CFStringRef> cfHostName = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault,
                                                                    hostName.c_str(),
                                                                    kCFStringEncodingASCII,
                                                                    kCFAllocatorNull);
    if(cfHostName.get() == nullptr)
    {
        return false;
    }
    cf_ref<SecPolicyRef> policy = SecPolicyCreateSSL(true /* client side */, cfHostName.get());
    cf_ref<SecTrustRef> trust;
    OSStatus status = SecTrustCreateWithCertificates(certsArray.get(), policy.get(), &trust.get());
    if(status == noErr)
    {
        // Perform actual certificate verification.
        SecTrustResultType trustResult;
        status = SecTrustEvaluate(trust.get(), &trustResult);
        if(status == noErr && (trustResult == kSecTrustResultUnspecified || trustResult == kSecTrustResultProceed))
        {
            return true;
        }
    }

    return false;
}
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
static int stransport_connect(git_stream *stream)
{
	stransport_stream *st = (stransport_stream *) stream;
	int error;
	SecTrustRef trust = NULL;
	SecTrustResultType sec_res;
	OSStatus ret;

	if ((error = git_stream_connect(st->io)) < 0)
		return error;

	ret = SSLHandshake(st->ctx);
	if (ret != errSSLServerAuthCompleted) {
		giterr_set(GITERR_SSL, "unexpected return value from ssl handshake %d", (int)ret);
		return -1;
	}

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

	if (!trust)
		return GIT_ECERTIFICATE;

	if ((ret = SecTrustEvaluate(trust, &sec_res)) != noErr)
		goto on_error;

	CFRelease(trust);

	if (sec_res == kSecTrustResultInvalid || sec_res == kSecTrustResultOtherError) {
		giterr_set(GITERR_SSL, "internal security trust error");
		return -1;
	}

	if (sec_res == kSecTrustResultDeny || sec_res == kSecTrustResultRecoverableTrustFailure ||
	    sec_res == kSecTrustResultFatalTrustFailure) {
		giterr_set(GITERR_SSL, "untrusted connection error");
		return GIT_ECERTIFICATE;
	}

	return 0;

on_error:
	if (trust)
		CFRelease(trust);

	return stransport_error(ret);
}
Esempio n. 7
0
int32_t AppleCryptoNative_X509ChainEvaluate(SecTrustRef chain,
                                            CFDateRef cfEvaluationTime,
                                            bool allowNetwork,
                                            int32_t* pOSStatus)
{
    if (pOSStatus != NULL)
        *pOSStatus = noErr;

    if (chain == NULL || pOSStatus == NULL)
        return -1;

    *pOSStatus = SecTrustSetVerifyDate(chain, cfEvaluationTime);

    if (*pOSStatus != noErr)
    {
        return -2;
    }

    *pOSStatus = SecTrustSetNetworkFetchAllowed(chain, allowNetwork);

    if (*pOSStatus != noErr)
    {
        return -3;
    }

    SecTrustResultType trustResult;
    *pOSStatus = SecTrustEvaluate(chain, &trustResult);

    // If any error is reported from the function or the trust result value indicates that
    // otherwise was a failed chain build (vs an untrusted chain, etc) return failure and
    // we'll throw in the managed layer.  (but if we hit the "or" the message is "No error")
    if (*pOSStatus != noErr || trustResult == kSecTrustResultInvalid)
    {
        return 0;
    }

    // If: The chain was built with no errors (Unspecified)
    // Or: The chain was built and involved an explicitly trusted cert (Proceed)
    // Then: Success.
    if (trustResult == kSecTrustResultUnspecified || trustResult == kSecTrustResultProceed)
    {
        return 1;
    }

    // Should this be a different return code?
    return 1;
}
static void tests(void)
{
    SecTrustResultType trustResult = kSecTrustResultProceed;
	SecPolicyRef policy = NULL;
	SecTrustRef trust = NULL;
	CFArrayRef certs = NULL;
	
	CFDataRef appleid_record_signing_cert_data = NULL;
	isnt(appleid_record_signing_cert_data = CFDataCreate(kCFAllocatorDefault, kLeafCert, sizeof(kLeafCert)), 
		NULL, "Get the AppleID Record Signing Leaf Certificate Data");
		
	SecCertificateRef appleid_record_signing_cert = NULL;
	isnt(appleid_record_signing_cert = SecCertificateCreateWithData(kCFAllocatorDefault, appleid_record_signing_cert_data),
		NULL, "Get the AppleID Record Signing Leaf Certificate Data");
		
	CFDataRef appleid_intermediate_cert_data = NULL;
	isnt(appleid_intermediate_cert_data = CFDataCreate(kCFAllocatorDefault, kIntermediateCert, sizeof(kIntermediateCert)), 
		NULL, "Get the AppleID Intermediate Certificate Data");
		
	SecCertificateRef appleid_intermediate_cert = NULL;
	isnt(appleid_intermediate_cert = SecCertificateCreateWithData(kCFAllocatorDefault, appleid_intermediate_cert_data),
		NULL, "Get the AppleID Intermediate Certificate");
		
	SecCertificateRef certs_to_use[] = {appleid_record_signing_cert, appleid_intermediate_cert};
		
	certs = CFArrayCreate(NULL, (const void **)certs_to_use, 2, NULL);
		
	isnt(policy = SecPolicyCreateAppleIDValidationRecordSigningPolicy(),
		NULL, "Create AppleID Record signing policy SecPolicyRef");
				
	ok_status(SecTrustCreateWithCertificates(certs, policy, &trust),
        "Create AppleID record signing leaf");

	ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate escrow service trust for club 1");
		
	is_status(trustResult, kSecTrustResultUnspecified,
		"Trust is kSecTrustResultUnspecified AppleID record signing leaf");
		
	CFReleaseSafe(trust);
	CFReleaseSafe(policy);
	CFReleaseSafe(certs);
	CFReleaseSafe(appleid_record_signing_cert);
    CFReleaseSafe(appleid_intermediate_cert_data);
    CFReleaseSafe(appleid_record_signing_cert_data);
}
static void tests(void)
{
    SecTrustRef trust;
    SecCertificateRef leaf, wwdr_intermediate;
    SecPolicyRef policy;

    isnt(wwdr_intermediate = SecCertificateCreateWithBytes(kCFAllocatorDefault,
        wwdr_intermediate_cert, sizeof(wwdr_intermediate_cert)), NULL, "create WWDR intermediate");
    isnt(leaf = SecCertificateCreateWithBytes(kCFAllocatorDefault,
        codesigning_certificate, sizeof(codesigning_certificate)), NULL, "create leaf");

    const void *vcerts[] = { leaf, wwdr_intermediate };
    CFArrayRef certs = CFArrayCreate(kCFAllocatorDefault, vcerts, 2, NULL);

    isnt(policy = SecPolicyCreateiPhoneProfileApplicationSigning(), NULL,
        "create iPhoneProfileApplicationSigning policy instance");
    ok_status(SecTrustCreateWithCertificates(certs, policy, &trust), "create trust for leaf");
    CFDateRef verifyDate = CFDateCreate(kCFAllocatorDefault, 228244066);
    ok_status(SecTrustSetVerifyDate(trust, verifyDate), "set verify date");
    CFReleaseNull(verifyDate);
    SecTrustResultType trustResult;
    CFArrayRef properties = NULL;
    properties = SecTrustCopyProperties(trust);
    is(properties, NULL, "no properties returned before eval");
    CFReleaseNull(properties);
    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
    is_status(trustResult, kSecTrustResultUnspecified, "trust is kSecTrustResultUnspecified");
    properties = SecTrustCopyProperties(trust);

    if (properties) {
        print_plist(properties);
        print_cert(leaf, true);
        print_cert(wwdr_intermediate, false);
    }

    CFReleaseNull(properties);
    CFReleaseNull(trust);
    CFReleaseNull(wwdr_intermediate);
    CFReleaseNull(leaf);
    CFReleaseNull(certs);
    CFReleaseNull(policy);
	CFReleaseNull(trust);
}
Esempio n. 10
0
//
// Pre-Signing contexts
//
PreSigningContext::PreSigningContext(const SecCodeSigner::Signer &signer)
{
	// construct a cert chain
	if (signer.signingIdentity() != SecIdentityRef(kCFNull)) {
		CFRef<SecCertificateRef> signingCert;
		MacOSError::check(SecIdentityCopyCertificate(signer.signingIdentity(), &signingCert.aref()));
		CFRef<SecPolicyRef> policy = SecPolicyCreateWithOID(kSecPolicyAppleCodeSigning);
		CFRef<SecTrustRef> trust;
		MacOSError::check(SecTrustCreateWithCertificates(CFArrayRef(signingCert.get()), policy, &trust.aref()));
		SecTrustResultType result;
		MacOSError::check(SecTrustEvaluate(trust, &result));
		CSSM_TP_APPLE_EVIDENCE_INFO *info;
		MacOSError::check(SecTrustGetResult(trust, &result, &mCerts.aref(), &info));
		this->certs = mCerts;
	}
	
	// other stuff
	this->identifier = signer.signingIdentifier();
}
static void tests(void)
{
    CFErrorRef error = NULL;
    CFDataRef testData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)testbytes, testbytes_size, kCFAllocatorNull);

    SecCertificateRef cert = SecCertificateCreateWithBytes(kCFAllocatorDefault, public_cert_der, sizeof(public_cert_der));
    CFArrayRef certInArray = CFArrayCreateForCFTypes(kCFAllocatorDefault, cert, NULL);

    SecKeyRef full_key = SecKeyCreateECPrivateKey(kCFAllocatorDefault, private_key_der, sizeof(private_key_der), kSecKeyEncodingPkcs1);

    SecTrustRef trust = NULL;
    SecPolicyRef basic = SecPolicyCreateBasicX509();
    OSStatus status = SecTrustCreateWithCertificates(cert, basic, &trust);
    ok_status(status, "created");
    CFReleaseNull(basic);
    status = SecTrustSetAnchorCertificates(trust, certInArray);
    ok_status(status, "Anchors");

    SecTrustResultType result;
    status = SecTrustEvaluate(trust, &result);
    ok_status(status, "Trust evaluation");
    is(result, (SecTrustResultType)kSecTrustResultUnspecified, "Trust result");

    CFDataRef encrypted = SecCopyEncryptedToServer(trust, testData, &error);
    ok(encrypted != NULL, "Encrypt to server (%@)", error);
    CFReleaseNull(error);

    ok(!CFEqualSafe(testData, encrypted), "encrypted different");

    CFDataRef decrypted = SecCopyDecryptedForServer(full_key, encrypted, &error);
    ok(decrypted != NULL, "Decrypt from server (%@)", error);
    ok(CFEqualSafe(testData, decrypted), "round trip");


    CFReleaseNull(cert);
    CFReleaseNull(certInArray);
    CFReleaseNull(trust);
    CFReleaseNull(testData);
    CFReleaseNull(encrypted);
    CFReleaseNull(decrypted);
}
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);
}
/* do a SecTrustEvaluate, ensure resultType is as specified */
static int doEval(
	CFArrayRef certs,
	SecPolicyRef policy,
	SecTrustResultType expectedResult,
	bool quiet)
{
	OSStatus ortn;
	SecTrustRef trustRef = NULL;
	SecTrustResultType result;
	int ourRtn = 0;

	ortn = SecTrustCreateWithCertificates(certs, policy, &trustRef);
	if(ortn) {
		cssmPerror("SecTrustCreateWithCertificates", ortn);
		return -1;
	}
	ortn = SecTrustEvaluate(trustRef, &result);
	if(ortn) {
		/* shouldn't fail no matter what resultType we expect */
		cssmPerror("SecTrustEvaluate", ortn);
		ourRtn = -1;
		goto errOut;
	}
	if(expectedResult == result) {
		if(!quiet) {
			printf("...got %s as expected\n", secTrustResultStr(result));
		}
	}
	else {
		printf("***Expected %s, got %s\n", secTrustResultStr(expectedResult),
			secTrustResultStr(result));
		ourRtn = -1;
	}
errOut:
	CFRelease(trustRef);
	return ourRtn;
}
Esempio n. 14
0
int tls_evaluate_trust(tls_handshake_t hdsk, bool server)
{
    int err;
    CFDictionaryRef trust_results = NULL;
    CFArrayRef trust_properties = NULL;
    SecTrustResultType trust_result = kSecTrustResultInvalid;
    SecTrustRef trustRef = NULL;

    require_noerr((err = tls_helper_create_peer_trust(hdsk, server, &trustRef)), errOut);

    if(trustRef) {
        require_noerr((err=SecTrustEvaluate(trustRef, &trust_result)), errOut);

        test_printf("SecTrustEvaluate result: %d\n", trust_result);

        trust_results = SecTrustCopyResult(trustRef);
        trust_properties = SecTrustCopyProperties(trustRef);

        //CFShow(trust_results);
        //CFShow(trust_properties);

        /* Pretend it's all OK so we can continue*/
        tls_handshake_set_peer_trust(hdsk, tls_handshake_trust_ok);
    } else {
        test_printf("No trustref (using cert-less ciphersuite maybe?)");
    }

    err = noErr;

errOut:
    CFReleaseSafe(trust_properties);
    CFReleaseSafe(trust_results);

    return err;

}
Esempio n. 15
0
bool Connection::readHandshake()
{
    log_trace("Connection::readHandshake");

    std::streambuf* sb = _ios->rdbuf();
    if( ! sb)
        return true;

    _maxImport = sb->in_avail();
    _wantRead = false;
    _isReading = true;
    OSStatus status = SSLHandshake(_context);
    _isReading = false;

    log_debug("SSLHandshake returns " << status);
    
    if( status == noErr )
    {
        log_debug("SSL handshake completed");
        _connected = true;
        return false;
    }

#ifdef PT_IOS
    if(status == errSSLPeerAuthCompleted)
#else
    if(status == errSSLServerAuthCompleted)
#endif
    {
        log_debug("authenticating peer");

        if( _ctx->verifyMode() != NoVerify )
        {
            log_debug("evaluating trust");
            
            SecTrustRef trust = NULL;
            SSLCopyPeerTrust(_context, &trust);

            CFArrayRef caArr = _ctx->impl()->caCertificates();
            SecTrustSetAnchorCertificates(trust, caArr);
            SecTrustSetAnchorCertificatesOnly(trust, true);

            SecTrustResultType result;
            OSStatus evalErr = SecTrustEvaluate(trust, &result);
            if(evalErr)
                throw HandshakeFailed("SSL handshake failed");
        
            CFIndex count = SecTrustGetCertificateCount(trust);
            log_debug("SecTrustEvaluate: " << result << " certs: " << count);
            
            if(trust)
                CFRelease(trust);
            
            // if peer presented no certificate, SecTrustGetCertificateCount
            // should return 0. If we require one because AlwaysVerify is
            // set, the handshake is considered to be failed
            if(_ctx->verifyMode() == AlwaysVerify && count == 0)
                throw HandshakeFailed("SSL handshake failed");

            if( (result != kSecTrustResultProceed) && 
                (result != kSecTrustResultUnspecified) )
                throw HandshakeFailed("SSL handshake failed");

            log_debug("authentication successful");
        }

        return readHandshake();
    }
    
    if( status != errSSLWouldBlock )
    {
        throw HandshakeFailed("SSL handshake failed");
    }

    return _wantRead;
}
Esempio n. 16
0
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 */
	SecTrustResultType	trustResult;

	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 = paramErr;
		goto errOut;
	}
	if (CFGetTypeID(identity) != SecIdentityGetTypeID()) {
		sslErrorLog("parseIncomingCerts: bad cert array (2)\n");
		ortn = paramErr;
		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 = memFullErr;
		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 = paramErr;
			goto errOut;
		}
		if (CFGetTypeID(intermediate) != SecCertificateGetTypeID()) {
			sslErrorLog("parseIncomingCerts: bad cert array (6)\n");
			ortn = paramErr;
			goto errOut;
		}

		CFArrayAppendValue(certChain, intermediate);
	}

	/* Obtain public key from cert */
#if TARGET_OS_IOS
	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;
	}
	ortn = SecTrustEvaluate(trust, &trustResult);
	if (ortn) {
		sslErrorLog("parseIncomingCerts: SecTrustEvaluate err %d\n",
			(int)ortn);
		goto errOut;
	}
	pubKey = SecTrustCopyPublicKey(trust);
	if (pubKey == NULL) {
		sslErrorLog("parseIncomingCerts: SecTrustCopyPublicKey failed\n");
		ortn = -67712; // errSecInvalidKeyRef
		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;
}
static OSStatus securetransport(ssl_test_handle * ssl)
{
    OSStatus ortn;
    SSLContextRef ctx = ssl->st;
    SecTrustRef trust = NULL;
    bool got_server_auth = false, got_client_cert_req = false;

    ortn = SSLHandshake(ctx);
    //fprintf(stderr, "Fell out of SSLHandshake with error: %ld\n", (long)ortn);
    
    size_t sent, received;
    const char *r=request;
    size_t l=sizeof(request);

    do {
        
        ortn = SSLWrite(ctx, r, l, &sent);
        
        if(ortn == errSSLWouldBlock) {
                r+=sent;
                l-=sent;
        }
        
        if (ortn == errSSLServerAuthCompleted)
        {
            require_string(!got_server_auth, out, "second server auth");
            require_string(!got_client_cert_req, out, "got client cert req before server auth");
            got_server_auth = true;
            require_string(!trust, out, "Got errSSLServerAuthCompleted twice?");
            /* verify peer cert chain */
            require_noerr(SSLCopyPeerTrust(ctx, &trust), out);
            SecTrustResultType trust_result = 0;
            /* this won't verify without setting up a trusted anchor */
            require_noerr(SecTrustEvaluate(trust, &trust_result), out);
        }
    } while(ortn == errSSLWouldBlock || ortn == errSSLServerAuthCompleted);

    //fprintf(stderr, "\nHTTP Request Sent\n");

    require_noerr_action_quiet(ortn, out, printf("SSLWrite failed with err %ld\n", (long)ortn));

    require_string(got_server_auth, out, "never got server auth");

    do {
        ortn = SSLRead(ctx, reply, sizeof(reply)-1, &received);
        //fprintf(stderr, "r"); usleep(1000);
    } while(ortn == errSSLWouldBlock);
    
    //fprintf(stderr, "\n");
    
    require_noerr_action_quiet(ortn, out, printf("SSLRead failed with err %ld\n", (long)ortn));

    reply[received]=0;

    //fprintf(stderr, "HTTP reply:\n");
    //fprintf(stderr, "%s\n",reply);
    
out:
    SSLClose(ctx);
    SSLDisposeContext(ctx);
    if (trust) CFRelease(trust);

    return ortn;
}
Esempio n. 18
0
int mailstream_cfstream_set_ssl_enabled(mailstream * s, int ssl_enabled)
{
#if HAVE_CFNETWORK
  struct mailstream_cfstream_data * cfstream_data;
  int r;
  
  cfstream_data = (struct mailstream_cfstream_data *) s->low->data;
  cfstream_data->ssl_enabled = ssl_enabled;
  if (ssl_enabled) {
    CFMutableDictionaryRef settings;
    
    settings = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    switch (cfstream_data->ssl_level) {
      case MAILSTREAM_CFSTREAM_SSL_LEVEL_NONE:
        CFDictionarySetValue(settings, kCFStreamSSLLevel, kCFStreamSocketSecurityLevelNone);
        break;
      case MAILSTREAM_CFSTREAM_SSL_LEVEL_SSLv2:
        CFDictionarySetValue(settings, kCFStreamSSLLevel, kCFStreamSocketSecurityLevelSSLv2);
        break;
      case MAILSTREAM_CFSTREAM_SSL_LEVEL_SSLv3:
        CFDictionarySetValue(settings, kCFStreamSSLLevel, kCFStreamSocketSecurityLevelSSLv3);
        break;
      case MAILSTREAM_CFSTREAM_SSL_LEVEL_TLSv1:
        CFDictionarySetValue(settings, kCFStreamSSLLevel, kCFStreamSocketSecurityLevelTLSv1);
        break;
      case MAILSTREAM_CFSTREAM_SSL_LEVEL_NEGOCIATED_SSL:
        CFDictionarySetValue(settings, kCFStreamSSLLevel, kCFStreamSocketSecurityLevelNegotiatedSSL);
        break;
    }
    
    if ((cfstream_data->ssl_certificate_verification_mask & MAILSTREAM_CFSTREAM_SSL_ALLOWS_EXPIRED_CERTIFICATES) != 0) {
      CFDictionarySetValue(settings, kCFStreamSSLAllowsExpiredCertificates, kCFBooleanTrue);
    }
    if ((cfstream_data->ssl_certificate_verification_mask & MAILSTREAM_CFSTREAM_SSL_ALLOWS_EXPIRED_ROOTS) != 0) {
      CFDictionarySetValue(settings, kCFStreamSSLAllowsExpiredRoots, kCFBooleanTrue);
    }
    if ((cfstream_data->ssl_certificate_verification_mask & MAILSTREAM_CFSTREAM_SSL_ALLOWS_ANY_ROOT) != 0) {
      CFDictionarySetValue(settings, kCFStreamSSLAllowsAnyRoot, kCFBooleanTrue);
    }
    if ((cfstream_data->ssl_certificate_verification_mask & MAILSTREAM_CFSTREAM_SSL_DISABLE_VALIDATES_CERTIFICATE_CHAIN) != 0) {
      CFDictionarySetValue(settings, kCFStreamSSLValidatesCertificateChain, kCFBooleanFalse);
    }
    
    CFReadStreamSetProperty(cfstream_data->readStream, kCFStreamPropertySSLSettings, settings);
    CFWriteStreamSetProperty(cfstream_data->writeStream, kCFStreamPropertySSLSettings, settings);
    CFRelease(settings);
  }
  else {
    CFMutableDictionaryRef settings;
    
    settings = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    CFDictionarySetValue(settings, kCFStreamSSLLevel, kCFStreamSocketSecurityLevelNone);
		CFReadStreamSetProperty(cfstream_data->readStream, kCFStreamPropertySSLSettings, settings);
		CFWriteStreamSetProperty(cfstream_data->writeStream, kCFStreamPropertySSLSettings, settings);
    CFRelease(settings);
    
    //fprintf(stderr, "is not ssl\n");
  }
  
  // We need to investigate more about how to establish a STARTTLS connection.
  // For now, wait until we get the certificate chain.
  while (1) {
    r = wait_runloop(s->low, STATE_WAIT_SSL);
    if (r != WAIT_RUNLOOP_EXIT_NO_ERROR) {
      return -1;
    }
    if (cfstream_data->writeSSLResult < 0)
      return -1;
    if (cfstream_data->readSSLResult < 0)
      return -1;
    
    SecTrustRef secTrust = (SecTrustRef)CFReadStreamCopyProperty(cfstream_data->readStream, kCFStreamPropertySSLPeerTrust);
    if (secTrust == NULL) {
      // No trust, wait more.
      continue;
    }
    
    // SecTrustEvaluate() needs to be called before SecTrustGetCertificateCount() in Mac OS X <= 10.8
    SecTrustEvaluate(secTrust, NULL);
    CFIndex count = SecTrustGetCertificateCount(secTrust);
    CFRelease(secTrust);
    
    if (count == 0) {
      // No certificates, wait more.
      continue;
    }
    break;
  }
  
  return 0;
#else
  return -1;
#endif
}
Esempio n. 19
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;
}
/*
 * Obtain the status of a CMS message's signature. A CMS message can
 * be signed my multiple signers; this function returns the status
 * associated with signer 'n' as indicated by the signerIndex parameter.
 */
OSStatus CMSDecoderCopySignerStatus(
                                    CMSDecoderRef		cmsDecoder,
                                    size_t				signerIndex,
                                    CFTypeRef			policyOrArray,
                                    Boolean				evaluateSecTrust,
                                    CMSSignerStatus		*signerStatus,			/* optional; RETURNED */
                                    SecTrustRef			*secTrust,				/* optional; RETURNED */
                                    OSStatus			*certVerifyResultCode)	/* optional; RETURNED */
{
	if((cmsDecoder == NULL) || (cmsDecoder->decState != DS_Final)) {
		return errSecParam;
	}
	
	/* initialize return values */
	if(signerStatus) {
		*signerStatus = kCMSSignerUnsigned;
	}
	if(secTrust) {
		*secTrust = NULL;
	}
	if(certVerifyResultCode) {
		*certVerifyResultCode = 0;
	}
	
	if(cmsDecoder->signedData == NULL) {
		*signerStatus = kCMSSignerUnsigned;	/* redundant, I know, but explicit */
		return errSecSuccess;
	}
	ASSERT(cmsDecoder->numSigners > 0);
	if(signerIndex >= cmsDecoder->numSigners) {
		*signerStatus = kCMSSignerInvalidIndex;
		return errSecSuccess;
	}
	if(!SecCmsSignedDataHasDigests(cmsDecoder->signedData)) {
		*signerStatus = kCMSSignerNeedsDetachedContent;
		return errSecSuccess;
	}
	
	/*
	 * OK, we should be able to verify this signerInfo.
	 * I think we have to do the SecCmsSignedDataVerifySignerInfo first
	 * in order get all the cert pieces into place before returning them
	 * to the caller.
	 */
	SecTrustRef theTrust = NULL;
	OSStatus vfyRtn = SecCmsSignedDataVerifySignerInfo(cmsDecoder->signedData,
                                                       (int)signerIndex,
                                                       /*
                                                        * FIXME this cast should not be necessary, but libsecurity_smime
                                                        * declares this argument as a SecKeychainRef
                                                        */
                                                       (SecKeychainRef)cmsDecoder->keychainOrArray,
                                                       policyOrArray,
                                                       &theTrust);
    /* Subsequent errors to errOut: */
    
	/*
	 * NOTE the smime lib did NOT evaluate that SecTrust - it only does
	 * SecTrustEvaluate() if we don't ask for a copy.
	 *
	 * FIXME deal with multitudes of status returns here...for now, proceed with
	 * obtaining components the caller wants and assume that a nonzero vfyRtn
	 * means "bad signature".
	 */
	OSStatus ortn = errSecSuccess;
	SecTrustResultType secTrustResult;
	CSSM_RETURN tpVfyStatus = CSSM_OK;
	OSStatus evalRtn;
	
	if(secTrust != NULL) {
		*secTrust = theTrust;
		/* we'll release our reference at the end */
		if (theTrust)
			CFRetain(theTrust);
	}
	SecCmsSignerInfoRef signerInfo =
    SecCmsSignedDataGetSignerInfo(cmsDecoder->signedData, (int)signerIndex);
	if(signerInfo == NULL) {
		/* should never happen */
		ASSERT(0);
		dprintf("CMSDecoderCopySignerStatus: no signerInfo\n");
		ortn = errSecInternalComponent;
		goto errOut;
	}
    
	/* now do the actual cert verify */
	if(evaluateSecTrust) {
		evalRtn = SecTrustEvaluate(theTrust, &secTrustResult);
		if(evalRtn) {
			/* should never happen */
			CSSM_PERROR("SecTrustEvaluate", evalRtn);
			dprintf("CMSDecoderCopySignerStatus: SecTrustEvaluate error\n");
			ortn = errSecInternalComponent;
			goto errOut;
		}
		switch(secTrustResult) {
			case kSecTrustResultUnspecified:
				/* cert chain valid, no special UserTrust assignments */
			case kSecTrustResultProceed:
				/* cert chain valid AND user explicitly trusts this */
				break;
			case kSecTrustResultDeny:
				tpVfyStatus = CSSMERR_APPLETP_TRUST_SETTING_DENY;
				break;
			case kSecTrustResultConfirm:
				dprintf("SecTrustEvaluate reported confirm\n");
				tpVfyStatus = CSSMERR_TP_NOT_TRUSTED;
				break;
			default:
			{
				/* get low-level TP error */
				OSStatus tpStatus;
				ortn = SecTrustGetCssmResultCode(theTrust, &tpStatus);
				if(ortn) {
					CSSM_PERROR("SecTrustGetCssmResultCode", ortn);
				}
				else {
					tpVfyStatus = tpStatus;
				}
				CSSM_PERROR("TP status after SecTrustEvaluate", tpVfyStatus);
				break;
			}
		} 	/* switch(secTrustResult) */
	}		/* evaluateSecTrust true */
	if(certVerifyResultCode != NULL) {
		*certVerifyResultCode = tpVfyStatus;
	}
	
	/* cook up global status based on vfyRtn and tpVfyStatus */
	if(signerStatus != NULL) {
		if((vfyRtn == errSecSuccess) && (tpVfyStatus == CSSM_OK))  {
			*signerStatus = kCMSSignerValid;
		}
		else if(vfyRtn != errSecSuccess) {
			/* this could mean other things, but for now... */
			*signerStatus = kCMSSignerInvalidSignature;
		}
		else {
			*signerStatus = kCMSSignerInvalidCert;
		}
	}
errOut:
	CFRELEASE(theTrust);
	return ortn;
}
Esempio n. 21
0
CFArrayRef CERT_CertChainFromCert(SecCertificateRef cert, SECCertUsage usage, Boolean includeRoot)
{
    SecPolicySearchRef searchRef = NULL;
    SecPolicyRef policy = NULL;
    CFArrayRef wrappedCert = NULL;
    SecTrustRef trust = NULL;
    CFArrayRef certChain = NULL;
    CSSM_TP_APPLE_EVIDENCE_INFO *statusChain;
    CFDataRef actionData = NULL;
    OSStatus status = 0;

    if (!cert)
	goto loser;

    status = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &searchRef);
    if (status)
	goto loser;
    status = SecPolicySearchCopyNext(searchRef, &policy);
    if (status)
	goto loser;

    wrappedCert = CERT_CertListFromCert(cert);
    status = SecTrustCreateWithCertificates(wrappedCert, policy, &trust);
    if (status)
	goto loser;

    /* Tell SecTrust that we don't care if any certs in the chain have expired,
       nor do we want to stop when encountering a cert with a trust setting;
       we always want to build the full chain.
    */
    CSSM_APPLE_TP_ACTION_DATA localActionData = {
        CSSM_APPLE_TP_ACTION_VERSION,
        CSSM_TP_ACTION_ALLOW_EXPIRED | CSSM_TP_ACTION_ALLOW_EXPIRED_ROOT
    };
    actionData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)&localActionData, sizeof(localActionData), kCFAllocatorNull);
    if (!actionData)
        goto loser;

    status = SecTrustSetParameters(trust, CSSM_TP_ACTION_DEFAULT, actionData);
    if (status)
        goto loser;

    status = SecTrustEvaluate(trust, NULL);
    if (status)
	goto loser;

    status = SecTrustGetResult(trust, NULL, &certChain, &statusChain);
    if (status)
	goto loser;

    /* We don't drop the root if there is only 1 (self signed) certificate in the chain. */
    if (!includeRoot && CFArrayGetCount(certChain) > 1)
    {
	CFMutableArrayRef subChain =  CFArrayCreateMutableCopy(NULL, 0, certChain);
	CFRelease(certChain);
	certChain = subChain;
	if (subChain)
	    CFArrayRemoveValueAtIndex(subChain, CFArrayGetCount(subChain) - 1);
    }

loser:
    if (searchRef)
	CFRelease(searchRef);
    if (policy)
	CFRelease(policy);
    if (wrappedCert)
	CFRelease(wrappedCert);
    if (trust)
	CFRelease(trust);
    if (actionData)
	CFRelease(actionData);
    if (certChain && status)
    {
	CFRelease(certChain);
	certChain = NULL;
    }

    return certChain;
}
/*
 * Given a SecIdentityRef, do our best to construct a complete, ordered, and 
 * verified cert chain, returning the result in a CFArrayRef. The result is 
 * suitable for use when calling SSLSetCertificate().
 */
OSStatus sslCompleteCertChain(
	SecIdentityRef 		identity, 
	SecCertificateRef	trustedAnchor,	// optional additional trusted anchor
	bool 				includeRoot, 	// include the root in outArray
	CFArrayRef			*outArray)		// created and RETURNED
{
	CFMutableArrayRef 			certArray;
	SecTrustRef					secTrust = NULL;
	SecPolicyRef				policy = NULL;
	SecPolicySearchRef			policySearch = NULL;
	SecTrustResultType			secTrustResult;
	CSSM_TP_APPLE_EVIDENCE_INFO *dummyEv;			// not used
	CFArrayRef					certChain = NULL;   // constructed chain
	CFIndex 					numResCerts;
	
	certArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
	CFArrayAppendValue(certArray, identity);
	
	/*
	 * Case 1: identity is a root; we're done. Note that this case
	 * overrides the includeRoot argument.
	 */
	SecCertificateRef certRef;
	OSStatus ortn = SecIdentityCopyCertificate(identity, &certRef);
	if(ortn) {
		/* should never happen */
		cssmPerror("SecIdentityCopyCertificate", ortn);
		return ortn;
	}
	bool isRoot = isCertRefRoot(certRef);
	if(isRoot) {
		*outArray = certArray;
		CFRelease(certRef);
		return errSecSuccess;
	}
	
	/* 
	 * Now use SecTrust to get a complete cert chain, using all of the 
	 * user's keychains to look for intermediate certs.
	 * NOTE this does NOT handle root certs which are not in the system
	 * root cert DB. (The above case, where the identity is a root cert, does.)
	 */
	CFMutableArrayRef subjCerts = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks);
	CFArraySetValueAtIndex(subjCerts, 0, certRef);
			
	/* the array owns the subject cert ref now */
	CFRelease(certRef);
	
	/* Get a SecPolicyRef for generic X509 cert chain verification */
	ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3,
		&CSSMOID_APPLE_X509_BASIC,
		NULL,				// value
		&policySearch);
	if(ortn) {
		cssmPerror("SecPolicySearchCreate", ortn);
		goto errOut;
	}
	ortn = SecPolicySearchCopyNext(policySearch, &policy);
	if(ortn) {
		cssmPerror("SecPolicySearchCopyNext", ortn);
		goto errOut;
	}

	/* build a SecTrustRef for specified policy and certs */
	ortn = SecTrustCreateWithCertificates(subjCerts,
		policy, &secTrust);
	if(ortn) {
		cssmPerror("SecTrustCreateWithCertificates", ortn);
		goto errOut;
	}
	
	if(trustedAnchor) {
		/* 
		 * Tell SecTrust to trust this one in addition to the current
		 * trusted system-wide anchors.
		 */
		CFMutableArrayRef newAnchors;
		CFArrayRef currAnchors;
		
		ortn = SecTrustCopyAnchorCertificates(&currAnchors);
		if(ortn) {
			/* should never happen */
			cssmPerror("SecTrustCopyAnchorCertificates", ortn);
			goto errOut;
		}
		newAnchors = CFArrayCreateMutableCopy(NULL,
			CFArrayGetCount(currAnchors) + 1,
			currAnchors);
		CFRelease(currAnchors);
		CFArrayAppendValue(newAnchors, trustedAnchor);
		ortn = SecTrustSetAnchorCertificates(secTrust, newAnchors);
		CFRelease(newAnchors);
		if(ortn) {
			cssmPerror("SecTrustSetAnchorCertificates", ortn);
			goto errOut;
		}
	}
	/* evaluate: GO */
	ortn = SecTrustEvaluate(secTrust, &secTrustResult);
	if(ortn) {
		cssmPerror("SecTrustEvaluate", ortn);
		goto errOut;
	}
	switch(secTrustResult) {
		case kSecTrustResultUnspecified:
			/* cert chain valid, no special UserTrust assignments */
		case kSecTrustResultProceed:
			/* cert chain valid AND user explicitly trusts this */
			break;
		default:
			/*
			 * Cert chain construction failed. 
			 * Just go with the single subject cert we were given.
			 */
			printf("***Warning: could not construct completed cert chain\n");
			ortn = errSecSuccess;
			goto errOut;
	}

	/* get resulting constructed cert chain */
	ortn = SecTrustGetResult(secTrust, &secTrustResult, &certChain, &dummyEv);
	if(ortn) {
		cssmPerror("SecTrustEvaluate", ortn);
		goto errOut;
	}
	
	/*
	 * Copy certs from constructed chain to our result array, skipping 
	 * the leaf (which is already there, as a SecIdentityRef) and possibly
	 * a root.
	 */
	numResCerts = CFArrayGetCount(certChain);
	if(numResCerts < 2) {
		/*
		 * Can't happen: if subject was a root, we'd already have returned. 
		 * If chain doesn't verify to a root, we'd have bailed after
		 * SecTrustEvaluate().
		 */
		printf("***sslCompleteCertChain screwup: numResCerts %d\n", 
			(int)numResCerts);
		ortn = errSecSuccess;
		goto errOut;
	}
	if(!includeRoot) {
		/* skip the last (root) cert) */
		numResCerts--;
	}
	for(CFIndex dex=1; dex<numResCerts; dex++) {
		certRef = (SecCertificateRef)CFArrayGetValueAtIndex(certChain, dex);
		CFArrayAppendValue(certArray, certRef);
	}
errOut:
	/* clean up */
	if(secTrust) {
		CFRelease(secTrust);
	}
	if(subjCerts) {
		CFRelease(subjCerts);
	}
	if(policy) {
		CFRelease(policy);
	}
	if(policySearch) {
		CFRelease(policySearch);
	}
	*outArray = certArray;
	return ortn;
}
/*
 * 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
}
static void tests(void)
{
	SecTrustRef trust;
	SecCertificateRef cert0, cert1;
	isnt(cert0 = SecCertificateCreateWithBytes(NULL, WWDR_NoRevInfo, sizeof(WWDR_NoRevInfo)),
			NULL, "create leaf");
	isnt(cert1 = SecCertificateCreateWithBytes(NULL, WWDR_CA, sizeof(WWDR_CA)),
			NULL, "create intermediate");
	CFMutableArrayRef certs = CFArrayCreateMutable(kCFAllocatorDefault, 0,
			&kCFTypeArrayCallBacks);
	CFArrayAppendValue(certs, cert0);
	CFArrayAppendValue(certs, cert1);

	/* at this point, we should have an OCSP responder for the WWDR-issued leaf cert,
	 * even though the leaf itself doesn't contain any revocation info.
	 */
	CFArrayRef ocspResponders = SecCertificateGetOCSPResponders(cert0);
	ok(ocspResponders != NULL, "synthesized OCSP responder successfully");

	SecPolicyRef signingPolicy = SecPolicyCreateCodeSigning();
	SecPolicyRef ocspPolicy = SecPolicyCreateRevocation();
	const void *v_policies[] = { signingPolicy, ocspPolicy };
	CFArrayRef policies = CFArrayCreate(NULL, v_policies,
			sizeof(v_policies) / sizeof(*v_policies), &kCFTypeArrayCallBacks);
	CFRelease(signingPolicy);
	CFRelease(ocspPolicy);
	ok_status(SecTrustCreateWithCertificates(certs, policies, &trust),
			"create trust");
	/* Aug 1st 2012. */
	CFGregorianDate g_date = { 2012, 8, 1, 12, 0, 0 }; // Aug 1 2012 12:00 PM
	CFDateRef date = CFDateCreate(kCFAllocatorDefault,
			CFGregorianDateGetAbsoluteTime(g_date, NULL));
#if 0
	/* will we trust the OCSP response for a verify date in the past?? */
	ok_status(SecTrustSetVerifyDate(trust, date), "set date");
#else
	ok_status(errSecSuccess, "using current date");
#endif

	SecTrustResultType trustResult;
	ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");

	/* The cert should either be reported as revoked (until Jan 13 2013),
	 * or as expired (after Jan 13 2013). That means its trust result value
     * should be 5 (kSecTrustResultRecoverableTrustFailure) or greater.
	 */
	ok(trustResult >= kSecTrustResultRecoverableTrustFailure,
       "trustResult must report a failure, cert is either expired or revoked");
#if 0
    fprintf(stderr, "=== trustResult %lu\n", trustResult);
    CFStringRef errStr = SecTrustCopyFailureDescription(trust);
    CFShow(errStr);
#endif

	CFReleaseSafe(trust);
	CFReleaseSafe(policies);
	CFReleaseSafe(certs);
	CFReleaseSafe(cert0);
	CFReleaseSafe(cert1);
	CFReleaseSafe(date);
}
Esempio n. 25
0
/*
** OLD OBSOLETE FUNCTIONS with enum SECCertUsage - DO NOT USE FOR NEW CODE
** verify a certificate by checking validity times against a certain time,
** that we trust the issuer, and that the signature on the certificate is
** valid.
**	"cert" the certificate to verify
**	"checkSig" only check signatures if true
*/
SECStatus
CERT_VerifyCert(SecKeychainRef keychainOrArray, SecCertificateRef cert,
		const CSSM_DATA_PTR *otherCerts,    /* intermediates */
		CFTypeRef policies, CFAbsoluteTime stime, SecTrustRef *trustRef)
{
    CFMutableArrayRef certificates = NULL;
    SecTrustRef trust = NULL;
    OSStatus rv;
    int numOtherCerts = SecCmsArrayCount((void **)otherCerts);
    int dex;
    
    /* 
     * Certs to evaluate: first the leaf - our cert - then all the rest we know
     * about. It's OK for otherCerts to contain a copy of the leaf. 
     */
    certificates = CFArrayCreateMutable(NULL, numOtherCerts + 1, &kCFTypeArrayCallBacks);
    CFArrayAppendValue(certificates, cert);
    for(dex=0; dex<numOtherCerts; dex++) {
	SecCertificateRef intCert;
	
	rv = SecCertificateCreateFromData(otherCerts[dex], 
	    CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER,
	    &intCert);
	if(rv) {
	    goto loser;
	}
	CFArrayAppendValue(certificates, intCert);
	CFRelease(intCert);
    }
    rv = SecTrustCreateWithCertificates(certificates, policies, &trust);
    CFRelease(certificates);
    certificates = NULL;
    if (rv)
	goto loser;

    rv = SecTrustSetKeychains(trust, keychainOrArray);
    if (rv)
	goto loser;

    CFDateRef verifyDate = CFDateCreate(NULL, stime);
    rv = SecTrustSetVerifyDate(trust, verifyDate);
    CFRelease(verifyDate);
    if (rv)
	goto loser;

    if (trustRef)
    {
	*trustRef = trust;
    }
    else
    {
	SecTrustResultType result;
	/* The caller doesn't want a SecTrust object, so let's evaluate it for them. */
	rv = SecTrustEvaluate(trust, &result);
	if (rv)
	    goto loser;

	switch (result)
	{
	case kSecTrustResultProceed:
	case kSecTrustResultUnspecified:
	    /* TP Verification succeeded and there was either a UserTurst entry
	       telling us to procceed, or no user trust setting was specified. */
	    CFRelease(trust);
	    break;
	default:
	    PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
	    rv = SECFailure;
	    goto loser;
	    break;
	}
    }

    return SECSuccess;
loser:
    if (trust)
	CFRelease(trust);
    if(certificates) 
	CFRelease(certificates);
    return rv;
}
Esempio n. 26
0
bool mailcore::checkCertificate(mailstream * stream, String * hostname)
{
#if __APPLE__
    bool result = false;
    CFStringRef hostnameCFString;
    SecPolicyRef policy;
    CFMutableArrayRef certificates;
    SecTrustRef trust = NULL;
    SecTrustResultType trustResult;
    OSStatus status;
    
    carray * cCerts = mailstream_get_certificate_chain(stream);
    if (cCerts == NULL) {
        fprintf(stderr, "warning: No certificate chain retrieved");
        goto err;
    }
    
    hostnameCFString = CFStringCreateWithCharacters(NULL, (const UniChar *) hostname->unicodeCharacters(),
                                                                hostname->length());
    policy = SecPolicyCreateSSL(true, hostnameCFString);
    certificates = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
    
    for(unsigned int i = 0 ; i < carray_count(cCerts) ; i ++) {
        MMAPString * str;
        str = (MMAPString *) carray_get(cCerts, i);
        CFDataRef data = CFDataCreate(NULL, (const UInt8 *) str->str, (CFIndex) str->len);
        SecCertificateRef cert = SecCertificateCreateWithData(NULL, data);
        CFArrayAppendValue(certificates, cert);
        CFRelease(data);
        CFRelease(cert);
    }
    
    static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
    
    // The below API calls are not thread safe. We're making sure not to call the concurrently.
    pthread_mutex_lock(&lock);
    
    status = SecTrustCreateWithCertificates(certificates, policy, &trust);
    if (status != noErr) {
        pthread_mutex_unlock(&lock);
        goto free_certs;
    }
    
    status = SecTrustEvaluate(trust, &trustResult);
    if (status != noErr) {
        pthread_mutex_unlock(&lock);
        goto free_certs;
    }
    
    pthread_mutex_unlock(&lock);
    
    switch (trustResult) {
        case kSecTrustResultUnspecified:
        case kSecTrustResultProceed:
            // certificate chain is ok
            result = true;
            break;
            
        default:
            // certificate chain is invalid
            break;
    }
    
    CFRelease(trust);
free_certs:
    CFRelease(certificates);
    mailstream_certificate_chain_free(cCerts);
    CFRelease(policy);
    CFRelease(hostnameCFString);
err:
    return result;
#else
    bool result = false;
    X509_STORE * store = NULL;
    X509_STORE_CTX * storectx = NULL;
    STACK_OF(X509) * certificates = NULL;
#if defined(ANDROID) || defined(__ANDROID__)
    DIR * dir = NULL;
    struct dirent * ent = NULL;
    FILE * f = NULL;
#endif
    int status;
    
    carray * cCerts = mailstream_get_certificate_chain(stream);
    if (cCerts == NULL) {
        fprintf(stderr, "warning: No certificate chain retrieved");
        goto err;
    }
    
    store = X509_STORE_new();
    if (store == NULL) {
        goto free_certs;
    }
    
#ifdef _MSC_VER
	HCERTSTORE systemStore = CertOpenSystemStore(NULL, L"ROOT");

	PCCERT_CONTEXT previousCert = NULL;
	while (1) {
		PCCERT_CONTEXT nextCert = CertEnumCertificatesInStore(systemStore, previousCert);
		if (nextCert == NULL) {
			break;
		}
		X509 * openSSLCert = d2i_X509(NULL, (const unsigned char **)&nextCert->pbCertEncoded, nextCert->cbCertEncoded);
		if (openSSLCert != NULL) {
			X509_STORE_add_cert(store, openSSLCert);
			X509_free(openSSLCert);
		}
		previousCert = nextCert;
	}
	CertCloseStore(systemStore, 0);
#elif defined(ANDROID) || defined(__ANDROID__)
    dir = opendir("/system/etc/security/cacerts");
    while (ent = readdir(dir)) {
        if (ent->d_name[0] == '.') {
            continue;
        }
        char filename[1024];
        snprintf(filename, sizeof(filename), "/system/etc/security/cacerts/%s", ent->d_name);
        f = fopen(filename, "rb");
        if (f != NULL) {
            X509 * cert = PEM_read_X509(f, NULL, NULL, NULL);
            if (cert != NULL) {
                X509_STORE_add_cert(store, cert);
                X509_free(cert);
            }
            fclose(f);
        }
    }
    closedir(dir);
#endif

	status = X509_STORE_set_default_paths(store);
    if (status != 1) {
        printf("Error loading the system-wide CA certificates");
    }
    
    certificates = sk_X509_new_null();
    for(unsigned int i = 0 ; i < carray_count(cCerts) ; i ++) {
        MMAPString * str;
        str = (MMAPString *) carray_get(cCerts, i);
        if (str == NULL) {
            goto free_certs;
        }
        BIO *bio = BIO_new_mem_buf((void *) str->str, str->len);
        X509 *certificate = d2i_X509_bio(bio, NULL);
        BIO_free(bio);
        if (!sk_X509_push(certificates, certificate)) {
            goto free_certs;
        }
    }
    
    storectx = X509_STORE_CTX_new();
    if (storectx == NULL) {
        goto free_certs;
    }
    
    status = X509_STORE_CTX_init(storectx, store, sk_X509_value(certificates, 0), certificates);
    if (status != 1) {
        goto free_certs;
    }
    
    status = X509_verify_cert(storectx);
    if (status == 1) {
        result = true;
    }
    
free_certs:
    mailstream_certificate_chain_free(cCerts);
    if (certificates != NULL) {
        sk_X509_pop_free((STACK_OF(X509) *) certificates, X509_free);
    }
Esempio n. 27
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. 28
0
static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options)
{
    TLSContext *c = h->priv_data;
    TLSShared *s = &c->tls_shared;
    int ret;

    if ((ret = ff_tls_open_underlying(s, h, uri, options)) < 0)
        goto fail;

    c->ssl_context = SSLCreateContext(NULL, s->listen ? kSSLServerSide : kSSLClientSide, kSSLStreamType);
    if (!c->ssl_context) {
        av_log(h, AV_LOG_ERROR, "Unable to create SSL context\n");
        ret = AVERROR(ENOMEM);
        goto fail;
    }
    if (s->ca_file) {
        if ((ret = load_ca(h)) < 0)
            goto fail;
    }
    if (s->ca_file || !s->verify)
        CHECK_ERROR(SSLSetSessionOption, c->ssl_context, kSSLSessionOptionBreakOnServerAuth, true);
    if (s->cert_file)
        if ((ret = load_cert(h)) < 0)
            goto fail;
    CHECK_ERROR(SSLSetPeerDomainName, c->ssl_context, s->host, strlen(s->host));
    CHECK_ERROR(SSLSetIOFuncs, c->ssl_context, tls_read_cb, tls_write_cb);
    CHECK_ERROR(SSLSetConnection, c->ssl_context, h);
    while (1) {
        OSStatus status = SSLHandshake(c->ssl_context);
        if (status == errSSLServerAuthCompleted) {
            SecTrustRef peerTrust;
            SecTrustResultType trustResult;
            if (!s->verify)
                continue;

            if (SSLCopyPeerTrust(c->ssl_context, &peerTrust) != noErr) {
                ret = AVERROR(ENOMEM);
                goto fail;
            }

            if (SecTrustSetAnchorCertificates(peerTrust, c->ca_array) != noErr) {
                ret = AVERROR_UNKNOWN;
                goto fail;
            }

            if (SecTrustEvaluate(peerTrust, &trustResult) != noErr) {
                ret = AVERROR_UNKNOWN;
                goto fail;
            }

            if (trustResult == kSecTrustResultProceed ||
                trustResult == kSecTrustResultUnspecified) {
                // certificate is trusted
                status = errSSLWouldBlock; // so we call SSLHandshake again
            } else if (trustResult == kSecTrustResultRecoverableTrustFailure) {
                // not trusted, for some reason other than being expired
                status = errSSLXCertChainInvalid;
            } else {
                // cannot use this certificate (fatal)
                status = errSSLBadCert;
            }

            if (peerTrust)
                CFRelease(peerTrust);
        }
        if (status == noErr)
            break;

        av_log(h, AV_LOG_ERROR, "Unable to negotiate TLS/SSL session: %i\n", (int)status);
        ret = AVERROR(EIO);
        goto fail;
    }

    return 0;
fail:
    tls_close(h);
    return ret;
}
Esempio n. 29
0
void Download::Initialize (CFDataRef ticket,
						   SecureDownloadTrustSetupCallback setup,
						   void* setupContext,
						   SecureDownloadTrustEvaluateCallback evaluate,
						   void* evaluateContext)
{
	// decode the ticket
	SecCmsMessageRef cmsMessage = GetCmsMessageFromData (ticket);
	
	// get a policy
	SecPolicyRef policy = GetPolicy ();

	// parse the CMS message
	int contentLevelCount = SecCmsMessageContentLevelCount (cmsMessage);
	SecCmsSignedDataRef signedData;

	OSStatus result;
	
	int i = 0;
	while (i < contentLevelCount)
	{
		SecCmsContentInfoRef contentInfo = SecCmsMessageContentLevel (cmsMessage, i++);
		SECOidTag contentTypeTag = SecCmsContentInfoGetContentTypeTag (contentInfo);
		
		if (contentTypeTag != SEC_OID_PKCS7_SIGNED_DATA)
		{
			continue;
		}

		signedData = (SecCmsSignedDataRef) SecCmsContentInfoGetContent (contentInfo);
		if (signedData == NULL)
		{
			MacOSError::throwMe (errSecureDownloadInvalidTicket);
		}
		
		// import the certificates found in the cms message
		result = SecCmsSignedDataImportCerts (signedData, NULL, certUsageObjectSigner, true);
		if (result != 0)
		{
			MacOSError::throwMe (errSecureDownloadInvalidTicket);
		}
		
		int numberOfSigners = SecCmsSignedDataSignerInfoCount (signedData);
		int j;
		
		if (numberOfSigners == 0) // no signers?  This is a possible attack
		{
			MacOSError::throwMe (errSecureDownloadInvalidTicket);
		}
		
		for (j = 0; j < numberOfSigners; ++j)
		{
			SecTrustResultType resultType;
			
			// do basic verification of the message
			SecTrustRef trustRef;
			result = SecCmsSignedDataVerifySignerInfo (signedData, j, NULL, policy, &trustRef);
			
			// notify the user of the new trust ref
			if (setup != NULL)
			{
				SecureDownloadTrustCallbackResult tcResult = setup (trustRef, setupContext);
				switch (tcResult)
				{
					case kSecureDownloadDoNotEvaluateSigner:
						continue;
					
					case kSecureDownloadFailEvaluation:
						MacOSError::throwMe (errSecureDownloadInvalidTicket);
					
					case kSecureDownloadEvaluateSigner:
					break;
				}
			}
			
			if (result != 0)
			{
				MacOSError::throwMe (errSecureDownloadInvalidTicket);
			}
			
			result = SecTrustEvaluate (trustRef, &resultType);
			if (result != noErr)
			{
				MacOSError::throwMe (errSecureDownloadInvalidTicket);
			}
			
			if (evaluate != NULL)
			{
				resultType = evaluate (trustRef, resultType, evaluateContext);
			}
			
			GoOrNoGo (resultType);
		}
	}
	
	// extract the message 
	CSSM_DATA_PTR message = SecCmsMessageGetContent (cmsMessage);
	CFDataRef ticketData = CFDataCreateWithBytesNoCopy (NULL, message->Data, message->Length, kCFAllocatorNull);
	CheckCFThingForNULL (ticketData);
	
	ParseTicket (ticketData);

	// setup for hashing
	CC_SHA256_Init (&mSHA256Context);
	
	// clean up
	CFRelease (ticketData);
	SecCmsMessageDestroy (cmsMessage);
}
Esempio n. 30
0
/*
 * Verify a chain of DER-encoded certs.
 * Last cert in a chain is the leaf; this must also be present
 * in ctx->trustedCerts.
 *
 * If arePeerCerts is true, host name verification is enabled and we
 * save the resulting SecTrustRef in ctx->peerSecTrust. Otherwise
 * we're just validating our own certs; no host name checking and
 * peerSecTrust is transient.
 */
extern OSStatus sslVerifyCertChain(
	SSLContext				*ctx,
	CFArrayRef				certChain,
	bool					arePeerCerts)
{
	OSStatus status;
	SecTrustRef trust = NULL;

    assert(certChain);

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

	status = sslCreateSecTrust(ctx, certChain, arePeerCerts, &trust);

	if (!ctx->enableCertVerify) {
		/* trivial case, this is caller's responsibility */
		status = noErr;
		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 = noErr;
            break;
        case kSecTrustResultDeny:
        case kSecTrustResultConfirm:
        case kSecTrustResultRecoverableTrustFailure:
        default:
            if(ctx->allowAnyRoot) {
                sslErrorLog("***Warning: accepting unverified cert chain\n");
                status = noErr;
            }
            else {
				/*
				 * If the caller provided a list of trusted leaf certs, check them here
				 */
				if(ctx->trustedLeafCerts) {
					if (sslGetMatchingCertInArray((SecCertificateRef)CFArrayGetValueAtIndex(certChain, 0),
								ctx->trustedLeafCerts)) {
						status = noErr;
						goto errOut;
					}
				}
				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:
	if (arePeerCerts)
		ctx->peerSecTrust = trust;
	else
        CFReleaseSafe(trust);

	return status;
}