Skip to content

Commit cb7966c

Browse files
committed
Added TLS API, and an mbedTLS-based implementation
1 parent 7fefb21 commit cb7966c

File tree

5 files changed

+1097
-2
lines changed

5 files changed

+1097
-2
lines changed

include/sockpp/mbedtls_context.h

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/**
2+
* @file mbedtls_socket.h
3+
*
4+
* TLS (SSL) socket implementation using mbedTLS.
5+
*
6+
* @author Jens Alfke
7+
* @author Couchbase, Inc.
8+
* @author www.couchbase.com
9+
*
10+
* @date August 2019
11+
*/
12+
13+
// --------------------------------------------------------------------------
14+
// This file is part of the "sockpp" C++ socket library.
15+
//
16+
// Copyright (c) 2014-2019 Frank Pagliughi
17+
// All rights reserved.
18+
//
19+
// Redistribution and use in source and binary forms, with or without
20+
// modification, are permitted provided that the following conditions are
21+
// met:
22+
//
23+
// 1. Redistributions of source code must retain the above copyright notice,
24+
// this list of conditions and the following disclaimer.
25+
//
26+
// 2. Redistributions in binary form must reproduce the above copyright
27+
// notice, this list of conditions and the following disclaimer in the
28+
// documentation and/or other materials provided with the distribution.
29+
//
30+
// 3. Neither the name of the copyright holder nor the names of its
31+
// contributors may be used to endorse or promote products derived from this
32+
// software without specific prior written permission.
33+
//
34+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
35+
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
36+
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
37+
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
38+
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
39+
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
40+
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
41+
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
42+
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
43+
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
44+
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45+
// --------------------------------------------------------------------------
46+
47+
#ifndef __sockpp_mbedtls_socket_h
48+
#define __sockpp_mbedtls_socket_h
49+
50+
#include "sockpp/tls_context.h"
51+
#include "sockpp/tls_socket.h"
52+
#include <memory>
53+
#include <string>
54+
55+
struct mbedtls_pk_context;
56+
struct mbedtls_ssl_config;
57+
struct mbedtls_x509_crt;
58+
59+
namespace sockpp {
60+
61+
/**
62+
* A concrete implementation of \ref tls_context, using the mbedTLS library.
63+
* You probably don't want to use this class directly, unless you want to instantiate a
64+
* custom context so you can have different contexts for different sockets.
65+
*/
66+
class mbedtls_context : public tls_context {
67+
public:
68+
mbedtls_context(role_t = CLIENT);
69+
~mbedtls_context() override;
70+
71+
void set_root_certs(const std::string &certData) override;
72+
void allow_invalid_peer_certs(bool) override;
73+
void allow_only_certificate(const std::string &certData) override;
74+
75+
void allow_only_certificate(mbedtls_x509_crt *certificate);
76+
77+
/**
78+
* Sets the identity certificate and private key using mbedTLS objects.
79+
*/
80+
void set_identity(mbedtls_x509_crt *certificate, mbedtls_pk_context *private_key);
81+
82+
void set_identity(const std::string &certificate_data,
83+
const std::string &private_key_data) override;
84+
85+
void set_identity_files(const std::string &certificate_file,
86+
const std::string &private_key_file,
87+
const std::string &private_key_password) override;
88+
89+
std::unique_ptr<tls_socket> wrap_socket(std::unique_ptr<stream_socket> socket,
90+
role_t,
91+
const std::string &peer_name) override;
92+
93+
role_t role();
94+
95+
static mbedtls_x509_crt* get_system_root_certs();
96+
97+
private:
98+
struct cert;
99+
100+
int verify_callback(mbedtls_x509_crt *crt, int depth, uint32_t *flags);
101+
static std::unique_ptr<cert> parse_cert(const std::string &cert_data);
102+
103+
std::unique_ptr<mbedtls_ssl_config> ssl_config_;
104+
std::unique_ptr<cert> root_certs_;
105+
std::unique_ptr<cert> pinned_cert_;
106+
107+
static cert *s_system_root_certs;
108+
109+
friend class mbedtls_socket;
110+
};
111+
112+
}
113+
114+
#endif

include/sockpp/socket.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ class socket
416416
* @param on Whether to turn non-blocking mode on or off.
417417
* @return @em true on success, @em false on failure.
418418
*/
419-
bool set_non_blocking(bool on=true);
419+
virtual bool set_non_blocking(bool on=true);
420420
/**
421421
* Gets a string describing the specified error.
422422
* This is typically the returned message from the system strerror().
@@ -446,7 +446,7 @@ class socket
446446
* @li SHUT_RDWR (2) Further reads and writes disallowed.
447447
* @return @em true on success, @em false on error.
448448
*/
449-
bool shutdown(int how=SHUT_RDWR);
449+
virtual bool shutdown(int how=SHUT_RDWR);
450450
/**
451451
* Closes the socket.
452452
* After closing the socket, the handle is @em invalid, and can not be

include/sockpp/tls_context.h

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
/**
2+
* @file tls_context.h
3+
*
4+
* Context object for TLS (SSL) sockets.
5+
*
6+
* @author Jens Alfke
7+
* @author Couchbase, Inc.
8+
* @author www.couchbase.com
9+
*
10+
* @date August 2019
11+
*/
12+
13+
// --------------------------------------------------------------------------
14+
// This file is part of the "sockpp" C++ socket library.
15+
//
16+
// Copyright (c) 2014-2019 Frank Pagliughi
17+
// All rights reserved.
18+
//
19+
// Redistribution and use in source and binary forms, with or without
20+
// modification, are permitted provided that the following conditions are
21+
// met:
22+
//
23+
// 1. Redistributions of source code must retain the above copyright notice,
24+
// this list of conditions and the following disclaimer.
25+
//
26+
// 2. Redistributions in binary form must reproduce the above copyright
27+
// notice, this list of conditions and the following disclaimer in the
28+
// documentation and/or other materials provided with the distribution.
29+
//
30+
// 3. Neither the name of the copyright holder nor the names of its
31+
// contributors may be used to endorse or promote products derived from this
32+
// software without specific prior written permission.
33+
//
34+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
35+
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
36+
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
37+
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
38+
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
39+
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
40+
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
41+
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
42+
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
43+
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
44+
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45+
// --------------------------------------------------------------------------
46+
47+
#ifndef __sockpp_tls_context_h
48+
#define __sockpp_tls_context_h
49+
50+
#include "sockpp/platform.h"
51+
#include <memory>
52+
#include <string>
53+
54+
namespace sockpp {
55+
class connector;
56+
class stream_socket;
57+
class tls_socket;
58+
59+
/**
60+
* Context / configuration for TLS (SSL) connections; also acts as a factory for
61+
* \ref tls_socket objects.
62+
*
63+
* A single context can be shared by any number of \ref tls_socket instances.
64+
* A context must remain in scope as long as any socket using it remains in scope.
65+
*/
66+
class tls_context
67+
{
68+
public:
69+
enum role_t {
70+
CLIENT = 0,
71+
SERVER = 1
72+
};
73+
/**
74+
* A singleton context that can be used if you don't need any per-connection
75+
* configuration.
76+
*/
77+
static tls_context& default_context();
78+
79+
virtual ~tls_context() =default;
80+
81+
/**
82+
* Tells whether the context is initialized and valid. Check this after constructing
83+
* an instance and do not use if not valid.
84+
* @return Zero if valid, a nonzero error code if initialization failed.
85+
* The code may be a POSIX code, or one specific to the TLS library.
86+
*/
87+
int status() const {
88+
return status_;
89+
}
90+
91+
operator bool() const {
92+
return status_ == 0;
93+
}
94+
95+
/**
96+
* Overrides the set of trusted root certificates used for validation.
97+
*/
98+
virtual void set_root_certs(const std::string &certData) =0;
99+
100+
/**
101+
* Allows connections to peers whose X.509 certificates are not valid.
102+
* **If enabled, you take responsibility for validating the certificate yourself!**
103+
* @param allow Pass true to allow invalid certs to be used, false to disallow
104+
* (default is false.)
105+
*/
106+
virtual void allow_invalid_peer_certs(bool allow) =0;
107+
108+
/**
109+
* Requires that the peer have the exact certificate given.
110+
* This is known as "cert-pinning". It's more secure, but requires that the client
111+
* update its copy of the certificate whenever the server updates it.
112+
* @param certData The X.509 certificate in DER or PEM form; or an empty string for
113+
* no pinning (the default).
114+
*/
115+
virtual void allow_only_certificate(const std::string &certData) =0;
116+
117+
virtual void set_identity(const std::string &certificate_data,
118+
const std::string &private_key_data) =0;
119+
120+
virtual void set_identity_files(const std::string &certificate_file,
121+
const std::string &private_key_file,
122+
const std::string &private_key_password) =0;
123+
124+
/**
125+
* Creates a new \ref tls_socket instance that wraps the given connector socket.
126+
* The \ref tls_socket takes ownership of the base socket and will close it when
127+
* it's closed.
128+
* When this method returns, the TLS handshake will already have completed;
129+
* be sure to check the stream's status, since the handshake may have failed.
130+
* @param socket The underlying connector socket that TLS will use for I/O.
131+
* @param role CLIENT or SERVER mode.
132+
* @param peer_name The peer's canonical hostname, or other distinguished name,
133+
* to be used for certificate validation.
134+
* @return A new \ref tls_socket to use for secure I/O.
135+
*/
136+
virtual std::unique_ptr<tls_socket> wrap_socket(std::unique_ptr<stream_socket> socket,
137+
role_t role,
138+
const std::string &peer_name) =0;
139+
140+
protected:
141+
tls_context() =default;
142+
143+
/**
144+
* Sets the error status of the context. Call this if initialization fails.
145+
*/
146+
void set_status(int s) const {
147+
status_ = s;
148+
}
149+
150+
private:
151+
tls_context(const tls_context&) =delete;
152+
153+
mutable int status_ =0;
154+
};
155+
156+
}
157+
158+
#endif

0 commit comments

Comments
 (0)