/* 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); }
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 }
/* * 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); }
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); }
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); }
// // 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; }
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; }
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; }
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; }
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 }
/* * 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; }
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); }
/* ** 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; }
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); }
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; }
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; }
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); }
/* * 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; }