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