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 #pragma once 16 17 #include "pw_preprocessor/compiler.h" 18 19 PW_MODIFY_DIAGNOSTICS_PUSH(); 20 PW_MODIFY_DIAGNOSTIC(ignored, "-Wcast-qual"); 21 PW_MODIFY_DIAGNOSTIC(ignored, "-Wignored-qualifiers"); 22 PW_MODIFY_DIAGNOSTIC(ignored, "-Wpedantic"); 23 #include <openssl/bio.h> 24 #include <openssl/pem.h> 25 #include <openssl/ssl.h> 26 PW_MODIFY_DIAGNOSTICS_POP(); 27 28 #include "pw_bytes/span.h" 29 #include "pw_result/result.h" 30 #include "pw_status/status.h" 31 #include "pw_stream/stream.h" 32 33 namespace pw::tls_client::test { 34 35 class FixedSizeFIFOBuffer : public stream::NonSeekableReaderWriter { 36 public: 37 FixedSizeFIFOBuffer() = delete; 38 FixedSizeFIFOBuffer(const FixedSizeFIFOBuffer&) = delete; 39 FixedSizeFIFOBuffer& operator=(const FixedSizeFIFOBuffer&) = delete; 40 FixedSizeFIFOBuffer(ByteSpan buffer)41 FixedSizeFIFOBuffer(ByteSpan buffer) : buffer_(buffer) {} clear()42 void clear() { current_size_ = 0; } 43 44 private: 45 StatusWithSize DoRead(ByteSpan dest) override; 46 Status DoWrite(ConstByteSpan data) override; 47 ByteSpan buffer_; 48 size_t current_size_ = 0; 49 }; 50 51 // Writing to the server is equivalent to sending data to the server. Server 52 // will be invoked to process the data when being written. The write does 53 // not return until the server completes processing it. 54 // Reading from the server is equivalent to receiving data from the server. 55 // 56 // The server accepts is only for one client and echo messages it sends. 57 class InMemoryTestServer : public stream::NonSeekableReaderWriter { 58 public: 59 InMemoryTestServer() = delete; 60 InMemoryTestServer(const InMemoryTestServer&) = delete; 61 InMemoryTestServer& operator=(const InMemoryTestServer&) = delete; 62 63 // `input_buffer` is for storing raw data sent from the client. 64 // `output_buffer` is for storing raw data server prepare and to be sent 65 // to the client. 66 // 67 // The required size of the buffer depends on the payload and needs to be 68 // determined by the users based on use cases. 69 InMemoryTestServer(ByteSpan input_buffer, ByteSpan output_buffer); 70 71 // Initialize a test server with a private key, server certificate, and 72 // CA chains (all DER format) 73 Status Initialize(ConstByteSpan key, 74 ConstByteSpan cert, 75 span<const ConstByteSpan> chains); 76 77 // Is handshake completed. SessionEstablished()78 bool SessionEstablished() { return is_handshake_done_; } 79 80 // Returns whether a shutdown request has been received from the client. 81 bool ClientShutdownReceived(); 82 GetLastBioStatus()83 Status GetLastBioStatus() { return last_bio_status_; } 84 85 private: 86 bssl::UniquePtr<SSL_CTX> ctx_; 87 bssl::UniquePtr<SSL> ssl_; 88 bool is_handshake_done_ = false; 89 90 // Buffer for storing data sent from the client. 91 FixedSizeFIFOBuffer input_buffer_; 92 93 // Buffer for storing data prepared by the server to send to the client. 94 FixedSizeFIFOBuffer output_buffer_; 95 96 // Store the last status of BIO operation (in BioRead() and BioWrite()); 97 Status last_bio_status_ = OkStatus(); 98 99 // Process the data written to the server as much as possible. 100 // If server is in handshake process, it processes handshake and prepares data 101 // to send to the server . If server is in application data exchange 102 // phase, it decrypts data and echoes back to the client. Client can retrieve 103 // the message by reading from the server. 104 Status ProcessPackets(); 105 106 // Methods for loading private key, certificate, and intermediate CA chain. 107 Status LoadPrivateKey(ConstByteSpan key); 108 Status LoadCertificate(ConstByteSpan cert); 109 Status LoadCAChain(span<const ConstByteSpan> chains); 110 111 // Methods for providing BIO interfaces. 112 static int BioRead(BIO* bio, char* out, int output_length); 113 static int BioWrite(BIO* bio, const char* in, int input_length); 114 115 StatusWithSize DoRead(ByteSpan dest) override; 116 Status DoWrite(ConstByteSpan data) override; 117 }; 118 119 // A helper function to parse a DER format certificate. 120 pw::Result<X509*> ParseDerCertificate(pw::ConstByteSpan cert); 121 122 } // namespace pw::tls_client::test 123