mssl updates
[tomato.git] / release / src / router / mssl / mssl.c
blob3d51003bc4e210a48d34047b589824bbc90f3f20
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 #include <openssl/rsa.h>
27 #include <openssl/crypto.h>
28 #include <openssl/x509.h>
29 #include <openssl/pem.h>
31 #define _dprintf(args...) while (0) {}
33 const char *allowedCiphers = "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA";
35 typedef struct {
36 SSL* ssl;
37 int sd;
38 } mssl_cookie_t;
40 static SSL_CTX* ctx;
42 static inline void mssl_print_err(SSL* ssl)
44 ERR_print_errors_fp(stderr);
47 static inline void mssl_cleanup(int err)
49 if (err) mssl_print_err(NULL);
50 SSL_CTX_free(ctx);
51 ctx = NULL;
54 static ssize_t mssl_read(void *cookie, char *buf, size_t len)
56 _dprintf("%s()\n", __FUNCTION__);
58 mssl_cookie_t *kuki = cookie;
59 int total = 0;
60 int n, err;
62 do {
63 n = SSL_read(kuki->ssl, &(buf[total]), len - total);
64 _dprintf("SSL_read(max=%d) returned %d\n", len - total, n);
66 err = SSL_get_error(kuki->ssl, n);
67 switch (err) {
68 case SSL_ERROR_NONE:
69 total += n;
70 break;
71 case SSL_ERROR_ZERO_RETURN:
72 total += n;
73 goto OUT;
74 case SSL_ERROR_WANT_WRITE:
75 case SSL_ERROR_WANT_READ:
76 break;
77 default:
78 _dprintf("%s(): SSL error %d\n", __FUNCTION__, err);
79 mssl_print_err(kuki->ssl);
80 if (total == 0) total = -1;
81 goto OUT;
83 } while ((len - total > 0) && SSL_pending(kuki->ssl));
85 OUT:
86 _dprintf("%s() returns %d\n", __FUNCTION__, total);
87 return total;
90 static ssize_t mssl_write(void *cookie, const char *buf, size_t len)
92 _dprintf("%s()\n", __FUNCTION__);
94 mssl_cookie_t *kuki = cookie;
95 int total = 0;
96 int n, err;
98 while (total < len) {
99 n = SSL_write(kuki->ssl, &(buf[total]), len - total);
100 _dprintf("SSL_write(max=%d) returned %d\n", len - total, n);
101 err = SSL_get_error(kuki->ssl, n);
102 switch (err) {
103 case SSL_ERROR_NONE:
104 total += n;
105 break;
106 case SSL_ERROR_ZERO_RETURN:
107 total += n;
108 goto OUT;
109 case SSL_ERROR_WANT_WRITE:
110 case SSL_ERROR_WANT_READ:
111 break;
112 default:
113 _dprintf("%s(): SSL error %d\n", __FUNCTION__, err);
114 mssl_print_err(kuki->ssl);
115 if (total == 0) total = -1;
116 goto OUT;
120 OUT:
121 _dprintf("%s() returns %d\n", __FUNCTION__, total);
122 return total;
125 static int mssl_seek(void *cookie, __offmax_t *pos, int whence)
127 _dprintf("%s()\n", __FUNCTION__);
128 errno = EIO;
129 return -1;
132 static int mssl_close(void *cookie)
134 _dprintf("%s()\n", __FUNCTION__);
136 mssl_cookie_t *kuki = cookie;
137 if (!kuki) return 0;
139 if (kuki->ssl) {
140 SSL_shutdown(kuki->ssl);
141 SSL_free(kuki->ssl);
144 free(kuki);
145 return 0;
148 static const cookie_io_functions_t mssl = {
149 mssl_read, mssl_write, mssl_seek, mssl_close
152 static FILE *_ssl_fopen(int sd, int client)
154 int r = 0;
155 int err;
156 mssl_cookie_t *kuki;
157 FILE *f;
159 _dprintf("%s()\n", __FUNCTION__);
160 //fprintf(stderr,"[ssl_fopen] ssl_fopen start!\n"); // tmp test
162 if ((kuki = calloc(1, sizeof(*kuki))) == NULL) {
163 errno = ENOMEM;
164 return NULL;
166 kuki->sd = sd;
168 // Create new SSL object
169 if ((kuki->ssl = SSL_new(ctx)) == NULL) {
170 fprintf(stderr,"[ssl_fopen] SSL_new failed!\n"); // tmp test
171 _dprintf("%s: SSL_new failed\n", __FUNCTION__);
172 goto ERROR;
175 // SSL structure for client authenticate after SSL_new()
176 SSL_set_verify(kuki->ssl, SSL_VERIFY_NONE, NULL);
177 SSL_set_mode(kuki->ssl, SSL_MODE_AUTO_RETRY);
179 // Bind the socket to SSL structure
180 // kuki->ssl : SSL structure
181 // kuki->sd : socket_fd
183 // Setup EC support
184 #ifdef NID_X9_62_prime256v1
185 EC_KEY *ecdh = NULL;
186 if (ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)) {
187 SSL_CTX_set_tmp_ecdh(ctx, ecdh);
188 EC_KEY_free(ecdh);
190 #endif
192 // Setup available ciphers
193 if (SSL_CTX_set_cipher_list(ctx, allowedCiphers) != 1) {
194 goto ERROR;
197 // Enforce our desired cipher order, disable obsolete protocols
198 SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 |
199 SSL_OP_NO_SSLv3 |
200 SSL_OP_CIPHER_SERVER_PREFERENCE |
201 SSL_OP_SAFARI_ECDHE_ECDSA_BUG);
203 r = SSL_set_fd(kuki->ssl, kuki->sd);
204 //fprintf(stderr,"[ssl_fopen] set_fd=%d\n", r); // tmp test
206 if (!client){
207 // Do the SSL Handshake
208 r = SSL_accept(kuki->ssl);
210 else{
211 // Connect to the server, SSL layer
212 r = SSL_connect(kuki->ssl);
215 //fprintf(stderr,"[ssl_fopen] client=%d, r=%d\n", client, r); // tmp test
216 // r = 0 show unknown CA, but we don't have any CA, so ignore.
217 if (r < 0){
218 // Check error in connect or accept
219 err = SSL_get_error(kuki->ssl, r);
220 fprintf(stderr,"[ssl_fopen] SSL error #%d in client=%d\n", err, client); // tmp test
221 mssl_print_err(kuki->ssl);
222 goto ERROR;
225 _dprintf("SSL connection using %s cipher\n", SSL_get_cipher(kuki->ssl));
227 if ((f = fopencookie(kuki, "r+", mssl)) == NULL) {
228 _dprintf("%s: fopencookie failed\n", __FUNCTION__);
229 goto ERROR;
232 //fprintf(stderr,"[ssl_fopen] SUCCESS!\n", r); // tmp test
233 _dprintf("%s() success\n", __FUNCTION__);
234 return f;
236 ERROR:
237 fprintf(stderr,"[ssl_fopen] ERROR!\n"); // tmp test
238 mssl_close(kuki);
239 return NULL;
242 FILE *ssl_server_fopen(int sd)
244 _dprintf("%s()\n", __FUNCTION__);
245 return _ssl_fopen(sd, 0);
248 FILE *ssl_client_fopen(int sd)
250 _dprintf("%s()\n", __FUNCTION__);
251 return _ssl_fopen(sd, 1);
254 int mssl_init(char *cert, char *priv)
256 _dprintf("%s()\n", __FUNCTION__);
258 int server = (cert != NULL);
259 //fprintf(stderr,"[ssl_init] server=%d\n", server); // tmp test
261 // Register error strings for libcrypto and libssl functions
262 SSL_load_error_strings();
263 SSLeay_add_ssl_algorithms();
265 // Create the new CTX with the method
266 // If server=1, use TLSv1_server_method() or SSLv23_server_method()
267 // else use TLSv1_client_method() or SSLv23_client_method()
268 ctx = SSL_CTX_new(server ? SSLv23_server_method() : SSLv23_client_method());
270 if (!ctx) {
271 fprintf(stderr,"[ssl_init] SSL_CTX_new() failed\n"); // tmp test
272 _dprintf("SSL_CTX_new() failed\n");
273 mssl_print_err(NULL);
274 return 0;
277 SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
279 if (server) {
280 // Set the certificate to be used
281 _dprintf("SSL_CTX_use_certificate_chain_file(%s)\n", cert);
282 if (SSL_CTX_use_certificate_chain_file(ctx, cert) <= 0) {
283 _dprintf("SSL_CTX_use_certificate_chain_file() failed\n");
284 mssl_cleanup(1);
285 return 0;
287 // Indicate the key file to be used
288 _dprintf("SSL_CTX_use_PrivateKey_file(%s)\n", priv);
289 if (SSL_CTX_use_PrivateKey_file(ctx, priv, SSL_FILETYPE_PEM) <= 0) {
290 _dprintf("SSL_CTX_use_PrivateKey_file() failed\n");
291 mssl_cleanup(1);
292 return 0;
294 // Make sure the key and certificate file match
295 if (!SSL_CTX_check_private_key(ctx)) {
296 _dprintf("Private key does not match the certificate public key\n");
297 mssl_cleanup(0);
298 return 0;
302 fprintf(stderr,"[ssl_init] success!!\n"); // tmp test
303 _dprintf("%s() success\n", __FUNCTION__);
304 return 1;