xref: /openbsd-src/lib/libtls/tls_server.c (revision cb39b41371628601fbe4c618205356d538b9d08a)
1 /* $OpenBSD: tls_server.c,v 1.7 2015/03/31 14:03:38 jsing Exp $ */
2 /*
3  * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <openssl/ec.h>
19 #include <openssl/ssl.h>
20 
21 #include <tls.h>
22 #include "tls_internal.h"
23 
24 struct tls *
25 tls_server(void)
26 {
27 	struct tls *ctx;
28 
29 	if ((ctx = tls_new()) == NULL)
30 		return (NULL);
31 
32 	ctx->flags |= TLS_SERVER;
33 
34 	return (ctx);
35 }
36 
37 struct tls *
38 tls_server_conn(struct tls *ctx)
39 {
40 	struct tls *conn_ctx;
41 
42 	if ((conn_ctx = tls_new()) == NULL)
43 		return (NULL);
44 
45 	conn_ctx->flags |= TLS_SERVER_CONN;
46 
47 	return (conn_ctx);
48 }
49 
50 int
51 tls_configure_server(struct tls *ctx)
52 {
53 	EC_KEY *ecdh_key;
54 	unsigned char sid[SSL_MAX_SSL_SESSION_ID_LENGTH];
55 
56 	if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) {
57 		tls_set_error(ctx, "ssl context failure");
58 		goto err;
59 	}
60 
61 	if (tls_configure_ssl(ctx) != 0)
62 		goto err;
63 	if (tls_configure_keypair(ctx) != 0)
64 		goto err;
65 
66 	if (ctx->config->dheparams == -1)
67 		SSL_CTX_set_dh_auto(ctx->ssl_ctx, 1);
68 	else if (ctx->config->dheparams == 1024)
69 		SSL_CTX_set_dh_auto(ctx->ssl_ctx, 2);
70 
71 	if (ctx->config->ecdhecurve == -1) {
72 		SSL_CTX_set_ecdh_auto(ctx->ssl_ctx, 1);
73 	} else if (ctx->config->ecdhecurve != NID_undef) {
74 		if ((ecdh_key = EC_KEY_new_by_curve_name(
75 		    ctx->config->ecdhecurve)) == NULL) {
76 			tls_set_error(ctx, "failed to set ECDHE curve");
77 			goto err;
78 		}
79 		SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_SINGLE_ECDH_USE);
80 		SSL_CTX_set_tmp_ecdh(ctx->ssl_ctx, ecdh_key);
81 		EC_KEY_free(ecdh_key);
82 	}
83 
84 	/*
85 	 * Set session ID context to a random value.  We don't support
86 	 * persistent caching of sessions so it is OK to set a temporary
87 	 * session ID context that is valid during run time.
88 	 */
89 	arc4random_buf(sid, sizeof(sid));
90 	if (!SSL_CTX_set_session_id_context(ctx->ssl_ctx, sid, sizeof(sid))) {
91 		tls_set_error(ctx, "failed to set session id context");
92 		goto err;
93 	}
94 
95 	return (0);
96 
97 err:
98 	return (-1);
99 }
100 
101 int
102 tls_accept_fds(struct tls *ctx, struct tls **cctx, int fd_read, int fd_write)
103 {
104 	struct tls *conn_ctx = *cctx;
105 	int ret, err;
106 
107 	if ((ctx->flags & TLS_SERVER) == 0) {
108 		tls_set_error(ctx, "not a server context");
109 		goto err;
110 	}
111 
112 	if (conn_ctx == NULL) {
113 		if ((conn_ctx = tls_server_conn(ctx)) == NULL) {
114 			tls_set_error(ctx, "connection context failure");
115 			goto err;
116 		}
117 		*cctx = conn_ctx;
118 
119 		if ((conn_ctx->ssl_conn = SSL_new(ctx->ssl_ctx)) == NULL) {
120 			tls_set_error(ctx, "ssl failure");
121 			goto err;
122 		}
123 
124 		if (SSL_set_rfd(conn_ctx->ssl_conn, fd_read) != 1 ||
125 		    SSL_set_wfd(conn_ctx->ssl_conn, fd_write) != 1) {
126 			tls_set_error(ctx, "ssl set fd failure");
127 			goto err;
128 		}
129 		SSL_set_app_data(conn_ctx->ssl_conn, conn_ctx);
130 	}
131 
132 	if ((ret = SSL_accept(conn_ctx->ssl_conn)) != 1) {
133 		err = tls_ssl_error(ctx, conn_ctx->ssl_conn, ret, "accept");
134 		if (err == TLS_READ_AGAIN || err == TLS_WRITE_AGAIN) {
135 			return (err);
136 		}
137 		goto err;
138 	}
139 
140 	return (0);
141 
142 err:
143 	return (-1);
144 }
145 
146 int
147 tls_accept_socket(struct tls *ctx, struct tls **cctx, int socket)
148 {
149 	int rv;
150 
151 	rv = tls_accept_fds(ctx, cctx, socket, socket);
152 	if (*cctx != NULL)
153 		(*cctx)->socket = socket;
154 
155 	return (rv);
156 }
157