tls.h (12070B)
1 // Copyright (c) 2016 Sandstorm Development Group, Inc. and contributors 2 // Licensed under the MIT License: 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a copy 5 // of this software and associated documentation files (the "Software"), to deal 6 // in the Software without restriction, including without limitation the rights 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 // copies of the Software, and to permit persons to whom the Software is 9 // furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 // THE SOFTWARE. 21 22 #pragma once 23 // This file implements TLS (aka SSL) encrypted networking. It is actually a wrapper, currently 24 // around OpenSSL / BoringSSL / LibreSSL, but the interface is intended to remain 25 // implementation-agnostic. 26 // 27 // Unlike OpenSSL's API, the API defined in this file is intended to be hard to use wrong. Good 28 // ciphers and settings are used by default. Certificates validation is performed automatically 29 // and cannot be bypassed. 30 31 #include <kj/async-io.h> 32 33 namespace kj { 34 35 class TlsPrivateKey; 36 class TlsCertificate; 37 struct TlsKeypair; 38 class TlsSniCallback; 39 class TlsConnection; 40 41 enum class TlsVersion { 42 SSL_3, // avoid; cryptographically broken 43 TLS_1_0, 44 TLS_1_1, 45 TLS_1_2 46 }; 47 48 class TlsContext { 49 // TLS system. Allocate one of these, configure it with the proper keys and certificates (or 50 // use the defaults), and then use it to wrap the standard KJ network interfaces in 51 // implementations that transparently use TLS. 52 53 public: 54 struct Options { 55 Options(); 56 // Initializes all values to reasonable defaults. 57 58 bool useSystemTrustStore; 59 // Whether or not to trust the system's default trust store. Default: true. 60 61 bool verifyClients; 62 // If true, when acting as a server, require the client to present a certificate. The 63 // certificate must be signed by one of the trusted CAs, otherwise the client will be rejected. 64 // (Typically you should set `useSystemTrustStore` false when using this flag, and specify 65 // your specific trusted CAs in `trustedCertificates`.) 66 // Default: false 67 68 kj::ArrayPtr<const TlsCertificate> trustedCertificates; 69 // Additional certificates which should be trusted. Default: none. 70 71 TlsVersion minVersion; 72 // Minimum version. Defaults to minimum version that hasn't been cryptographically broken. 73 // If you override this, consider doing: 74 // 75 // options.minVersion = kj::max(myVersion, options.minVersion); 76 77 kj::StringPtr cipherList; 78 // OpenSSL cipher list string. The default is a curated list designed to be compatible with 79 // almost all software in curent use (specifically, based on Mozilla's "intermediate" 80 // recommendations). The defaults will change in future versions of this library to account 81 // for the latest cryptanalysis. 82 // 83 // Generally you should only specify your own `cipherList` if: 84 // - You have extreme backwards-compatibility needs and wish to enable obsolete and/or broken 85 // algorithms. 86 // - You need quickly to disable an algorithm recently discovered to be broken. 87 88 kj::Maybe<const TlsKeypair&> defaultKeypair; 89 // Default keypair to use for all connections. Required for servers; optional for clients. 90 91 kj::Maybe<TlsSniCallback&> sniCallback; 92 // Callback that can be used to choose a different key/certificate based on the specific 93 // hostname requested by the client. 94 95 kj::Maybe<kj::Timer&> timer; 96 // The timer used for `acceptTimeout` below. 97 98 kj::Maybe<kj::Duration> acceptTimeout; 99 // Timeout applied to accepting a new TLS connection. `timer` is required if this is set. 100 }; 101 102 TlsContext(Options options = Options()); 103 ~TlsContext() noexcept(false); 104 KJ_DISALLOW_COPY(TlsContext); 105 106 kj::Promise<kj::Own<kj::AsyncIoStream>> wrapServer(kj::Own<kj::AsyncIoStream> stream); 107 // Upgrade a regular network stream to TLS and begin the initial handshake as the server. The 108 // returned promise resolves when the handshake has completed successfully. 109 110 kj::Promise<kj::Own<kj::AsyncIoStream>> wrapClient( 111 kj::Own<kj::AsyncIoStream> stream, kj::StringPtr expectedServerHostname); 112 // Upgrade a regular network stream to TLS and begin the initial handshake as a client. The 113 // returned promise resolves when the handshake has completed successfully, including validating 114 // the server's certificate. 115 // 116 // You must specify the server's hostname. This is used for two purposes: 117 // 1. It is sent to the server in the initial handshake via the TLS SNI extension, so that a 118 // server serving multiple hosts knows which certificate to use. 119 // 2. The server's certificate is validated against this hostname. If validation fails, the 120 // promise returned by wrapClient() will be broken; you'll never get a stream. 121 122 kj::Promise<kj::AuthenticatedStream> wrapServer(kj::AuthenticatedStream stream); 123 kj::Promise<kj::AuthenticatedStream> wrapClient( 124 kj::AuthenticatedStream stream, kj::StringPtr expectedServerHostname); 125 // Like wrapServer() and wrapClient(), but also produces information about the peer's 126 // certificate (if any). The returned `peerIdentity` will be a `TlsPeerIdentity`. 127 128 kj::Own<kj::ConnectionReceiver> wrapPort(kj::Own<kj::ConnectionReceiver> port); 129 // Upgrade a ConnectionReceiver to one that automatically upgrades all accepted connections to 130 // TLS (acting as the server). 131 132 kj::Own<kj::Network> wrapNetwork(kj::Network& network); 133 // Upgrade a Network to one that automatically upgrades all connections to TLS. The network will 134 // only accept addresses of the form "hostname" and "hostname:port" (it does not accept raw IP 135 // addresses). It will automatically use SNI and verify certificates based on these hostnames. 136 137 private: 138 void* ctx; // actually type SSL_CTX, but we don't want to #include the OpenSSL headers here 139 kj::Maybe<kj::Timer&> timer; 140 kj::Maybe<kj::Duration> acceptTimeout; 141 142 struct SniCallback; 143 }; 144 145 class TlsPrivateKey { 146 // A private key suitable for use in a TLS server. 147 148 public: 149 TlsPrivateKey(kj::ArrayPtr<const byte> asn1); 150 // Parse a single binary (ASN1) private key. Supports PKCS8 keys as well as "traditional format" 151 // RSA and DSA keys. Does not accept encrypted keys; it is the caller's responsibility to 152 // decrypt. 153 154 TlsPrivateKey(kj::StringPtr pem, kj::Maybe<kj::StringPtr> password = nullptr); 155 // Parse a single PEM-encoded private key. Supports PKCS8 keys as well as "traditional format" 156 // RSA and DSA keys. A password may optionally be provided and will be used if the key is 157 // encrypted. 158 159 ~TlsPrivateKey() noexcept(false); 160 161 TlsPrivateKey(const TlsPrivateKey& other); 162 TlsPrivateKey& operator=(const TlsPrivateKey& other); 163 // Copy-by-refcount. 164 165 inline TlsPrivateKey(TlsPrivateKey&& other): pkey(other.pkey) { other.pkey = nullptr; } 166 inline TlsPrivateKey& operator=(TlsPrivateKey&& other) { 167 pkey = other.pkey; other.pkey = nullptr; 168 return *this; 169 } 170 171 private: 172 void* pkey; // actually type EVP_PKEY* 173 174 friend class TlsContext; 175 176 static int passwordCallback(char* buf, int size, int rwflag, void* u); 177 }; 178 179 class TlsCertificate { 180 // A TLS certificate, possibly with chained intermediate certificates. 181 182 public: 183 TlsCertificate(kj::ArrayPtr<const byte> asn1); 184 // Parse a single binary (ASN1) X509 certificate. 185 186 TlsCertificate(kj::ArrayPtr<const kj::ArrayPtr<const byte>> asn1); 187 // Parse a chain of binary (ASN1) X509 certificates. 188 189 TlsCertificate(kj::StringPtr pem); 190 // Parse a PEM-encode X509 certificate or certificate chain. A chain can be constructed by 191 // concatenating multiple PEM-encoded certificates, starting with the leaf certificate. 192 193 ~TlsCertificate() noexcept(false); 194 195 TlsCertificate(const TlsCertificate& other); 196 TlsCertificate& operator=(const TlsCertificate& other); 197 // Copy-by-refcount. 198 199 inline TlsCertificate(TlsCertificate&& other) { 200 memcpy(chain, other.chain, sizeof(chain)); 201 memset(other.chain, 0, sizeof(chain)); 202 } 203 inline TlsCertificate& operator=(TlsCertificate&& other) { 204 memcpy(chain, other.chain, sizeof(chain)); 205 memset(other.chain, 0, sizeof(chain)); 206 return *this; 207 } 208 209 private: 210 void* chain[10]; 211 // Actually type X509*[10]. 212 // 213 // Note that OpenSSL has a default maximum cert chain length of 10. Although configurable at 214 // runtime, you'd actually have to convince the _peer_ to reconfigure, which is unlikely except 215 // in specific use cases. So to avoid excess allocations we just assume a max of 10 certs. 216 // 217 // If this proves to be a problem, we should maybe use STACK_OF(X509) here, but stacks are not 218 // refcounted -- the X509_chain_up_ref() function actually allocates a new stack and uprefs all 219 // the certs. 220 221 friend class TlsContext; 222 }; 223 224 struct TlsKeypair { 225 // A pair of a private key and a certificate, for use by a server. 226 227 TlsPrivateKey privateKey; 228 TlsCertificate certificate; 229 }; 230 231 class TlsSniCallback { 232 // Callback object to implement Server Name Indication, in which the server is able to decide 233 // what key and certificate to use based on the hostname that the client is requesting. 234 // 235 // TODO(someday): Currently this callback is synchronous, because the OpenSSL API seems to be 236 // synchronous. Other people (e.g. Node) have figured out how to do it asynchronously, but 237 // it's unclear to me if and how this is possible while using the OpenSSL APIs. It looks like 238 // Node may be manually parsing the ClientHello message rather than relying on OpenSSL. We 239 // could do that but it's too much work for today. 240 241 public: 242 virtual kj::Maybe<TlsKeypair> getKey(kj::StringPtr hostname) = 0; 243 // Get the key to use for `hostname`. Null return means use the default from 244 // TlsContext::Options::defaultKeypair. 245 }; 246 247 class TlsPeerIdentity final: public kj::PeerIdentity { 248 public: 249 KJ_DISALLOW_COPY(TlsPeerIdentity); 250 ~TlsPeerIdentity() noexcept(false); 251 252 kj::String toString() override; 253 254 kj::PeerIdentity& getNetworkIdentity() { return *inner; } 255 // Gets the PeerIdentity of the underlying network connection. 256 257 bool hasCertificate() { return cert != nullptr; } 258 // Did the peer even present a (trusted) certificate? Servers must always present certificates. 259 // Clients need only present certificates when the `verifyClients` option is enabled. 260 // 261 // Methods of this class that read details of the certificate will throw exceptions when no 262 // certificate was presented. We don't have them return `Maybe`s because most applications know 263 // in advance whether or not a certificate should be present, so it would lead to lots of 264 // `KJ_ASSERT_NONNULL`... 265 266 kj::String getCommonName(); 267 // Get the authenticated common name from the certificate. 268 269 bool matchesHostname(kj::StringPtr hostname); 270 // Check if the certificate authenticates the given hostname, considering wildcards and SAN 271 // extensions. If no certificate was provided, always returns false. 272 273 // TODO(someday): Methods for other things. Match hostnames (i.e. evaluate wildcards and SAN)? 274 // Key fingerprint? Other certificate fields? 275 276 private: 277 void* cert; // actually type X509*, but we don't want to #include the OpenSSL headers here. 278 kj::Own<kj::PeerIdentity> inner; 279 280 public: // (not really public, only TlsConnection can call this) 281 TlsPeerIdentity(void* cert, kj::Own<kj::PeerIdentity> inner, kj::Badge<TlsConnection>) 282 : cert(cert), inner(kj::mv(inner)) {} 283 }; 284 285 } // namespace kj