diff options
author | 2021-09-17 18:08:38 -0700 | |
---|---|---|
committer | 2021-09-20 15:45:28 -0700 | |
commit | ffdaf952255550c221330a4af053911d6a78dcc2 (patch) | |
tree | b18fe78027dcacc08f9ce09367ef30cd9eed3a36 | |
parent | b160f8c4df0b2ba8dcb33864e0b3cb127bf852fb (diff) |
binder: abstract out key/cert config
This change allows certificates and keys to be configured in
a custom way.
Bug: 199344157
Fixes: 200195645
Test: pass
Change-Id: I7b88f21652142fd78e99bc5352f1e78000ca050f
-rw-r--r-- | libs/binder/RpcTransportTls.cpp | 74 | ||||
-rw-r--r-- | libs/binder/include_tls/binder/RpcAuth.h | 46 | ||||
-rw-r--r-- | libs/binder/include_tls/binder/RpcTransportTls.h | 10 | ||||
-rw-r--r-- | libs/binder/tests/Android.bp | 1 | ||||
-rw-r--r-- | libs/binder/tests/RpcAuthTesting.cpp | 73 | ||||
-rw-r--r-- | libs/binder/tests/RpcAuthTesting.h | 38 | ||||
-rw-r--r-- | libs/binder/tests/binderRpcTest.cpp | 13 |
7 files changed, 191 insertions, 64 deletions
diff --git a/libs/binder/RpcTransportTls.cpp b/libs/binder/RpcTransportTls.cpp index 8c066ee6b2..f8cd71d434 100644 --- a/libs/binder/RpcTransportTls.cpp +++ b/libs/binder/RpcTransportTls.cpp @@ -44,8 +44,6 @@ using android::base::Result; namespace android { namespace { -constexpr const int kCertValidDays = 30; - // Implement BIO for socket that ignores SIGPIPE. int socketNew(BIO* bio) { BIO_set_data(bio, reinterpret_cast<void*>(-1)); @@ -100,49 +98,6 @@ bssl::UniquePtr<BIO> newSocketBio(android::base::borrowed_fd fd) { return ret; } -bssl::UniquePtr<EVP_PKEY> makeKeyPairForSelfSignedCert() { - bssl::UniquePtr<EC_KEY> ec_key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); - if (ec_key == nullptr || !EC_KEY_generate_key(ec_key.get())) { - ALOGE("Failed to generate key pair."); - return nullptr; - } - bssl::UniquePtr<EVP_PKEY> evp_pkey(EVP_PKEY_new()); - // Use set1 instead of assign to avoid leaking ec_key when assign fails. set1 increments - // the refcount of the ec_key, so it is okay to release it at the end of this function. - if (evp_pkey == nullptr || !EVP_PKEY_set1_EC_KEY(evp_pkey.get(), ec_key.get())) { - ALOGE("Failed to assign key pair."); - return nullptr; - } - return evp_pkey; -} - -bssl::UniquePtr<X509> makeSelfSignedCert(EVP_PKEY* evp_pkey, const int valid_days) { - bssl::UniquePtr<X509> x509(X509_new()); - bssl::UniquePtr<BIGNUM> serial(BN_new()); - bssl::UniquePtr<BIGNUM> serialLimit(BN_new()); - TEST_AND_RETURN(nullptr, BN_lshift(serialLimit.get(), BN_value_one(), 128)); - TEST_AND_RETURN(nullptr, BN_rand_range(serial.get(), serialLimit.get())); - TEST_AND_RETURN(nullptr, BN_to_ASN1_INTEGER(serial.get(), X509_get_serialNumber(x509.get()))); - TEST_AND_RETURN(nullptr, X509_gmtime_adj(X509_getm_notBefore(x509.get()), 0)); - TEST_AND_RETURN(nullptr, - X509_gmtime_adj(X509_getm_notAfter(x509.get()), 60 * 60 * 24 * valid_days)); - - X509_NAME* subject = X509_get_subject_name(x509.get()); - TEST_AND_RETURN(nullptr, - X509_NAME_add_entry_by_txt(subject, "O", MBSTRING_ASC, - reinterpret_cast<const uint8_t*>("Android"), -1, -1, - 0)); - TEST_AND_RETURN(nullptr, - X509_NAME_add_entry_by_txt(subject, "CN", MBSTRING_ASC, - reinterpret_cast<const uint8_t*>("BinderRPC"), -1, - -1, 0)); - TEST_AND_RETURN(nullptr, X509_set_issuer_name(x509.get(), subject)); - - TEST_AND_RETURN(nullptr, X509_set_pubkey(x509.get(), evp_pkey)); - TEST_AND_RETURN(nullptr, X509_sign(x509.get(), evp_pkey, EVP_sha256())); - return x509; -} - [[maybe_unused]] void sslDebugLog(const SSL* ssl, int type, int value) { switch (type) { case SSL_CB_HANDSHAKE_START: @@ -437,7 +392,7 @@ public: template <typename Impl, typename = std::enable_if_t<std::is_base_of_v<RpcTransportCtxTls, Impl>>> static std::unique_ptr<RpcTransportCtxTls> create( - std::shared_ptr<RpcCertificateVerifier> verifier); + std::shared_ptr<RpcCertificateVerifier> verifier, RpcAuth* auth); std::unique_ptr<RpcTransport> newTransport(android::base::unique_fd fd, FdTrigger* fdTrigger) const override; std::vector<uint8_t> getCertificate(RpcCertificateFormat) const override; @@ -479,16 +434,15 @@ ssl_verify_result_t RpcTransportCtxTls::sslCustomVerify(SSL* ssl, uint8_t* outAl // provided as a template argument so that this function can initialize an |Impl| object. template <typename Impl, typename> std::unique_ptr<RpcTransportCtxTls> RpcTransportCtxTls::create( - std::shared_ptr<RpcCertificateVerifier> verifier) { + std::shared_ptr<RpcCertificateVerifier> verifier, RpcAuth* auth) { bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method())); TEST_AND_RETURN(nullptr, ctx != nullptr); - auto evp_pkey = makeKeyPairForSelfSignedCert(); - TEST_AND_RETURN(nullptr, evp_pkey != nullptr); - auto cert = makeSelfSignedCert(evp_pkey.get(), kCertValidDays); - TEST_AND_RETURN(nullptr, cert != nullptr); - TEST_AND_RETURN(nullptr, SSL_CTX_use_PrivateKey(ctx.get(), evp_pkey.get())); - TEST_AND_RETURN(nullptr, SSL_CTX_use_certificate(ctx.get(), cert.get())); + if (status_t authStatus = auth->configure(ctx.get()); authStatus != OK) { + ALOGE("%s: Failed to configure auth info: %s", __PRETTY_FUNCTION__, + statusToString(authStatus).c_str()); + return nullptr; + }; // Enable two-way authentication by setting SSL_VERIFY_FAIL_IF_NO_PEER_CERT on server. // Client ignores SSL_VERIFY_FAIL_IF_NO_PEER_CERT flag. @@ -538,11 +492,13 @@ protected: } // namespace std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTls::newServerCtx() const { - return android::RpcTransportCtxTls::create<RpcTransportCtxTlsServer>(mCertVerifier); + return android::RpcTransportCtxTls::create<RpcTransportCtxTlsServer>(mCertVerifier, + mAuth.get()); } std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTls::newClientCtx() const { - return android::RpcTransportCtxTls::create<RpcTransportCtxTlsClient>(mCertVerifier); + return android::RpcTransportCtxTls::create<RpcTransportCtxTlsClient>(mCertVerifier, + mAuth.get()); } const char* RpcTransportCtxFactoryTls::toCString() const { @@ -550,13 +506,17 @@ const char* RpcTransportCtxFactoryTls::toCString() const { } std::unique_ptr<RpcTransportCtxFactory> RpcTransportCtxFactoryTls::make( - std::shared_ptr<RpcCertificateVerifier> verifier) { + std::shared_ptr<RpcCertificateVerifier> verifier, std::unique_ptr<RpcAuth> auth) { if (verifier == nullptr) { ALOGE("%s: Must provide a certificate verifier", __PRETTY_FUNCTION__); return nullptr; } + if (auth == nullptr) { + ALOGE("%s: Must provide an auth provider", __PRETTY_FUNCTION__); + return nullptr; + } return std::unique_ptr<RpcTransportCtxFactoryTls>( - new RpcTransportCtxFactoryTls(std::move(verifier))); + new RpcTransportCtxFactoryTls(std::move(verifier), std::move(auth))); } } // namespace android diff --git a/libs/binder/include_tls/binder/RpcAuth.h b/libs/binder/include_tls/binder/RpcAuth.h new file mode 100644 index 0000000000..4c2f296135 --- /dev/null +++ b/libs/binder/include_tls/binder/RpcAuth.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <openssl/ssl.h> +#include <utils/Errors.h> + +namespace android { + +// An interface with a function that configures the SSL_CTX object with authentication information, +// including certificates and private keys. +class RpcAuth { +public: + virtual ~RpcAuth() = default; + + // The keys and certificates to provide is up to the implementation. Multiple calls to + // |configure()| may configure |ctx| with the same keys / certificates, or generate a + // different key / certificate every time |configure()| is called. + // + // It is guaranteed that, when a context object (RpcTransportCtx) is created, + // libbinder_tls calls |configure()| on server RpcAuth exactly once. + // + // The implementation may use the following function to set the private + // keys and certificates: + // - SSL_CTX_use_PrivateKey + // - SSL_CTX_use_certificate + // - SSL_CTX_set*_chain + // - SSL_CTX_add0_chain_cert + virtual status_t configure(SSL_CTX* ctx) = 0; +}; + +} // namespace android diff --git a/libs/binder/include_tls/binder/RpcTransportTls.h b/libs/binder/include_tls/binder/RpcTransportTls.h index f26a3e95f5..8a11125197 100644 --- a/libs/binder/include_tls/binder/RpcTransportTls.h +++ b/libs/binder/include_tls/binder/RpcTransportTls.h @@ -18,6 +18,7 @@ #pragma once +#include <binder/RpcAuth.h> #include <binder/RpcCertificateVerifier.h> #include <binder/RpcTransport.h> @@ -26,17 +27,20 @@ namespace android { // RpcTransportCtxFactory with TLS enabled with self-signed certificate. class RpcTransportCtxFactoryTls : public RpcTransportCtxFactory { public: - static std::unique_ptr<RpcTransportCtxFactory> make(std::shared_ptr<RpcCertificateVerifier>); + static std::unique_ptr<RpcTransportCtxFactory> make(std::shared_ptr<RpcCertificateVerifier>, + std::unique_ptr<RpcAuth>); std::unique_ptr<RpcTransportCtx> newServerCtx() const override; std::unique_ptr<RpcTransportCtx> newClientCtx() const override; const char* toCString() const override; private: - RpcTransportCtxFactoryTls(std::shared_ptr<RpcCertificateVerifier> verifier) - : mCertVerifier(std::move(verifier)){}; + RpcTransportCtxFactoryTls(std::shared_ptr<RpcCertificateVerifier> verifier, + std::unique_ptr<RpcAuth> auth) + : mCertVerifier(std::move(verifier)), mAuth(std::move(auth)){}; std::shared_ptr<RpcCertificateVerifier> mCertVerifier; + std::unique_ptr<RpcAuth> mAuth; }; } // namespace android diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index 1968058aed..6f3c6e2d0a 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -153,6 +153,7 @@ cc_test { srcs: [ "binderRpcTest.cpp", + "RpcAuthTesting.cpp", "RpcCertificateVerifierSimple.cpp", ], shared_libs: [ diff --git a/libs/binder/tests/RpcAuthTesting.cpp b/libs/binder/tests/RpcAuthTesting.cpp new file mode 100644 index 0000000000..76f7bce863 --- /dev/null +++ b/libs/binder/tests/RpcAuthTesting.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "RpcAuthTesting.h" +#include "../Utils.h" // for TEST_AND_RETURN + +namespace android { + +bssl::UniquePtr<EVP_PKEY> makeKeyPairForSelfSignedCert() { + bssl::UniquePtr<EC_KEY> ec_key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); + if (ec_key == nullptr || !EC_KEY_generate_key(ec_key.get())) { + ALOGE("Failed to generate key pair."); + return nullptr; + } + bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new()); + // Use set1 instead of assign to avoid leaking ec_key when assign fails. set1 increments + // the refcount of the ec_key, so it is okay to release it at the end of this function. + if (pkey == nullptr || !EVP_PKEY_set1_EC_KEY(pkey.get(), ec_key.get())) { + ALOGE("Failed to assign key pair."); + return nullptr; + } + return pkey; +} + +bssl::UniquePtr<X509> makeSelfSignedCert(EVP_PKEY* pkey, const uint32_t validSeconds) { + bssl::UniquePtr<X509> x509(X509_new()); + bssl::UniquePtr<BIGNUM> serial(BN_new()); + bssl::UniquePtr<BIGNUM> serialLimit(BN_new()); + TEST_AND_RETURN(nullptr, BN_lshift(serialLimit.get(), BN_value_one(), 128)); + TEST_AND_RETURN(nullptr, BN_rand_range(serial.get(), serialLimit.get())); + TEST_AND_RETURN(nullptr, BN_to_ASN1_INTEGER(serial.get(), X509_get_serialNumber(x509.get()))); + TEST_AND_RETURN(nullptr, X509_gmtime_adj(X509_getm_notBefore(x509.get()), 0)); + TEST_AND_RETURN(nullptr, X509_gmtime_adj(X509_getm_notAfter(x509.get()), validSeconds)); + + X509_NAME* subject = X509_get_subject_name(x509.get()); + TEST_AND_RETURN(nullptr, + X509_NAME_add_entry_by_txt(subject, "O", MBSTRING_ASC, + reinterpret_cast<const uint8_t*>("Android"), -1, -1, + 0)); + TEST_AND_RETURN(nullptr, + X509_NAME_add_entry_by_txt(subject, "CN", MBSTRING_ASC, + reinterpret_cast<const uint8_t*>("BinderRPC"), -1, + -1, 0)); + TEST_AND_RETURN(nullptr, X509_set_issuer_name(x509.get(), subject)); + + TEST_AND_RETURN(nullptr, X509_set_pubkey(x509.get(), pkey)); + TEST_AND_RETURN(nullptr, X509_sign(x509.get(), pkey, EVP_sha256())); + return x509; +} + +status_t RpcAuthSelfSigned::configure(SSL_CTX* ctx) { + auto pkey = makeKeyPairForSelfSignedCert(); + TEST_AND_RETURN(UNKNOWN_ERROR, pkey != nullptr); + auto cert = makeSelfSignedCert(pkey.get(), mValidSeconds); + TEST_AND_RETURN(UNKNOWN_ERROR, cert != nullptr); + TEST_AND_RETURN(INVALID_OPERATION, SSL_CTX_use_PrivateKey(ctx, pkey.get())); + TEST_AND_RETURN(INVALID_OPERATION, SSL_CTX_use_certificate(ctx, cert.get())); + return OK; +} + +} // namespace android diff --git a/libs/binder/tests/RpcAuthTesting.h b/libs/binder/tests/RpcAuthTesting.h new file mode 100644 index 0000000000..fdc731d01e --- /dev/null +++ b/libs/binder/tests/RpcAuthTesting.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <binder/RpcAuth.h> + +namespace android { + +constexpr const uint32_t kCertValidSeconds = 30 * (60 * 60 * 24); // 30 days +bssl::UniquePtr<EVP_PKEY> makeKeyPairForSelfSignedCert(); +bssl::UniquePtr<X509> makeSelfSignedCert(EVP_PKEY* pKey, uint32_t validSeconds); + +// An implementation of RpcAuth that generates a key pair and a self-signed +// certificate every time configure() is called. +class RpcAuthSelfSigned : public RpcAuth { +public: + RpcAuthSelfSigned(uint32_t validSeconds = kCertValidSeconds) : mValidSeconds(validSeconds) {} + status_t configure(SSL_CTX* ctx) override; + +private: + const uint32_t mValidSeconds; +}; + +} // namespace android diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index cc1d2fae56..05c50309c6 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -48,8 +48,9 @@ #include "../FdTrigger.h" #include "../RpcSocketAddress.h" // for testing preconnected clients -#include "../RpcState.h" // for debugging -#include "../vm_sockets.h" // for VMADDR_* +#include "../RpcState.h" // for debugging +#include "../vm_sockets.h" // for VMADDR_* +#include "RpcAuthTesting.h" #include "RpcCertificateVerifierSimple.h" using namespace std::chrono_literals; @@ -71,7 +72,8 @@ static inline std::vector<RpcSecurity> RpcSecurityValues() { } static inline std::unique_ptr<RpcTransportCtxFactory> newFactory( - RpcSecurity rpcSecurity, std::shared_ptr<RpcCertificateVerifier> verifier = nullptr) { + RpcSecurity rpcSecurity, std::shared_ptr<RpcCertificateVerifier> verifier = nullptr, + std::unique_ptr<RpcAuth> auth = nullptr) { switch (rpcSecurity) { case RpcSecurity::RAW: return RpcTransportCtxFactoryRaw::make(); @@ -79,7 +81,10 @@ static inline std::unique_ptr<RpcTransportCtxFactory> newFactory( if (verifier == nullptr) { verifier = std::make_shared<RpcCertificateVerifierSimple>(); } - return RpcTransportCtxFactoryTls::make(std::move(verifier)); + if (auth == nullptr) { + auth = std::make_unique<RpcAuthSelfSigned>(); + } + return RpcTransportCtxFactoryTls::make(std::move(verifier), std::move(auth)); } default: LOG_ALWAYS_FATAL("Unknown RpcSecurity %d", rpcSecurity); |