xref: /dragonfly/contrib/libpcap/sslutils.c (revision ea16f64e)
1*ea16f64eSAntonio Huete Jimenez /*
2*ea16f64eSAntonio Huete Jimenez  * Copyright (c) 2002 - 2003
3*ea16f64eSAntonio Huete Jimenez  * NetGroup, Politecnico di Torino (Italy)
4*ea16f64eSAntonio Huete Jimenez  * All rights reserved.
5*ea16f64eSAntonio Huete Jimenez  *
6*ea16f64eSAntonio Huete Jimenez  * Redistribution and use in source and binary forms, with or without
7*ea16f64eSAntonio Huete Jimenez  * modification, are permitted provided that the following conditions
8*ea16f64eSAntonio Huete Jimenez  * are met:
9*ea16f64eSAntonio Huete Jimenez  *
10*ea16f64eSAntonio Huete Jimenez  * 1. Redistributions of source code must retain the above copyright
11*ea16f64eSAntonio Huete Jimenez  * notice, this list of conditions and the following disclaimer.
12*ea16f64eSAntonio Huete Jimenez  * 2. Redistributions in binary form must reproduce the above copyright
13*ea16f64eSAntonio Huete Jimenez  * notice, this list of conditions and the following disclaimer in the
14*ea16f64eSAntonio Huete Jimenez  * documentation and/or other materials provided with the distribution.
15*ea16f64eSAntonio Huete Jimenez  * 3. Neither the name of the Politecnico di Torino nor the names of its
16*ea16f64eSAntonio Huete Jimenez  * contributors may be used to endorse or promote products derived from
17*ea16f64eSAntonio Huete Jimenez  * this software without specific prior written permission.
18*ea16f64eSAntonio Huete Jimenez  *
19*ea16f64eSAntonio Huete Jimenez  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20*ea16f64eSAntonio Huete Jimenez  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21*ea16f64eSAntonio Huete Jimenez  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22*ea16f64eSAntonio Huete Jimenez  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23*ea16f64eSAntonio Huete Jimenez  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24*ea16f64eSAntonio Huete Jimenez  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25*ea16f64eSAntonio Huete Jimenez  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26*ea16f64eSAntonio Huete Jimenez  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27*ea16f64eSAntonio Huete Jimenez  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28*ea16f64eSAntonio Huete Jimenez  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29*ea16f64eSAntonio Huete Jimenez  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30*ea16f64eSAntonio Huete Jimenez  *
31*ea16f64eSAntonio Huete Jimenez  */
32*ea16f64eSAntonio Huete Jimenez 
33*ea16f64eSAntonio Huete Jimenez #ifdef HAVE_CONFIG_H
34*ea16f64eSAntonio Huete Jimenez #include <config.h>
35*ea16f64eSAntonio Huete Jimenez #endif
36*ea16f64eSAntonio Huete Jimenez 
37*ea16f64eSAntonio Huete Jimenez #ifdef HAVE_OPENSSL
38*ea16f64eSAntonio Huete Jimenez #include <stdlib.h>
39*ea16f64eSAntonio Huete Jimenez 
40*ea16f64eSAntonio Huete Jimenez #include "portability.h"
41*ea16f64eSAntonio Huete Jimenez 
42*ea16f64eSAntonio Huete Jimenez #include "sslutils.h"
43*ea16f64eSAntonio Huete Jimenez 
44*ea16f64eSAntonio Huete Jimenez static const char *ssl_keyfile = "";   //!< file containing the private key in PEM format
45*ea16f64eSAntonio Huete Jimenez static const char *ssl_certfile = "";  //!< file containing the server's certificate in PEM format
46*ea16f64eSAntonio Huete Jimenez static const char *ssl_rootfile = "";  //!< file containing the list of CAs trusted by the client
47*ea16f64eSAntonio Huete Jimenez // TODO: a way to set ssl_rootfile from the command line, or an envvar?
48*ea16f64eSAntonio Huete Jimenez 
49*ea16f64eSAntonio Huete Jimenez // TODO: lock?
50*ea16f64eSAntonio Huete Jimenez static SSL_CTX *ctx;
51*ea16f64eSAntonio Huete Jimenez 
ssl_set_certfile(const char * certfile)52*ea16f64eSAntonio Huete Jimenez void ssl_set_certfile(const char *certfile)
53*ea16f64eSAntonio Huete Jimenez {
54*ea16f64eSAntonio Huete Jimenez 	ssl_certfile = certfile;
55*ea16f64eSAntonio Huete Jimenez }
56*ea16f64eSAntonio Huete Jimenez 
ssl_set_keyfile(const char * keyfile)57*ea16f64eSAntonio Huete Jimenez void ssl_set_keyfile(const char *keyfile)
58*ea16f64eSAntonio Huete Jimenez {
59*ea16f64eSAntonio Huete Jimenez 	ssl_keyfile = keyfile;
60*ea16f64eSAntonio Huete Jimenez }
61*ea16f64eSAntonio Huete Jimenez 
ssl_init_once(int is_server,int enable_compression,char * errbuf,size_t errbuflen)62*ea16f64eSAntonio Huete Jimenez int ssl_init_once(int is_server, int enable_compression, char *errbuf, size_t errbuflen)
63*ea16f64eSAntonio Huete Jimenez {
64*ea16f64eSAntonio Huete Jimenez 	static int inited = 0;
65*ea16f64eSAntonio Huete Jimenez 	if (inited) return 0;
66*ea16f64eSAntonio Huete Jimenez 
67*ea16f64eSAntonio Huete Jimenez 	SSL_library_init();
68*ea16f64eSAntonio Huete Jimenez 	SSL_load_error_strings();
69*ea16f64eSAntonio Huete Jimenez 	OpenSSL_add_ssl_algorithms();
70*ea16f64eSAntonio Huete Jimenez 	if (enable_compression)
71*ea16f64eSAntonio Huete Jimenez 		SSL_COMP_get_compression_methods();
72*ea16f64eSAntonio Huete Jimenez 
73*ea16f64eSAntonio Huete Jimenez 	SSL_METHOD const *meth =
74*ea16f64eSAntonio Huete Jimenez 	    is_server ? SSLv23_server_method() : SSLv23_client_method();
75*ea16f64eSAntonio Huete Jimenez 	ctx = SSL_CTX_new(meth);
76*ea16f64eSAntonio Huete Jimenez 	if (! ctx)
77*ea16f64eSAntonio Huete Jimenez 	{
78*ea16f64eSAntonio Huete Jimenez 		snprintf(errbuf, errbuflen, "Cannot get a new SSL context: %s", ERR_error_string(ERR_get_error(), NULL));
79*ea16f64eSAntonio Huete Jimenez 		goto die;
80*ea16f64eSAntonio Huete Jimenez 	}
81*ea16f64eSAntonio Huete Jimenez 
82*ea16f64eSAntonio Huete Jimenez 	SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
83*ea16f64eSAntonio Huete Jimenez 
84*ea16f64eSAntonio Huete Jimenez 	if (is_server)
85*ea16f64eSAntonio Huete Jimenez 	{
86*ea16f64eSAntonio Huete Jimenez 		char const *certfile = ssl_certfile[0] ? ssl_certfile : "cert.pem";
87*ea16f64eSAntonio Huete Jimenez 		if (1 != SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM))
88*ea16f64eSAntonio Huete Jimenez 		{
89*ea16f64eSAntonio Huete Jimenez 			snprintf(errbuf, errbuflen, "Cannot read certificate file %s: %s", certfile, ERR_error_string(ERR_get_error(), NULL));
90*ea16f64eSAntonio Huete Jimenez 			goto die;
91*ea16f64eSAntonio Huete Jimenez 		}
92*ea16f64eSAntonio Huete Jimenez 
93*ea16f64eSAntonio Huete Jimenez 		char const *keyfile = ssl_keyfile[0] ? ssl_keyfile : "key.pem";
94*ea16f64eSAntonio Huete Jimenez 		if (1 != SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM))
95*ea16f64eSAntonio Huete Jimenez 		{
96*ea16f64eSAntonio Huete Jimenez 			snprintf(errbuf, errbuflen, "Cannot read private key file %s: %s", keyfile, ERR_error_string(ERR_get_error(), NULL));
97*ea16f64eSAntonio Huete Jimenez 			goto die;
98*ea16f64eSAntonio Huete Jimenez 		}
99*ea16f64eSAntonio Huete Jimenez 	}
100*ea16f64eSAntonio Huete Jimenez 	else
101*ea16f64eSAntonio Huete Jimenez 	{
102*ea16f64eSAntonio Huete Jimenez 		if (ssl_rootfile[0])
103*ea16f64eSAntonio Huete Jimenez 		{
104*ea16f64eSAntonio Huete Jimenez 			if (! SSL_CTX_load_verify_locations(ctx, ssl_rootfile, 0))
105*ea16f64eSAntonio Huete Jimenez 			{
106*ea16f64eSAntonio Huete Jimenez 				snprintf(errbuf, errbuflen, "Cannot read CA list from %s", ssl_rootfile);
107*ea16f64eSAntonio Huete Jimenez 				goto die;
108*ea16f64eSAntonio Huete Jimenez 			}
109*ea16f64eSAntonio Huete Jimenez 		}
110*ea16f64eSAntonio Huete Jimenez 		else
111*ea16f64eSAntonio Huete Jimenez 		{
112*ea16f64eSAntonio Huete Jimenez 			SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
113*ea16f64eSAntonio Huete Jimenez 		}
114*ea16f64eSAntonio Huete Jimenez 	}
115*ea16f64eSAntonio Huete Jimenez 
116*ea16f64eSAntonio Huete Jimenez #if 0
117*ea16f64eSAntonio Huete Jimenez 	if (! RAND_load_file(RANDOM, 1024*1024))
118*ea16f64eSAntonio Huete Jimenez 	{
119*ea16f64eSAntonio Huete Jimenez 		snprintf(errbuf, errbuflen, "Cannot init random");
120*ea16f64eSAntonio Huete Jimenez 		goto die;
121*ea16f64eSAntonio Huete Jimenez 	}
122*ea16f64eSAntonio Huete Jimenez 
123*ea16f64eSAntonio Huete Jimenez 	if (is_server)
124*ea16f64eSAntonio Huete Jimenez 	{
125*ea16f64eSAntonio Huete Jimenez 		SSL_CTX_set_session_id_context(ctx, (void *)&s_server_session_id_context, sizeof(s_server_session_id_context));
126*ea16f64eSAntonio Huete Jimenez 	}
127*ea16f64eSAntonio Huete Jimenez #endif
128*ea16f64eSAntonio Huete Jimenez 
129*ea16f64eSAntonio Huete Jimenez 	inited = 1;
130*ea16f64eSAntonio Huete Jimenez 	return 0;
131*ea16f64eSAntonio Huete Jimenez 
132*ea16f64eSAntonio Huete Jimenez die:
133*ea16f64eSAntonio Huete Jimenez 	return -1;
134*ea16f64eSAntonio Huete Jimenez }
135*ea16f64eSAntonio Huete Jimenez 
ssl_promotion(int is_server,SOCKET s,char * errbuf,size_t errbuflen)136*ea16f64eSAntonio Huete Jimenez SSL *ssl_promotion(int is_server, SOCKET s, char *errbuf, size_t errbuflen)
137*ea16f64eSAntonio Huete Jimenez {
138*ea16f64eSAntonio Huete Jimenez 	if (ssl_init_once(is_server, 1, errbuf, errbuflen) < 0) {
139*ea16f64eSAntonio Huete Jimenez 		return NULL;
140*ea16f64eSAntonio Huete Jimenez 	}
141*ea16f64eSAntonio Huete Jimenez 
142*ea16f64eSAntonio Huete Jimenez 	SSL *ssl = SSL_new(ctx); // TODO: also a DTLS context
143*ea16f64eSAntonio Huete Jimenez 	SSL_set_fd(ssl, (int)s);
144*ea16f64eSAntonio Huete Jimenez 
145*ea16f64eSAntonio Huete Jimenez 	if (is_server) {
146*ea16f64eSAntonio Huete Jimenez 		if (SSL_accept(ssl) <= 0) {
147*ea16f64eSAntonio Huete Jimenez 			snprintf(errbuf, errbuflen, "SSL_accept(): %s",
148*ea16f64eSAntonio Huete Jimenez 					ERR_error_string(ERR_get_error(), NULL));
149*ea16f64eSAntonio Huete Jimenez 			return NULL;
150*ea16f64eSAntonio Huete Jimenez 		}
151*ea16f64eSAntonio Huete Jimenez 	} else {
152*ea16f64eSAntonio Huete Jimenez 		if (SSL_connect(ssl) <= 0) {
153*ea16f64eSAntonio Huete Jimenez 			snprintf(errbuf, errbuflen, "SSL_connect(): %s",
154*ea16f64eSAntonio Huete Jimenez 					ERR_error_string(ERR_get_error(), NULL));
155*ea16f64eSAntonio Huete Jimenez 			return NULL;
156*ea16f64eSAntonio Huete Jimenez 		}
157*ea16f64eSAntonio Huete Jimenez 	}
158*ea16f64eSAntonio Huete Jimenez 
159*ea16f64eSAntonio Huete Jimenez 	return ssl;
160*ea16f64eSAntonio Huete Jimenez }
161*ea16f64eSAntonio Huete Jimenez 
162*ea16f64eSAntonio Huete Jimenez // Finish using an SSL handle; shut down the connection and free the
163*ea16f64eSAntonio Huete Jimenez // handle.
ssl_finish(SSL * ssl)164*ea16f64eSAntonio Huete Jimenez void ssl_finish(SSL *ssl)
165*ea16f64eSAntonio Huete Jimenez {
166*ea16f64eSAntonio Huete Jimenez 	//
167*ea16f64eSAntonio Huete Jimenez 	// We won't be using this again, so we can just send the
168*ea16f64eSAntonio Huete Jimenez 	// shutdown alert and free up the handle, and have our
169*ea16f64eSAntonio Huete Jimenez 	// caller close the socket.
170*ea16f64eSAntonio Huete Jimenez 	//
171*ea16f64eSAntonio Huete Jimenez 	// XXX - presumably, if the connection is shut down on
172*ea16f64eSAntonio Huete Jimenez 	// our side, either our peer won't have a problem sending
173*ea16f64eSAntonio Huete Jimenez 	// their shutdown alert or will not treat such a problem
174*ea16f64eSAntonio Huete Jimenez 	// as an error.  If this causes errors to be reported,
175*ea16f64eSAntonio Huete Jimenez 	// fix that as appropriate.
176*ea16f64eSAntonio Huete Jimenez 	//
177*ea16f64eSAntonio Huete Jimenez 	SSL_shutdown(ssl);
178*ea16f64eSAntonio Huete Jimenez 	SSL_free(ssl);
179*ea16f64eSAntonio Huete Jimenez }
180*ea16f64eSAntonio Huete Jimenez 
181*ea16f64eSAntonio Huete Jimenez // Same return value as sock_send:
182*ea16f64eSAntonio Huete Jimenez // 0 on OK, -1 on error but closed connection (-2).
ssl_send(SSL * ssl,char const * buffer,int size,char * errbuf,size_t errbuflen)183*ea16f64eSAntonio Huete Jimenez int ssl_send(SSL *ssl, char const *buffer, int size, char *errbuf, size_t errbuflen)
184*ea16f64eSAntonio Huete Jimenez {
185*ea16f64eSAntonio Huete Jimenez 	int status = SSL_write(ssl, buffer, size);
186*ea16f64eSAntonio Huete Jimenez 	if (status > 0)
187*ea16f64eSAntonio Huete Jimenez 	{
188*ea16f64eSAntonio Huete Jimenez 		// "SSL_write() will only return with success, when the complete contents (...) has been written."
189*ea16f64eSAntonio Huete Jimenez 		return 0;
190*ea16f64eSAntonio Huete Jimenez 	}
191*ea16f64eSAntonio Huete Jimenez 	else
192*ea16f64eSAntonio Huete Jimenez 	{
193*ea16f64eSAntonio Huete Jimenez 		int ssl_err = SSL_get_error(ssl, status); // TODO: does it pop the error?
194*ea16f64eSAntonio Huete Jimenez 		if (ssl_err == SSL_ERROR_ZERO_RETURN)
195*ea16f64eSAntonio Huete Jimenez 		{
196*ea16f64eSAntonio Huete Jimenez 			return -2;
197*ea16f64eSAntonio Huete Jimenez 		}
198*ea16f64eSAntonio Huete Jimenez 		else if (ssl_err == SSL_ERROR_SYSCALL)
199*ea16f64eSAntonio Huete Jimenez 		{
200*ea16f64eSAntonio Huete Jimenez #ifndef _WIN32
201*ea16f64eSAntonio Huete Jimenez 			if (errno == ECONNRESET || errno == EPIPE) return -2;
202*ea16f64eSAntonio Huete Jimenez #endif
203*ea16f64eSAntonio Huete Jimenez 		}
204*ea16f64eSAntonio Huete Jimenez 		snprintf(errbuf, errbuflen, "SSL_write(): %s",
205*ea16f64eSAntonio Huete Jimenez 		    ERR_error_string(ERR_get_error(), NULL));
206*ea16f64eSAntonio Huete Jimenez 		return -1;
207*ea16f64eSAntonio Huete Jimenez 	}
208*ea16f64eSAntonio Huete Jimenez }
209*ea16f64eSAntonio Huete Jimenez 
210*ea16f64eSAntonio Huete Jimenez // Returns the number of bytes read, or -1 on syserror, or -2 on SSL error.
ssl_recv(SSL * ssl,char * buffer,int size,char * errbuf,size_t errbuflen)211*ea16f64eSAntonio Huete Jimenez int ssl_recv(SSL *ssl, char *buffer, int size, char *errbuf, size_t errbuflen)
212*ea16f64eSAntonio Huete Jimenez {
213*ea16f64eSAntonio Huete Jimenez 	int status = SSL_read(ssl, buffer, size);
214*ea16f64eSAntonio Huete Jimenez 	if (status <= 0)
215*ea16f64eSAntonio Huete Jimenez 	{
216*ea16f64eSAntonio Huete Jimenez 		int ssl_err = SSL_get_error(ssl, status);
217*ea16f64eSAntonio Huete Jimenez 		if (ssl_err == SSL_ERROR_ZERO_RETURN)
218*ea16f64eSAntonio Huete Jimenez 		{
219*ea16f64eSAntonio Huete Jimenez 			return 0;
220*ea16f64eSAntonio Huete Jimenez 		}
221*ea16f64eSAntonio Huete Jimenez 		else if (ssl_err == SSL_ERROR_SYSCALL)
222*ea16f64eSAntonio Huete Jimenez 		{
223*ea16f64eSAntonio Huete Jimenez 			return -1;
224*ea16f64eSAntonio Huete Jimenez 		}
225*ea16f64eSAntonio Huete Jimenez 		else
226*ea16f64eSAntonio Huete Jimenez 		{
227*ea16f64eSAntonio Huete Jimenez 			// Should not happen
228*ea16f64eSAntonio Huete Jimenez 			snprintf(errbuf, errbuflen, "SSL_read(): %s",
229*ea16f64eSAntonio Huete Jimenez 			    ERR_error_string(ERR_get_error(), NULL));
230*ea16f64eSAntonio Huete Jimenez 			return -2;
231*ea16f64eSAntonio Huete Jimenez 		}
232*ea16f64eSAntonio Huete Jimenez 	}
233*ea16f64eSAntonio Huete Jimenez 	else
234*ea16f64eSAntonio Huete Jimenez 	{
235*ea16f64eSAntonio Huete Jimenez 		return status;
236*ea16f64eSAntonio Huete Jimenez 	}
237*ea16f64eSAntonio Huete Jimenez }
238*ea16f64eSAntonio Huete Jimenez 
239*ea16f64eSAntonio Huete Jimenez #endif // HAVE_OPENSSL
240