Root/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
27static 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
47static 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
64void SetCallbackIORecv_Ctx(SSL_CTX*, int (*)(char *, int, void *));
65void SetCallbackIOSend_Ctx(SSL_CTX*, int (*)(char *, int, void *));
66
67static 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
75static 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
82static 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
108static 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
122static 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
132static 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
140static void uh_tls_ctx_setup(SSL_CTX *ctx)
141{
142    SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
143    return;
144}
145
146static 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
161SSL_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
174int 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
184int 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
194void uh_tls_ctx_free(struct listener *l)
195{
196    SSL_CTX_free(l->tls);
197}
198
199
200int 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
224done:
225    return rv;
226
227cleanup:
228    SSL_free(c->tls);
229    c->tls = NULL;
230    goto done;
231}
232
233int 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
239int 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
245void 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}
255

Archive Download this file



interactive