summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSara Golemon <sara.golemon@mongodb.com>2019-02-06 21:49:47 -0600
committerSara Golemon <sara.golemon@mongodb.com>2019-03-22 17:17:10 +0000
commit0eecc58363a2173d9a2bc91e9e7dc8665e12bfac (patch)
treed2021f0b238a8afc50798f0b4ba0f959764f7a9a
parentc1650e3a6df1196f0c2ebf0824d630ace8db0b4e (diff)
downloadmongo-0eecc58363a2173d9a2bc91e9e7dc8665e12bfac.tar.gz
SERVER-39217 SecureTransport with Intermediate CA
(cherry picked from commit 987e5fc980b2288371ebd2c133b58466cc646d60)
-rw-r--r--jstests/libs/server-intermediate-ca.pem69
-rwxr-xr-xjstests/libs/server-intermediate-ca.pem.sh33
-rw-r--r--jstests/ssl/ssl_intermediate_ca.js37
-rw-r--r--src/mongo/util/net/ssl_manager_apple.cpp273
4 files changed, 328 insertions, 84 deletions
diff --git a/jstests/libs/server-intermediate-ca.pem b/jstests/libs/server-intermediate-ca.pem
new file mode 100644
index 00000000000..49177236cdf
--- /dev/null
+++ b/jstests/libs/server-intermediate-ca.pem
@@ -0,0 +1,69 @@
+-----BEGIN CERTIFICATE-----
+MIIDeTCCAmECFHw+FnGIXPbuzpqG28urvjff3s2tMA0GCSqGSIb3DQEBCwUAMHUx
+CzAJBgNVBAYTAlVTMREwDwYDVQQIDAhOZXcgWW9yazEWMBQGA1UEBwwNTmV3IFlv
+cmsgQ2l0eTEQMA4GA1UECgwHTW9uZ29EQjEPMA0GA1UECwwGS2VybmVsMRgwFgYD
+VQQDDA9JbnRlcm1lZGlhdGUgQ0EwHhcNMTkwMjI3MTY0NjExWhcNMjkwMjI0MTY0
+NjExWjB9MQswCQYDVQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcM
+DU5ldyBZb3JrIENpdHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5l
+bDEgMB4GA1UEAwwXU2VydmVyIFZpYSBJbnRlcm1lZGlhdGUwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQCZ7sGixY2OsOTWzB1Ww08iFToqFxdo7/nqoEX6
+kktPVSKdCCCsx55hWcgR0jwIfuXOQWFvD6b50NTmdxRSGodgcv4hcrGqPbyxxEns
+2+hKUaULjgOox9wS8aiSSoQtGXEGlyd06coatOMIbPIG/7Txq8NuzCnznby86wkw
+ptO21crMa/Q9B0sFzl8DJaGsMcDjoyzN52eJ7xnzDoyDkzLnJZDlK55m1xB2TpPY
+0m+0eg2QUUP9KKkQ0oM4rChBgj3FeUlitiIQo6SS1VtgAgQh8Gecfrk4J9cp+W3Q
+PoMZWM62WqVfEG3j4Fe2I5QS3R/8SeYYXcohI97ie5LAn2PTAgMBAAEwDQYJKoZI
+hvcNAQELBQADggEBAFl7XxkK25GRW1J/pBYb6VJ3YiZeK5xVVSltIBoUs12Vq5se
+BD05opUfQyfB7Y3CwbiSUcFmr+zqrQMPSgT08dRF+1VarRB5q/Pn3uHOPPGgO5uA
+ZNzLjMkEwazKCs5R6+7z6INARW8356PQziYCRyMjBTi2vYghDq6Hji4V7w1n+9l2
+DUCPbAdD35NOv62y6SRBtWwV2zQJ8LSB7zRcQCzxz7e3WZSVv/ztP74huYrPeSpK
+7oLAwItP+5o4dc6ApsvTspXb+m46+GU6DG4hdAJ6lX+9P96sHWTkR72lBIPVMs32
+RlD1A0yqVwxoFUKwyeMtmS0ZvX1zh9xxVj1wX/o=
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAme7BosWNjrDk1swdVsNPIhU6KhcXaO/56qBF+pJLT1UinQgg
+rMeeYVnIEdI8CH7lzkFhbw+m+dDU5ncUUhqHYHL+IXKxqj28scRJ7NvoSlGlC44D
+qMfcEvGokkqELRlxBpcndOnKGrTjCGzyBv+08avDbswp8528vOsJMKbTttXKzGv0
+PQdLBc5fAyWhrDHA46Mszednie8Z8w6Mg5My5yWQ5SueZtcQdk6T2NJvtHoNkFFD
+/SipENKDOKwoQYI9xXlJYrYiEKOkktVbYAIEIfBnnH65OCfXKflt0D6DGVjOtlql
+XxBt4+BXtiOUEt0f/EnmGF3KISPe4nuSwJ9j0wIDAQABAoIBADblWtD9uvoEQ9gG
+ewASLwpsn42bJpIZ4vq1pb8ypQDpz6pI175Ggkkdh6gzXY16E+J2lpTQ9C9rNkHq
+fai6JUVUPSUYjhu0YLLU2bhKxJCchUuVneB3RhjLbd6eDH048YH0LfIX3iegEsdS
+cw3j61e0dcHxtZRX0JNfDqv3EtHE5x76Qm7brfTwVt4O3dKKEodR8WKmIBPhJ/UI
+vZWym79doEaHXgFdvn5qxRhxDS4Fm2l22x4apSV/mVYFONoV7RrUkKYxB02DPImM
+mVtScNdYEI+LWnUJGFVvxpNYLR6IgoiPaGPFtFCH5X746tpW7Nj4eKHpQcIobEGt
+yucbz2ECgYEAzTnvHSRXNeQlX3BntDYxYEjgW6RJGPaaSgI1Ggk6rJeO9XKJdUYQ
+WfWgugL9GHmdda0V0CJQXyciarw4AXaGDb7IoxYi7lBhgAFYP2WNX5a6lYdQOyds
+HKPxIBYjqNqyy4bnq1sBzDKlIdblluBX7H+lh7NIQykuTGveKtpENw8CgYEAwAQf
+rZfaqPM8ppABqfkt1/rhvcpq+M+xN0WewLOQSGzXJdoJSnY263iPUYqVLjsjSr4v
+cP8aUsLy7GR1vbyVf6BTBtVA556rcnWccpkEern+Ip2SoJX5UJl7+FhIrQsxrUzI
+W6Pzurqa4EYLikigX8h31kkF47oz5EiAQ4ZrZv0CgYA5g/YGhcvHN7RdpgP6VoHK
+CUKPjGBMFbix6yJ0tId0HVmcYkgxzLwCajtsRjAmbtb5RtPpK+S4diBIJ43Ooyf4
+rDJQuoB5p59bn4Ta55wSYQzToUOUAH1lHXETXAEMbpZTQfClbnD3iG4NKMvZV/Bs
+QG3ktRMYd28ZTdXKzrb1cwKBgQCVIN7FgMHHI5pANmnEbA1px6SZNWNdOFkHd1+z
+hAIT7cwuzqcWmLdQrAKLLtlr3WwseYb4+HemPVhTtjYnlRZ617aEAQ32lanMLIHE
+EwmCk39HvR+K7s+CBKJen5paIu6DDLYzTiNWK+VrN5tw27UKjvRbjb0wP4Zbzt8n
+EnfJtQKBgCPfec6SZ1ptZ1Tfhim2j61AnqMvGSm7drOLI5cMsLE92fEhttb21A7u
+i1qy9Qkm4HN4DvqNPc8XVkdn3+qn/TAS30V8G/yrpUFJHSLAikKqyadpiTd60dqR
+qrt3S81/HL9Mq0NLuFS9stiBDM2hVWB9dXiX2husS09ZZfXmyvvX
+-----END RSA PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIIDcDCCAlgCFDUYb355zUYCIVzHyv83FTWWlFDOMA0GCSqGSIb3DQEBCwUAMHQx
+FzAVBgNVBAMTDktlcm5lbCBUZXN0IENBMQ8wDQYDVQQLEwZLZXJuZWwxEDAOBgNV
+BAoTB01vbmdvREIxFjAUBgNVBAcTDU5ldyBZb3JrIENpdHkxETAPBgNVBAgTCE5l
+dyBZb3JrMQswCQYDVQQGEwJVUzAeFw0xOTAyMjcxNjQ2MTFaFw0yOTAyMjQxNjQ2
+MTFaMHUxCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhOZXcgWW9yazEWMBQGA1UEBwwN
+TmV3IFlvcmsgQ2l0eTEQMA4GA1UECgwHTW9uZ29EQjEPMA0GA1UECwwGS2VybmVs
+MRgwFgYDVQQDDA9JbnRlcm1lZGlhdGUgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQCojypRgkrYr12fDrPBsVChLHKXaoKVp+vSITmzxvwhu6iORUeF
+nZCUxEDGreZrMF30KLtRNXOGrFlgUhxVdZrqt0YM4BFIJFeoYTuEOPrZVEtF6Qi8
+po+6zms8FBAdtk+zLJ4sRfq1Oqdbh/Fl6k53z/zV6ueRkSVZYArrzNwgUynRGvGN
+7PF+ivb4qG8qCo9iKcwp2Ie4k346XyTxMOkzcV+kGmAgmfO+yehmS5XFu62tH1ek
+V3BGgU2rbQlty40P0f1EVlF0mWyzzZVSIOUnYZruRsYHwXs1hy+l4otfEcBb76Sk
+vLHtPC/nXmf6Vamw86FiJkIRGhwmmeYjHeo9AgMBAAEwDQYJKoZIhvcNAQELBQAD
+ggEBAGO+3qQVjmwtjnoJY3DnWV15ySBj4b6Ir1LlKfngXfpfwlksOZaQsg0mLv3S
+sNfWK1BgQAZZ6iRxIc+T4stpIe3GppDB+a194s7ZuhXP1HpdEZEjr5CkD5cQ5YKv
+OgDry6iGeHnUkaATRHR1iXHCnbAWVkKRNObkcL5Haxa1jLlyiHdMJmqwlfVWVOlx
+NlpEz/Nw6eVXE6vOfYx5lRCVxzP4Ym1RH8+D/c+xoixEgXpif5PpEeEP4IYm1xkr
+nUCpkvESWaAVGnBpeHUs5WuovyvBrvxBSB6sjIvrr45jLMwX0agJ8rx8RzZ9IShA
+WyA3ZWFlGiMWYzxi/2B/z+GhIS8=
+-----END CERTIFICATE-----
diff --git a/jstests/libs/server-intermediate-ca.pem.sh b/jstests/libs/server-intermediate-ca.pem.sh
new file mode 100755
index 00000000000..3860ca899b9
--- /dev/null
+++ b/jstests/libs/server-intermediate-ca.pem.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+# Create an intermediate signing authority and use it to sign a server certificate.
+# Run this from the base directory of the server source.
+set -ev
+
+PREFIX="/C=US/ST=New York/L=New York City/O=MongoDB/OU=Kernel"
+OPENSSL="/opt/mongodbtoolchain/v3/bin/openssl"
+
+cd jstests/libs
+
+# Build intermediate CA.
+$OPENSSL req -new -subj "${PREFIX}/CN=Intermediate CA" \
+ -keyout intermediate-ca.key -out intermediate-ca.csr \
+ -nodes -batch -sha256 -newkey rsa:2048
+$OPENSSL rsa -in intermediate-ca.key -out intermediate-ca.rsa
+$OPENSSL x509 -in intermediate-ca.csr -out intermediate-ca.pem \
+ -req -CA ca.pem -days 3650 -CAcreateserial
+
+# Build leaf cert signed by intermediate CA.
+$OPENSSL req -new -subj "${PREFIX}/CN=Server Via Intermediate" \
+ -keyout server-intermediate-ca.key -out server-intermediate-ca.csr \
+ -nodes -batch -sha256 -newkey rsa:2048
+$OPENSSL rsa -in server-intermediate-ca.key -out server-intermediate-ca.rsa
+$OPENSSL x509 -in server-intermediate-ca.csr -out server-intermediate-ca.pem \
+ -req -CA intermediate-ca.pem -CAkey intermediate-ca.rsa \
+ -days 3650 -CAcreateserial
+
+# Create final bundle and cleanup.
+cat server-intermediate-ca.rsa intermediate-ca.pem >> server-intermediate-ca.pem
+
+rm ca.srl intermediate-ca.srl
+rm server-intermediate-ca.key server-intermediate-ca.rsa server-intermediate-ca.csr
+rm intermediate-ca.pem intermediate-ca.rsa intermediate-ca.key intermediate-ca.csr
diff --git a/jstests/ssl/ssl_intermediate_ca.js b/jstests/ssl/ssl_intermediate_ca.js
new file mode 100644
index 00000000000..838f43bcb30
--- /dev/null
+++ b/jstests/ssl/ssl_intermediate_ca.js
@@ -0,0 +1,37 @@
+// Test that including intermediate certificates
+// in the certificate key file will be sent to the remote.
+
+(function() {
+ 'use strict';
+
+ load('jstests/ssl/libs/ssl_helpers.js');
+
+ if (determineSSLProvider() === 'windows') {
+ // FIXME: SERVER-39574
+ print("Skipping test with windows SChannel pending SERVER-39574");
+ return;
+ }
+
+ // server-intermediate-ca was signed by ca.pem, not trusted-ca.pem
+ const VALID_CA = 'jstests/libs/ca.pem';
+ const INVALID_CA = 'jstests/libs/trusted-ca.pem';
+
+ function runTest(inbound, outbound) {
+ const mongod = MongoRunner.runMongod({
+ sslMode: 'requireSSL',
+ sslAllowConnectionsWithoutCertificates: '',
+ sslPEMKeyFile: 'jstests/libs/server-intermediate-ca.pem',
+ sslCAFile: outbound,
+ sslClusterCAFile: inbound,
+ });
+ assert(mongod);
+ assert.eq(mongod.getDB('admin').system.users.find({}).toArray(), []);
+ MongoRunner.stopMongod(mongod);
+ }
+
+ // Normal mode, we have a valid CA being presented for outbound and inbound.
+ runTest(VALID_CA, VALID_CA);
+
+ // Alternate CA mode, only the inbound CA is valid.
+ runTest(VALID_CA, INVALID_CA);
+})();
diff --git a/src/mongo/util/net/ssl_manager_apple.cpp b/src/mongo/util/net/ssl_manager_apple.cpp
index 952bbfe9d19..d0b2e9125bf 100644
--- a/src/mongo/util/net/ssl_manager_apple.cpp
+++ b/src/mongo/util/net/ssl_manager_apple.cpp
@@ -69,6 +69,11 @@ namespace mongo {
namespace {
+template <typename T>
+constexpr T cf_cast(::CFTypeRef val) {
+ return static_cast<T>(const_cast<void*>(val));
+}
+
// CFAbsoluteTime and X.509 is relative to Jan 1 2001 00:00:00 GMT
// Unix Epoch (and thereby Date_t) is relative to Jan 1, 1970 00:00:00 GMT
static const ::CFAbsoluteTime k20010101_000000_GMT = 978307200;
@@ -490,6 +495,174 @@ StatusWith<std::vector<std::string>> extractSubjectAlternateNames(::CFDictionary
return ret;
}
+bool isCFDataEqual(::CFDataRef a, ::CFDataRef b) {
+ const auto len = ::CFDataGetLength(a);
+ if (::CFDataGetLength(b) != len) {
+ return false;
+ }
+
+ const auto* A = ::CFDataGetBytePtr(a);
+ const auto* B = ::CFDataGetBytePtr(b);
+ return 0 == memcmp(A, B, len);
+}
+
+/**
+ * Attempt to merge a security item bundle into an
+ * identity and optional cert chain.
+ *
+ * The file must have exactly one key which will be paired with
+ * the first available certificate, or exactly one identity.
+ */
+StatusWith<::CFArrayRef> bindIdentity(::CFArrayRef certs) {
+ auto count = ::CFArrayGetCount(certs);
+ if (count == 0) {
+ return certs;
+ }
+
+ // Ideal case, exactly one identity.
+ if (count == 1) {
+ auto idElem = ::CFArrayGetValueAtIndex(certs, 0);
+ if (::CFGetTypeID(idElem) == ::SecIdentityGetTypeID()) {
+ return certs;
+ }
+ }
+
+ // Optimistic case, exactly one cert-key pair.
+ if (count == 2) {
+ auto certElem = ::CFArrayGetValueAtIndex(certs, 0);
+ auto keyElem = ::CFArrayGetValueAtIndex(certs, 1);
+ if (::CFGetTypeID(certElem) == ::SecKeyGetTypeID()) {
+ std::swap(certElem, keyElem);
+ }
+ if ((::CFGetTypeID(certElem) == ::SecCertificateGetTypeID()) &&
+ (::CFGetTypeID(keyElem) == ::SecKeyGetTypeID())) {
+ CFUniquePtr<::SecIdentityRef> cfid(::SecIdentityCreate(
+ nullptr, cf_cast<::SecCertificateRef>(certElem), cf_cast<::SecKeyRef>(keyElem)));
+ if (cfid) {
+ auto id = static_cast<const void*>(cfid.get());
+ return ::CFArrayCreate(nullptr, &id, 1, &kCFTypeArrayCallBacks);
+ }
+ }
+ }
+
+ // Complex case, multiple certs.
+ // Find the key, pair it with the first cert, and bundle the remaining certs in.
+ std::vector<::SecCertificateRef> intermediateCerts;
+ ::SecIdentityRef id = nullptr;
+ ::SecCertificateRef leafCert = nullptr;
+ ::SecKeyRef key = nullptr;
+ for (::CFIndex i = 0; i < count; ++i) {
+ auto elem = ::CFArrayGetValueAtIndex(certs, i);
+ invariant(elem);
+
+ const auto elemType = ::CFGetTypeID(elem);
+ if (elemType == ::SecIdentityGetTypeID()) {
+ if (id) {
+ return {ErrorCodes::InvalidSSLConfiguration,
+ str::stream() << "Multiple identities found in PEM file"};
+ }
+ id = cf_cast<::SecIdentityRef>(elem);
+ continue;
+ }
+
+ if (elemType == ::SecKeyGetTypeID()) {
+ if (key) {
+ return {ErrorCodes::InvalidSSLConfiguration,
+ str::stream() << "Multiple private keys found in PEM file"};
+ }
+ key = cf_cast<::SecKeyRef>(elem);
+ continue;
+ }
+
+ if (elemType != ::SecCertificateGetTypeID()) {
+ // Ignore other types.
+ continue;
+ }
+
+ if (leafCert) {
+ intermediateCerts.push_back(cf_cast<::SecCertificateRef>(elem));
+ } else {
+ leafCert = cf_cast<::SecCertificateRef>(elem);
+ }
+ }
+
+ if (id && key) {
+ return {ErrorCodes::InvalidSSLConfiguration,
+ "Found both identity and private key in PEM file"};
+ }
+ if (key && !leafCert) {
+ return {ErrorCodes::InvalidSSLConfiguration, "Found key without certificate in PEM file"};
+ }
+
+ CFUniquePtr<::CFMutableArrayRef> ret(
+ ::CFArrayCreateMutable(nullptr, count, &kCFTypeArrayCallBacks));
+
+ if (id) {
+ ::CFArrayAppendValue(ret.get(), id);
+ }
+
+ if (key) {
+ CFUniquePtr<::SecIdentityRef> ident(::SecIdentityCreate(nullptr, leafCert, key));
+ if (!ident) {
+ return {ErrorCodes::InvalidSSLConfiguration, "Unable to create Identity from keyfile"};
+ }
+ ::CFArrayAppendValue(ret.get(), ident.get());
+ } else if (leafCert) {
+ ::CFArrayAppendValue(ret.get(), leafCert);
+ }
+
+ for (auto& cert : intermediateCerts) {
+ ::CFArrayAppendValue(ret.get(), cert);
+ }
+
+ return ret.release();
+}
+
+/**
+ * Strip a security item bundle down to just Certificates.
+ * This means ignoring SecKeyRef and splitting SecIdentityRef
+ * into just their SecCertificateRef potions.
+ */
+StatusWith<::CFArrayRef> stripKeys(::CFArrayRef certs) {
+ auto count = ::CFArrayGetCount(certs);
+
+ if (count == 0) {
+ return certs;
+ }
+
+ // Strip unpaired keys and identities.
+ CFUniquePtr<::CFMutableArrayRef> ret(
+ ::CFArrayCreateMutable(nullptr, count, &kCFTypeArrayCallBacks));
+ for (::CFIndex i = 0; i < count; ++i) {
+ auto elem = ::CFArrayGetValueAtIndex(certs, i);
+ if (!elem) {
+ continue;
+ }
+ const auto type = ::CFGetTypeID(elem);
+ if (type == ::SecCertificateGetTypeID()) {
+ // Preserve Certificates.
+ ::CFArrayAppendValue(ret.get(), elem);
+ continue;
+ }
+ if (type != ::SecIdentityGetTypeID()) {
+ continue;
+ }
+
+ // Extract public certificate from Identity.
+ ::SecCertificateRef cert = nullptr;
+ const auto status = ::SecIdentityCopyCertificate(cf_cast<::SecIdentityRef>(elem), &cert);
+ CFUniquePtr<::SecCertificateRef> cfcert(cert);
+ if (status != ::errSecSuccess) {
+ return {ErrorCodes::InternalError,
+ str::stream() << "Unable to extract certificate from identity: "
+ << stringFromOSStatus(status)};
+ }
+ ::CFArrayAppendValue(ret.get(), cfcert.get());
+ }
+
+ return ret.release();
+}
+
enum LoadPEMMode {
kLoadPEMBindIdentities = true,
kLoadPEMStripKeys = false,
@@ -511,7 +684,8 @@ StatusWith<CFUniquePtr<::CFArrayRef>> loadPEM(const std::string& keyfilepath,
const auto retFail = [&keyfilepath, &passphrase](const std::string& msg = "") {
return Status(ErrorCodes::InvalidSSLConfiguration,
str::stream() << "Unable to load PEM from '" << keyfilepath << "'"
- << (passphrase.empty() ? "" : " with passphrase: ")
+ << (passphrase.empty() ? "" : " with passphrase")
+ << (msg.empty() ? "" : ": ")
<< msg);
};
@@ -561,89 +735,22 @@ StatusWith<CFUniquePtr<::CFArrayRef>> loadPEM(const std::string& keyfilepath,
<< stringFromOSStatus(status));
}
- auto count = ::CFArrayGetCount(cfcerts.get());
- if ((count > 0) && (mode == kLoadPEMBindIdentities)) {
- // Turn Certificate/Key pairs into identities.
- CFUniquePtr<::CFMutableArrayRef> bind(
- ::CFArrayCreateMutable(nullptr, count, &kCFTypeArrayCallBacks));
- for (::CFIndex i = 0; i < count; ++i) {
- auto elem = ::CFArrayGetValueAtIndex(cfcerts.get(), i);
- invariant(elem);
- const auto type = ::CFGetTypeID(elem);
- if (type == ::SecIdentityGetTypeID()) {
- // Our import had a proper identity in it, ready to go.
- ::CFArrayAppendValue(bind.get(), elem);
- continue;
- }
- if (type != ::SecCertificateGetTypeID()) {
- continue;
- }
-
- // Attempt to match the certificate to a private key in the aggregate we just imported.
- CFUniquePtr<::SecIdentityRef> cfid;
- for (::CFIndex j = 0; j < count; ++j) {
- auto key = ::CFArrayGetValueAtIndex(cfcerts.get(), j);
- invariant(key);
- if (::CFGetTypeID(key) != ::SecKeyGetTypeID()) {
- continue;
- }
- auto id =
- ::SecIdentityCreate(nullptr,
- static_cast<::SecCertificateRef>(const_cast<void*>(elem)),
- static_cast<::SecKeyRef>(const_cast<void*>(key)));
- if (id) {
- cfid.reset(id);
- break;
- }
- }
- if (cfid) {
- ::CFArrayAppendValue(bind.get(), cfid.get());
- } else {
- ::CFArrayAppendValue(bind.get(), elem);
- }
+ if (mode == kLoadPEMBindIdentities) {
+ auto swCerts = bindIdentity(cfcerts.get());
+ if (!swCerts.isOK()) {
+ return swCerts.getStatus();
}
- // Reencapsulate to allow the inner type to change.
- cfcerts.reset(bind.release());
- count = ::CFArrayGetCount(cfcerts.get());
- }
-
- if ((count > 0) && (mode == kLoadPEMStripKeys)) {
- // Strip unpaired keys and identities.
- CFUniquePtr<::CFMutableArrayRef> strip(
- ::CFArrayCreateMutable(nullptr, count, &kCFTypeArrayCallBacks));
- for (::CFIndex i = 0; i < count; ++i) {
- auto elem = ::CFArrayGetValueAtIndex(cfcerts.get(), i);
- if (!elem) {
- continue;
- }
- const auto type = ::CFGetTypeID(elem);
- if (type == ::SecCertificateGetTypeID()) {
- // Preserve Certificates.
- ::CFArrayAppendValue(strip.get(), elem);
- continue;
- }
- if (type != ::SecIdentityGetTypeID()) {
- continue;
- }
-
- // Extract public certificate from Identity.
- ::SecCertificateRef cert = nullptr;
- const auto status = ::SecIdentityCopyCertificate(
- static_cast<::SecIdentityRef>(const_cast<void*>(elem)), &cert);
- CFUniquePtr<::SecCertificateRef> cfcert(cert);
- if (status != ::errSecSuccess) {
- return {ErrorCodes::InternalError,
- str::stream() << "Unable to extract certificate from identity: "
- << stringFromOSStatus(status)};
- }
- ::CFArrayAppendValue(strip.get(), cfcert.get());
+ cfcerts.reset(swCerts.getValue());
+ } else {
+ invariant(mode == kLoadPEMStripKeys);
+ auto swCerts = stripKeys(cfcerts.get());
+ if (!swCerts.isOK()) {
+ return swCerts.getStatus();
}
- // Reencapsulate to allow the inner type to change.
- cfcerts.reset(strip.release());
- count = ::CFArrayGetCount(cfcerts.get());
+ cfcerts.reset(swCerts.getValue());
}
- if (count <= 0) {
+ if (::CFArrayGetCount(cfcerts.get()) <= 0) {
return {ErrorCodes::InvalidSSLConfiguration,
str::stream() << "PEM file '" << keyfilepath << "' has no certificates"};
}
@@ -710,8 +817,7 @@ StatusWith<SSLX509Name> certificateGetSubject(::CFArrayRef certs, Date_t* expire
}
::SecCertificateRef idcert = nullptr;
- auto status = ::SecIdentityCopyCertificate(
- static_cast<::SecIdentityRef>(const_cast<void*>(root)), &idcert);
+ auto status = ::SecIdentityCopyCertificate(cf_cast<::SecIdentityRef>(root), &idcert);
if (status != ::errSecSuccess) {
return {ErrorCodes::InvalidSSLConfiguration,
str::stream() << "Unable to get certificate from identity: "
@@ -791,8 +897,7 @@ StatusWith<CFUniquePtr<::CFArrayRef>> copyMatchingCertificate(
CFUniquePtr<::CFMutableArrayRef> cfresult(
::CFArrayCreateMutable(nullptr, 1, &::kCFTypeArrayCallBacks));
for (::CFIndex i = 0; i < ::CFArrayGetCount(cfident.get()); ++i) {
- auto ident = static_cast<::SecIdentityRef>(
- const_cast<void*>(::CFArrayGetValueAtIndex(cfident.get(), i)));
+ auto ident = cf_cast<::SecIdentityRef>(::CFArrayGetValueAtIndex(cfident.get(), i));
if (::CFGetTypeID(ident) != ::SecIdentityGetTypeID()) {
continue;
}