1 /* $NetBSD: ssl-bozo.c,v 1.18 2014/07/17 06:27:52 mrg Exp $ */
3 /* $eterna: ssl-bozo.c,v 1.15 2011/11/18 09:21:15 mrg Exp $ */
6 * Copyright (c) 1997-2014 Matthew R. Green
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer and
16 * dedication in the documentation and/or other materials provided
17 * with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 /* this code implements SSL and backend IO for bozohttpd */
40 #include "bozohttpd.h"
42 #ifndef NO_SSL_SUPPORT
44 #include <openssl/ssl.h>
45 #include <openssl/err.h>
48 #define USE_ARG(x) /*LINTED*/(void)&(x)
51 /* this structure encapsulates the ssl info */
52 typedef struct sslinfo_t
{
54 const SSL_METHOD
*ssl_method
;
56 char *certificate_file
;
57 char *privatekey_file
;
61 * bozo_clear_ssl_queue: print the contents of the SSL error queue
64 bozo_clear_ssl_queue(bozohttpd_t
*httpd
)
66 unsigned long sslcode
= ERR_get_error();
69 static const char sslfmt
[] = "SSL Error: %s:%s:%s";
71 if (httpd
->logstderr
|| isatty(STDERR_FILENO
)) {
72 fprintf(stderr
, sslfmt
,
73 ERR_lib_error_string(sslcode
),
74 ERR_func_error_string(sslcode
),
75 ERR_reason_error_string(sslcode
));
77 syslog(LOG_ERR
, sslfmt
,
78 ERR_lib_error_string(sslcode
),
79 ERR_func_error_string(sslcode
),
80 ERR_reason_error_string(sslcode
));
82 } while (0 != (sslcode
= ERR_get_error()));
86 * bozo_ssl_warn works just like bozo_warn, plus the SSL error queue
88 BOZO_PRINTFLIKE(2, 3) static void
89 bozo_ssl_warn(bozohttpd_t
*httpd
, const char *fmt
, ...)
94 if (httpd
->logstderr
|| isatty(STDERR_FILENO
)) {
95 vfprintf(stderr
, fmt
, ap
);
98 vsyslog(LOG_ERR
, fmt
, ap
);
101 bozo_clear_ssl_queue(httpd
);
106 * bozo_ssl_err works just like bozo_err, plus the SSL error queue
108 BOZO_PRINTFLIKE(3, 4) BOZO_DEAD
static void
109 bozo_ssl_err(bozohttpd_t
*httpd
, int code
, const char *fmt
, ...)
114 if (httpd
->logstderr
|| isatty(STDERR_FILENO
)) {
115 vfprintf(stderr
, fmt
, ap
);
118 vsyslog(LOG_ERR
, fmt
, ap
);
121 bozo_clear_ssl_queue(httpd
);
126 * bozo_check_error_queue: print warnings if the error isn't expected
129 bozo_check_error_queue(bozohttpd_t
*httpd
, const char *tag
, int ret
)
134 const sslinfo_t
*sslinfo
= httpd
->sslinfo
;
135 const int sslerr
= SSL_get_error(sslinfo
->bozossl
, ret
);
137 if (sslerr
!= SSL_ERROR_ZERO_RETURN
&&
138 sslerr
!= SSL_ERROR_SYSCALL
&&
139 sslerr
!= SSL_ERROR_NONE
)
140 bozo_ssl_warn(httpd
, "%s: SSL_ERROR %d", tag
, sslerr
);
143 static BOZO_PRINTFLIKE(2, 0) int
144 bozo_ssl_printf(bozohttpd_t
*httpd
, const char * fmt
, va_list ap
)
149 if ((nbytes
= vasprintf(&buf
, fmt
, ap
)) != -1) {
150 const sslinfo_t
*sslinfo
= httpd
->sslinfo
;
151 int ret
= SSL_write(sslinfo
->bozossl
, buf
, nbytes
);
152 bozo_check_error_queue(httpd
, "write", ret
);
161 bozo_ssl_read(bozohttpd_t
*httpd
, int fd
, void *buf
, size_t nbytes
)
163 const sslinfo_t
*sslinfo
= httpd
->sslinfo
;
167 ret
= SSL_read(sslinfo
->bozossl
, buf
, (int)nbytes
);
168 bozo_check_error_queue(httpd
, "read", ret
);
174 bozo_ssl_write(bozohttpd_t
*httpd
, int fd
, const void *buf
, size_t nbytes
)
176 const sslinfo_t
*sslinfo
= httpd
->sslinfo
;
180 ret
= SSL_write(sslinfo
->bozossl
, buf
, (int)nbytes
);
181 bozo_check_error_queue(httpd
, "write", ret
);
187 bozo_ssl_init(bozohttpd_t
*httpd
)
189 sslinfo_t
*sslinfo
= httpd
->sslinfo
;
191 if (sslinfo
== NULL
|| !sslinfo
->certificate_file
)
194 SSL_load_error_strings();
196 sslinfo
->ssl_method
= SSLv23_server_method();
197 sslinfo
->ssl_context
= SSL_CTX_new(sslinfo
->ssl_method
);
199 if (NULL
== sslinfo
->ssl_context
)
200 bozo_ssl_err(httpd
, EXIT_FAILURE
,
201 "SSL context creation failed");
203 if (1 != SSL_CTX_use_certificate_chain_file(sslinfo
->ssl_context
,
204 sslinfo
->certificate_file
))
205 bozo_ssl_err(httpd
, EXIT_FAILURE
,
206 "Unable to use certificate file '%s'",
207 sslinfo
->certificate_file
);
209 if (1 != SSL_CTX_use_PrivateKey_file(sslinfo
->ssl_context
,
210 sslinfo
->privatekey_file
, SSL_FILETYPE_PEM
))
211 bozo_ssl_err(httpd
, EXIT_FAILURE
,
212 "Unable to use private key file '%s'",
213 sslinfo
->privatekey_file
);
215 /* check consistency of key vs certificate */
216 if (!SSL_CTX_check_private_key(sslinfo
->ssl_context
))
217 bozo_ssl_err(httpd
, EXIT_FAILURE
,
218 "Check private key failed");
222 * returns non-zero for failure
225 bozo_ssl_accept(bozohttpd_t
*httpd
)
227 sslinfo_t
*sslinfo
= httpd
->sslinfo
;
229 if (sslinfo
== NULL
|| !sslinfo
->ssl_context
)
232 sslinfo
->bozossl
= SSL_new(sslinfo
->ssl_context
);
233 if (sslinfo
->bozossl
== NULL
)
234 bozo_err(httpd
, 1, "SSL_new failed");
236 SSL_set_rfd(sslinfo
->bozossl
, 0);
237 SSL_set_wfd(sslinfo
->bozossl
, 1);
239 const int ret
= SSL_accept(sslinfo
->bozossl
);
240 bozo_check_error_queue(httpd
, "accept", ret
);
246 bozo_ssl_destroy(bozohttpd_t
*httpd
)
248 const sslinfo_t
*sslinfo
= httpd
->sslinfo
;
250 if (sslinfo
&& sslinfo
->bozossl
)
251 SSL_free(sslinfo
->bozossl
);
255 bozo_ssl_set_opts(bozohttpd_t
*httpd
, const char *cert
, const char *priv
)
257 sslinfo_t
*sslinfo
= httpd
->sslinfo
;
259 if (sslinfo
== NULL
) {
260 sslinfo
= bozomalloc(httpd
, sizeof(*sslinfo
));
262 bozo_err(httpd
, 1, "sslinfo allocation failed");
263 httpd
->sslinfo
= sslinfo
;
265 sslinfo
->certificate_file
= strdup(cert
);
266 sslinfo
->privatekey_file
= strdup(priv
);
267 debug((httpd
, DEBUG_NORMAL
, "using cert/priv files: %s & %s",
268 sslinfo
->certificate_file
,
269 sslinfo
->privatekey_file
));
270 if (!httpd
->bindport
)
271 httpd
->bindport
= strdup("https");
274 #endif /* NO_SSL_SUPPORT */
277 bozo_printf(bozohttpd_t
*httpd
, const char *fmt
, ...)
283 #ifndef NO_SSL_SUPPORT
285 cc
= bozo_ssl_printf(httpd
, fmt
, args
);
288 cc
= vprintf(fmt
, args
);
294 bozo_read(bozohttpd_t
*httpd
, int fd
, void *buf
, size_t len
)
296 #ifndef NO_SSL_SUPPORT
298 return bozo_ssl_read(httpd
, fd
, buf
, len
);
300 return read(fd
, buf
, len
);
304 bozo_write(bozohttpd_t
*httpd
, int fd
, const void *buf
, size_t len
)
306 #ifndef NO_SSL_SUPPORT
308 return bozo_ssl_write(httpd
, fd
, buf
, len
);
310 return write(fd
, buf
, len
);
314 bozo_flush(bozohttpd_t
*httpd
, FILE *fp
)
316 #ifndef NO_SSL_SUPPORT