xref: /aosp_15_r20/external/pigweed/pw_tls_client/test_server_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2021 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include "pw_tls_client/test/test_server.h"
16 
17 #include <string>
18 
19 #include "pw_span/span.h"
20 #include "pw_unit_test/framework.h"
21 
22 // The following header contains a set of test certificates and keys.
23 // It is generated by
24 // third_party/boringssl/py/boringssl/generate_test_data.py.
25 #include "test_certs_and_keys.h"
26 
27 namespace pw::tls_client::test {
28 namespace {
29 
TestClientBioRead(BIO * bio,char * out,int outl)30 int TestClientBioRead(BIO* bio, char* out, int outl) {
31   auto read_writer = static_cast<stream::ReaderWriter*>(bio->ptr);
32   auto res = read_writer->Read(out, outl);
33   if (!res.ok()) {
34     return -1;
35   }
36   if (res.value().empty()) {
37     BIO_set_retry_read(bio);
38     return -1;
39   }
40   return res.value().size();
41 }
42 
TestClientBioWrite(BIO * bio,const char * in,int inl)43 int TestClientBioWrite(BIO* bio, const char* in, int inl) {
44   auto read_writer = static_cast<stream::ReaderWriter*>(bio->ptr);
45   auto res = read_writer->Write(in, inl);
46   if (!res.ok()) {
47     return -1;
48   }
49   return inl;
50 }
51 
TestClientBioNew(BIO * bio)52 int TestClientBioNew(BIO* bio) {
53   bio->init = 1;
54   return 1;
55 }
56 
TestClientBioCtrl(BIO *,int,long,void *)57 long TestClientBioCtrl(BIO*, int, long, void*) { return 1; }
58 
TestClientBioFree(BIO *)59 int TestClientBioFree(BIO*) { return 1; }
60 
61 const BIO_METHOD bio_method = {
62     BIO_TYPE_MEM,
63     "bio test server test",
64     TestClientBioWrite,
65     TestClientBioRead,
66     nullptr,
67     nullptr,
68     TestClientBioCtrl,
69     TestClientBioNew,
70     TestClientBioFree,
71     nullptr,
72 };
73 
74 // Server needs to send certificate. Thus the send buffer needs to be bigger.
75 std::array<std::byte, 4096> server_send_buffer;
76 std::array<std::byte, 512> server_receive_buffer;
77 
78 // Create a raw BoringSSL client and load test trust anchors.
CreateSSLClient(bssl::UniquePtr<SSL_CTX> * ctx,bssl::UniquePtr<SSL> * client,stream::ReaderWriter * read_writer)79 void CreateSSLClient(bssl::UniquePtr<SSL_CTX>* ctx,
80                      bssl::UniquePtr<SSL>* client,
81                      stream::ReaderWriter* read_writer) {
82   *ctx = bssl::UniquePtr<SSL_CTX>(SSL_CTX_new(TLS_method()));
83   ASSERT_NE(*ctx, nullptr);
84   *client = bssl::UniquePtr<SSL>(SSL_new(ctx->get()));
85   ASSERT_NE(*client, nullptr);
86   BIO* bio = BIO_new(&bio_method);
87   ASSERT_NE(bio, nullptr);
88 
89   // Load trust anchors to client
90   auto store = SSL_CTX_get_cert_store(ctx->get());
91   X509_VERIFY_PARAM_clear_flags(X509_STORE_get0_param(store),
92                                 X509_V_FLAG_USE_CHECK_TIME);
93   const pw::ConstByteSpan kTrustAnchors[] = {kRootACert, kRootBCert};
94   for (auto cert : kTrustAnchors) {
95     auto res = ParseDerCertificate(cert);
96     PW_TEST_ASSERT_OK(res.status());
97     ASSERT_EQ(X509_STORE_add_cert(store, res.value()), 1);
98     X509_free(res.value());
99   }
100   bio->ptr = read_writer;
101   SSL_set_bio(client->get(), bio, bio);
102 }
103 
104 }  // namespace
105 
TEST(InMemoryTestServer,NormalConnectionSucceed)106 TEST(InMemoryTestServer, NormalConnectionSucceed) {
107   InMemoryTestServer server(server_receive_buffer, server_send_buffer);
108   const ConstByteSpan kIntermediates[] = {kSubCACert};
109   PW_TEST_ASSERT_OK(server.Initialize(kServerKey, kServerCert, kIntermediates));
110 
111   // Create a raw BoringSSL client
112   bssl::UniquePtr<SSL_CTX> client_ctx;
113   bssl::UniquePtr<SSL> ssl_client;
114   CreateSSLClient(&client_ctx, &ssl_client, &server);
115 
116   // Handshake should be OK
117   ASSERT_EQ(SSL_connect(ssl_client.get()), 1);
118   ASSERT_TRUE(server.SessionEstablished());
119 
120   // Client should pass certificate verification.
121   ASSERT_EQ(SSL_get_verify_result(ssl_client.get()), 0);
122 
123   // Send some data to server
124   const char send_expected[] = "hello";
125   int send_len =
126       SSL_write(ssl_client.get(), send_expected, sizeof(send_expected));
127   ASSERT_EQ(static_cast<size_t>(send_len), sizeof(send_expected));
128 
129   char receive_actual[sizeof(send_expected) + 1] = {0};
130   int read_ret =
131       SSL_read(ssl_client.get(), receive_actual, sizeof(receive_actual));
132   ASSERT_EQ(static_cast<size_t>(read_ret), sizeof(send_expected));
133   ASSERT_STREQ(send_expected, receive_actual);
134 
135   // Shutdown
136   EXPECT_FALSE(server.ClientShutdownReceived());
137   ASSERT_NE(SSL_shutdown(ssl_client.get()), -1);
138   ASSERT_TRUE(server.ClientShutdownReceived());
139 }
140 
TEST(InMemoryTestServer,BufferTooSmallErrorsOut)141 TEST(InMemoryTestServer, BufferTooSmallErrorsOut) {
142   std::array<std::byte, 1> insufficient_buffer;
143   InMemoryTestServer server(server_receive_buffer, insufficient_buffer);
144   const ConstByteSpan kIntermediates[] = {kSubCACert};
145   PW_TEST_ASSERT_OK(server.Initialize(kServerKey, kServerCert, kIntermediates));
146 
147   // Create a raw BoringSSL client
148   bssl::UniquePtr<SSL_CTX> client_ctx;
149   bssl::UniquePtr<SSL> ssl_client;
150   CreateSSLClient(&client_ctx, &ssl_client, &server);
151 
152   // Handshake should fail as server shouldn't have enough buffer
153   ASSERT_NE(SSL_connect(ssl_client.get()), 1);
154   ASSERT_EQ(server.GetLastBioStatus(), Status::ResourceExhausted());
155 }
156 
157 }  // namespace pw::tls_client::test
158