E-MailRelay
gssl_openssl.h
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2021 Graeme Walker <graeme_walker@users.sourceforge.net>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16// ===
17///
18/// \file gssl_openssl.h
19///
20
21#ifndef G_SSL_OPENSSL_H
22#define G_SSL_OPENSSL_H
23
24#include "gdef.h"
25#include "gssl.h"
26#include "gassert.h"
27#include <openssl/ssl.h>
28#include <openssl/err.h>
29#include <openssl/rand.h>
30#include <openssl/md5.h>
31#include <openssl/sha.h>
32#include <openssl/evp.h>
33#include <stdexcept>
34#include <functional>
35#include <map>
36#include <memory>
37
38// debugging...
39// * network logging
40// $ sudo tcpdump -s 0 -n -i eth0 -X tcp port 587
41// * emailrelay smtp proxy to gmail
42// $ emailrelay --client-tls --forward-to smtp.gmail.com:587 ...
43// * openssl smtp client to gmail
44// $ openssl s_client -tls1 -msg -debug -starttls smtp -crlf -connect smtp.gmail.com:587
45// * certificate
46// $ openssl req -x509 -nodes -subj /CN=example.com -newkey rsa:1024 -keyout example.pem -out example.pem
47// $ cp example.pem /etc/ssl/certs/
48// $ cd /etc/ssl/certs && ln -s example.pem `openssl x509 -noout -hash -in example.pem`.0
49// * openssl server (without smtp)
50// $ openssl s_server -accept 10025 -cert /etc/ssl/certs/example.pem -debug -msg -tls1
51//
52
53namespace GSsl
54{
55 namespace OpenSSL /// A namespace for implementing the GSsl interface using the OpenSSL library.
56 {
57 class Error ;
58 class Certificate ;
59 class CertificateChain ;
60 class LibraryImp ;
61 class ProfileImp ;
62 class ProtocolImp ;
63 class DigesterImp ;
64 class Config ;
65 }
66}
67
68//| \class GSsl::OpenSSL::Certificate
69/// Holds a certificate taken from an OpenSSL X509 structure.
70///
72{
73public:
74 Certificate( X509* , bool do_free ) ;
75 std::string str() const ;
76
77private:
78 std::string m_str ;
79} ;
80
81//| \class GSsl::OpenSSL::Config
82/// Holds protocol version information, etc.
83///
85{
86public:
87 using Fn = const SSL_METHOD *(*)() ;
88 explicit Config( G::StringArray & config ) ;
89 Fn fn( bool server ) ;
90 long set() const ;
91 long reset() const ;
92 int min_() const ;
93 int max_() const ;
94 bool noverify() const ;
95
96private:
97 static bool consume( G::StringArray & , const std::string & ) ;
98 static int map( int , int ) ;
99
100private:
101 Fn m_server_fn ;
102 Fn m_client_fn ;
103 int m_min ;
104 int m_max ;
105 long m_options_set ;
106 long m_options_reset ;
107 bool m_noverify ;
108} ;
109
110//| \class GSsl::OpenSSL::CertificateChain
111/// Holds a certificate chain taken from a stack of OpenSSL X509 structures.
112///
114{
115public:
116 explicit CertificateChain( STACK_OF(X509) * chain ) ;
117 std::string str() const ;
118
119private:
120 std::string m_str ;
121} ;
122
123//| \class GSsl::OpenSSL::Error
124/// An exception class for GSsl::OpenSSL classes.
125///
126class GSsl::OpenSSL::Error : public std::runtime_error
127{
128public:
129 explicit Error( const std::string & ) ;
130 Error( const std::string & , unsigned long ) ;
131 Error( const std::string & , unsigned long , const std::string & path ) ;
132 static void clearErrors() ;
133
134private:
135 static std::string text( unsigned long ) ;
136} ;
137
138//| \class GSsl::OpenSSL::ProfileImp
139/// An implementation of the GSsl::Profile interface for OpenSSL.
140///
142{
143public:
144 using Error = OpenSSL::Error ;
145
146 ProfileImp( const LibraryImp & , bool is_server_profile , const std::string & key_file ,
147 const std::string & cert_file , const std::string & ca_file ,
148 const std::string & default_peer_certificate_name , const std::string & default_peer_host_name ,
149 const std::string & profile_config ) ;
150 ~ProfileImp() override ;
151 SSL_CTX * p() const ;
152 const LibraryImp & lib() const ;
153 const std::string & defaultPeerCertificateName() const ;
154 const std::string & defaultPeerHostName() const ;
155 void apply( const Config & ) ;
156
157private: // overrides
158 std::unique_ptr<ProtocolImpBase> newProtocol( const std::string & , const std::string & ) const override ;
159
160public:
161 ProfileImp( const ProfileImp & ) = delete ;
162 ProfileImp( ProfileImp && ) = delete ;
163 void operator=( const ProfileImp & ) = delete ;
164 void operator=( ProfileImp && ) = delete ;
165
166private:
167 static void check( int , const std::string & , const std::string & = std::string() ) ;
168 static int verifyPass( int , X509_STORE_CTX * ) ;
169 static int verifyPeerName( int , X509_STORE_CTX * ) ;
170 static std::string name( X509_NAME * ) ;
171 static void deleter( SSL_CTX * ) ;
172
173private:
174 const LibraryImp & m_library_imp ;
175 const std::string m_default_peer_certificate_name ;
176 const std::string m_default_peer_host_name ;
177 std::unique_ptr<SSL_CTX,std::function<void(SSL_CTX*)>> m_ssl_ctx ;
178} ;
179
180//| \class GSsl::OpenSSL::LibraryImp
181/// An implementation of the GSsl::LibraryImpBase interface for OpenSSL.
182///
184{
185public:
187
188 LibraryImp( G::StringArray & library_config , Library::LogFn , bool verbose ) ;
189 ~LibraryImp() override ;
190 Config config() const ;
191 bool noverify() const ;
192
193 Library::LogFn log() const ;
194 bool verbose() const ;
195 int index() const ;
196 static std::string credit( const std::string & prefix , const std::string & eol , const std::string & eot ) ;
197 static std::string sid() ;
198
199private: // overrides
200 void addProfile( const std::string & name , bool is_server_profile ,
201 const std::string & key_file , const std::string & cert_file , const std::string & ca_file ,
202 const std::string & default_peer_certificate_name , const std::string & default_peer_host_name ,
203 const std::string & profile_config ) override ;
204 bool hasProfile( const std::string & ) const override ;
205 const GSsl::Profile & profile( const std::string & ) const override ;
206 std::string id() const override ;
207 bool generateKeyAvailable() const override ;
208 std::string generateKey( const std::string & ) const override ;
209 G::StringArray digesters( bool ) const override ;
210 Digester digester( const std::string & , const std::string & , bool ) const override ;
211
212public:
213 LibraryImp( const LibraryImp & ) = delete ;
214 LibraryImp( LibraryImp && ) = delete ;
215 void operator=( const LibraryImp & ) = delete ;
216 void operator=( LibraryImp && ) = delete ;
217
218private:
219 static void cleanup() ;
220
221private:
222 using Map = std::map<std::string,std::shared_ptr<ProfileImp>> ;
223 std::string m_library_config ;
224 Library::LogFn m_log_fn ;
225 bool m_verbose ;
226 Map m_profile_map ;
227 int m_index ; // SSL_get_ex_new_index()
228 Config m_config ;
229} ;
230
231//| \class GSsl::OpenSSL::ProtocolImp
232/// An implementation of the GSsl::ProtocolImpBase interface for OpenSSL.
233///
235{
236public:
237 using Result = Protocol::Result ;
238 using Error = OpenSSL::Error ;
241
242 ProtocolImp( const ProfileImp & , const std::string & , const std::string & ) ;
243 ~ProtocolImp() override ;
244 std::string requiredPeerCertificateName() const ;
245
246private: // overrides
247 Result connect( G::ReadWrite & ) override ;
248 Result accept( G::ReadWrite & ) override ;
249 Result shutdown() override ;
250 Result read( char * buffer , std::size_t buffer_size , ssize_t & read_size ) override ;
251 Result write( const char * buffer , std::size_t size_in , ssize_t & size_out ) override ;
252 std::string peerCertificate() const override ;
253 std::string peerCertificateChain() const override ;
254 std::string protocol() const override ;
255 std::string cipher() const override ;
256 bool verified() const override ;
257
258public:
259 ProtocolImp( const ProtocolImp & ) = delete ;
260 ProtocolImp( ProtocolImp && ) = delete ;
261 void operator=( const ProtocolImp & ) = delete ;
262 void operator=( ProtocolImp && ) = delete ;
263
264private:
265 int error( const char * , int ) const ;
266 void set( int ) ;
267 Result connect() ;
268 Result accept() ;
269 static Result convert( int ) ;
270 static void clearErrors() ;
271 void logErrors( const std::string & op , int rc , int e , const std::string & ) const ;
272 void saveResult() ;
273 static void deleter( SSL * ) ;
274
275private:
276 std::unique_ptr<SSL,std::function<void(SSL*)>> m_ssl ;
277 Library::LogFn m_log_fn ;
278 bool m_verbose ;
279 bool m_fd_set ;
280 std::string m_required_peer_certificate_name ;
281 std::string m_peer_certificate ;
282 std::string m_peer_certificate_chain ;
283 bool m_verified ;
284} ;
285
286//| \class GSsl::OpenSSL::DigesterImp
287/// An implementation of the GSsl::DigesterImpBase interface for OpenSSL.
288///
290{
291public:
292 DigesterImp( const std::string & , const std::string & , bool ) ;
293 ~DigesterImp() override ;
294
295private: // overrides
296 void add( const std::string & ) override ;
297 std::string value() override ;
298 std::string state() override ;
299 std::size_t blocksize() const override ;
300 std::size_t valuesize() const override ;
301 std::size_t statesize() const override ;
302
303public:
304 DigesterImp( const DigesterImp & ) = delete ;
305 DigesterImp( DigesterImp && ) = delete ;
306 void operator=( const DigesterImp & ) = delete ;
307 void operator=( DigesterImp && ) = delete ;
308
309private:
310 enum class Type { Md5 , Sha1 , Sha256 , Other } ;
311 Type m_hash_type ;
312 MD5_CTX m_md5 {} ;
313 SHA_CTX m_sha1 {} ;
314 SHA256_CTX m_sha256 {} ;
315 EVP_MD_CTX * m_evp_ctx ;
316 std::size_t m_block_size {0} ;
317 std::size_t m_value_size {0} ;
318 std::size_t m_state_size {0} ;
319} ;
320
321#endif
A base interface for GSsl::Digester pimple classes.
Definition: gssl.h:483
A class for objects that can perform a cryptographic hash.
Definition: gssl.h:213
A base interface for GSsl::Library pimple classes.
Definition: gssl.h:390
Holds a certificate chain taken from a stack of OpenSSL X509 structures.
Definition: gssl_openssl.h:114
Holds a certificate taken from an OpenSSL X509 structure.
Definition: gssl_openssl.h:72
Holds protocol version information, etc.
Definition: gssl_openssl.h:85
An implementation of the GSsl::DigesterImpBase interface for OpenSSL.
Definition: gssl_openssl.h:290
An exception class for GSsl::OpenSSL classes.
Definition: gssl_openssl.h:127
An implementation of the GSsl::LibraryImpBase interface for OpenSSL.
Definition: gssl_openssl.h:184
An implementation of the GSsl::Profile interface for OpenSSL.
Definition: gssl_openssl.h:142
An implementation of the GSsl::ProtocolImpBase interface for OpenSSL.
Definition: gssl_openssl.h:235
A base interface for profile classes that work with concrete classes derived from GSsl::LibraryImpBas...
Definition: gssl.h:430
A base interface for GSsl::Protocol pimple classes.
Definition: gssl.h:443
An abstract interface for reading and writing from a non-blocking i/o channel.
Definition: greadwrite.h:50
An interface to an underlying TLS library.
TLS/SSL transport layer security classes.
Definition: gssl.h:34
std::vector< std::string > StringArray
A std::vector of std::strings.
Definition: gstrings.h:31