libsodium: Needed for Dnscrypto-proxy Release 1.3.0
[tomato.git] / release / src / router / mssl / mssl.c
blob9a4d3c984887fb5bc5add896766794f19b16852e
1 /*
3 Minimal CyaSSL/OpenSSL Helper
4 Copyright (C) 2006-2009 Jonathan Zarate
5 Copyright (C) 2010 Fedor Kozhevnikov
7 Licensed under GNU GPL v2 or later
9 */
11 #define _GNU_SOURCE
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <unistd.h>
17 #include <syslog.h>
18 #include <fcntl.h>
19 #include <stdarg.h>
20 #include <stdint.h>
21 #include <errno.h>
23 #include <openssl/ssl.h>
24 #include <openssl/err.h>
26 #ifdef USE_OPENSSL
27 #include <openssl/rsa.h>
28 #include <openssl/crypto.h>
29 #include <openssl/x509.h>
30 #include <openssl/pem.h>
31 #else // CyaSSL
32 #include <cyassl_error.h>
33 #endif
35 #define _dprintf(args...) while (0) {}
37 typedef struct {
38 SSL* ssl;
39 int sd;
40 } mssl_cookie_t;
42 static SSL_CTX* ctx;
44 static inline void mssl_print_err(SSL* ssl)
46 #ifdef USE_OPENSSL
47 ERR_print_errors_fp(stderr);
48 #else
49 _dprintf("CyaSSL error %d\n", ssl ? SSL_get_error(ssl, 0) : -1);
50 #endif
53 static inline void mssl_cleanup(int err)
55 if (err) mssl_print_err(NULL);
56 SSL_CTX_free(ctx);
57 ctx = NULL;
60 static ssize_t mssl_read(void *cookie, char *buf, size_t len)
62 _dprintf("%s()\n", __FUNCTION__);
64 mssl_cookie_t *kuki = cookie;
65 int total = 0;
66 int n, err;
68 do {
69 n = SSL_read(kuki->ssl, &(buf[total]), len - total);
70 _dprintf("SSL_read(max=%d) returned %d\n", len - total, n);
72 err = SSL_get_error(kuki->ssl, n);
73 switch (err) {
74 case SSL_ERROR_NONE:
75 total += n;
76 break;
77 case SSL_ERROR_ZERO_RETURN:
78 total += n;
79 goto OUT;
80 case SSL_ERROR_WANT_WRITE:
81 case SSL_ERROR_WANT_READ:
82 break;
83 default:
84 _dprintf("%s(): SSL error %d\n", __FUNCTION__, err);
85 mssl_print_err(kuki->ssl);
86 if (total == 0) total = -1;
87 goto OUT;
89 } while ((len - total > 0) && SSL_pending(kuki->ssl));
91 OUT:
92 _dprintf("%s() returns %d\n", __FUNCTION__, total);
93 return total;
96 static ssize_t mssl_write(void *cookie, const char *buf, size_t len)
98 _dprintf("%s()\n", __FUNCTION__);
100 mssl_cookie_t *kuki = cookie;
101 int total = 0;
102 int n, err;
104 while (total < len) {
105 n = SSL_write(kuki->ssl, &(buf[total]), len - total);
106 _dprintf("SSL_write(max=%d) returned %d\n", len - total, n);
107 err = SSL_get_error(kuki->ssl, n);
108 switch (err) {
109 case SSL_ERROR_NONE:
110 total += n;
111 break;
112 case SSL_ERROR_ZERO_RETURN:
113 total += n;
114 goto OUT;
115 case SSL_ERROR_WANT_WRITE:
116 case SSL_ERROR_WANT_READ:
117 break;
118 default:
119 _dprintf("%s(): SSL error %d\n", __FUNCTION__, err);
120 mssl_print_err(kuki->ssl);
121 if (total == 0) total = -1;
122 goto OUT;
126 OUT:
127 _dprintf("%s() returns %d\n", __FUNCTION__, total);
128 return total;
131 static int mssl_seek(void *cookie, __offmax_t *pos, int whence)
133 _dprintf("%s()\n", __FUNCTION__);
134 errno = EIO;
135 return -1;
138 static int mssl_close(void *cookie)
140 _dprintf("%s()\n", __FUNCTION__);
142 mssl_cookie_t *kuki = cookie;
143 if (!kuki) return 0;
145 if (kuki->ssl) {
146 SSL_shutdown(kuki->ssl);
147 SSL_free(kuki->ssl);
150 free(kuki);
151 return 0;
154 static const cookie_io_functions_t mssl = {
155 mssl_read, mssl_write, mssl_seek, mssl_close
158 static FILE *_ssl_fopen(int sd, int client)
160 int r;
161 mssl_cookie_t *kuki;
162 FILE *f;
164 _dprintf("%s()\n", __FUNCTION__);
166 if ((kuki = calloc(1, sizeof(*kuki))) == NULL) {
167 errno = ENOMEM;
168 return NULL;
170 kuki->sd = sd;
172 if ((kuki->ssl = SSL_new(ctx)) == NULL) {
173 _dprintf("%s: SSL_new failed\n", __FUNCTION__);
174 goto ERROR;
177 #ifdef USE_OPENSSL
178 SSL_set_verify(kuki->ssl, SSL_VERIFY_NONE, NULL);
179 SSL_set_mode(kuki->ssl, SSL_MODE_AUTO_RETRY);
180 #endif
181 SSL_set_fd(kuki->ssl, kuki->sd);
183 r = client ? SSL_connect(kuki->ssl) : SSL_accept(kuki->ssl);
184 if (r <= 0) {
185 _dprintf("%s: SSL handshake failed\n", __FUNCTION__);
186 mssl_print_err(kuki->ssl);
187 goto ERROR;
190 #ifdef USE_OPENSSL
191 _dprintf("SSL connection using %s cipher\n", SSL_get_cipher(kuki->ssl));
192 #endif
194 if ((f = fopencookie(kuki, "r+", mssl)) == NULL) {
195 _dprintf("%s: fopencookie failed\n", __FUNCTION__);
196 goto ERROR;
199 _dprintf("%s() success\n", __FUNCTION__);
200 return f;
202 ERROR:
203 mssl_close(kuki);
204 return NULL;
207 FILE *ssl_server_fopen(int sd)
209 _dprintf("%s()\n", __FUNCTION__);
210 return _ssl_fopen(sd, 0);
213 FILE *ssl_client_fopen(int sd)
215 _dprintf("%s()\n", __FUNCTION__);
216 return _ssl_fopen(sd, 1);
219 int mssl_init(char *cert, char *priv)
221 _dprintf("%s()\n", __FUNCTION__);
223 int server = (cert != NULL);
225 #ifdef USE_OPENSSL
226 SSL_load_error_strings();
227 SSLeay_add_ssl_algorithms();
228 #endif
230 ctx = SSL_CTX_new(server ? TLSv1_server_method() : TLSv1_client_method());
231 if (!ctx) {
232 _dprintf("SSL_CTX_new() failed\n");
233 mssl_print_err(NULL);
234 return 0;
237 #ifndef USE_OPENSSL
238 SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
239 #endif
241 if (server) {
242 _dprintf("SSL_CTX_use_certificate_file(%s)\n", cert);
243 if (SSL_CTX_use_certificate_file(ctx, cert, SSL_FILETYPE_PEM) <= 0) {
244 _dprintf("SSL_CTX_use_certificate_file() failed\n");
245 mssl_cleanup(1);
246 return 0;
248 _dprintf("SSL_CTX_use_PrivateKey_file(%s)\n", priv);
249 if (SSL_CTX_use_PrivateKey_file(ctx, priv, SSL_FILETYPE_PEM) <= 0) {
250 _dprintf("SSL_CTX_use_PrivateKey_file() failed\n");
251 mssl_cleanup(1);
252 return 0;
254 #ifdef USE_OPENSSL
255 if (!SSL_CTX_check_private_key(ctx)) {
256 _dprintf("Private key does not match the certificate public key\n");
257 mssl_cleanup(0);
258 return 0;
260 #endif
263 _dprintf("%s() success\n", __FUNCTION__);
264 return 1;