blob: 19b1efedf6ad16bd27160f902724c0f6f4520984 [file] [log] [blame]
Yecheng Zhao121de172021-05-14 11:18:54 -07001// 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
Yecheng Zhao79174152021-07-22 12:52:29 -070015#include "pw_tls_client/test/test_server.h"
Yecheng Zhao121de172021-05-14 11:18:54 -070016
17#include <span>
18#include <string>
19
20#include "gtest/gtest.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#define ASSERT_OK(expr) ASSERT_EQ(pw::OkStatus(), expr)
28
Yecheng Zhao79174152021-07-22 12:52:29 -070029namespace pw::tls_client::test {
Yecheng Zhao121de172021-05-14 11:18:54 -070030namespace {
31
32int TestClientBioRead(BIO* bio, char* out, int outl) {
Yecheng Zhao79174152021-07-22 12:52:29 -070033 auto read_writer = static_cast<stream::ReaderWriter*>(bio->ptr);
Yecheng Zhao121de172021-05-14 11:18:54 -070034 auto res = read_writer->Read(out, outl);
35 if (!res.ok()) {
36 return -1;
37 }
Ted Pudlik10ec2bd2021-10-27 21:17:09 +000038 if (res.value().empty()) {
Yecheng Zhao121de172021-05-14 11:18:54 -070039 BIO_set_retry_read(bio);
40 return -1;
41 }
42 return res.value().size();
43}
44
45int TestClientBioWrite(BIO* bio, const char* in, int inl) {
Yecheng Zhao79174152021-07-22 12:52:29 -070046 auto read_writer = static_cast<stream::ReaderWriter*>(bio->ptr);
Yecheng Zhao121de172021-05-14 11:18:54 -070047 auto res = read_writer->Write(in, inl);
48 if (!res.ok()) {
49 return -1;
50 }
51 return inl;
52}
53
54int TestClientBioNew(BIO* bio) {
55 bio->init = 1;
56 return 1;
57}
58
59long TestClientBioCtrl(BIO*, int, long, void*) { return 1; }
60
61int TestClientBioFree(BIO*) { return 1; }
62
63const BIO_METHOD bio_method = {
64 BIO_TYPE_MEM,
65 "bio test server test",
66 TestClientBioWrite,
67 TestClientBioRead,
68 nullptr,
69 nullptr,
70 TestClientBioCtrl,
71 TestClientBioNew,
72 TestClientBioFree,
73 nullptr,
74};
75
76// Server needs to send certificate. Thus the send buffer needs to be bigger.
77std::array<std::byte, 4096> server_send_buffer;
78std::array<std::byte, 512> server_receive_buffer;
79
80// Create a raw BoringSSL client and load test trust anchors.
81void CreateSSLClient(bssl::UniquePtr<SSL_CTX>* ctx,
82 bssl::UniquePtr<SSL>* client,
Yecheng Zhao79174152021-07-22 12:52:29 -070083 stream::ReaderWriter* read_writer) {
Yecheng Zhao121de172021-05-14 11:18:54 -070084 *ctx = bssl::UniquePtr<SSL_CTX>(SSL_CTX_new(TLS_method()));
85 ASSERT_NE(*ctx, nullptr);
86 *client = bssl::UniquePtr<SSL>(SSL_new(ctx->get()));
87 ASSERT_NE(*client, nullptr);
88 BIO* bio = BIO_new(&bio_method);
89 ASSERT_NE(bio, nullptr);
90
91 // Load trust anchors to client
92 auto store = SSL_CTX_get_cert_store(ctx->get());
93 X509_VERIFY_PARAM_clear_flags(store->param, X509_V_FLAG_USE_CHECK_TIME);
94 const pw::ConstByteSpan kTrustAnchors[] = {kRootACert, kRootBCert};
95 for (auto cert : kTrustAnchors) {
Yecheng Zhao79174152021-07-22 12:52:29 -070096 auto res = ParseDerCertificate(cert);
Yecheng Zhao121de172021-05-14 11:18:54 -070097 ASSERT_OK(res.status());
98 ASSERT_EQ(X509_STORE_add_cert(store, res.value()), 1);
99 X509_free(res.value());
100 }
101 bio->ptr = read_writer;
102 SSL_set_bio(client->get(), bio, bio);
103}
104
105} // namespace
106
Yecheng Zhao121de172021-05-14 11:18:54 -0700107TEST(InMemoryTestServer, NormalConnectionSucceed) {
108 InMemoryTestServer server(server_receive_buffer, server_send_buffer);
109 const ConstByteSpan kIntermediates[] = {kSubCACert};
110 ASSERT_OK(server.Initialize(kServerKey, kServerCert, kIntermediates));
111
112 // Create a raw BoringSSL client
113 bssl::UniquePtr<SSL_CTX> client_ctx;
114 bssl::UniquePtr<SSL> ssl_client;
115 CreateSSLClient(&client_ctx, &ssl_client, &server);
116
117 // Handshake should be OK
118 ASSERT_EQ(SSL_connect(ssl_client.get()), 1);
119 ASSERT_TRUE(server.SessionEstablished());
120
121 // Client should pass certificate verification.
122 ASSERT_EQ(SSL_get_verify_result(ssl_client.get()), 0);
123
124 // Send some data to server
125 const char send_expected[] = "hello";
126 int send_len =
127 SSL_write(ssl_client.get(), send_expected, sizeof(send_expected));
128 ASSERT_EQ(static_cast<size_t>(send_len), sizeof(send_expected));
129
130 char receive_actual[sizeof(send_expected) + 1] = {0};
131 int read_ret =
132 SSL_read(ssl_client.get(), receive_actual, sizeof(receive_actual));
133 ASSERT_EQ(static_cast<size_t>(read_ret), sizeof(send_expected));
134 ASSERT_STREQ(send_expected, receive_actual);
135
136 // Shutdown
137 EXPECT_FALSE(server.ClientShutdownReceived());
138 ASSERT_NE(SSL_shutdown(ssl_client.get()), -1);
139 ASSERT_TRUE(server.ClientShutdownReceived());
140}
141
142TEST(InMemoryTestServer, BufferTooSmallErrorsOut) {
143 std::array<std::byte, 1> insufficient_buffer;
144 InMemoryTestServer server(server_receive_buffer, insufficient_buffer);
145 const ConstByteSpan kIntermediates[] = {kSubCACert};
146 ASSERT_OK(server.Initialize(kServerKey, kServerCert, kIntermediates));
147
148 // Create a raw BoringSSL client
149 bssl::UniquePtr<SSL_CTX> client_ctx;
150 bssl::UniquePtr<SSL> ssl_client;
151 CreateSSLClient(&client_ctx, &ssl_client, &server);
152
153 // Handshake should fail as server shouldn't have enough buffer
154 ASSERT_NE(SSL_connect(ssl_client.get()), 1);
155 ASSERT_EQ(server.GetLastBioStatus(), Status::ResourceExhausted());
156}
157
Yecheng Zhao79174152021-07-22 12:52:29 -0700158} // namespace pw::tls_client::test