forked from ravinet/mahimahi
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsecure_socket.cc
112 lines (90 loc) · 3.79 KB
/
secure_socket.cc
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
/* -*-mode:c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include "secure_socket.hh"
#include "certificate.hh"
#include <fstream>
#include <string>
#include <iostream>
#include <cassert>
using namespace std;
SecureSocket::SecureSocket( Socket && sock, SSL_MODE type )
: underlying_socket( move( sock ) ),
ctx(),
ssl_connection(),
mode( type )
{
/* create client/server supporting TLS version 1 */
if ( mode == CLIENT ) { /* client */
ctx = SSL_CTX_new( TLSv1_client_method() );
} else { /* server */
ctx = SSL_CTX_new( TLSv1_server_method() );
if ( SSL_CTX_use_certificate_ASN1( ctx, 678, certificate ) < 1 ) {
throw Exception( "SSL_CTX_use_certificate_ASN1", ERR_error_string( ERR_get_error(), nullptr ) );
}
if ( SSL_CTX_use_RSAPrivateKey_ASN1( ctx, private_key, 1191 ) < 1 ) {
throw Exception( "SSL_CTX_use_RSAPrivateKey_ASN1", ERR_error_string( ERR_get_error(), nullptr ) );
}
/* check consistency of private key with loaded certificate */
if ( SSL_CTX_check_private_key( ctx ) < 1 ) {
throw Exception( "SSL_CTX_check_private_key", ERR_error_string( ERR_get_error(), nullptr ) );
}
}
if ( ctx == NULL ) {
throw Exception( "SSL_CTX_new", ERR_error_string( ERR_get_error(), nullptr ) );
}
if ( (ssl_connection = SSL_new( ctx ) ) == NULL ) {
throw Exception( "SSL_new", ERR_error_string( ERR_get_error(), nullptr ) );
}
if ( SSL_set_fd( ssl_connection, underlying_socket.fd().num() ) < 1 ) {
throw Exception( "SSL_set_fd", ERR_error_string( ERR_get_error(), nullptr ) );
}
/* enable read/write to return only after handshake/renegotiation and successful completion */
SSL_set_mode( ssl_connection, SSL_MODE_AUTO_RETRY );
handshake();
}
void SecureSocket::handshake( void )
{
if ( mode == CLIENT ) { /* client-initiate handshake */
if ( SSL_connect( ssl_connection ) < 1 ) {
throw Exception( "SSL_connect", ERR_error_string( ERR_get_error(), nullptr ) );
}
} else { /* server-finish handshake */
if ( SSL_accept( ssl_connection ) < 1 ) {
throw Exception( "SSL_accept", ERR_error_string( ERR_get_error(), nullptr ) );
}
}
}
void SecureSocket::check_server_certificate( void )
{
X509 *server_certificate;
server_certificate = SSL_get_peer_certificate( ssl_connection );
if ( SSL_get_verify_result( ssl_connection ) == X509_V_OK ) { /* verification succeeded of no certificate presented */
X509_free( server_certificate );
} else { /* verification failed */
throw Exception( "SSL_get_verify_result", ERR_error_string( SSL_get_verify_result( ssl_connection ), nullptr ) );
}
}
string SecureSocket::read( void )
{
/* SSL record max size is 16kB */
const size_t SSL_max_record_length = 16384;
char buffer[ SSL_max_record_length ];
ssize_t bytes_read = SSL_read( ssl_connection, &buffer, SSL_max_record_length );
/* Make sure that we really are reading from the underlying fd */
assert( 0 == SSL_pending( ssl_connection ) );
if ( bytes_read == 0 ) {
return string(); /* EOF */
} else if ( bytes_read < 0 ) {
throw Exception( "SSL_read", ERR_error_string( SSL_get_error( ssl_connection, bytes_read ), nullptr ) );
} else {
/* success */
return string( buffer, bytes_read );
}
}
void SecureSocket::write(const string & message )
{
/* SSL_write returns with success if complete contents of message are written */
ssize_t bytes_written = SSL_write( ssl_connection, message.c_str(), message.length() );
if ( bytes_written < 0 ) {
throw Exception( "SSL_write", ERR_error_string( SSL_get_error( ssl_connection, bytes_written ), nullptr ) );
}
}