xref: /aosp_15_r20/external/pigweed/pw_tls_client_mbedtls/tls_client_mbedtls.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_assert/check.h"
16 #include "pw_log/log.h"
17 #include "pw_tls_client/entropy.h"
18 #include "pw_tls_client/session.h"
19 #include "pw_tls_client_mbedtls/backend_types.h"
20 
21 namespace pw::tls_client {
22 namespace backend {
23 
MbedTlsWrite(void * ctx,const uint8_t * buf,size_t len)24 int SessionImplementation::MbedTlsWrite(void* ctx,
25                                         const uint8_t* buf,
26                                         size_t len) {
27   PW_CHECK_NOTNULL(ctx);
28   PW_CHECK_NOTNULL(buf);
29   auto writer =
30       static_cast<SessionImplementation*>(ctx)->session_options_.transport();
31   PW_CHECK_NOTNULL(writer);
32   return writer->Write(buf, len).ok() ? len : -1;
33 }
34 
MbedTlsRead(void * ctx,unsigned char * buf,size_t len)35 int SessionImplementation::MbedTlsRead(void* ctx,
36                                        unsigned char* buf,
37                                        size_t len) {
38   PW_CHECK_NOTNULL(ctx);
39   PW_CHECK_NOTNULL(buf);
40   auto reader =
41       static_cast<SessionImplementation*>(ctx)->session_options_.transport();
42   PW_CHECK_NOTNULL(reader);
43   auto res = reader->Read(buf, len);
44   if (!res.ok()) {
45     return -1;
46   }
47   return res.value().empty() ? MBEDTLS_ERR_SSL_WANT_READ : res.value().size();
48 }
49 
50 Status SessionImplementation::entropy_source_status_ = OkStatus();
51 
SetEntropySourceStatus(Status status)52 void SessionImplementation::SetEntropySourceStatus(Status status) {
53   entropy_source_status_ = status;
54 }
55 
56 // Entropy source callback
MbedTlsEntropySource(void * ctx,unsigned char * out,size_t len,size_t * output_length)57 int SessionImplementation::MbedTlsEntropySource(void* ctx,
58                                                 unsigned char* out,
59                                                 size_t len,
60                                                 size_t* output_length) {
61   Status status;
62   if (entropy_source_status_ != OkStatus()) {
63     status = entropy_source_status_;
64   } else {
65     status = GetRandomBytes({out, len});
66   }
67 
68   if (!status.ok()) {
69     PW_LOG_DEBUG("Failed to generate random bytes");
70     auto session_impl = static_cast<SessionImplementation*>(ctx);
71     session_impl->SetTlsStatus(pw::tls_client::TLSStatus::kEntropySourceFailed);
72     return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
73   }
74   *output_length = len;
75   return 0;
76 }
77 
SessionImplementation(SessionOptions options)78 SessionImplementation::SessionImplementation(SessionOptions options)
79     : session_options_(options) {
80   mbedtls_ssl_init(&ssl_ctx_);
81   mbedtls_ssl_config_init(&ssl_config_);
82   mbedtls_ctr_drbg_init(&drbg_ctx_);
83   mbedtls_entropy_init(&entropy_ctx_);
84 }
85 
~SessionImplementation()86 SessionImplementation::~SessionImplementation() {
87   mbedtls_ssl_free(&ssl_ctx_);
88   mbedtls_ssl_config_free(&ssl_config_);
89   mbedtls_ctr_drbg_free(&drbg_ctx_);
90   mbedtls_entropy_free(&entropy_ctx_);
91 }
92 
Setup()93 Status SessionImplementation::Setup() {
94   int ret = 0;
95 
96   // Set up default configuration.
97   ret = mbedtls_ssl_config_defaults(
98       &ssl_config_,
99       // Configured as client.
100       MBEDTLS_SSL_IS_CLIENT,
101       // Statndard TLS. The other option is MBEDTLS_SSL_TRANSPORT_DATAGRAM
102       // for DTLS, which we'll consider later.
103       MBEDTLS_SSL_TRANSPORT_STREAM,
104       // This option is used in all MbedTLS native examples.
105       // The other option is MBEDTLS_SSL_PRESET_SUITEB.
106       // However, there is no document/comment availalbe on what they do.
107       // Base on the source code, these options will restrict the version
108       // of TLS protocol. MBEDTLS_SSL_PRESET_SUITEB forces TLS 1.2.
109       // MBEDTLS_SSL_PRESET_DEFAULT is more relaxed. But since we
110       // define MBEDTLS_SSL_PROTO_TLS1_2 for all configs. There shouldn't be
111       // any difference.
112       MBEDTLS_SSL_PRESET_DEFAULT);
113   if (ret) {
114     return Status::Internal();
115   }
116 
117   // Set up an entropy source.
118   ret = mbedtls_entropy_add_source(&entropy_ctx_,
119                                    MbedTlsEntropySource,
120                                    this,
121                                    1,
122                                    MBEDTLS_ENTROPY_SOURCE_STRONG);
123   if (ret) {
124     return Status::Internal();
125   }
126 
127   // Set up drbg.
128   unsigned char personalized_bytes[] = "pw_tls_client";
129   ret = mbedtls_ctr_drbg_seed(&drbg_ctx_,
130                               mbedtls_entropy_func,
131                               &entropy_ctx_,
132                               personalized_bytes,
133                               sizeof(personalized_bytes));
134   if (ret) {
135     if (ret == MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED) {
136       tls_status_ = TLSStatus::kEntropySourceFailed;
137     }
138     return Status::Internal();
139   }
140 
141   // The API does not fail.
142   mbedtls_ssl_conf_rng(&ssl_config_, mbedtls_ctr_drbg_random, &drbg_ctx_);
143 
144   // The API does not fail.
145   mbedtls_ssl_conf_authmode(&ssl_config_, MBEDTLS_SSL_VERIFY_REQUIRED);
146 
147   // TODO: b/235289501 - Add logic for loading trust anchors.
148 
149   // Load configuration to SSL.
150   ret = mbedtls_ssl_setup(&ssl_ctx_, &ssl_config_);
151   if (ret) {
152     return Status::Internal();
153   }
154 
155   // Set up transport.
156   // The API does not fail.
157   mbedtls_ssl_set_bio(&ssl_ctx_, this, MbedTlsWrite, MbedTlsRead, nullptr);
158 
159   ret = mbedtls_ssl_set_hostname(&ssl_ctx_,
160                                  session_options_.server_name().data());
161   if (ret) {
162     return Status::Internal();
163   }
164 
165   return OkStatus();
166 }
167 
168 }  // namespace backend
169 
Session(const SessionOptions & options)170 Session::Session(const SessionOptions& options) : session_impl_(options) {}
171 
172 Session::~Session() = default;
173 
Create(const SessionOptions & options)174 Result<Session*> Session::Create(const SessionOptions& options) {
175   if (!options.transport()) {
176     PW_LOG_DEBUG("Must provide a transport");
177     return Status::Internal();
178   }
179 
180   auto sess = new Session(options);
181   if (!sess) {
182     return Status::ResourceExhausted();
183   }
184 
185   // Set up the client.
186   auto setup_status = sess->session_impl_.Setup();
187   if (!setup_status.ok()) {
188     PW_LOG_DEBUG("Failed to setup");
189     // TODO: b/235289501 - `tls_status_` may be set, but the session object will
190     // be released. Map `tls_stauts_` to string and print out here so that
191     // the information can be catched.
192     delete sess;
193     return setup_status;
194   }
195 
196   return sess;
197 }
198 
Open()199 Status Session::Open() {
200   // TODO: b/235289501 - To implement
201   return Status::Unimplemented();
202 }
203 
Close()204 Status Session::Close() {
205   // TODO: b/235289501 - To implement
206   return Status::Unimplemented();
207 }
208 
DoRead(ByteSpan)209 StatusWithSize Session::DoRead(ByteSpan) {
210   // TODO: b/235289501 - To implement
211   return StatusWithSize(Status::Unimplemented(), 0);
212 }
213 
DoWrite(ConstByteSpan)214 Status Session::DoWrite(ConstByteSpan) {
215   // TODO: b/235289501 - To implement
216   return Status::Unimplemented();
217 }
218 
GetLastTLSStatus()219 TLSStatus Session::GetLastTLSStatus() { return session_impl_.GetTlsStatus(); }
220 
221 }  // namespace pw::tls_client
222