aboutsummaryrefslogtreecommitdiff
path: root/pw_tls_client/public/pw_tls_client/test/test_server.h
blob: 372463198286e57b2c41f7fbb417799201a0d25f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// Copyright 2021 The Pigweed Authors
//
// 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
//
//     https://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/bio.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>

#include "pw_bytes/span.h"
#include "pw_result/result.h"
#include "pw_status/status.h"
#include "pw_stream/stream.h"

namespace pw::tls_client::test {

class FixedSizeFIFOBuffer : public stream::NonSeekableReaderWriter {
 public:
  FixedSizeFIFOBuffer() = delete;
  FixedSizeFIFOBuffer(const FixedSizeFIFOBuffer&) = delete;
  FixedSizeFIFOBuffer& operator=(const FixedSizeFIFOBuffer&) = delete;

  FixedSizeFIFOBuffer(ByteSpan buffer) : buffer_(buffer) {}
  void clear() { current_size_ = 0; }

 private:
  StatusWithSize DoRead(ByteSpan dest) override;
  Status DoWrite(ConstByteSpan data) override;
  ByteSpan buffer_;
  size_t current_size_ = 0;
};

// Writing to the server is equivalent to sending data to the server. Server
// will be invoked to process the data when being written. The write does
// not return until the server completes processing it.
// Reading from the server is equivalent to receiving data from the server.
//
// The server accepts is only for one client and echo messages it sends.
class InMemoryTestServer : public stream::NonSeekableReaderWriter {
 public:
  InMemoryTestServer() = delete;
  InMemoryTestServer(const InMemoryTestServer&) = delete;
  InMemoryTestServer& operator=(const InMemoryTestServer&) = delete;

  // `input_buffer` is for storing raw data sent from the client.
  // `output_buffer` is for storing raw data server prepare and to be sent
  // to the client.
  //
  // The required size of the buffer depends on the payload and needs to be
  // determined by the users based on use cases.
  InMemoryTestServer(ByteSpan input_buffer, ByteSpan output_buffer);

  // Initialize a test server with a private key, server certificate, and
  // CA chains (all DER format)
  Status Initialize(ConstByteSpan key,
                    ConstByteSpan cert,
                    std::span<const ConstByteSpan> chains);

  // Is handshake completed.
  bool SessionEstablished() { return is_handshake_done_; }

  // Returns whether a shutdown request has been received from the client.
  bool ClientShutdownReceived();

  Status GetLastBioStatus() { return last_bio_status_; }

 private:
  bssl::UniquePtr<SSL_CTX> ctx_;
  bssl::UniquePtr<SSL> ssl_;
  bool is_handshake_done_ = false;

  // Buffer for storing data sent from the client.
  FixedSizeFIFOBuffer input_buffer_;

  // Buffer for storing data prepared by the server to send to the client.
  FixedSizeFIFOBuffer output_buffer_;

  // Store the last status of BIO operation (in BioRead() and BioWrite());
  Status last_bio_status_ = OkStatus();

  // Process the data written to the server as much as possible.
  // If server is in handshake process, it processes handshake and prepares data
  // to send to the server . If server is in application data exchange
  // phase, it decrypts data and echoes back to the client. Client can retrieve
  // the message by reading from the server.
  Status ProcessPackets();

  // Methods for loading private key, certificate, and intermediate CA chain.
  Status LoadPrivateKey(ConstByteSpan key);
  Status LoadCertificate(ConstByteSpan cert);
  Status LoadCAChain(std::span<const ConstByteSpan> chains);

  // Methods for providing BIO interfaces.
  static int BioRead(BIO* bio, char* out, int output_length);
  static int BioWrite(BIO* bio, const char* in, int input_length);

  StatusWithSize DoRead(ByteSpan dest) override;
  Status DoWrite(ConstByteSpan data) override;
};

// A helper function to parse a DER format certificate.
pw::Result<X509*> ParseDerCertificate(pw::ConstByteSpan cert);

}  // namespace pw::tls_client::test