CyaSSL configure: disable examples and tests, fix zlib test
[tomato.git] / release / src / router / mssl / mssl_openssl.c
blob7a81ef9bd1c88c35e0835a88840ed5efbfbd6a29
1 /*
3 Minimal OpenSSL Helper
4 Copyright (C) 2010 Fedor Kozhevnikov
6 Licensed under GNU GPL v2 or later
8 */
10 #define _GNU_SOURCE
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <syslog.h>
16 #include <fcntl.h>
17 #include <stdarg.h>
18 #include <stdint.h>
20 #include <openssl/rsa.h>
21 #include <openssl/crypto.h>
22 #include <openssl/x509.h>
23 #include <openssl/pem.h>
24 #include <openssl/ssl.h>
25 #include <openssl/err.h>
28 #define _dprintf(args...) while (0) {}
30 typedef struct {
31 SSL* ssl;
32 int sd;
33 } mssl_cookie_t;
35 static SSL_CTX* ctx;
37 static inline void mssl_cleanup(int err)
39 if (err) ERR_print_errors_fp(stderr);
40 SSL_CTX_free(ctx);
41 ctx = NULL;
44 static ssize_t mssl_read(void *cookie, char *buf, size_t len)
46 _dprintf("%s()\n", __FUNCTION__);
48 mssl_cookie_t *kuki = cookie;
49 int total = 0;
50 int n, err;
52 do {
53 n = SSL_read(kuki->ssl, &(buf[total]), len - total);
54 _dprintf("SSL_read(max=%d) returned %d\n", len - total, n);
56 err = SSL_get_error(kuki->ssl, n);
57 switch (err) {
58 case SSL_ERROR_NONE:
59 total += n;
60 break;
61 case SSL_ERROR_ZERO_RETURN:
62 total += n;
63 goto OUT;
64 case SSL_ERROR_WANT_WRITE:
65 case SSL_ERROR_WANT_READ:
66 break;
67 default:
68 _dprintf("%s(): SSL error %d\n", __FUNCTION__, err);
69 ERR_print_errors_fp(stderr);
70 goto OUT;
72 } while (SSL_pending(kuki->ssl));
74 OUT:
75 _dprintf("%s() returns %d\n", __FUNCTION__, total);
76 return total;
79 static ssize_t mssl_write(void *cookie, const char *buf, size_t len)
81 _dprintf("%s()\n", __FUNCTION__);
83 mssl_cookie_t *kuki = cookie;
84 int total = 0;
85 int n, err;
87 while (total < len) {
88 n = SSL_write(kuki->ssl, &(buf[total]), len - total);
89 _dprintf("SSL_write(max=%d) returned %d\n", len - total, n);
91 err = SSL_get_error(kuki->ssl, n);
92 switch (err) {
93 case SSL_ERROR_NONE:
94 total += n;
95 break;
96 case SSL_ERROR_ZERO_RETURN:
97 total += n;
98 goto OUT;
99 case SSL_ERROR_WANT_WRITE:
100 case SSL_ERROR_WANT_READ:
101 break;
102 default:
103 _dprintf("%s(): SSL error %d\n", __FUNCTION__, err);
104 ERR_print_errors_fp(stderr);
105 goto OUT;
109 OUT:
110 _dprintf("%s() returns %d\n", __FUNCTION__, total);
111 return total;
114 static int mssl_seek(void *cookie, __offmax_t *pos, int whence)
116 _dprintf("%s()\n", __FUNCTION__);
117 errno = EIO;
118 return -1;
121 static int mssl_close(void *cookie)
123 _dprintf("%s()\n", __FUNCTION__);
125 mssl_cookie_t *kuki = cookie;
126 if (!kuki) return 0;
128 if (kuki->ssl) {
129 SSL_shutdown(kuki->ssl);
130 SSL_free(kuki->ssl);
133 free(kuki);
134 return 0;
137 static const cookie_io_functions_t mssl = {
138 mssl_read, mssl_write, mssl_seek, mssl_close
141 static FILE *_ssl_fopen(int sd, int client)
143 int r;
144 mssl_cookie_t *kuki;
145 FILE *f;
147 _dprintf("%s()\n", __FUNCTION__);
149 if ((kuki = calloc(1, sizeof(*kuki))) == NULL) {
150 errno = ENOMEM;
151 return NULL;
153 kuki->sd = sd;
155 if ((kuki->ssl = SSL_new(ctx)) == NULL) {
156 _dprintf("%s: SSL_new failed\n", __FUNCTION__);
157 goto ERROR;
160 SSL_set_fd(kuki->ssl, kuki->sd);
161 SSL_set_verify(kuki->ssl, SSL_VERIFY_NONE, NULL);
162 SSL_set_mode(kuki->ssl, SSL_MODE_AUTO_RETRY);
164 r = client ? SSL_connect(kuki->ssl) : SSL_accept(kuki->ssl);
165 if (r == -1) {
166 _dprintf("%s: SSL handshake failed\n", __FUNCTION__);
167 ERR_print_errors_fp(stderr);
168 goto ERROR;
171 _dprintf("SSL connection using %s cipher\n", SSL_get_cipher(kuki->ssl));
173 if ((f = fopencookie(kuki, "r+", mssl)) == NULL) {
174 _dprintf("%s: fopencookie failed\n", __FUNCTION__);
175 goto ERROR;
177 return f;
179 ERROR:
180 mssl_close(kuki);
181 return NULL;
184 FILE *ssl_server_fopen(int sd)
186 _dprintf("%s()\n", __FUNCTION__);
187 return _ssl_fopen(sd, 0);
190 FILE *ssl_client_fopen(int sd)
192 _dprintf("%s()\n", __FUNCTION__);
193 return _ssl_fopen(sd, 1);
196 int mssl_init(char *cert, char *priv)
198 int client = (cert == NULL);
200 _dprintf("%s()\n", __FUNCTION__);
202 SSL_load_error_strings();
203 SSLeay_add_ssl_algorithms();
205 ctx = SSL_CTX_new(client ? SSLv23_client_method() : SSLv23_server_method());
206 if (!ctx) {
207 _dprintf("SSL_CTX_new() failed\n");
208 ERR_print_errors_fp(stderr);
209 return 0;
212 if (cert) {
213 _dprintf("SSL_CTX_use_certificate_file(%s)\n", cert);
214 if (SSL_CTX_use_certificate_file(ctx, cert, SSL_FILETYPE_PEM) <= 0) {
215 _dprintf("SSL_CTX_use_certificate_file() failed\n");
216 mssl_cleanup(1);
217 return 0;
220 if (cert && priv) {
221 _dprintf("SSL_CTX_use_PrivateKey_file(%s)\n", priv);
222 if (SSL_CTX_use_PrivateKey_file(ctx, priv, SSL_FILETYPE_PEM) <= 0) {
223 _dprintf("SSL_CTX_use_PrivateKey_file() failed\n");
224 mssl_cleanup(1);
225 return 0;
227 if (!SSL_CTX_check_private_key(ctx)) {
228 _dprintf("Private key does not match the certificate public key\n");
229 mssl_cleanup(0);
230 return 0;
234 _dprintf("%s() success\n", __FUNCTION__);
235 return 1;