/* 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 int tls_create_trust_from_certs(const SSLCertificate *cert, SecTrustRef *trustRef) { int err; CFMutableArrayRef certArray = NULL; CFDataRef certData = NULL; SecCertificateRef cfCert = NULL; if(cert==NULL) { test_printf("No certs, do not create SecTrustRef\n"); *trustRef = NULL; return 0; } certArray = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); while(cert) { base64_dump(cert->derCert, "CERTIFICATE"); require_action((certData = CFDataCreate(kCFAllocatorDefault, cert->derCert.data, cert->derCert.length)), out, err = errSecAllocate); require_action((cfCert = SecCertificateCreateWithData(kCFAllocatorDefault, certData)), out, err = errSecAllocate); CFArrayAppendValue(certArray, cfCert); CFReleaseNull(cfCert); CFReleaseNull(certData); cert=cert->next; } require_noerr((err=SecTrustCreateWithCertificates(certArray, NULL, trustRef)), out); out: CFReleaseSafe(certData); CFReleaseSafe(cfCert); CFReleaseSafe(certArray); return err; }
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); }
OSStatus sslCreateSecTrust( SSLContext *ctx, CFArrayRef certChain, bool arePeerCerts, SecTrustRef *pTrust) /* RETURNED */ { OSStatus status = memFullErr; CFStringRef peerDomainName = NULL; CFTypeRef policies = NULL; SecTrustRef trust = NULL; if (CFArrayGetCount(certChain) == 0) { status = errSSLBadCert; goto errOut; } if (arePeerCerts) { if (ctx->peerDomainNameLen && ctx->peerDomainName) { CFIndex len = ctx->peerDomainNameLen; if (ctx->peerDomainName[len - 1] == 0) { len--; //secwarning("peerDomainName is zero terminated!"); } /* @@@ Double check that this is the correct encoding. */ require(peerDomainName = CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8 *)ctx->peerDomainName, len, kCFStringEncodingUTF8, false), errOut); } } /* If we are the client, our peer certificates must satisfy the ssl server policy. */ bool server = ctx->protocolSide == kSSLClientSide; require(policies = SecPolicyCreateSSL(server, peerDomainName), errOut); require_noerr(status = SecTrustCreateWithCertificates(certChain, policies, &trust), errOut); /* If we have trustedAnchors we set them here. */ if (ctx->trustedCerts) { require_noerr(status = SecTrustSetAnchorCertificates(trust, ctx->trustedCerts), errOut); require_noerr(status = SecTrustSetAnchorCertificatesOnly(trust, ctx->trustedCertsOnly), errOut); } status = noErr; errOut: CFReleaseSafe(peerDomainName); CFReleaseSafe(policies); *pTrust = trust; return status; }
int32_t AppleCryptoNative_X509ChainCreate(CFTypeRef certs, CFTypeRef policies, SecTrustRef* pTrustOut, int32_t* pOSStatus) { if (pTrustOut != NULL) *pTrustOut = NULL; if (pOSStatus != NULL) *pOSStatus = noErr; if (certs == NULL || policies == NULL || pTrustOut == NULL || pOSStatus == NULL) return -1; *pOSStatus = SecTrustCreateWithCertificates(certs, policies, pTrustOut); return *pOSStatus == noErr; }
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); }
/* Extract public SecKeyRef from Certificate Chain */ static int sslCopyPeerPubKey(const SSLCertificate *certchain, SecKeyRef *pubKey) { int err; check(pubKey); SecTrustRef trust = NULL; const SSLCertificate *cert; CFMutableArrayRef certArray = NULL; CFDataRef certData = NULL; SecCertificateRef cfCert = NULL; err = errSSLInternal; certArray = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); cert = certchain; while(cert) { require((certData = CFDataCreate(kCFAllocatorDefault, cert->derCert.data, cert->derCert.length)), out); require((cfCert = SecCertificateCreateWithData(kCFAllocatorDefault, certData)), out); CFArrayAppendValue(certArray, cfCert); CFReleaseNull(cfCert); CFReleaseNull(certData); cert=cert->next; } require_noerr((err=SecTrustCreateWithCertificates(certArray, NULL, &trust)), out); SecKeyRef key = SecTrustCopyPublicKey(trust); require_action(key, out, err=-9808); // errSSLBadCert *pubKey = key; err = errSecSuccess; out: CFReleaseSafe(certData); CFReleaseSafe(cfCert); CFReleaseSafe(trust); CFReleaseSafe(certArray); return err; }
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; }
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; }
/* * 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 }
/* ** 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); }
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; }
// // Installer archive. // Hybrid policy: If we detect an installer signature, use and validate that. // If we don't, check for a code signature instead. // void PolicyEngine::evaluateInstall(CFURLRef path, SecAssessmentFlags flags, CFDictionaryRef context, CFMutableDictionaryRef result) { const AuthorityType type = kAuthorityInstall; Xar xar(cfString(path).c_str()); if (!xar) { // follow the code signing path evaluateCode(path, type, flags, context, result); return; } SQLite3::int64 latentID = 0; // first (highest priority) disabled matching ID std::string latentLabel; // ... and associated label, if any if (!xar.isSigned()) { // unsigned xar if (SYSPOLICY_ASSESS_OUTCOME_UNSIGNED_ENABLED()) SYSPOLICY_ASSESS_OUTCOME_UNSIGNED(cfString(path).c_str(), type); cfadd(result, "{%O=%B}", kSecAssessmentAssessmentVerdict, false); addAuthority(result, "no usable signature"); return; } if (CFRef<CFArrayRef> certs = xar.copyCertChain()) { CFRef<CFTypeRef> policy = installerPolicy(); CFRef<SecTrustRef> trust; MacOSError::check(SecTrustCreateWithCertificates(certs, policy, &trust.aref())); // MacOSError::check(SecTrustSetAnchorCertificates(trust, cfEmptyArray())); // no anchors MacOSError::check(SecTrustSetOptions(trust, kSecTrustOptionAllowExpired | kSecTrustOptionImplicitAnchors)); SecTrustResultType trustResult; MacOSError::check(SecTrustEvaluate(trust, &trustResult)); CFRef<CFArrayRef> chain; CSSM_TP_APPLE_EVIDENCE_INFO *info; MacOSError::check(SecTrustGetResult(trust, &trustResult, &chain.aref(), &info)); if (flags & kSecAssessmentFlagRequestOrigin) setOrigin(chain, result); switch (trustResult) { case kSecTrustResultProceed: case kSecTrustResultUnspecified: break; default: { OSStatus rc; MacOSError::check(SecTrustGetCssmResultCode(trust, &rc)); MacOSError::throwMe(rc); } } SQLite::Statement query(*this, "SELECT allow, requirement, id, label, flags, disabled FROM scan_authority" " WHERE type = :type" " ORDER BY priority DESC;"); query.bind(":type").integer(type); while (query.nextRow()) { bool allow = int(query[0]); const char *reqString = query[1]; SQLite3::int64 id = query[2]; const char *label = query[3]; //sqlite_uint64 ruleFlags = query[4]; SQLite3::int64 disabled = query[5]; CFRef<SecRequirementRef> requirement; MacOSError::check(SecRequirementCreateWithString(CFTempString(reqString), kSecCSDefaultFlags, &requirement.aref())); switch (OSStatus rc = SecRequirementEvaluate(requirement, chain, NULL, kSecCSDefaultFlags)) { case noErr: // success break; case errSecCSReqFailed: // requirement missed, but otherwise okay continue; default: // broken in some way; all tests will fail like this so bail out MacOSError::throwMe(rc); } if (disabled) { if (latentID == 0) { latentID = id; if (label) latentLabel = label; } continue; // the loop } if (SYSPOLICY_ASSESS_OUTCOME_ACCEPT_ENABLED() || SYSPOLICY_ASSESS_OUTCOME_DENY_ENABLED()) { if (allow) SYSPOLICY_ASSESS_OUTCOME_ACCEPT(cfString(path).c_str(), type, label, NULL); else SYSPOLICY_ASSESS_OUTCOME_DENY(cfString(path).c_str(), type, label, NULL); } // not adding to the object cache - we could, but it's not likely to be worth it cfadd(result, "{%O=%B}", kSecAssessmentAssessmentVerdict, allow); addAuthority(result, label, id); return; } } if (SYSPOLICY_ASSESS_OUTCOME_DEFAULT_ENABLED()) SYSPOLICY_ASSESS_OUTCOME_DEFAULT(cfString(path).c_str(), type, latentLabel.c_str(), NULL); // no applicable authority. Deny by default cfadd(result, "{%O=#F}", kSecAssessmentAssessmentVerdict); addAuthority(result, latentLabel.c_str(), latentID); }
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); }
/* Test basic add delete update copy matching stuff. */ static void tests(void) { SecTrustRef trust; SecCertificateRef iAP1CA, iAP2CA, leaf0, leaf1; isnt(iAP1CA = SecCertificateCreateWithBytes(NULL, _iAP1CA, sizeof(_iAP1CA)), NULL, "create iAP1CA"); isnt(iAP2CA = SecCertificateCreateWithBytes(NULL, _iAP2CA, sizeof(_iAP2CA)), NULL, "create iAP2CA"); isnt(leaf0 = SecCertificateCreateWithBytes(NULL, _leaf0, sizeof(_leaf0)), NULL, "create leaf0"); isnt(leaf1 = SecCertificateCreateWithBytes(NULL, _leaf1, sizeof(_leaf1)), NULL, "create leaf1"); { // temporarily grab some stack space and fill it with 0xFF; // when we exit this scope, the stack pointer should shrink but leave the memory filled. // this tests for a stack overflow bug inside SecPolicyCreateiAP (rdar://16056248) char buf[2048]; memset(buf, 0xFF, sizeof(buf)); } SecPolicyRef policy = SecPolicyCreateiAP(); const void *v_anchors[] = { iAP1CA, iAP2CA }; CFArrayRef anchors = CFArrayCreate(NULL, v_anchors, array_size(v_anchors), NULL); CFArrayRef certs0 = CFArrayCreate(NULL, (const void **)&leaf0, 1, NULL); CFArrayRef certs1 = CFArrayCreate(NULL, (const void **)&leaf1, 1, NULL); ok_status(SecTrustCreateWithCertificates(certs0, policy, &trust), "create trust for leaf0"); ok_status(SecTrustSetAnchorCertificates(trust, anchors), "set anchors"); /* Jan 1st 2008. */ CFDateRef date = CFDateCreate(NULL, 220752000.0); ok_status(SecTrustSetVerifyDate(trust, date), "set date"); SecTrustResultType trustResult; ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust"); is_status(trustResult, kSecTrustResultUnspecified, "trust is kSecTrustResultUnspecified"); is(SecTrustGetCertificateCount(trust), 2, "cert count is 2"); CFReleaseSafe(trust); ok_status(SecTrustCreateWithCertificates(certs1, policy, &trust), "create trust for leaf1"); ok_status(SecTrustSetAnchorCertificates(trust, anchors), "set anchors"); ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust"); TODO: { todo("We need the actual iAP1 intermediate"); is_status(trustResult, kSecTrustResultUnspecified, "trust is kSecTrustResultUnspecified"); } CFReleaseSafe(anchors); CFReleaseSafe(certs1); CFReleaseSafe(certs0); CFReleaseSafe(trust); CFReleaseSafe(policy); CFReleaseSafe(leaf0); CFReleaseSafe(leaf1); CFReleaseSafe(iAP1CA); CFReleaseSafe(iAP2CA); CFReleaseSafe(date); }
/* Test basic add delete update copy matching stuff. */ static void tests(void) { SecTrustRef trust; SecCertificateRef cert0, cert1; isnt(cert0 = SecCertificateCreateWithBytes(NULL, _c0, sizeof(_c0)), NULL, "create cert0"); isnt(cert1 = SecCertificateCreateWithBytes(NULL, _c1, sizeof(_c1)), NULL, "create cert1"); const void *v_certs[] = { cert0, cert1 }; SecPolicyRef policy = SecPolicyCreateSSL(false, NULL); CFArrayRef certs = CFArrayCreate(NULL, v_certs, array_size(v_certs), NULL); /* SecTrustCreateWithCertificates using single cert. */ ok_status(SecTrustCreateWithCertificates(cert0, policy, &trust), "create trust with single cert0"); is(SecTrustGetCertificateCount(trust), 1, "cert count is 1"); is(SecTrustGetCertificateAtIndex(trust, 0), cert0, "cert 0 is leaf"); CFReleaseNull(trust); /* SecTrustCreateWithCertificates failures. */ is_status(SecTrustCreateWithCertificates(kCFBooleanTrue, policy, &trust), errSecParam, "create trust with boolean instead of cert"); is_status(SecTrustCreateWithCertificates(cert0, kCFBooleanTrue, &trust), errSecParam, "create trust with boolean instead of policy"); /* SecTrustCreateWithCertificates using array of certs. */ ok_status(SecTrustCreateWithCertificates(certs, policy, &trust), "create trust"); /* NOTE: prior to <rdar://11810677 SecTrustGetCertificateCount would return 1 at this point. * Now, however, we do an implicit SecTrustEvaluate to build the chain if it has not yet been * evaluated, so we now expect the full chain length. */ is(SecTrustGetCertificateCount(trust), 3, "cert count is 3"); is(SecTrustGetCertificateAtIndex(trust, 0), cert0, "cert 0 is leaf"); /* Jan 1st 2006. */ CFDateRef date = CFDateCreate(NULL, 157680000.0); ok_status(SecTrustSetVerifyDate(trust, date), "set date"); is(SecTrustGetVerifyTime(trust), 157680000.0, "get date"); SecTrustResultType trustResult; SKIP: { #ifdef NO_SERVER skip("Can't fail to connect to securityd in NO_SERVER mode", 4, false); #endif // Test Restore OS environment SecServerSetMachServiceName("com.apple.security.doesn't-exist"); ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust without securityd running"); is_status(trustResult, kSecTrustResultInvalid, "trustResult is kSecTrustResultInvalid"); is(SecTrustGetCertificateCount(trust), 1, "cert count is 1 without securityd running"); SecKeyRef pubKey = NULL; ok(pubKey = SecTrustCopyPublicKey(trust), "copy public key without securityd running"); CFReleaseNull(pubKey); SecServerSetMachServiceName(NULL); // End of Restore OS environment tests } ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust"); is_status(trustResult, kSecTrustResultUnspecified, "trustResult is kSecTrustResultUnspecified"); is(SecTrustGetCertificateCount(trust), 3, "cert count is 3"); CFDataRef c0_serial = CFDataCreate(NULL, _c0_serial, sizeof(_c0_serial)); CFDataRef serial; ok(serial = SecCertificateCopySerialNumber(cert0), "copy cert0 serial"); ok(CFEqual(c0_serial, serial), "serial matches"); CFArrayRef anchors = CFArrayCreate(NULL, (const void **)&cert1, 1, &kCFTypeArrayCallBacks); ok_status(SecTrustSetAnchorCertificates(trust, anchors), "set anchors"); ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust"); is_status(trustResult, kSecTrustResultUnspecified, "trust is kSecTrustResultUnspecified"); is(SecTrustGetCertificateCount(trust), 2, "cert count is 2"); CFReleaseSafe(anchors); anchors = CFArrayCreate(NULL, NULL, 0, NULL); ok_status(SecTrustSetAnchorCertificates(trust, anchors), "set empty anchors list"); ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust"); is_status(trustResult, kSecTrustResultRecoverableTrustFailure, "trust is kSecTrustResultRecoverableTrustFailure"); ok_status(SecTrustSetAnchorCertificatesOnly(trust, false), "trust passed in anchors and system anchors"); ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust"); is_status(trustResult, kSecTrustResultUnspecified, "trust is kSecTrustResultUnspecified"); ok_status(SecTrustSetAnchorCertificatesOnly(trust, true), "only trust passed in anchors (default)"); ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust"); is_status(trustResult, kSecTrustResultRecoverableTrustFailure, "trust is kSecTrustResultRecoverableTrustFailure"); /* Test cert_1 intermididate from the keychain. */ CFReleaseSafe(trust); ok_status(SecTrustCreateWithCertificates(cert0, policy, &trust), "create trust with single cert0"); ok_status(SecTrustSetVerifyDate(trust, date), "set date"); // Add cert1 CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, kSecClass, kSecClassCertificate, kSecValueRef, cert1, NULL); ok_status(SecItemAdd(query, NULL), "add cert1 to keychain"); ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust"); // Cleanup added cert1. ok_status(SecItemDelete(query), "remove cert1 from keychain"); CFReleaseSafe(query); is_status(trustResult, kSecTrustResultUnspecified, "trust is kSecTrustResultUnspecified"); is(SecTrustGetCertificateCount(trust), 3, "cert count is 3"); /* Set certs to be the xedge2 leaf. */ CFReleaseSafe(certs); const void *cert_xedge2; isnt(cert_xedge2 = SecCertificateCreateWithBytes(NULL, xedge2_certificate, sizeof(xedge2_certificate)), NULL, "create cert_xedge2"); certs = CFArrayCreate(NULL, &cert_xedge2, 1, NULL); CFReleaseSafe(trust); CFReleaseSafe(policy); CFReleaseSafe(date); bool server = true; policy = SecPolicyCreateSSL(server, CFSTR("xedge2.apple.com")); ok_status(SecTrustCreateWithCertificates(certs, policy, &trust), "create trust for ssl server xedge2.apple.com"); /* Jan 1st 2009. */ date = CFDateCreate(NULL, 252288000.0); ok_status(SecTrustSetVerifyDate(trust, date), "set xedge2 trust date to Jan 1st 2009"); ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate xedge2 trust"); is_status(trustResult, kSecTrustResultUnspecified, "trust is kSecTrustResultUnspecified"); CFReleaseSafe(trust); CFReleaseSafe(policy); server = false; policy = SecPolicyCreateSSL(server, CFSTR("xedge2.apple.com")); ok_status(SecTrustCreateWithCertificates(certs, policy, &trust), "create trust for ssl client xedge2.apple.com"); ok_status(SecTrustSetVerifyDate(trust, date), "set xedge2 trust date to Jan 1st 2009"); ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate xedge2 trust"); is_status(trustResult, kSecTrustResultRecoverableTrustFailure, "trust is kSecTrustResultRecoverableTrustFailure"); CFReleaseSafe(trust); CFReleaseSafe(policy); server = true; policy = SecPolicyCreateIPSec(server, CFSTR("xedge2.apple.com")); ok_status(SecTrustCreateWithCertificates(certs, policy, &trust), "create trust for ip server xedge2.apple.com"); ok_status(SecTrustSetVerifyDate(trust, date), "set xedge2 trust date to Jan 1st 2009"); ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate xedge2 trust"); #if 0 /* Although this shouldn't be a valid ipsec cert, since we no longer check for ekus in the ipsec policy it is. */ is_status(trustResult, kSecTrustResultRecoverableTrustFailure, "trust is kSecTrustResultRecoverableTrustFailure"); #else is_status(trustResult, kSecTrustResultUnspecified, "trust is kSecTrustResultUnspecified"); #endif CFReleaseSafe(trust); CFReleaseSafe(policy); server = true; policy = SecPolicyCreateSSL(server, CFSTR("nowhere.com")); ok_status(SecTrustCreateWithCertificates(certs, policy, &trust), "create trust for ssl server nowhere.com"); SecPolicyRef replacementPolicy = SecPolicyCreateSSL(server, CFSTR("xedge2.apple.com")); SecTrustSetPolicies(trust, replacementPolicy); CFReleaseSafe(replacementPolicy); ok_status(SecTrustSetVerifyDate(trust, date), "set xedge2 trust date to Jan 1st 2009"); ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate xedge2 trust"); is_status(trustResult, kSecTrustResultUnspecified, "trust is kSecTrustResultUnspecified"); CFReleaseSafe(trust); CFReleaseSafe(policy); server = true; policy = SecPolicyCreateSSL(server, CFSTR("nowhere.com")); ok_status(SecTrustCreateWithCertificates(certs, policy, &trust), "create trust for ssl server nowhere.com"); SecPolicyRef replacementPolicy2 = SecPolicyCreateSSL(server, CFSTR("xedge2.apple.com")); CFArrayRef replacementPolicies = CFArrayCreate(kCFAllocatorDefault, (CFTypeRef*)&replacementPolicy2, 1, &kCFTypeArrayCallBacks); SecTrustSetPolicies(trust, replacementPolicies); CFReleaseSafe(replacementPolicy2); CFReleaseSafe(replacementPolicies); ok_status(SecTrustSetVerifyDate(trust, date), "set xedge2 trust date to Jan 1st 2009"); ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate xedge2 trust"); is_status(trustResult, kSecTrustResultUnspecified, "trust is kSecTrustResultUnspecified"); /* Test self signed ssl cert with cert itself set as anchor. */ CFReleaseSafe(trust); CFReleaseSafe(policy); CFReleaseSafe(certs); CFReleaseSafe(date); const void *garthc2; server = true; isnt(garthc2 = SecCertificateCreateWithBytes(NULL, garthc2_certificate, sizeof(garthc2_certificate)), NULL, "create garthc2"); certs = CFArrayCreate(NULL, &garthc2, 1, NULL); policy = SecPolicyCreateSSL(server, CFSTR("garthc2.apple.com")); ok_status(SecTrustCreateWithCertificates(certs, policy, &trust), "create trust for ip server garthc2.apple.com"); date = CFDateCreate(NULL, 269568000.0); ok_status(SecTrustSetVerifyDate(trust, date), "set garthc2 trust date to Aug 2009"); ok_status(SecTrustSetAnchorCertificates(trust, certs), "set garthc2 as anchor"); ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate self signed cert with cert as anchor"); is_status(trustResult, kSecTrustResultUnspecified, "trust is kSecTrustResultUnspecified"); CFReleaseSafe(garthc2); CFReleaseSafe(cert_xedge2); CFReleaseSafe(anchors); CFReleaseSafe(trust); CFReleaseSafe(serial); CFReleaseSafe(c0_serial); CFReleaseSafe(policy); CFReleaseSafe(certs); CFReleaseSafe(cert0); CFReleaseSafe(cert1); CFReleaseSafe(date); /* Test prt_forest_fi */ const void *prt_forest_fi; isnt(prt_forest_fi = SecCertificateCreateWithBytes(NULL, prt_forest_fi_certificate, sizeof(prt_forest_fi_certificate)), NULL, "create prt_forest_fi"); isnt(certs = CFArrayCreate(NULL, &prt_forest_fi, 1, NULL), NULL, "failed to create cert array"); policy = SecPolicyCreateSSL(false, CFSTR("owa.prt-forest.fi")); ok_status(SecTrustCreateWithCertificates(certs, policy, &trust), "create trust for ip client owa.prt-forest.fi"); date = CFDateCreate(NULL, 391578321.0); ok_status(SecTrustSetVerifyDate(trust, date), "set owa.prt-forest.fi trust date to May 2013"); SecKeyRef pubkey = SecTrustCopyPublicKey(trust); is(pubkey, NULL, "pubkey returned"); CFReleaseSafe(certs); CFReleaseNull(prt_forest_fi); CFReleaseNull(policy); CFReleaseNull(trust); CFReleaseNull(pubkey); CFReleaseNull(date); }