9c6eb81db3f5283934295930f8eead45b605beed
[openwrt.git] / package / network / services / uhttpd / src / uhttpd-tls.c
1 /*
2  * uhttpd - Tiny single-threaded httpd - TLS helper
3  *
4  *   Copyright (C) 2010 Jo-Philipp Wich <xm@subsignal.org>
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License.
17  */
18
19 #include "uhttpd.h"
20 #include "uhttpd-tls.h"
21 #include "uhttpd-utils.h"
22
23 #include <syslog.h>
24 #define dbg(...) syslog(LOG_INFO, __VA_ARGS__)
25
26 SSL_CTX * uh_tls_ctx_init(void)
27 {
28         SSL_CTX *c;
29
30         SSL_load_error_strings();
31         SSL_library_init();
32
33 #if TLS_IS_OPENSSL
34         if ((c = SSL_CTX_new(SSLv23_server_method())) != NULL)
35 #else
36         if ((c = SSL_CTX_new(TLSv1_server_method())) != NULL)
37 #endif
38                 SSL_CTX_set_verify(c, SSL_VERIFY_NONE, NULL);
39
40         return c;
41 }
42
43 int uh_tls_ctx_cert(SSL_CTX *c, const char *file)
44 {
45         int rv;
46
47         if( (rv = SSL_CTX_use_certificate_file(c, file, SSL_FILETYPE_PEM)) < 1 )
48                 rv = SSL_CTX_use_certificate_file(c, file, SSL_FILETYPE_ASN1);
49
50         return rv;
51 }
52
53 int uh_tls_ctx_key(SSL_CTX *c, const char *file)
54 {
55         int rv;
56
57         if( (rv = SSL_CTX_use_PrivateKey_file(c, file, SSL_FILETYPE_PEM)) < 1 )
58                 rv = SSL_CTX_use_PrivateKey_file(c, file, SSL_FILETYPE_ASN1);
59
60         return rv;
61 }
62
63 void uh_tls_ctx_free(struct listener *l)
64 {
65         SSL_CTX_free(l->tls);
66 }
67
68
69 int uh_tls_client_accept(struct client *c)
70 {
71         int rv, err;
72         int fd = c->fd.fd;
73
74         if (!c->server || !c->server->tls)
75         {
76                 c->tls = NULL;
77                 return 1;
78         }
79
80         if ((c->tls = SSL_new(c->server->tls)))
81         {
82                 if ((rv = SSL_set_fd(c->tls, fd)) < 1)
83                 {
84                         SSL_free(c->tls);
85                         c->tls = NULL;
86                 }
87                 else
88                 {
89                         while (true)
90                         {
91                                 rv = SSL_accept(c->tls);
92                                 err = SSL_get_error(c->tls, rv);
93
94                                 if ((rv != 1) &&
95                                         (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE))
96                                 {
97                                         if (uh_socket_wait(fd, c->server->conf->network_timeout,
98                                                                            (err == SSL_ERROR_WANT_WRITE)))
99                                         {
100                                                 D("TLS: accept(%d) = retry\n", fd);
101                                                 continue;
102                                         }
103
104                                         D("TLS: accept(%d) = timeout\n", fd);
105                                 }
106                                 else if (rv == 1)
107                                 {
108                                         D("TLS: accept(%d) = %p\n", fd, c->tls);
109                                         return 1;
110                                 }
111
112 #ifdef TLS_IS_OPENSSL
113                                 D("TLS: accept(%d) = failed: %s\n",
114                                   fd, ERR_error_string(ERR_get_error(), NULL));
115 #endif
116
117                                 SSL_free(c->tls);
118                                 c->tls = NULL;
119                                 break;
120                         }
121                 }
122         }
123
124         return 0;
125 }
126
127 int uh_tls_client_recv(struct client *c, char *buf, int len)
128 {
129         int rv = SSL_read(c->tls, buf, len);
130         int err = SSL_get_error(c->tls, 0);
131
132         if ((rv == -1) && (err == SSL_ERROR_WANT_READ))
133         {
134                 D("TLS: recv(%d, %d) = retry\n", c->fd.fd, len);
135                 errno = EAGAIN;
136                 return -1;
137         }
138
139         D("TLS: recv(%d, %d) = %d\n", c->fd.fd, len, rv);
140         return rv;
141 }
142
143 int uh_tls_client_send(struct client *c, const char *buf, int len)
144 {
145         int rv = SSL_write(c->tls, buf, len);
146         int err = SSL_get_error(c->tls, 0);
147
148         if ((rv == -1) && (err == SSL_ERROR_WANT_WRITE))
149         {
150                 D("TLS: send(%d, %d) = retry\n", c->fd.fd, len);
151                 errno = EAGAIN;
152                 return -1;
153         }
154
155         D("TLS: send(%d, %d) = %d\n", c->fd.fd, len, rv);
156         return rv;
157 }
158
159 void uh_tls_client_close(struct client *c)
160 {
161         if (c->tls)
162         {
163                 D("TLS: close(%d)\n", c->fd.fd);
164
165                 SSL_shutdown(c->tls);
166                 SSL_free(c->tls);
167
168                 c->tls = NULL;
169         }
170 }