summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Yifan Hong <elsk@google.com> 2021-09-14 00:41:10 +0000
committer Gerrit Code Review <noreply-gerritcodereview@google.com> 2021-09-14 00:41:10 +0000
commita3612f324c0d4c296930123ba07e915bbebb6dc2 (patch)
tree612ba7de6bbe155a5c0cfa57c2b54103466cac54
parente9b2010fb1a8dcd0f23cac1731f510b0bfa4301f (diff)
parent9734cfc736b89134987b98e35210e304ca618b75 (diff)
Merge changes Ifaea4598,I78b4d2b1,I6c1f0f88,I6b4d0ebc,I5c17f464
* changes: binder: CertificateFormat -> RpcCertificateFormat. binder: Support DER format certificates. binder: implement simple TLS verification for testing binder: X509 are serialized to vector<uint8_t> binder: delegate cert verification to RpcCertificateVerifier
-rw-r--r--libs/binder/Android.bp1
-rw-r--r--libs/binder/RpcCertificateUtils.cpp78
-rw-r--r--libs/binder/RpcServer.cpp2
-rw-r--r--libs/binder/RpcSession.cpp2
-rw-r--r--libs/binder/RpcTransportRaw.cpp2
-rw-r--r--libs/binder/RpcTransportTls.cpp57
-rw-r--r--libs/binder/include/binder/RpcCertificateFormat.h41
-rw-r--r--libs/binder/include/binder/RpcServer.h2
-rw-r--r--libs/binder/include/binder/RpcSession.h4
-rw-r--r--libs/binder/include/binder/RpcTransport.h5
-rw-r--r--libs/binder/include_tls/binder/RpcCertificateUtils.h34
-rw-r--r--libs/binder/tests/Android.bp3
-rw-r--r--libs/binder/tests/BinderRpcTestClientInfo.aidl (renamed from libs/binder/include/binder/CertificateFormat.h)15
-rw-r--r--libs/binder/tests/BinderRpcTestServerInfo.aidl22
-rw-r--r--libs/binder/tests/ParcelableCertificateData.aidl19
-rw-r--r--libs/binder/tests/RpcCertificateVerifierSimple.cpp24
-rw-r--r--libs/binder/tests/RpcCertificateVerifierSimple.h24
-rw-r--r--libs/binder/tests/binderRpcTest.cpp436
18 files changed, 713 insertions, 58 deletions
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index b0d7478b96..9bca1f3482 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -262,6 +262,7 @@ cc_defaults {
],
srcs: [
"RpcTransportTls.cpp",
+ "RpcCertificateUtils.cpp",
],
}
diff --git a/libs/binder/RpcCertificateUtils.cpp b/libs/binder/RpcCertificateUtils.cpp
new file mode 100644
index 0000000000..d91736cca2
--- /dev/null
+++ b/libs/binder/RpcCertificateUtils.cpp
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "RpcCertificateUtils"
+#include <log/log.h>
+
+#include <binder/RpcCertificateUtils.h>
+
+#include "Utils.h"
+
+namespace android {
+
+namespace {
+
+bssl::UniquePtr<X509> fromPem(const std::vector<uint8_t>& cert) {
+ if (cert.size() > std::numeric_limits<int>::max()) return nullptr;
+ bssl::UniquePtr<BIO> certBio(BIO_new_mem_buf(cert.data(), static_cast<int>(cert.size())));
+ return bssl::UniquePtr<X509>(PEM_read_bio_X509(certBio.get(), nullptr, nullptr, nullptr));
+}
+
+bssl::UniquePtr<X509> fromDer(const std::vector<uint8_t>& cert) {
+ if (cert.size() > std::numeric_limits<long>::max()) return nullptr;
+ const unsigned char* data = cert.data();
+ auto expectedEnd = data + cert.size();
+ bssl::UniquePtr<X509> ret(d2i_X509(nullptr, &data, static_cast<long>(cert.size())));
+ if (data != expectedEnd) {
+ ALOGE("%s: %td bytes remaining!", __PRETTY_FUNCTION__, expectedEnd - data);
+ return nullptr;
+ }
+ return ret;
+}
+
+} // namespace
+
+bssl::UniquePtr<X509> deserializeCertificate(const std::vector<uint8_t>& cert,
+ RpcCertificateFormat format) {
+ switch (format) {
+ case RpcCertificateFormat::PEM:
+ return fromPem(cert);
+ case RpcCertificateFormat::DER:
+ return fromDer(cert);
+ }
+ LOG_ALWAYS_FATAL("Unsupported format %d", static_cast<int>(format));
+}
+
+std::vector<uint8_t> serializeCertificate(X509* x509, RpcCertificateFormat format) {
+ bssl::UniquePtr<BIO> certBio(BIO_new(BIO_s_mem()));
+ switch (format) {
+ case RpcCertificateFormat::PEM: {
+ TEST_AND_RETURN({}, PEM_write_bio_X509(certBio.get(), x509));
+ } break;
+ case RpcCertificateFormat::DER: {
+ TEST_AND_RETURN({}, i2d_X509_bio(certBio.get(), x509));
+ } break;
+ default: {
+ LOG_ALWAYS_FATAL("Unsupported format %d", static_cast<int>(format));
+ }
+ }
+ const uint8_t* data;
+ size_t len;
+ TEST_AND_RETURN({}, BIO_mem_contents(certBio.get(), &data, &len));
+ return std::vector<uint8_t>(data, data + len);
+}
+
+} // namespace android
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index 7fa2f5764f..5733993b3b 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -141,7 +141,7 @@ sp<IBinder> RpcServer::getRootObject() {
return ret;
}
-std::string RpcServer::getCertificate(CertificateFormat format) {
+std::vector<uint8_t> RpcServer::getCertificate(RpcCertificateFormat format) {
std::lock_guard<std::mutex> _l(mLock);
return mCtx->getCertificate(format);
}
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index c5a8dd1ddf..9395b505e1 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -703,7 +703,7 @@ bool RpcSession::removeIncomingConnection(const sp<RpcConnection>& connection) {
return false;
}
-std::string RpcSession::getCertificate(CertificateFormat format) {
+std::vector<uint8_t> RpcSession::getCertificate(RpcCertificateFormat format) {
return mCtx->getCertificate(format);
}
diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp
index 62c953007a..c012df84f7 100644
--- a/libs/binder/RpcTransportRaw.cpp
+++ b/libs/binder/RpcTransportRaw.cpp
@@ -111,7 +111,7 @@ public:
std::unique_ptr<RpcTransport> newTransport(android::base::unique_fd fd, FdTrigger*) const {
return std::make_unique<RpcTransportRaw>(std::move(fd));
}
- std::string getCertificate(CertificateFormat) const override { return {}; }
+ std::vector<uint8_t> getCertificate(RpcCertificateFormat) const override { return {}; }
};
} // namespace
diff --git a/libs/binder/RpcTransportTls.cpp b/libs/binder/RpcTransportTls.cpp
index e9a494f9af..d40cfc84fc 100644
--- a/libs/binder/RpcTransportTls.cpp
+++ b/libs/binder/RpcTransportTls.cpp
@@ -22,6 +22,7 @@
#include <openssl/bn.h>
#include <openssl/ssl.h>
+#include <binder/RpcCertificateUtils.h>
#include <binder/RpcTransportTls.h>
#include "FdTrigger.h"
@@ -446,25 +447,54 @@ class RpcTransportCtxTls : public RpcTransportCtx {
public:
template <typename Impl,
typename = std::enable_if_t<std::is_base_of_v<RpcTransportCtxTls, Impl>>>
- static std::unique_ptr<RpcTransportCtxTls> create();
+ static std::unique_ptr<RpcTransportCtxTls> create(
+ std::shared_ptr<RpcCertificateVerifier> verifier);
std::unique_ptr<RpcTransport> newTransport(android::base::unique_fd fd,
FdTrigger* fdTrigger) const override;
- std::string getCertificate(CertificateFormat) const override;
+ std::vector<uint8_t> getCertificate(RpcCertificateFormat) const override;
protected:
+ static ssl_verify_result_t sslCustomVerify(SSL* ssl, uint8_t* outAlert);
virtual void preHandshake(Ssl* ssl) const = 0;
bssl::UniquePtr<SSL_CTX> mCtx;
+ std::shared_ptr<RpcCertificateVerifier> mCertVerifier;
};
-std::string RpcTransportCtxTls::getCertificate(CertificateFormat) const {
- // TODO(b/195166979): return certificate here
- return {};
+std::vector<uint8_t> RpcTransportCtxTls::getCertificate(RpcCertificateFormat format) const {
+ X509* x509 = SSL_CTX_get0_certificate(mCtx.get()); // does not own
+ return serializeCertificate(x509, format);
+}
+
+// Verify by comparing the leaf of peer certificate with every certificate in
+// mTrustedPeerCertificates. Does not support certificate chains.
+ssl_verify_result_t RpcTransportCtxTls::sslCustomVerify(SSL* ssl, uint8_t* outAlert) {
+ LOG_ALWAYS_FATAL_IF(outAlert == nullptr);
+ const char* logPrefix = SSL_is_server(ssl) ? "Server" : "Client";
+
+ bssl::UniquePtr<X509> peerCert(SSL_get_peer_certificate(ssl)); // Does not set error queue
+ LOG_ALWAYS_FATAL_IF(peerCert == nullptr,
+ "%s: libssl should not ask to verify non-existing cert", logPrefix);
+
+ auto ctx = SSL_get_SSL_CTX(ssl); // Does not set error queue
+ LOG_ALWAYS_FATAL_IF(ctx == nullptr);
+ // void* -> RpcTransportCtxTls*
+ auto rpcTransportCtxTls = reinterpret_cast<RpcTransportCtxTls*>(SSL_CTX_get_app_data(ctx));
+ LOG_ALWAYS_FATAL_IF(rpcTransportCtxTls == nullptr);
+
+ status_t verifyStatus = rpcTransportCtxTls->mCertVerifier->verify(peerCert.get(), outAlert);
+ if (verifyStatus == OK) {
+ return ssl_verify_ok;
+ }
+ LOG_TLS_DETAIL("%s: Failed to verify client: status = %s, alert = %s", logPrefix,
+ statusToString(verifyStatus).c_str(), SSL_alert_desc_string_long(*outAlert));
+ return ssl_verify_invalid;
}
// Common implementation for creating server and client contexts. The child class, |Impl|, is
// 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::unique_ptr<RpcTransportCtxTls> RpcTransportCtxTls::create(
+ std::shared_ptr<RpcCertificateVerifier> verifier) {
bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
TEST_AND_RETURN(nullptr, ctx != nullptr);
@@ -475,10 +505,10 @@ std::unique_ptr<RpcTransportCtxTls> RpcTransportCtxTls::create() {
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()));
- // TODO(b/195166979): peer should send certificate in a different channel, and this class
- // should verify it here.
- SSL_CTX_set_custom_verify(ctx.get(), SSL_VERIFY_PEER,
- [](SSL*, uint8_t*) -> ssl_verify_result_t { return ssl_verify_ok; });
+ // 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.
+ SSL_CTX_set_custom_verify(ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+ sslCustomVerify);
// Require at least TLS 1.3
TEST_AND_RETURN(nullptr, SSL_CTX_set_min_proto_version(ctx.get(), TLS1_3_VERSION));
@@ -488,7 +518,10 @@ std::unique_ptr<RpcTransportCtxTls> RpcTransportCtxTls::create() {
}
auto ret = std::make_unique<Impl>();
+ // RpcTransportCtxTls* -> void*
+ TEST_AND_RETURN(nullptr, SSL_CTX_set_app_data(ctx.get(), reinterpret_cast<void*>(ret.get())));
ret->mCtx = std::move(ctx);
+ ret->mCertVerifier = std::move(verifier);
return ret;
}
@@ -520,11 +553,11 @@ protected:
} // namespace
std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTls::newServerCtx() const {
- return android::RpcTransportCtxTls::create<RpcTransportCtxTlsServer>();
+ return android::RpcTransportCtxTls::create<RpcTransportCtxTlsServer>(mCertVerifier);
}
std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTls::newClientCtx() const {
- return android::RpcTransportCtxTls::create<RpcTransportCtxTlsClient>();
+ return android::RpcTransportCtxTls::create<RpcTransportCtxTlsClient>(mCertVerifier);
}
const char* RpcTransportCtxFactoryTls::toCString() const {
diff --git a/libs/binder/include/binder/RpcCertificateFormat.h b/libs/binder/include/binder/RpcCertificateFormat.h
new file mode 100644
index 0000000000..bc9d814773
--- /dev/null
+++ b/libs/binder/include/binder/RpcCertificateFormat.h
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+// Formats for serializing TLS certificate.
+
+#pragma once
+
+#include <string>
+
+namespace android {
+
+enum class RpcCertificateFormat {
+ PEM,
+ DER,
+};
+
+static inline std::string PrintToString(RpcCertificateFormat format) {
+ switch (format) {
+ case RpcCertificateFormat::PEM:
+ return "PEM";
+ case RpcCertificateFormat::DER:
+ return "DER";
+ default:
+ return "<unknown>";
+ }
+}
+
+} // namespace android
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index 5229cfeb5b..fb2cf23cd0 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -135,7 +135,7 @@ public:
/**
* See RpcTransportCtx::getCertificate
*/
- std::string getCertificate(CertificateFormat);
+ std::vector<uint8_t> getCertificate(RpcCertificateFormat);
/**
* Runs join() in a background thread. Immediately returns.
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index 91db637f43..71eb223a07 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -53,7 +53,7 @@ public:
// Create an RpcSession with default configuration (raw sockets).
static sp<RpcSession> make();
- // Create an RpcSession with the given configuration. |serverCertificateFormat| and
+ // Create an RpcSession with the given configuration. |serverRpcCertificateFormat| and
// |serverCertificate| must have values or be nullopt simultaneously. If they have values, set
// server certificate.
static sp<RpcSession> make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory);
@@ -131,7 +131,7 @@ public:
/**
* See RpcTransportCtx::getCertificate
*/
- std::string getCertificate(CertificateFormat);
+ std::vector<uint8_t> getCertificate(RpcCertificateFormat);
/**
* Shuts down the service.
diff --git a/libs/binder/include/binder/RpcTransport.h b/libs/binder/include/binder/RpcTransport.h
index da132a1abb..1c0bb18e4a 100644
--- a/libs/binder/include/binder/RpcTransport.h
+++ b/libs/binder/include/binder/RpcTransport.h
@@ -25,7 +25,7 @@
#include <android-base/unique_fd.h>
#include <utils/Errors.h>
-#include <binder/CertificateFormat.h>
+#include <binder/RpcCertificateFormat.h>
namespace android {
@@ -73,7 +73,8 @@ public:
// Implementation details:
// - For raw sockets, this always returns empty string.
// - For TLS, this returns the certificate. See RpcTransportTls for details.
- [[nodiscard]] virtual std::string getCertificate(CertificateFormat format) const = 0;
+ [[nodiscard]] virtual std::vector<uint8_t> getCertificate(
+ RpcCertificateFormat format) const = 0;
protected:
RpcTransportCtx() = default;
diff --git a/libs/binder/include_tls/binder/RpcCertificateUtils.h b/libs/binder/include_tls/binder/RpcCertificateUtils.h
new file mode 100644
index 0000000000..8d07835344
--- /dev/null
+++ b/libs/binder/include_tls/binder/RpcCertificateUtils.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+// Utilities for serializing and deserializing X509 certificates.
+
+#pragma once
+
+#include <vector>
+
+#include <openssl/ssl.h>
+
+#include <binder/RpcCertificateFormat.h>
+
+namespace android {
+
+bssl::UniquePtr<X509> deserializeCertificate(const std::vector<uint8_t>& cert,
+ RpcCertificateFormat format);
+
+std::vector<uint8_t> serializeCertificate(X509* x509, RpcCertificateFormat format);
+
+} // namespace android
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index a9bc15d5b3..1968058aed 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -120,9 +120,12 @@ aidl_interface {
host_supported: true,
unstable: true,
srcs: [
+ "BinderRpcTestClientInfo.aidl",
+ "BinderRpcTestServerInfo.aidl",
"IBinderRpcCallback.aidl",
"IBinderRpcSession.aidl",
"IBinderRpcTest.aidl",
+ "ParcelableCertificateData.aidl",
],
backend: {
java: {
diff --git a/libs/binder/include/binder/CertificateFormat.h b/libs/binder/tests/BinderRpcTestClientInfo.aidl
index 4f7e71eee8..b4baebc013 100644
--- a/libs/binder/include/binder/CertificateFormat.h
+++ b/libs/binder/tests/BinderRpcTestClientInfo.aidl
@@ -14,15 +14,8 @@
* limitations under the License.
*/
-// Formats for serializing TLS certificate.
+import ParcelableCertificateData;
-#pragma once
-
-namespace android {
-
-enum class CertificateFormat {
- PEM,
- // TODO(b/195166979): support other formats, e.g. DER
-};
-
-} // namespace android
+parcelable BinderRpcTestClientInfo {
+ ParcelableCertificateData[] certs;
+}
diff --git a/libs/binder/tests/BinderRpcTestServerInfo.aidl b/libs/binder/tests/BinderRpcTestServerInfo.aidl
new file mode 100644
index 0000000000..00dc0bcf81
--- /dev/null
+++ b/libs/binder/tests/BinderRpcTestServerInfo.aidl
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+import ParcelableCertificateData;
+
+parcelable BinderRpcTestServerInfo {
+ long port;
+ ParcelableCertificateData cert;
+}
diff --git a/libs/binder/tests/ParcelableCertificateData.aidl b/libs/binder/tests/ParcelableCertificateData.aidl
new file mode 100644
index 0000000000..38c382eb1f
--- /dev/null
+++ b/libs/binder/tests/ParcelableCertificateData.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+parcelable ParcelableCertificateData {
+ byte[] data;
+}
diff --git a/libs/binder/tests/RpcCertificateVerifierSimple.cpp b/libs/binder/tests/RpcCertificateVerifierSimple.cpp
index 68e7c6567c..4694d1b2e0 100644
--- a/libs/binder/tests/RpcCertificateVerifierSimple.cpp
+++ b/libs/binder/tests/RpcCertificateVerifierSimple.cpp
@@ -16,12 +16,32 @@
#define LOG_TAG "RpcCertificateVerifierSimple"
#include <log/log.h>
+#include <binder/RpcCertificateUtils.h>
+
#include "RpcCertificateVerifierSimple.h"
namespace android {
-status_t RpcCertificateVerifierSimple::verify(const X509*, uint8_t*) {
- // TODO(b/195166979): implement this
+status_t RpcCertificateVerifierSimple::verify(const X509* peerCert, uint8_t* outAlert) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ for (const auto& trustedCert : mTrustedPeerCertificates) {
+ if (0 == X509_cmp(trustedCert.get(), peerCert)) {
+ return OK;
+ }
+ }
+ *outAlert = SSL_AD_CERTIFICATE_UNKNOWN;
+ return PERMISSION_DENIED;
+}
+
+status_t RpcCertificateVerifierSimple::addTrustedPeerCertificate(RpcCertificateFormat format,
+ const std::vector<uint8_t>& cert) {
+ bssl::UniquePtr<X509> x509 = deserializeCertificate(cert, format);
+ if (x509 == nullptr) {
+ ALOGE("Certificate is not in the proper format %s", PrintToString(format).c_str());
+ return BAD_VALUE;
+ }
+ std::lock_guard<std::mutex> lock(mMutex);
+ mTrustedPeerCertificates.push_back(std::move(x509));
return OK;
}
diff --git a/libs/binder/tests/RpcCertificateVerifierSimple.h b/libs/binder/tests/RpcCertificateVerifierSimple.h
index aff5c7cae5..1f2e531b5b 100644
--- a/libs/binder/tests/RpcCertificateVerifierSimple.h
+++ b/libs/binder/tests/RpcCertificateVerifierSimple.h
@@ -16,14 +16,38 @@
#pragma once
+#include <mutex>
+#include <string_view>
+#include <vector>
+
+#include <openssl/ssl.h>
+
+#include <binder/RpcCertificateFormat.h>
#include <binder/RpcCertificateVerifier.h>
namespace android {
// A simple certificate verifier for testing.
+// Keep a list of leaf certificates as trusted. No certificate chain support.
+//
+// All APIs are thread-safe. However, if verify() and addTrustedPeerCertificate() are called
+// simultaneously in different threads, it is not deterministic whether verify() will use the
+// certificate being added.
class RpcCertificateVerifierSimple : public RpcCertificateVerifier {
public:
status_t verify(const X509*, uint8_t*) override;
+
+ // Add a trusted peer certificate. Peers presenting this certificate are accepted.
+ //
+ // Caller must ensure that RpcTransportCtx::newTransport() are called after all trusted peer
+ // certificates are added. Otherwise, RpcTransport-s created before may not trust peer
+ // certificates added later.
+ [[nodiscard]] status_t addTrustedPeerCertificate(RpcCertificateFormat format,
+ const std::vector<uint8_t>& cert);
+
+private:
+ std::mutex mMutex; // for below
+ std::vector<bssl::UniquePtr<X509>> mTrustedPeerCertificates;
};
} // namespace android
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index dbf8899904..a4e37adde9 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <BinderRpcTestClientInfo.h>
+#include <BinderRpcTestServerInfo.h>
#include <BnBinderRpcCallback.h>
#include <BnBinderRpcSession.h>
#include <BnBinderRpcTest.h>
@@ -40,15 +42,20 @@
#include <thread>
#include <type_traits>
+#include <poll.h>
#include <sys/prctl.h>
#include <unistd.h>
+#include "../FdTrigger.h"
#include "../RpcSocketAddress.h" // for testing preconnected clients
#include "../RpcState.h" // for debugging
#include "../vm_sockets.h" // for VMADDR_*
#include "RpcCertificateVerifierSimple.h"
using namespace std::chrono_literals;
+using testing::AssertionFailure;
+using testing::AssertionResult;
+using testing::AssertionSuccess;
namespace android {
@@ -68,7 +75,6 @@ static inline std::unique_ptr<RpcTransportCtxFactory> newFactory(
case RpcSecurity::RAW:
return RpcTransportCtxFactoryRaw::make();
case RpcSecurity::TLS: {
- // TODO(b/198833574): exchange keys and set proper verifier
if (verifier == nullptr) {
verifier = std::make_shared<RpcCertificateVerifierSimple>();
}
@@ -311,14 +317,17 @@ sp<IBinder> MyBinderRpcTest::mHeldBinder;
class Process {
public:
Process(Process&&) = default;
- Process(const std::function<void(android::base::borrowed_fd /* writeEnd */)>& f) {
- android::base::unique_fd writeEnd;
- CHECK(android::base::Pipe(&mReadEnd, &writeEnd)) << strerror(errno);
+ Process(const std::function<void(android::base::borrowed_fd /* writeEnd */,
+ android::base::borrowed_fd /* readEnd */)>& f) {
+ android::base::unique_fd childWriteEnd;
+ android::base::unique_fd childReadEnd;
+ CHECK(android::base::Pipe(&mReadEnd, &childWriteEnd)) << strerror(errno);
+ CHECK(android::base::Pipe(&childReadEnd, &mWriteEnd)) << strerror(errno);
if (0 == (mPid = fork())) {
// racey: assume parent doesn't crash before this is set
prctl(PR_SET_PDEATHSIG, SIGHUP);
- f(writeEnd);
+ f(childWriteEnd, childReadEnd);
exit(0);
}
@@ -329,16 +338,20 @@ public:
}
}
android::base::borrowed_fd readEnd() { return mReadEnd; }
+ android::base::borrowed_fd writeEnd() { return mWriteEnd; }
private:
pid_t mPid = 0;
android::base::unique_fd mReadEnd;
+ android::base::unique_fd mWriteEnd;
};
static std::string allocateSocketAddress() {
static size_t id = 0;
std::string temp = getenv("TMPDIR") ?: "/tmp";
- return temp + "/binderRpcTest_" + std::to_string(id++);
+ auto ret = temp + "/binderRpcTest_" + std::to_string(id++);
+ unlink(ret.c_str());
+ return ret;
};
static unsigned int allocateVsockPort() {
@@ -441,16 +454,17 @@ static inline std::string PrintToString(SocketType socketType) {
}
}
-static base::unique_fd connectToUds(const char* addrStr) {
- UnixSocketAddress addr(addrStr);
+static base::unique_fd connectTo(const RpcSocketAddress& addr) {
base::unique_fd serverFd(
TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
int savedErrno = errno;
- CHECK(serverFd.ok()) << "Could not create socket " << addrStr << ": " << strerror(savedErrno);
+ CHECK(serverFd.ok()) << "Could not create socket " << addr.toString() << ": "
+ << strerror(savedErrno);
if (0 != TEMP_FAILURE_RETRY(connect(serverFd.get(), addr.addr(), addr.addrSize()))) {
int savedErrno = errno;
- LOG(FATAL) << "Could not connect to socket " << addrStr << ": " << strerror(savedErrno);
+ LOG(FATAL) << "Could not connect to socket " << addr.toString() << ": "
+ << strerror(savedErrno);
}
return serverFd;
}
@@ -468,6 +482,37 @@ public:
return PrintToString(type) + "_" + newFactory(security)->toCString();
}
+ static inline void writeString(android::base::borrowed_fd fd, std::string_view str) {
+ uint64_t length = str.length();
+ CHECK(android::base::WriteFully(fd, &length, sizeof(length)));
+ CHECK(android::base::WriteFully(fd, str.data(), str.length()));
+ }
+
+ static inline std::string readString(android::base::borrowed_fd fd) {
+ uint64_t length;
+ CHECK(android::base::ReadFully(fd, &length, sizeof(length)));
+ std::string ret(length, '\0');
+ CHECK(android::base::ReadFully(fd, ret.data(), length));
+ return ret;
+ }
+
+ static inline void writeToFd(android::base::borrowed_fd fd, const Parcelable& parcelable) {
+ Parcel parcel;
+ CHECK_EQ(OK, parcelable.writeToParcel(&parcel));
+ writeString(fd,
+ std::string(reinterpret_cast<const char*>(parcel.data()), parcel.dataSize()));
+ }
+
+ template <typename T>
+ static inline T readFromFd(android::base::borrowed_fd fd) {
+ std::string data = readString(fd);
+ Parcel parcel;
+ CHECK_EQ(OK, parcel.setData(reinterpret_cast<const uint8_t*>(data.data()), data.size()));
+ T object;
+ CHECK_EQ(OK, object.readFromParcel(&parcel));
+ return object;
+ }
+
// This creates a new process serving an interface on a certain number of
// threads.
ProcessSession createRpcTestSocketServerProcess(
@@ -479,11 +524,12 @@ public:
unsigned int vsockPort = allocateVsockPort();
std::string addr = allocateSocketAddress();
- unlink(addr.c_str());
auto ret = ProcessSession{
- .host = Process([&](android::base::borrowed_fd writeEnd) {
- sp<RpcServer> server = RpcServer::make(newFactory(rpcSecurity));
+ .host = Process([&](android::base::borrowed_fd writeEnd,
+ android::base::borrowed_fd readEnd) {
+ auto certVerifier = std::make_shared<RpcCertificateVerifierSimple>();
+ sp<RpcServer> server = RpcServer::make(newFactory(rpcSecurity, certVerifier));
server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
server->setMaxThreads(options.numThreads);
@@ -508,7 +554,20 @@ public:
LOG_ALWAYS_FATAL("Unknown socket type");
}
- CHECK(android::base::WriteFully(writeEnd, &outPort, sizeof(outPort)));
+ BinderRpcTestServerInfo serverInfo;
+ serverInfo.port = static_cast<int64_t>(outPort);
+ serverInfo.cert.data = server->getCertificate(RpcCertificateFormat::PEM);
+ writeToFd(writeEnd, serverInfo);
+ auto clientInfo = readFromFd<BinderRpcTestClientInfo>(readEnd);
+
+ if (rpcSecurity == RpcSecurity::TLS) {
+ for (const auto& clientCert : clientInfo.certs) {
+ CHECK_EQ(OK,
+ certVerifier
+ ->addTrustedPeerCertificate(RpcCertificateFormat::PEM,
+ clientCert.data));
+ }
+ }
configure(server);
@@ -519,23 +578,41 @@ public:
}),
};
- // always read socket, so that we have waited for the server to start
- unsigned int outPort = 0;
- CHECK(android::base::ReadFully(ret.host.readEnd(), &outPort, sizeof(outPort)));
+ std::vector<sp<RpcSession>> sessions;
+ auto certVerifier = std::make_shared<RpcCertificateVerifierSimple>();
+ for (size_t i = 0; i < options.numSessions; i++) {
+ sessions.emplace_back(RpcSession::make(newFactory(rpcSecurity, certVerifier)));
+ }
+
+ auto serverInfo = readFromFd<BinderRpcTestServerInfo>(ret.host.readEnd());
+ BinderRpcTestClientInfo clientInfo;
+ for (const auto& session : sessions) {
+ auto& parcelableCert = clientInfo.certs.emplace_back();
+ parcelableCert.data = session->getCertificate(RpcCertificateFormat::PEM);
+ }
+ writeToFd(ret.host.writeEnd(), clientInfo);
+
+ CHECK_LE(serverInfo.port, std::numeric_limits<unsigned int>::max());
if (socketType == SocketType::INET) {
- CHECK_NE(0, outPort);
+ CHECK_NE(0, serverInfo.port);
+ }
+
+ if (rpcSecurity == RpcSecurity::TLS) {
+ const auto& serverCert = serverInfo.cert.data;
+ CHECK_EQ(OK,
+ certVerifier->addTrustedPeerCertificate(RpcCertificateFormat::PEM,
+ serverCert));
}
status_t status;
- for (size_t i = 0; i < options.numSessions; i++) {
- sp<RpcSession> session = RpcSession::make(newFactory(rpcSecurity));
+ for (const auto& session : sessions) {
session->setMaxThreads(options.numIncomingConnections);
switch (socketType) {
case SocketType::PRECONNECTED:
status = session->setupPreconnectedClient({}, [=]() {
- return connectToUds(addr.c_str());
+ return connectTo(UnixSocketAddress(addr.c_str()));
});
if (status == OK) goto success;
break;
@@ -548,7 +625,7 @@ public:
if (status == OK) goto success;
break;
case SocketType::INET:
- status = session->setupInetClient("127.0.0.1", outPort);
+ status = session->setupInetClient("127.0.0.1", serverInfo.port);
if (status == OK) goto success;
break;
default:
@@ -1221,8 +1298,10 @@ static bool testSupportVsockLoopback() {
return status == OK;
}
-static std::vector<SocketType> testSocketTypes() {
- std::vector<SocketType> ret = {SocketType::PRECONNECTED, SocketType::UNIX, SocketType::INET};
+static std::vector<SocketType> testSocketTypes(bool hasPreconnected = true) {
+ std::vector<SocketType> ret = {SocketType::UNIX, SocketType::INET};
+
+ if (hasPreconnected) ret.push_back(SocketType::PRECONNECTED);
static bool hasVsockLoopback = testSupportVsockLoopback();
@@ -1291,7 +1370,6 @@ private:
TEST_P(BinderRpcSimple, Shutdown) {
auto addr = allocateSocketAddress();
- unlink(addr.c_str());
auto server = RpcServer::make(newFactory(GetParam()));
server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
ASSERT_EQ(OK, server->setupUnixDomainServer(addr.c_str()));
@@ -1356,6 +1434,314 @@ TEST(BinderRpc, Java) {
INSTANTIATE_TEST_CASE_P(BinderRpc, BinderRpcSimple, ::testing::ValuesIn(RpcSecurityValues()),
BinderRpcSimple::PrintTestParam);
+class RpcTransportTest
+ : public ::testing::TestWithParam<std::tuple<SocketType, RpcSecurity, RpcCertificateFormat>> {
+public:
+ using ConnectToServer = std::function<base::unique_fd()>;
+ static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
+ auto [socketType, rpcSecurity, certificateFormat] = info.param;
+ return PrintToString(socketType) + "_" + newFactory(rpcSecurity)->toCString() + "_" +
+ PrintToString(certificateFormat);
+ }
+ void TearDown() override {
+ for (auto& server : mServers) server->shutdown();
+ }
+
+ // A server that handles client socket connections.
+ class Server {
+ public:
+ explicit Server() {}
+ Server(Server&&) = default;
+ ~Server() { shutdown(); }
+ [[nodiscard]] AssertionResult setUp() {
+ auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+ auto rpcServer = RpcServer::make(newFactory(rpcSecurity));
+ rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
+ switch (socketType) {
+ case SocketType::PRECONNECTED: {
+ return AssertionFailure() << "Not supported by this test";
+ } break;
+ case SocketType::UNIX: {
+ auto addr = allocateSocketAddress();
+ auto status = rpcServer->setupUnixDomainServer(addr.c_str());
+ if (status != OK) {
+ return AssertionFailure()
+ << "setupUnixDomainServer: " << statusToString(status);
+ }
+ mConnectToServer = [addr] {
+ return connectTo(UnixSocketAddress(addr.c_str()));
+ };
+ } break;
+ case SocketType::VSOCK: {
+ auto port = allocateVsockPort();
+ auto status = rpcServer->setupVsockServer(port);
+ if (status != OK) {
+ return AssertionFailure() << "setupVsockServer: " << statusToString(status);
+ }
+ mConnectToServer = [port] {
+ return connectTo(VsockSocketAddress(VMADDR_CID_LOCAL, port));
+ };
+ } break;
+ case SocketType::INET: {
+ unsigned int port;
+ auto status = rpcServer->setupInetServer(kLocalInetAddress, 0, &port);
+ if (status != OK) {
+ return AssertionFailure() << "setupInetServer: " << statusToString(status);
+ }
+ mConnectToServer = [port] {
+ const char* addr = kLocalInetAddress;
+ auto aiStart = InetSocketAddress::getAddrInfo(addr, port);
+ if (aiStart == nullptr) return base::unique_fd{};
+ for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
+ auto fd = connectTo(
+ InetSocketAddress(ai->ai_addr, ai->ai_addrlen, addr, port));
+ if (fd.ok()) return fd;
+ }
+ ALOGE("None of the socket address resolved for %s:%u can be connected",
+ addr, port);
+ return base::unique_fd{};
+ };
+ }
+ }
+ mFd = rpcServer->releaseServer();
+ if (!mFd.ok()) return AssertionFailure() << "releaseServer returns invalid fd";
+ mCtx = newFactory(rpcSecurity, mCertVerifier)->newServerCtx();
+ if (mCtx == nullptr) return AssertionFailure() << "newServerCtx";
+ mSetup = true;
+ return AssertionSuccess();
+ }
+ RpcTransportCtx* getCtx() const { return mCtx.get(); }
+ std::shared_ptr<RpcCertificateVerifierSimple> getCertVerifier() const {
+ return mCertVerifier;
+ }
+ ConnectToServer getConnectToServerFn() { return mConnectToServer; }
+ void start() {
+ LOG_ALWAYS_FATAL_IF(!mSetup, "Call Server::setup first!");
+ mThread = std::make_unique<std::thread>(&Server::run, this);
+ }
+ void run() {
+ LOG_ALWAYS_FATAL_IF(!mSetup, "Call Server::setup first!");
+
+ std::vector<std::thread> threads;
+ while (OK == mFdTrigger->triggerablePoll(mFd, POLLIN)) {
+ base::unique_fd acceptedFd(
+ TEMP_FAILURE_RETRY(accept4(mFd.get(), nullptr, nullptr /*length*/,
+ SOCK_CLOEXEC | SOCK_NONBLOCK)));
+ threads.emplace_back(&Server::handleOne, this, std::move(acceptedFd));
+ }
+
+ for (auto& thread : threads) thread.join();
+ }
+ void handleOne(android::base::unique_fd acceptedFd) {
+ ASSERT_TRUE(acceptedFd.ok());
+ auto serverTransport = mCtx->newTransport(std::move(acceptedFd), mFdTrigger.get());
+ if (serverTransport == nullptr) return; // handshake failed
+ std::string message(kMessage);
+ ASSERT_EQ(OK,
+ serverTransport->interruptableWriteFully(mFdTrigger.get(), message.data(),
+ message.size()));
+ }
+ void shutdown() {
+ mFdTrigger->trigger();
+ if (mThread != nullptr) {
+ mThread->join();
+ mThread = nullptr;
+ }
+ }
+
+ private:
+ std::unique_ptr<std::thread> mThread;
+ ConnectToServer mConnectToServer;
+ std::unique_ptr<FdTrigger> mFdTrigger = FdTrigger::make();
+ base::unique_fd mFd;
+ std::unique_ptr<RpcTransportCtx> mCtx;
+ std::shared_ptr<RpcCertificateVerifierSimple> mCertVerifier =
+ std::make_shared<RpcCertificateVerifierSimple>();
+ bool mSetup = false;
+ };
+
+ class Client {
+ public:
+ explicit Client(ConnectToServer connectToServer) : mConnectToServer(connectToServer) {}
+ Client(Client&&) = default;
+ [[nodiscard]] AssertionResult setUp() {
+ auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+ mFd = mConnectToServer();
+ if (!mFd.ok()) return AssertionFailure() << "Cannot connect to server";
+ mFdTrigger = FdTrigger::make();
+ mCtx = newFactory(rpcSecurity, mCertVerifier)->newClientCtx();
+ if (mCtx == nullptr) return AssertionFailure() << "newClientCtx";
+ return AssertionSuccess();
+ }
+ RpcTransportCtx* getCtx() const { return mCtx.get(); }
+ std::shared_ptr<RpcCertificateVerifierSimple> getCertVerifier() const {
+ return mCertVerifier;
+ }
+ void run(bool handshakeOk = true, bool readOk = true) {
+ auto clientTransport = mCtx->newTransport(std::move(mFd), mFdTrigger.get());
+ if (clientTransport == nullptr) {
+ ASSERT_FALSE(handshakeOk) << "newTransport returns nullptr, but it shouldn't";
+ return;
+ }
+ ASSERT_TRUE(handshakeOk) << "newTransport does not return nullptr, but it should";
+ std::string expectedMessage(kMessage);
+ std::string readMessage(expectedMessage.size(), '\0');
+ status_t readStatus =
+ clientTransport->interruptableReadFully(mFdTrigger.get(), readMessage.data(),
+ readMessage.size());
+ if (readOk) {
+ ASSERT_EQ(OK, readStatus);
+ ASSERT_EQ(readMessage, expectedMessage);
+ } else {
+ ASSERT_NE(OK, readStatus);
+ }
+ }
+
+ private:
+ ConnectToServer mConnectToServer;
+ base::unique_fd mFd;
+ std::unique_ptr<FdTrigger> mFdTrigger = FdTrigger::make();
+ std::unique_ptr<RpcTransportCtx> mCtx;
+ std::shared_ptr<RpcCertificateVerifierSimple> mCertVerifier =
+ std::make_shared<RpcCertificateVerifierSimple>();
+ };
+
+ // Make A trust B.
+ template <typename A, typename B>
+ status_t trust(A* a, B* b) {
+ auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+ if (rpcSecurity != RpcSecurity::TLS) return OK;
+ auto bCert = b->getCtx()->getCertificate(certificateFormat);
+ return a->getCertVerifier()->addTrustedPeerCertificate(certificateFormat, bCert);
+ }
+
+ static constexpr const char* kMessage = "hello";
+ std::vector<std::unique_ptr<Server>> mServers;
+};
+
+TEST_P(RpcTransportTest, GoodCertificate) {
+ auto server = mServers.emplace_back(std::make_unique<Server>()).get();
+ ASSERT_TRUE(server->setUp());
+
+ Client client(server->getConnectToServerFn());
+ ASSERT_TRUE(client.setUp());
+
+ ASSERT_EQ(OK, trust(&client, server));
+ ASSERT_EQ(OK, trust(server, &client));
+
+ server->start();
+ client.run();
+}
+
+TEST_P(RpcTransportTest, MultipleClients) {
+ auto server = mServers.emplace_back(std::make_unique<Server>()).get();
+ ASSERT_TRUE(server->setUp());
+
+ std::vector<Client> clients;
+ for (int i = 0; i < 2; i++) {
+ auto& client = clients.emplace_back(server->getConnectToServerFn());
+ ASSERT_TRUE(client.setUp());
+ ASSERT_EQ(OK, trust(&client, server));
+ ASSERT_EQ(OK, trust(server, &client));
+ }
+
+ server->start();
+ for (auto& client : clients) client.run();
+}
+
+TEST_P(RpcTransportTest, UntrustedServer) {
+ auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+
+ auto untrustedServer = mServers.emplace_back(std::make_unique<Server>()).get();
+ ASSERT_TRUE(untrustedServer->setUp());
+
+ Client client(untrustedServer->getConnectToServerFn());
+ ASSERT_TRUE(client.setUp());
+
+ ASSERT_EQ(OK, trust(untrustedServer, &client));
+
+ untrustedServer->start();
+
+ // For TLS, this should reject the certificate. For RAW sockets, it should pass because
+ // the client can't verify the server's identity.
+ bool handshakeOk = rpcSecurity != RpcSecurity::TLS;
+ client.run(handshakeOk);
+}
+TEST_P(RpcTransportTest, MaliciousServer) {
+ auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+ auto validServer = mServers.emplace_back(std::make_unique<Server>()).get();
+ ASSERT_TRUE(validServer->setUp());
+
+ auto maliciousServer = mServers.emplace_back(std::make_unique<Server>()).get();
+ ASSERT_TRUE(maliciousServer->setUp());
+
+ Client client(maliciousServer->getConnectToServerFn());
+ ASSERT_TRUE(client.setUp());
+
+ ASSERT_EQ(OK, trust(&client, validServer));
+ ASSERT_EQ(OK, trust(validServer, &client));
+ ASSERT_EQ(OK, trust(maliciousServer, &client));
+
+ maliciousServer->start();
+
+ // For TLS, this should reject the certificate. For RAW sockets, it should pass because
+ // the client can't verify the server's identity.
+ bool handshakeOk = rpcSecurity != RpcSecurity::TLS;
+ client.run(handshakeOk);
+}
+
+TEST_P(RpcTransportTest, UntrustedClient) {
+ auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+ auto server = mServers.emplace_back(std::make_unique<Server>()).get();
+ ASSERT_TRUE(server->setUp());
+
+ Client client(server->getConnectToServerFn());
+ ASSERT_TRUE(client.setUp());
+
+ ASSERT_EQ(OK, trust(&client, server));
+
+ server->start();
+
+ // For TLS, Client should be able to verify server's identity, so client should see
+ // do_handshake() successfully executed. However, server shouldn't be able to verify client's
+ // identity and should drop the connection, so client shouldn't be able to read anything.
+ bool readOk = rpcSecurity != RpcSecurity::TLS;
+ client.run(true, readOk);
+}
+
+TEST_P(RpcTransportTest, MaliciousClient) {
+ auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+ auto server = mServers.emplace_back(std::make_unique<Server>()).get();
+ ASSERT_TRUE(server->setUp());
+
+ Client validClient(server->getConnectToServerFn());
+ ASSERT_TRUE(validClient.setUp());
+ Client maliciousClient(server->getConnectToServerFn());
+ ASSERT_TRUE(maliciousClient.setUp());
+
+ ASSERT_EQ(OK, trust(&validClient, server));
+ ASSERT_EQ(OK, trust(&maliciousClient, server));
+
+ server->start();
+
+ // See UntrustedClient.
+ bool readOk = rpcSecurity != RpcSecurity::TLS;
+ maliciousClient.run(true, readOk);
+}
+
+std::vector<RpcCertificateFormat> testRpcCertificateFormats() {
+ return {
+ RpcCertificateFormat::PEM,
+ RpcCertificateFormat::DER,
+ };
+}
+
+INSTANTIATE_TEST_CASE_P(BinderRpc, RpcTransportTest,
+ ::testing::Combine(::testing::ValuesIn(testSocketTypes(false)),
+ ::testing::ValuesIn(RpcSecurityValues()),
+ ::testing::ValuesIn(testRpcCertificateFormats())),
+ RpcTransportTest::PrintParamInfo);
+
} // namespace android
int main(int argc, char** argv) {