package/ar7-atm: refresh patches
[openwrt.git] / package / 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 #ifdef TLS_IS_CYASSL
27 static int uh_cyassl_recv_cb(char *buf, int sz, void *ctx)
28 {
29         int rv;
30         int socket = *(int *)ctx;
31         struct client *cl;
32
33         if (!(cl = uh_client_lookup(socket)))
34                 return -1; /* unexpected error */
35
36         rv = uh_tcp_recv_lowlevel(cl, buf, sz);
37
38         if (rv < 0)
39                 return -4; /* interrupted */
40
41         if (rv == 0)
42                 return -5; /* connection closed */
43
44         return rv;
45 }
46
47 static int uh_cyassl_send_cb(char *buf, int sz, void *ctx)
48 {
49         int rv;
50         int socket = *(int *)ctx;
51         struct client *cl;
52
53         if (!(cl = uh_client_lookup(socket)))
54                 return -1; /* unexpected error */
55
56         rv = uh_tcp_send_lowlevel(cl, buf, sz);
57
58         if (rv <= 0)
59                 return -5; /* connection dead */
60
61         return rv;
62 }
63
64 void SetCallbackIORecv_Ctx(SSL_CTX*, int (*)(char *, int, void *));
65 void SetCallbackIOSend_Ctx(SSL_CTX*, int (*)(char *, int, void *));
66
67 static void uh_tls_ctx_setup(SSL_CTX *ctx)
68 {
69         SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
70         SetCallbackIORecv_Ctx(ctx, uh_cyassl_recv_cb);
71         SetCallbackIOSend_Ctx(ctx, uh_cyassl_send_cb);
72         return;
73 }
74
75 static int uh_tls_client_ctx_setup(SSL *ssl, int socket)
76 {
77         return SSL_set_fd(ssl, socket);
78 }
79 #endif /* TLS_IS_CYASSL */
80
81 #ifdef TLS_IS_OPENSSL
82 static long uh_openssl_bio_ctrl_cb(BIO *b, int cmd, long num, void *ptr)
83 {
84         long rv = 1;
85
86         switch (cmd)
87         {
88                 case BIO_C_SET_FD:
89                         b->num      = *((int *)ptr);
90                         b->shutdown = (int)num;
91                         b->init     = 1;
92                         break;
93
94                 case BIO_C_GET_FD:
95                         if (!b->init)
96                                 return -1;
97
98                         if (ptr)
99                                 *((int *)ptr) = b->num;
100
101                         rv = b->num;
102                         break;
103         }
104
105         return rv;
106 }
107
108 static int uh_openssl_bio_read_cb(BIO *b, char *out, int outl)
109 {
110         int rv = 0;
111         struct client *cl;
112
113         if (!(cl = uh_client_lookup(b->num)))
114                 return -1;
115
116         if (out != NULL)
117                 rv = uh_tcp_recv_lowlevel(cl, out, outl);
118
119         return rv;
120 }
121
122 static int uh_openssl_bio_write_cb(BIO *b, const char *in, int inl)
123 {
124         struct client *cl;
125
126         if (!(cl = uh_client_lookup(b->num)))
127                 return -1;
128
129         return uh_tcp_send_lowlevel(cl, in, inl);
130 }
131
132 static BIO_METHOD uh_openssl_bio_methods = {
133         .type   = BIO_TYPE_SOCKET,
134         .name   = "uhsocket",
135         .ctrl   = uh_openssl_bio_ctrl_cb,
136         .bwrite = uh_openssl_bio_write_cb,
137         .bread  = uh_openssl_bio_read_cb
138 };
139
140 static void uh_tls_ctx_setup(SSL_CTX *ctx)
141 {
142         SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
143         return;
144 }
145
146 static int uh_tls_client_ctx_setup(SSL *ssl, int socket)
147 {
148         BIO *b;
149
150         if (!(b = BIO_new(&uh_openssl_bio_methods)))
151                 return 0;
152
153         BIO_set_fd(b, socket, BIO_NOCLOSE);
154         SSL_set_bio(ssl, b, b);
155
156         return 1;
157 }
158 #endif /* TLS_IS_OPENSSL */
159
160
161 SSL_CTX * uh_tls_ctx_init()
162 {
163         SSL_CTX *c;
164
165         SSL_load_error_strings();
166         SSL_library_init();
167
168         if ((c = SSL_CTX_new(TLSv1_server_method())) != NULL)
169                 uh_tls_ctx_setup(c);
170
171         return c;
172 }
173
174 int uh_tls_ctx_cert(SSL_CTX *c, const char *file)
175 {
176         int rv;
177
178         if( (rv = SSL_CTX_use_certificate_file(c, file, SSL_FILETYPE_PEM)) < 1 )
179                 rv = SSL_CTX_use_certificate_file(c, file, SSL_FILETYPE_ASN1);
180
181         return rv;
182 }
183
184 int uh_tls_ctx_key(SSL_CTX *c, const char *file)
185 {
186         int rv;
187
188         if( (rv = SSL_CTX_use_PrivateKey_file(c, file, SSL_FILETYPE_PEM)) < 1 )
189                 rv = SSL_CTX_use_PrivateKey_file(c, file, SSL_FILETYPE_ASN1);
190
191         return rv;
192 }
193
194 void uh_tls_ctx_free(struct listener *l)
195 {
196         SSL_CTX_free(l->tls);
197 }
198
199
200 int uh_tls_client_accept(struct client *c)
201 {
202         int rv;
203
204         if( c->server && c->server->tls )
205         {
206                 c->tls = SSL_new(c->server->tls);
207                 if( c->tls )
208                 {
209                         if( (rv = uh_tls_client_ctx_setup(c->tls, c->socket)) < 1 )
210                                 goto cleanup;
211
212                         if( (rv = SSL_accept(c->tls)) < 1 )
213                                 goto cleanup;
214                 }
215                 else
216                         rv = 0;
217         }
218         else
219         {
220                 c->tls = NULL;
221                 rv = 1;
222         }
223
224 done:
225         return rv;
226
227 cleanup:
228         SSL_free(c->tls);
229         c->tls = NULL;
230         goto done;
231 }
232
233 int uh_tls_client_recv(struct client *c, void *buf, int len)
234 {
235         int rv = SSL_read(c->tls, buf, len);
236         return (rv > 0) ? rv : -1;
237 }
238
239 int uh_tls_client_send(struct client *c, void *buf, int len)
240 {
241         int rv = SSL_write(c->tls, buf, len);
242         return (rv > 0) ? rv : -1;
243 }
244
245 void uh_tls_client_close(struct client *c)
246 {
247         if( c->tls )
248         {
249                 SSL_shutdown(c->tls);
250                 SSL_free(c->tls);
251
252                 c->tls = NULL;
253         }
254 }