1 /*
2
3 Copyright (c) 2009-2013 uim Project https://github.com/uim/uim
4
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in the
15 documentation and/or other materials provided with the distribution.
16 3. Neither the name of authors nor the names of its contributors
17 may be used to endorse or promote products derived from this software
18 without specific prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
21 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
24 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 SUCH DAMAGE.
31
32 */
33
34 #include <config.h>
35 #include <string.h>
36 #include <openssl/crypto.h>
37 #include <openssl/ssl.h>
38 #include <openssl/rand.h>
39 #include <openssl/err.h>
40
41 #include "uim.h"
42 #include "uim-scm.h"
43 #include "uim-scm-abbrev.h"
44 #include "uim-posix.h"
45 #include "uim-notify.h"
46 #include "gettext.h"
47 #include "dynlib.h"
48
49 #ifdef USE_OPENSSL_ENGINE
50 # include <openssl/engine.h>
51 #endif
52
53 static uim_lisp
c_ERR_get_error(void)54 c_ERR_get_error(void)
55 {
56 return MAKE_INT(ERR_get_error());
57 }
58
59 static uim_lisp
c_ERR_error_string(uim_lisp e_)60 c_ERR_error_string(uim_lisp e_)
61 {
62 char buf[BUFSIZ];
63
64 /* XXX: long->int */
65 ERR_error_string_n(C_INT(e_), buf, sizeof(buf));
66 return MAKE_STR(buf);
67 }
68
69 static uim_lisp
c_SSL_CTX_new(uim_lisp meth_)70 c_SSL_CTX_new(uim_lisp meth_)
71 {
72 SSL_CTX *ctx = SSL_CTX_new(C_PTR(meth_));
73
74 if (!ctx)
75 return uim_scm_f();
76 return MAKE_PTR(ctx);
77 }
78
79 static uim_lisp
c_SSL_CTX_free(uim_lisp ctx_)80 c_SSL_CTX_free(uim_lisp ctx_)
81 {
82 SSL_CTX_free(C_PTR(ctx_));
83 return uim_scm_t();
84 }
85
86
87 static uim_lisp
c_SSL_new(uim_lisp ctx_)88 c_SSL_new(uim_lisp ctx_)
89 {
90 SSL *ssl = SSL_new(C_PTR(ctx_));
91
92 if (!ssl)
93 return uim_scm_f();
94
95 return MAKE_PTR(ssl);
96 }
97
98 static uim_lisp
c_SSL_free(uim_lisp s_)99 c_SSL_free(uim_lisp s_)
100 {
101 SSL_free(C_PTR(s_));
102 return uim_scm_t();
103 }
104
105 static uim_lisp
c_SSL_get_version(uim_lisp s_)106 c_SSL_get_version(uim_lisp s_)
107 {
108 return MAKE_STR(SSL_get_version(C_PTR(s_)));
109 }
110
111
112 static uim_lisp
c_SSL_get_cipher(uim_lisp s_)113 c_SSL_get_cipher(uim_lisp s_)
114 {
115 return MAKE_STR(SSL_get_cipher(C_PTR(s_)));
116 }
117
118
119 static uim_lisp
c_SSL_shutdown(uim_lisp s_)120 c_SSL_shutdown(uim_lisp s_)
121 {
122 return MAKE_INT(SSL_shutdown(C_PTR(s_)));
123 }
124
125 static uim_lisp
c_SSL_set_fd(uim_lisp s_,uim_lisp fd_)126 c_SSL_set_fd(uim_lisp s_, uim_lisp fd_)
127 {
128 return MAKE_INT(SSL_set_fd(C_PTR(s_), C_INT(fd_)));
129 }
130
131 static uim_lisp
c_SSL_connect(uim_lisp s_)132 c_SSL_connect(uim_lisp s_)
133 {
134
135 RAND_poll();
136 srand(time(NULL));
137
138 while (RAND_status() == 0) {
139 unsigned short seed = (unsigned short)rand();
140
141 RAND_seed(&seed, sizeof(seed));
142 }
143 return MAKE_INT(SSL_connect(C_PTR(s_)));
144 }
145
146 struct c_SSL_read_args {
147 const unsigned char *buf;
148 int nr;
149 };
150
151 static uim_lisp
c_SSL_read_internal(struct c_SSL_read_args * args)152 c_SSL_read_internal(struct c_SSL_read_args *args)
153 {
154 int i;
155 uim_lisp ret_ = uim_scm_null();
156 const unsigned char *p = args->buf;
157
158 for (i = 0; i < args->nr; i++) {
159 ret_ = CONS(MAKE_CHAR(*p), ret_);
160 p++;
161 }
162 return ret_;
163 }
164
165 static uim_lisp
c_SSL_read(uim_lisp s_,uim_lisp nbytes_)166 c_SSL_read(uim_lisp s_, uim_lisp nbytes_)
167 {
168 unsigned char *buf;
169 uim_lisp ret_;
170 int nbytes = C_INT(nbytes_);
171 int nr;
172 struct c_SSL_read_args args;
173
174 buf = uim_malloc(nbytes);
175 if ((nr = SSL_read(C_PTR(s_), buf, nbytes)) == 0)
176 return uim_scm_eof();
177 if (nr < 0)
178 return uim_scm_f();
179
180 args.buf = buf;
181 args.nr = nr;
182 ret_ = (uim_lisp)uim_scm_call_with_gc_ready_stack((uim_gc_gate_func_ptr)c_SSL_read_internal,
183 (void *)&args);
184 free(buf);
185 return uim_scm_callf("reverse", "o", ret_);
186 }
187
188 static uim_lisp
c_SSL_write(uim_lisp s_,uim_lisp buf_)189 c_SSL_write(uim_lisp s_, uim_lisp buf_)
190 {
191 int nbytes = uim_scm_length(buf_);
192 uim_lisp ret_;
193 unsigned char *buf;
194 unsigned char *p;
195
196 buf = p = uim_malloc(nbytes);
197 while (!NULLP(buf_)) {
198 *p = C_CHAR(CAR(buf_));
199 p++;
200 buf_ = CDR(buf_);
201 }
202 ret_ = MAKE_INT((int)SSL_write(C_PTR(s_), buf, nbytes));
203 free(buf);
204 return ret_;
205 }
206
207 /* SSLv2 */
208 static uim_lisp
c_SSLv2_method(void)209 c_SSLv2_method(void)
210 {
211 #ifndef OPENSSL_NO_SSL2
212 return MAKE_PTR(SSLv2_method());
213 #else
214 uim_notify_fatal(N_("uim-openssl: SSLv2_method() is not supported on this system"));
215 return uim_scm_f();
216 #endif
217 }
218 static uim_lisp
c_SSLv2_server_method(void)219 c_SSLv2_server_method(void)
220 {
221 #ifndef OPENSSL_NO_SSL2
222 return MAKE_PTR(SSLv2_server_method());
223 #else
224 uim_notify_fatal(N_("uim-openssl: SSLv2_server_method() is not supported on this system"));
225 return uim_scm_f();
226 #endif
227 }
228 static uim_lisp
c_SSLv2_client_method(void)229 c_SSLv2_client_method(void)
230 {
231 #ifndef OPENSSL_NO_SSL2
232 return MAKE_PTR(SSLv2_client_method());
233 #else
234 uim_notify_fatal(N_("uim-openssl: SSLv2_client_method() is not supported on this system"));
235 return uim_scm_f();
236 #endif
237 }
238
239 /* SSLv3 */
240 static uim_lisp
c_SSLv3_method(void)241 c_SSLv3_method(void)
242 {
243 #ifndef OPENSSL_NO_SSL3
244 return MAKE_PTR(SSLv3_method());
245 #else
246 uim_notify_fatal(N_("uim-openssl: SSLv3_method() is not supported on this system"));
247 return uim_scm_f();
248 #endif
249 }
250 static uim_lisp
c_SSLv3_server_method(void)251 c_SSLv3_server_method(void)
252 {
253 #ifndef OPENSSL_NO_SSL3
254 return MAKE_PTR(SSLv3_server_method());
255 #else
256 uim_notify_fatal(N_("uim-openssl: SSLv3_server_method() is not supported on this system"));
257 return uim_scm_f();
258 #endif
259 }
260 static uim_lisp
c_SSLv3_client_method(void)261 c_SSLv3_client_method(void)
262 {
263 #ifndef OPENSSL_NO_SSL3
264 return MAKE_PTR(SSLv3_client_method());
265 #else
266 uim_notify_fatal(N_("uim-openssl: SSLv3_client_method() is not supported on this system"));
267 return uim_scm_f();
268 #endif
269 }
270
271 /* SSLv3 but can rollback to v2 */
272 static uim_lisp
c_SSLv23_method(void)273 c_SSLv23_method(void)
274 {
275 return MAKE_PTR(SSLv23_method());
276 }
277 static uim_lisp
c_SSLv23_server_method(void)278 c_SSLv23_server_method(void)
279 {
280 return MAKE_PTR(SSLv23_server_method());
281 }
282 static uim_lisp
c_SSLv23_client_method(void)283 c_SSLv23_client_method(void)
284 {
285 return MAKE_PTR(SSLv23_client_method());
286 }
287
288 /* TLSv1.0 */
289 static uim_lisp
c_TLSv1_method(void)290 c_TLSv1_method(void)
291 {
292 return MAKE_PTR(TLSv1_method());
293 }
294 static uim_lisp
c_TLSv1_server_method(void)295 c_TLSv1_server_method(void)
296 {
297 return MAKE_PTR(TLSv1_server_method());
298 }
299 static uim_lisp
c_TLSv1_client_method(void)300 c_TLSv1_client_method(void)
301 {
302 return MAKE_PTR(TLSv1_client_method());
303 }
304
305 /* DTLSv1.0 */
306 static uim_lisp
c_DTLSv1_method(void)307 c_DTLSv1_method(void)
308 {
309 #ifdef HAVE_OPENSSL_DTLSv1
310 return MAKE_PTR(DTLSv1_method());
311 #else
312 uim_notify_fatal(N_("uim-openssl: DTLSv1_method() is not supported on this system"));
313 return uim_scm_f();
314 #endif
315 }
316 static uim_lisp
c_DTLSv1_server_method(void)317 c_DTLSv1_server_method(void)
318 {
319 #ifdef HAVE_OPENSSL_DTLSv1
320 return MAKE_PTR(DTLSv1_server_method());
321 #else
322 uim_notify_fatal(N_("uim-openssl: DTLSv1_server_method() is not supported on this system"));
323 return uim_scm_f();
324 #endif
325 }
326 static uim_lisp
c_DTLSv1_client_method(void)327 c_DTLSv1_client_method(void)
328 {
329 #ifdef HAVE_OPENSSL_DTLSv1
330 return MAKE_PTR(DTLSv1_client_method());
331 #else
332 uim_notify_fatal(N_("uim-openssl: DTLSv1_client_method() is not supported on this system"));
333 return uim_scm_f();
334 #endif
335 }
336
337
338 void
uim_plugin_instance_init(void)339 uim_plugin_instance_init(void)
340 {
341 /* too old? */
342 if (!SSLeay_add_ssl_algorithms())
343 return;
344 if (!SSL_library_init())
345 return;
346 #ifdef USE_OPENSSL_ENGINE
347 ENGINE_load_builtin_engines();
348 ENGINE_register_all_complete();
349 #endif
350
351 SSL_load_error_strings();
352
353 uim_scm_init_proc0("ERR-get-error", c_ERR_get_error);
354 uim_scm_init_proc1("ERR-error-string", c_ERR_error_string);
355 uim_scm_init_proc1("SSL-CTX-new", c_SSL_CTX_new);
356 uim_scm_init_proc1("SSL-CTX-free", c_SSL_CTX_free);
357 uim_scm_init_proc1("SSL-new", c_SSL_new);
358 uim_scm_init_proc1("SSL-free", c_SSL_free);
359 uim_scm_init_proc1("SSL-get-version", c_SSL_get_version);
360 uim_scm_init_proc1("SSL-get-cipher", c_SSL_get_cipher);
361 uim_scm_init_proc1("SSL-shutdown", c_SSL_shutdown);
362 uim_scm_init_proc2("SSL-set-fd", c_SSL_set_fd);
363 uim_scm_init_proc1("SSL-connect", c_SSL_connect);
364 uim_scm_init_proc2("SSL-read", c_SSL_read);
365 uim_scm_init_proc2("SSL-write", c_SSL_write);
366 uim_scm_init_proc0("SSLv2-method", c_SSLv2_method);
367 uim_scm_init_proc0("SSLv2-server-method", c_SSLv2_server_method);
368 uim_scm_init_proc0("SSLv2-client-method", c_SSLv2_client_method);
369 uim_scm_init_proc0("SSLv3-method", c_SSLv3_method);
370 uim_scm_init_proc0("SSLv3-server-method", c_SSLv3_server_method);
371 uim_scm_init_proc0("SSLv3-client-method", c_SSLv3_client_method);
372 uim_scm_init_proc0("SSLv23-method", c_SSLv23_method);
373 uim_scm_init_proc0("SSLv23-server-method", c_SSLv23_server_method);
374 uim_scm_init_proc0("SSLv23-client-method", c_SSLv23_client_method);
375 uim_scm_init_proc0("TLSv1-method", c_TLSv1_method);
376 uim_scm_init_proc0("TLSv1-server-method", c_TLSv1_server_method);
377 uim_scm_init_proc0("TLSv1-client-method", c_TLSv1_client_method);
378 uim_scm_init_proc0("DTLSv1-method", c_DTLSv1_method);
379 uim_scm_init_proc0("DTLSv1-server-metho", c_DTLSv1_server_method);
380 uim_scm_init_proc0("DTLSv1-client-method", c_DTLSv1_client_method);
381 }
382
383 void
uim_plugin_instance_quit(void)384 uim_plugin_instance_quit(void)
385 {
386 ERR_free_strings();
387 }
388