OSDN Git Service

ruby-1.9.1-rc1
[splhack/AndroidRuby.git] / lib / ruby-1.9.1-rc1 / ext / openssl / ossl_ssl.c
1 /*
2  * $Id: ossl_ssl.c 19080 2008-09-03 08:00:05Z ko1 $
3  * 'OpenSSL for Ruby' project
4  * Copyright (C) 2000-2002  GOTOU Yuuzou <gotoyuzo@notwork.org>
5  * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
6  * Copyright (C) 2001-2007  Technorama Ltd. <oss-ruby@technorama.net>
7  * All rights reserved.
8  */
9 /*
10  * This program is licenced under the same licence as Ruby.
11  * (See the file 'LICENCE'.)
12  */
13 #include "ossl.h"
14
15 #if defined(HAVE_UNISTD_H)
16 #  include <unistd.h> /* for read(), and write() */
17 #endif
18
19 #define numberof(ary) (sizeof(ary)/sizeof(ary[0]))
20
21 #ifdef _WIN32
22 #  define TO_SOCKET(s) _get_osfhandle(s)
23 #else
24 #  define TO_SOCKET(s) s
25 #endif
26
27 VALUE mSSL;
28 VALUE eSSLError;
29 VALUE cSSLContext;
30 VALUE cSSLSocket;
31
32 #define ossl_sslctx_set_cert(o,v)        rb_iv_set((o),"@cert",(v))
33 #define ossl_sslctx_set_key(o,v)         rb_iv_set((o),"@key",(v))
34 #define ossl_sslctx_set_client_ca(o,v)   rb_iv_set((o),"@client_ca",(v))
35 #define ossl_sslctx_set_ca_file(o,v)     rb_iv_set((o),"@ca_file",(v))
36 #define ossl_sslctx_set_ca_path(o,v)     rb_iv_set((o),"@ca_path",(v))
37 #define ossl_sslctx_set_timeout(o,v)     rb_iv_set((o),"@timeout",(v))
38 #define ossl_sslctx_set_verify_mode(o,v) rb_iv_set((o),"@verify_mode",(v))
39 #define ossl_sslctx_set_verify_dep(o,v)  rb_iv_set((o),"@verify_depth",(v))
40 #define ossl_sslctx_set_verify_cb(o,v)   rb_iv_set((o),"@verify_callback",(v))
41 #define ossl_sslctx_set_options(o,v)     rb_iv_set((o),"@options",(v))
42 #define ossl_sslctx_set_cert_store(o,v)  rb_iv_set((o),"@cert_store",(v))
43 #define ossl_sslctx_set_extra_cert(o,v)  rb_iv_set((o),"@extra_chain_cert",(v))
44 #define ossl_sslctx_set_client_cert_cb(o,v) rb_iv_set((o),"@client_cert_cb",(v))
45 #define ossl_sslctx_set_tmp_dh_cb(o,v)   rb_iv_set((o),"@tmp_dh_callback",(v))
46 #define ossl_sslctx_set_sess_id_ctx(o, v) rb_iv_get((o),"@session_id_context"(v))
47
48 #define ossl_sslctx_get_cert(o)          rb_iv_get((o),"@cert")
49 #define ossl_sslctx_get_key(o)           rb_iv_get((o),"@key")
50 #define ossl_sslctx_get_client_ca(o)     rb_iv_get((o),"@client_ca")
51 #define ossl_sslctx_get_ca_file(o)       rb_iv_get((o),"@ca_file")
52 #define ossl_sslctx_get_ca_path(o)       rb_iv_get((o),"@ca_path")
53 #define ossl_sslctx_get_timeout(o)       rb_iv_get((o),"@timeout")
54 #define ossl_sslctx_get_verify_mode(o)   rb_iv_get((o),"@verify_mode")
55 #define ossl_sslctx_get_verify_dep(o)    rb_iv_get((o),"@verify_depth")
56 #define ossl_sslctx_get_verify_cb(o)     rb_iv_get((o),"@verify_callback")
57 #define ossl_sslctx_get_options(o)       rb_iv_get((o),"@options")
58 #define ossl_sslctx_get_cert_store(o)    rb_iv_get((o),"@cert_store")
59 #define ossl_sslctx_get_extra_cert(o)    rb_iv_get((o),"@extra_chain_cert")
60 #define ossl_sslctx_get_client_cert_cb(o) rb_iv_get((o),"@client_cert_cb")
61 #define ossl_sslctx_get_tmp_dh_cb(o)     rb_iv_get((o),"@tmp_dh_callback")
62 #define ossl_sslctx_get_sess_id_ctx(o)   rb_iv_get((o),"@session_id_context")
63
64 static const char *ossl_sslctx_attrs[] = {
65     "cert", "key", "client_ca", "ca_file", "ca_path",
66     "timeout", "verify_mode", "verify_depth",
67     "verify_callback", "options", "cert_store", "extra_chain_cert",
68     "client_cert_cb", "tmp_dh_callback", "session_id_context",
69     "session_get_cb", "session_new_cb", "session_remove_cb",
70 };
71
72 #define ossl_ssl_get_io(o)           rb_iv_get((o),"@io")
73 #define ossl_ssl_get_ctx(o)          rb_iv_get((o),"@context")
74 #define ossl_ssl_get_sync_close(o)   rb_iv_get((o),"@sync_close")
75 #define ossl_ssl_get_x509(o)         rb_iv_get((o),"@x509")
76 #define ossl_ssl_get_key(o)          rb_iv_get((o),"@key")
77 #define ossl_ssl_get_tmp_dh(o)       rb_iv_get((o),"@tmp_dh")
78
79 #define ossl_ssl_set_io(o,v)         rb_iv_set((o),"@io",(v))
80 #define ossl_ssl_set_ctx(o,v)        rb_iv_set((o),"@context",(v))
81 #define ossl_ssl_set_sync_close(o,v) rb_iv_set((o),"@sync_close",(v))
82 #define ossl_ssl_set_x509(o,v)       rb_iv_set((o),"@x509",(v))
83 #define ossl_ssl_set_key(o,v)        rb_iv_set((o),"@key",(v))
84 #define ossl_ssl_set_tmp_dh(o,v)     rb_iv_set((o),"@tmp_dh",(v))
85
86 static const char *ossl_ssl_attr_readers[] = { "io", "context", };
87 static const char *ossl_ssl_attrs[] = { "sync_close", };
88
89 ID ID_callback_state;
90
91 /*
92  * SSLContext class
93  */
94 struct {
95     const char *name;
96     SSL_METHOD *(*func)(void);
97 } ossl_ssl_method_tab[] = {
98 #define OSSL_SSL_METHOD_ENTRY(name) { #name, name##_method }
99     OSSL_SSL_METHOD_ENTRY(TLSv1),
100     OSSL_SSL_METHOD_ENTRY(TLSv1_server),
101     OSSL_SSL_METHOD_ENTRY(TLSv1_client),
102     OSSL_SSL_METHOD_ENTRY(SSLv2),
103     OSSL_SSL_METHOD_ENTRY(SSLv2_server),
104     OSSL_SSL_METHOD_ENTRY(SSLv2_client),
105     OSSL_SSL_METHOD_ENTRY(SSLv3),
106     OSSL_SSL_METHOD_ENTRY(SSLv3_server),
107     OSSL_SSL_METHOD_ENTRY(SSLv3_client),
108     OSSL_SSL_METHOD_ENTRY(SSLv23),
109     OSSL_SSL_METHOD_ENTRY(SSLv23_server),
110     OSSL_SSL_METHOD_ENTRY(SSLv23_client),
111 #undef OSSL_SSL_METHOD_ENTRY
112 };
113
114 int ossl_ssl_ex_vcb_idx;
115 int ossl_ssl_ex_store_p;
116 int ossl_ssl_ex_ptr_idx;
117 int ossl_ssl_ex_client_cert_cb_idx;
118 int ossl_ssl_ex_tmp_dh_callback_idx;
119
120 static void
121 ossl_sslctx_free(SSL_CTX *ctx)
122 {
123     if(ctx && SSL_CTX_get_ex_data(ctx, ossl_ssl_ex_store_p)== (void*)1)
124         ctx->cert_store = NULL;
125     SSL_CTX_free(ctx);
126 }
127
128 static VALUE
129 ossl_sslctx_s_alloc(VALUE klass)
130 {
131     SSL_CTX *ctx;
132
133     ctx = SSL_CTX_new(SSLv23_method());
134     if (!ctx) {
135         ossl_raise(eSSLError, "SSL_CTX_new:");
136     }
137     SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
138     SSL_CTX_set_options(ctx, SSL_OP_ALL);
139     return Data_Wrap_Struct(klass, 0, ossl_sslctx_free, ctx);
140 }
141
142 static VALUE
143 ossl_sslctx_set_ssl_version(VALUE self, VALUE ssl_method)
144 {
145     SSL_METHOD *method = NULL;
146     const char *s;
147     int i;
148
149     SSL_CTX *ctx;
150     if(TYPE(ssl_method) == T_SYMBOL)
151         s = rb_id2name(SYM2ID(ssl_method));
152     else
153         s =  StringValuePtr(ssl_method);
154     for (i = 0; i < numberof(ossl_ssl_method_tab); i++) {
155         if (strcmp(ossl_ssl_method_tab[i].name, s) == 0) {
156             method = ossl_ssl_method_tab[i].func();
157             break;
158         }
159     }
160     if (!method) {
161         ossl_raise(rb_eArgError, "unknown SSL method `%s'.", s);
162     }
163     Data_Get_Struct(self, SSL_CTX, ctx);
164     if (SSL_CTX_set_ssl_version(ctx, method) != 1) {
165         ossl_raise(eSSLError, "SSL_CTX_set_ssl_version:");
166     }
167
168     return ssl_method;
169 }
170
171 /*
172  * call-seq:
173  *    SSLContext.new => ctx
174  *    SSLContext.new(:TLSv1) => ctx
175  *    SSLContext.new("SSLv23_client") => ctx
176  *
177  * You can get a list of valid methods with OpenSSL::SSL::SSLContext::METHODS
178  */
179 static VALUE
180 ossl_sslctx_initialize(int argc, VALUE *argv, VALUE self)
181 {
182     VALUE ssl_method;
183     int i;
184
185     for(i = 0; i < numberof(ossl_sslctx_attrs); i++){
186         char buf[32];
187         snprintf(buf, sizeof(buf), "@%s", ossl_sslctx_attrs[i]);
188         rb_iv_set(self, buf, Qnil);
189     }
190     if (rb_scan_args(argc, argv, "01", &ssl_method) == 0){
191         return self;
192     }
193     ossl_sslctx_set_ssl_version(self, ssl_method);
194
195     return self;
196 }
197
198 static VALUE
199 ossl_call_client_cert_cb(VALUE obj)
200 {
201     VALUE cb, ary, cert, key;
202     SSL *ssl;
203
204     Data_Get_Struct(obj, SSL, ssl);
205     cb = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_client_cert_cb_idx);
206     if (NIL_P(cb)) return Qfalse;
207     ary = rb_funcall(cb, rb_intern("call"), 1, obj);
208     Check_Type(ary, T_ARRAY);
209     GetX509CertPtr(cert = rb_ary_entry(ary, 0));
210     GetPKeyPtr(key = rb_ary_entry(ary, 1));
211     ossl_ssl_set_x509(obj, cert);
212     ossl_ssl_set_key(obj, key);
213
214     return Qtrue;
215 }
216
217 static int
218 ossl_client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
219 {
220     VALUE obj;
221     int status, success;
222
223     obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);
224     success = rb_protect((VALUE(*)_((VALUE)))ossl_call_client_cert_cb,
225                          obj, &status);
226     if (status || !success) return 0;
227     *x509 = DupX509CertPtr(ossl_ssl_get_x509(obj));
228     *pkey = DupPKeyPtr(ossl_ssl_get_key(obj));
229
230     return 1;
231 }
232
233 #if !defined(OPENSSL_NO_DH)
234 static VALUE
235 ossl_call_tmp_dh_callback(VALUE *args)
236 {
237     SSL *ssl;
238     VALUE cb, dh;
239     EVP_PKEY *pkey;
240
241     Data_Get_Struct(args[0], SSL, ssl);
242     cb = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_tmp_dh_callback_idx);
243     if (NIL_P(cb)) return Qfalse;
244     dh = rb_funcall(cb, rb_intern("call"), 3, args[0], args[1], args[2]);
245     pkey = GetPKeyPtr(dh);
246     if (EVP_PKEY_type(pkey->type) != EVP_PKEY_DH) return Qfalse;
247     ossl_ssl_set_tmp_dh(args[0], dh);
248
249     return Qtrue;
250 }
251
252 static DH*
253 ossl_tmp_dh_callback(SSL *ssl, int is_export, int keylength)
254 {
255     VALUE args[3];
256     int status, success;
257
258     args[0] = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);
259     args[1] = INT2FIX(is_export);
260     args[2] = INT2FIX(keylength);
261     success = rb_protect((VALUE(*)_((VALUE)))ossl_call_tmp_dh_callback,
262                          (VALUE)args, &status);
263     if (status || !success) return NULL;
264
265     return GetPKeyPtr(ossl_ssl_get_tmp_dh(args[0]))->pkey.dh;
266 }
267
268 static DH*
269 ossl_default_tmp_dh_callback(SSL *ssl, int is_export, int keylength)
270 {
271     rb_warning("using default DH parameters.");
272
273     switch(keylength){
274     case 512:
275         return OSSL_DEFAULT_DH_512;
276     case 1024:
277         return OSSL_DEFAULT_DH_1024;
278     }
279     return NULL;
280 }
281 #endif /* OPENSSL_NO_DH */
282
283 static int
284 ossl_ssl_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
285 {
286     VALUE cb;
287     SSL *ssl;
288
289     ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
290     cb = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_vcb_idx);
291     X509_STORE_CTX_set_ex_data(ctx, ossl_verify_cb_idx, (void*)cb);
292     return ossl_verify_cb(preverify_ok, ctx);
293 }
294
295 static VALUE
296 ossl_call_session_get_cb(VALUE ary)
297 {
298     VALUE ssl_obj, sslctx_obj, cb;
299     
300     Check_Type(ary, T_ARRAY);
301     ssl_obj = rb_ary_entry(ary, 0);
302
303     sslctx_obj = rb_iv_get(ssl_obj, "@context");
304     if (NIL_P(sslctx_obj)) return Qnil;
305     cb = rb_iv_get(sslctx_obj, "@session_get_cb");
306     if (NIL_P(cb)) return Qnil;
307
308     return rb_funcall(cb, rb_intern("call"), 1, ary);
309 }
310
311 /* this method is currently only called for servers (in OpenSSL <= 0.9.8e) */
312 static SSL_SESSION *
313 ossl_sslctx_session_get_cb(SSL *ssl, unsigned char *buf, int len, int *copy)
314 {
315     VALUE ary, ssl_obj, ret_obj;
316     SSL_SESSION *sess;
317     void *ptr;
318     int state = 0;
319
320     OSSL_Debug("SSL SESSION get callback entered");
321     if ((ptr = SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx)) == NULL)
322         return NULL;
323     ssl_obj = (VALUE)ptr;
324     ary = rb_ary_new2(2);
325     rb_ary_push(ary, ssl_obj);
326     rb_ary_push(ary, rb_str_new((const char *)buf, len));
327
328     ret_obj = rb_protect((VALUE(*)_((VALUE)))ossl_call_session_get_cb, ary, &state);
329     if (state) {
330         rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(state));
331         return NULL;
332     }
333     if (!rb_obj_is_instance_of(ret_obj, cSSLSession))
334         return NULL;
335
336     SafeGetSSLSession(ret_obj, sess);
337     *copy = 1;
338
339     return sess;
340 }
341
342 static VALUE
343 ossl_call_session_new_cb(VALUE ary)
344 {
345     VALUE ssl_obj, sslctx_obj, cb;
346     
347     Check_Type(ary, T_ARRAY);
348     ssl_obj = rb_ary_entry(ary, 0);
349
350     sslctx_obj = rb_iv_get(ssl_obj, "@context");
351     if (NIL_P(sslctx_obj)) return Qnil;
352     cb = rb_iv_get(sslctx_obj, "@session_new_cb");
353     if (NIL_P(cb)) return Qnil;
354
355     return rb_funcall(cb, rb_intern("call"), 1, ary);
356 }
357
358 /* return 1 normal.  return 0 removes the session */
359 static int
360 ossl_sslctx_session_new_cb(SSL *ssl, SSL_SESSION *sess)
361 {
362     VALUE ary, ssl_obj, sess_obj, ret_obj;
363     void *ptr;
364     int state = 0;
365
366     OSSL_Debug("SSL SESSION new callback entered");
367
368     if ((ptr = SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx)) == NULL)
369         return 1;
370     ssl_obj = (VALUE)ptr;
371     sess_obj = rb_obj_alloc(cSSLSession);
372     CRYPTO_add(&sess->references, 1, CRYPTO_LOCK_SSL_SESSION);
373     DATA_PTR(sess_obj) = sess;
374
375     ary = rb_ary_new2(2);
376     rb_ary_push(ary, ssl_obj);
377     rb_ary_push(ary, sess_obj);
378
379     ret_obj = rb_protect((VALUE(*)_((VALUE)))ossl_call_session_new_cb, ary, &state);
380     if (state) {
381         rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(state));
382         return 0; /* what should be returned here??? */
383     }
384
385     return RTEST(ret_obj) ? 1 : 0;
386 }
387
388 #if 0                           /* unused */
389 static VALUE
390 ossl_call_session_remove_cb(VALUE ary)
391 {
392     VALUE sslctx_obj, cb;
393     
394     Check_Type(ary, T_ARRAY);
395     sslctx_obj = rb_ary_entry(ary, 0);
396
397     cb = rb_iv_get(sslctx_obj, "@session_remove_cb");
398     if (NIL_P(cb)) return Qnil;
399
400     return rb_funcall(cb, rb_intern("call"), 1, ary);
401 }
402 #endif
403
404 static void
405 ossl_sslctx_session_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess)
406 {
407     VALUE ary, sslctx_obj, sess_obj, ret_obj;
408     void *ptr;
409     int state = 0;
410
411     OSSL_Debug("SSL SESSION remove callback entered");
412
413     if ((ptr = SSL_CTX_get_ex_data(ctx, ossl_ssl_ex_ptr_idx)) == NULL)
414         return;
415     sslctx_obj = (VALUE)ptr;
416     sess_obj = rb_obj_alloc(cSSLSession);
417     CRYPTO_add(&sess->references, 1, CRYPTO_LOCK_SSL_SESSION);
418     DATA_PTR(sess_obj) = sess;
419
420     ary = rb_ary_new2(2);
421     rb_ary_push(ary, sslctx_obj);
422     rb_ary_push(ary, sess_obj);
423
424     ret_obj = rb_protect((VALUE(*)_((VALUE)))ossl_call_session_new_cb, ary, &state);
425     if (state) {
426 /*
427   the SSL_CTX is frozen, nowhere to save state.
428   there is no common accessor method to check it either.
429         rb_ivar_set(sslctx_obj, ID_callback_state, INT2NUM(state));
430 */
431     }
432 }
433
434 static VALUE
435 ossl_sslctx_add_extra_chain_cert_i(VALUE i, VALUE arg)
436 {
437     X509 *x509;
438     SSL_CTX *ctx;
439
440     Data_Get_Struct(arg, SSL_CTX, ctx);
441     x509 = DupX509CertPtr(i);
442     if(!SSL_CTX_add_extra_chain_cert(ctx, x509)){
443         ossl_raise(eSSLError, NULL);
444     }
445
446     return i;
447 }
448
449 /*
450  * call-seq:
451  *    ctx.setup => Qtrue # first time
452  *    ctx.setup => nil # thereafter
453  *
454  * This method is called automatically when a new SSLSocket is created.
455  * Normally you do not need to call this method (unless you are writing an extension in C).
456  */
457 static VALUE
458 ossl_sslctx_setup(VALUE self)
459 {
460     SSL_CTX *ctx;
461     X509 *cert = NULL, *client_ca = NULL;
462     X509_STORE *store;
463     EVP_PKEY *key = NULL;
464     char *ca_path = NULL, *ca_file = NULL;
465     int i, verify_mode;
466     VALUE val;
467
468     if(OBJ_FROZEN(self)) return Qnil;
469     Data_Get_Struct(self, SSL_CTX, ctx);
470
471 #if !defined(OPENSSL_NO_DH)
472     if (RTEST(ossl_sslctx_get_tmp_dh_cb(self))){
473         SSL_CTX_set_tmp_dh_callback(ctx, ossl_tmp_dh_callback);
474     }
475     else{
476         SSL_CTX_set_tmp_dh_callback(ctx, ossl_default_tmp_dh_callback);
477     }
478 #endif
479     SSL_CTX_set_ex_data(ctx, ossl_ssl_ex_ptr_idx, (void*)self);
480
481     val = ossl_sslctx_get_cert_store(self);
482     if(!NIL_P(val)){
483         /*
484          * WORKAROUND:
485          *   X509_STORE can count references, but
486          *   X509_STORE_free() doesn't care it.
487          *   So we won't increment it but mark it by ex_data.
488          */
489         store = GetX509StorePtr(val); /* NO NEED TO DUP */
490         SSL_CTX_set_cert_store(ctx, store);
491         SSL_CTX_set_ex_data(ctx, ossl_ssl_ex_store_p, (void*)1);
492     }
493
494     val = ossl_sslctx_get_extra_cert(self);
495     if(!NIL_P(val)){
496         rb_block_call(val, rb_intern("each"), 0, 0, ossl_sslctx_add_extra_chain_cert_i, self);
497     }
498
499     /* private key may be bundled in certificate file. */
500     val = ossl_sslctx_get_cert(self);
501     cert = NIL_P(val) ? NULL : GetX509CertPtr(val); /* NO DUP NEEDED */
502     val = ossl_sslctx_get_key(self);
503     key = NIL_P(val) ? NULL : GetPKeyPtr(val); /* NO DUP NEEDED */
504     if (cert && key) {
505         if (!SSL_CTX_use_certificate(ctx, cert)) {
506             /* Adds a ref => Safe to FREE */
507             ossl_raise(eSSLError, "SSL_CTX_use_certificate:");
508         }
509         if (!SSL_CTX_use_PrivateKey(ctx, key)) {
510             /* Adds a ref => Safe to FREE */
511             ossl_raise(eSSLError, "SSL_CTX_use_PrivateKey:");
512         }
513         if (!SSL_CTX_check_private_key(ctx)) {
514             ossl_raise(eSSLError, "SSL_CTX_check_private_key:");
515         }
516     }
517
518     val = ossl_sslctx_get_client_ca(self);
519     if(!NIL_P(val)){
520         if(TYPE(val) == T_ARRAY){
521             for(i = 0; i < RARRAY_LEN(val); i++){
522                 client_ca = GetX509CertPtr(RARRAY_PTR(val)[i]);
523                 if (!SSL_CTX_add_client_CA(ctx, client_ca)){
524                     /* Copies X509_NAME => FREE it. */
525                     ossl_raise(eSSLError, "SSL_CTX_add_client_CA");
526                 }
527             }
528         }
529         else{
530             client_ca = GetX509CertPtr(val); /* NO DUP NEEDED. */
531             if (!SSL_CTX_add_client_CA(ctx, client_ca)){
532                 /* Copies X509_NAME => FREE it. */
533                 ossl_raise(eSSLError, "SSL_CTX_add_client_CA");
534             }
535         }
536     }
537
538     val = ossl_sslctx_get_ca_file(self);
539     ca_file = NIL_P(val) ? NULL : StringValuePtr(val);
540     val = ossl_sslctx_get_ca_path(self);
541     ca_path = NIL_P(val) ? NULL : StringValuePtr(val);
542     if(ca_file || ca_path){
543         if (!SSL_CTX_load_verify_locations(ctx, ca_file, ca_path))
544             rb_warning("can't set verify locations");
545     }
546
547     val = ossl_sslctx_get_verify_mode(self);
548     verify_mode = NIL_P(val) ? SSL_VERIFY_NONE : NUM2INT(val);
549     SSL_CTX_set_verify(ctx, verify_mode, ossl_ssl_verify_callback);
550     if (RTEST(ossl_sslctx_get_client_cert_cb(self)))
551         SSL_CTX_set_client_cert_cb(ctx, ossl_client_cert_cb);
552
553     val = ossl_sslctx_get_timeout(self);
554     if(!NIL_P(val)) SSL_CTX_set_timeout(ctx, NUM2LONG(val));
555
556     val = ossl_sslctx_get_verify_dep(self);
557     if(!NIL_P(val)) SSL_CTX_set_verify_depth(ctx, NUM2LONG(val));
558
559     val = ossl_sslctx_get_options(self);
560     if(!NIL_P(val)) SSL_CTX_set_options(ctx, NUM2LONG(val));
561     rb_obj_freeze(self);
562
563     val = ossl_sslctx_get_sess_id_ctx(self);
564     if (!NIL_P(val)){
565         StringValue(val);
566         if (!SSL_CTX_set_session_id_context(ctx, (unsigned char *)RSTRING_PTR(val),
567                                             RSTRING_LEN(val))){
568             ossl_raise(eSSLError, "SSL_CTX_set_session_id_context:");
569         }
570     }
571
572     if (RTEST(rb_iv_get(self, "@session_get_cb"))) {
573         SSL_CTX_sess_set_get_cb(ctx, ossl_sslctx_session_get_cb);
574         OSSL_Debug("SSL SESSION get callback added");
575     }
576     if (RTEST(rb_iv_get(self, "@session_new_cb"))) {
577         SSL_CTX_sess_set_new_cb(ctx, ossl_sslctx_session_new_cb);
578         OSSL_Debug("SSL SESSION new callback added");
579     }
580     if (RTEST(rb_iv_get(self, "@session_remove_cb"))) {
581         SSL_CTX_sess_set_remove_cb(ctx, ossl_sslctx_session_remove_cb);
582         OSSL_Debug("SSL SESSION remove callback added");
583     }
584     return Qtrue;
585 }
586
587 static VALUE
588 ossl_ssl_cipher_to_ary(SSL_CIPHER *cipher)
589 {
590     VALUE ary;
591     int bits, alg_bits;
592
593     ary = rb_ary_new2(4);
594     rb_ary_push(ary, rb_str_new2(SSL_CIPHER_get_name(cipher)));
595     rb_ary_push(ary, rb_str_new2(SSL_CIPHER_get_version(cipher)));
596     bits = SSL_CIPHER_get_bits(cipher, &alg_bits);
597     rb_ary_push(ary, INT2FIX(bits));
598     rb_ary_push(ary, INT2FIX(alg_bits));
599
600     return ary;
601 }
602
603 /*
604  * call-seq:
605  *    ctx.ciphers => [[name, version, bits, alg_bits], ...]
606  */
607 static VALUE
608 ossl_sslctx_get_ciphers(VALUE self)
609 {
610     SSL_CTX *ctx;
611     STACK_OF(SSL_CIPHER) *ciphers;
612     SSL_CIPHER *cipher;
613     VALUE ary;
614     int i, num;
615
616     Data_Get_Struct(self, SSL_CTX, ctx);
617     if(!ctx){
618         rb_warning("SSL_CTX is not initialized.");
619         return Qnil;
620     }
621     ciphers = ctx->cipher_list;
622
623     if (!ciphers)
624         return rb_ary_new();
625
626     num = sk_num((STACK*)ciphers);
627     ary = rb_ary_new2(num);
628     for(i = 0; i < num; i++){
629         cipher = (SSL_CIPHER*)sk_value((STACK*)ciphers, i);
630         rb_ary_push(ary, ossl_ssl_cipher_to_ary(cipher));
631     }
632     return ary;
633 }
634
635 /*
636  * call-seq:
637  *    ctx.ciphers = "cipher1:cipher2:..."
638  *    ctx.ciphers = [name, ...]
639  *    ctx.ciphers = [[name, version, bits, alg_bits], ...]
640  */
641 static VALUE
642 ossl_sslctx_set_ciphers(VALUE self, VALUE v)
643 {
644     SSL_CTX *ctx;
645     VALUE str, elem;
646     int i;
647
648     rb_check_frozen(self);
649     if (NIL_P(v))
650         return v;
651     else if (TYPE(v) == T_ARRAY) {
652         str = rb_str_new(0, 0);
653         for (i = 0; i < RARRAY_LEN(v); i++) {
654             elem = rb_ary_entry(v, i);
655             if (TYPE(elem) == T_ARRAY) elem = rb_ary_entry(elem, 0);
656             elem = rb_String(elem);
657             rb_str_append(str, elem);
658             if (i < RARRAY_LEN(v)-1) rb_str_cat2(str, ":");
659         }
660     } else {
661         str = v;
662         StringValue(str);
663     }
664
665     Data_Get_Struct(self, SSL_CTX, ctx);
666     if(!ctx){
667         ossl_raise(eSSLError, "SSL_CTX is not initialized.");
668         return Qnil;
669     }
670     if (!SSL_CTX_set_cipher_list(ctx, RSTRING_PTR(str))) {
671         ossl_raise(eSSLError, "SSL_CTX_set_cipher_list:");
672     }
673
674     return v;
675 }
676
677
678 /*
679  *  call-seq:
680  *     ctx.session_add(session) -> true | false
681  *
682  */
683 static VALUE
684 ossl_sslctx_session_add(VALUE self, VALUE arg)
685 {
686     SSL_CTX *ctx;
687     SSL_SESSION *sess;
688
689     Data_Get_Struct(self, SSL_CTX, ctx);
690     SafeGetSSLSession(arg, sess);
691
692     return SSL_CTX_add_session(ctx, sess) == 1 ? Qtrue : Qfalse;
693 }
694
695 /*
696  *  call-seq:
697  *     ctx.session_remove(session) -> true | false
698  *
699  */
700 static VALUE
701 ossl_sslctx_session_remove(VALUE self, VALUE arg)
702 {
703     SSL_CTX *ctx;
704     SSL_SESSION *sess;
705
706     Data_Get_Struct(self, SSL_CTX, ctx);
707     SafeGetSSLSession(arg, sess);
708
709     return SSL_CTX_remove_session(ctx, sess) == 1 ? Qtrue : Qfalse;
710 }
711
712 /*
713  *  call-seq:
714  *     ctx.session_cache_mode -> integer
715  *
716  */
717 static VALUE
718 ossl_sslctx_get_session_cache_mode(VALUE self)
719 {
720     SSL_CTX *ctx;
721
722     Data_Get_Struct(self, SSL_CTX, ctx);
723
724     return LONG2NUM(SSL_CTX_get_session_cache_mode(ctx));
725 }
726
727 /*
728  *  call-seq:
729  *     ctx.session_cache_mode=(integer) -> integer
730  *
731  */
732 static VALUE
733 ossl_sslctx_set_session_cache_mode(VALUE self, VALUE arg)
734 {
735     SSL_CTX *ctx;
736
737     Data_Get_Struct(self, SSL_CTX, ctx);
738
739     SSL_CTX_set_session_cache_mode(ctx, NUM2LONG(arg));
740
741     return arg;
742 }
743
744 /*
745  *  call-seq:
746  *     ctx.session_cache_size -> integer
747  *
748  */
749 static VALUE
750 ossl_sslctx_get_session_cache_size(VALUE self)
751 {
752     SSL_CTX *ctx;
753
754     Data_Get_Struct(self, SSL_CTX, ctx);
755
756     return LONG2NUM(SSL_CTX_sess_get_cache_size(ctx));
757 }
758
759 /*
760  *  call-seq:
761  *     ctx.session_cache_size=(integer) -> integer
762  *
763  */
764 static VALUE
765 ossl_sslctx_set_session_cache_size(VALUE self, VALUE arg)
766 {
767     SSL_CTX *ctx;
768
769     Data_Get_Struct(self, SSL_CTX, ctx);
770
771     SSL_CTX_sess_set_cache_size(ctx, NUM2LONG(arg));
772
773     return arg;
774 }
775
776 /*
777  *  call-seq:
778  *     ctx.session_cache_stats -> Hash
779  *
780  */
781 static VALUE
782 ossl_sslctx_get_session_cache_stats(VALUE self)
783 {
784     SSL_CTX *ctx;
785     VALUE hash;
786
787     Data_Get_Struct(self, SSL_CTX, ctx);
788
789     hash = rb_hash_new();
790     rb_hash_aset(hash, ID2SYM(rb_intern("cache_num")), LONG2NUM(SSL_CTX_sess_number(ctx)));
791     rb_hash_aset(hash, ID2SYM(rb_intern("connect")), LONG2NUM(SSL_CTX_sess_connect(ctx)));
792     rb_hash_aset(hash, ID2SYM(rb_intern("connect_good")), LONG2NUM(SSL_CTX_sess_connect_good(ctx)));
793     rb_hash_aset(hash, ID2SYM(rb_intern("connect_renegotiate")), LONG2NUM(SSL_CTX_sess_connect_renegotiate(ctx)));
794     rb_hash_aset(hash, ID2SYM(rb_intern("accept")), LONG2NUM(SSL_CTX_sess_accept(ctx)));
795     rb_hash_aset(hash, ID2SYM(rb_intern("accept_good")), LONG2NUM(SSL_CTX_sess_accept_good(ctx)));
796     rb_hash_aset(hash, ID2SYM(rb_intern("accept_renegotiate")), LONG2NUM(SSL_CTX_sess_accept_renegotiate(ctx)));
797     rb_hash_aset(hash, ID2SYM(rb_intern("cache_hits")), LONG2NUM(SSL_CTX_sess_hits(ctx)));
798     rb_hash_aset(hash, ID2SYM(rb_intern("cb_hits")), LONG2NUM(SSL_CTX_sess_cb_hits(ctx)));
799     rb_hash_aset(hash, ID2SYM(rb_intern("cache_misses")), LONG2NUM(SSL_CTX_sess_misses(ctx)));
800     rb_hash_aset(hash, ID2SYM(rb_intern("cache_full")), LONG2NUM(SSL_CTX_sess_cache_full(ctx)));
801     rb_hash_aset(hash, ID2SYM(rb_intern("timeouts")), LONG2NUM(SSL_CTX_sess_timeouts(ctx)));
802
803     return hash;
804 }
805
806
807 /*
808  *  call-seq:
809  *     ctx.flush_sessions(time | nil) -> self
810  *
811  */
812 static VALUE
813 ossl_sslctx_flush_sessions(int argc, VALUE *argv, VALUE self)
814 {
815     VALUE arg1;
816     SSL_CTX *ctx;
817     time_t tm = 0;
818
819     rb_scan_args(argc, argv, "01", &arg1);
820
821     Data_Get_Struct(self, SSL_CTX, ctx);
822
823     if (NIL_P(arg1)) {
824         tm = time(0);
825     } else if (rb_obj_is_instance_of(arg1, rb_cTime)) {
826         tm = NUM2LONG(rb_funcall(arg1, rb_intern("to_i"), 0));
827     } else {
828         rb_raise(rb_eArgError, "arg must be Time or nil");
829     }
830
831     SSL_CTX_flush_sessions(ctx, tm);
832
833     return self;
834 }
835
836 /*
837  * SSLSocket class
838  */
839 static void
840 ossl_ssl_shutdown(SSL *ssl)
841 {
842     if (ssl) {
843         SSL_shutdown(ssl);
844         SSL_clear(ssl);
845     }
846 }
847
848 static void
849 ossl_ssl_free(SSL *ssl)
850 {
851     ossl_ssl_shutdown(ssl);
852     SSL_free(ssl);
853 }
854
855 static VALUE
856 ossl_ssl_s_alloc(VALUE klass)
857 {
858     return Data_Wrap_Struct(klass, 0, ossl_ssl_free, NULL);
859 }
860
861 /*
862  * call-seq:
863  *    SSLSocket.new(io) => aSSLSocket
864  *    SSLSocket.new(io, ctx) => aSSLSocket
865  *
866  * === Parameters
867  * * +io+ is a real ruby IO object.  Not an IO like object that responds to read/write.
868  * * +ctx+ is an OpenSSLSSL::SSLContext.
869  *
870  * The OpenSSL::Buffering module provides additional IO methods.
871  *
872  * This method will freeze the SSLContext if one is provided;
873  * however, session management is still allowed in the frozen SSLContext.
874  */
875 static VALUE
876 ossl_ssl_initialize(int argc, VALUE *argv, VALUE self)
877 {
878     VALUE io, ctx;
879
880     if (rb_scan_args(argc, argv, "11", &io, &ctx) == 1) {
881         ctx = rb_funcall(cSSLContext, rb_intern("new"), 0);
882     }
883     OSSL_Check_Kind(ctx, cSSLContext);
884     Check_Type(io, T_FILE);
885     ossl_ssl_set_io(self, io);
886     ossl_ssl_set_ctx(self, ctx);
887     ossl_ssl_set_sync_close(self, Qfalse);
888     ossl_sslctx_setup(ctx);
889     rb_call_super(0, 0);
890
891     return self;
892 }
893
894 static VALUE
895 ossl_ssl_setup(VALUE self)
896 {
897     VALUE io, v_ctx, cb;
898     SSL_CTX *ctx;
899     SSL *ssl;
900     rb_io_t *fptr;
901
902     Data_Get_Struct(self, SSL, ssl);
903     if(!ssl){
904         v_ctx = ossl_ssl_get_ctx(self);
905         Data_Get_Struct(v_ctx, SSL_CTX, ctx);
906
907         ssl = SSL_new(ctx);
908         if (!ssl) {
909             ossl_raise(eSSLError, "SSL_new:");
910         }
911         DATA_PTR(self) = ssl;
912
913         io = ossl_ssl_get_io(self);
914         GetOpenFile(io, fptr);
915         rb_io_check_readable(fptr);
916         rb_io_check_writable(fptr);
917         SSL_set_fd(ssl, TO_SOCKET(FPTR_TO_FD(fptr)));
918         SSL_set_ex_data(ssl, ossl_ssl_ex_ptr_idx, (void*)self);
919         cb = ossl_sslctx_get_verify_cb(v_ctx);
920         SSL_set_ex_data(ssl, ossl_ssl_ex_vcb_idx, (void*)cb);
921         cb = ossl_sslctx_get_client_cert_cb(v_ctx);
922         SSL_set_ex_data(ssl, ossl_ssl_ex_client_cert_cb_idx, (void*)cb);
923         cb = ossl_sslctx_get_tmp_dh_cb(v_ctx);
924         SSL_set_ex_data(ssl, ossl_ssl_ex_tmp_dh_callback_idx, (void*)cb);
925     }
926
927     return Qtrue;
928 }
929
930 #ifdef _WIN32
931 #define ssl_get_error(ssl, ret) (errno = WSAGetLastError(), SSL_get_error(ssl, ret))
932 #else
933 #define ssl_get_error(ssl, ret) SSL_get_error(ssl, ret)
934 #endif
935
936 static VALUE
937 ossl_start_ssl(VALUE self, int (*func)(), const char *funcname)
938 {
939     SSL *ssl;
940     rb_io_t *fptr;
941     int ret, ret2;
942     VALUE cb_state;
943
944     rb_ivar_set(self, ID_callback_state, Qnil);
945
946     Data_Get_Struct(self, SSL, ssl);
947     GetOpenFile(ossl_ssl_get_io(self), fptr);
948     for(;;){
949         if((ret = func(ssl)) > 0) break;
950         switch((ret2 = ssl_get_error(ssl, ret))){
951         case SSL_ERROR_WANT_WRITE:
952             rb_io_wait_writable(FPTR_TO_FD(fptr));
953             continue;
954         case SSL_ERROR_WANT_READ:
955             rb_io_wait_readable(FPTR_TO_FD(fptr));
956             continue;
957         case SSL_ERROR_SYSCALL:
958             if (errno) rb_sys_fail(funcname);
959             ossl_raise(eSSLError, "%s SYSCALL returned=%d errno=%d state=%s", funcname, ret2, errno, SSL_state_string_long(ssl));
960         default:
961             ossl_raise(eSSLError, "%s returned=%d errno=%d state=%s", funcname, ret2, errno, SSL_state_string_long(ssl));
962         }
963     }
964
965     cb_state = rb_ivar_get(self, ID_callback_state);
966     if (!NIL_P(cb_state))
967         rb_jump_tag(NUM2INT(cb_state));
968
969     return self;
970 }
971
972 /*
973  * call-seq:
974  *    ssl.connect => self
975  */
976 static VALUE
977 ossl_ssl_connect(VALUE self)
978 {
979     ossl_ssl_setup(self);
980     return ossl_start_ssl(self, SSL_connect, "SSL_connect");
981 }
982
983 /*
984  * call-seq:
985  *    ssl.accept => self
986  */
987 static VALUE
988 ossl_ssl_accept(VALUE self)
989 {
990     ossl_ssl_setup(self);
991     return ossl_start_ssl(self, SSL_accept, "SSL_accept");
992 }
993
994 /*
995  * call-seq:
996  *    ssl.sysread(length) => string
997  *    ssl.sysread(length, buffer) => buffer
998  *
999  * === Parameters
1000  * * +length+ is a positive integer.
1001  * * +buffer+ is a string used to store the result.
1002  */
1003 static VALUE
1004 ossl_ssl_read(int argc, VALUE *argv, VALUE self)
1005 {
1006     SSL *ssl;
1007     int ilen, nread = 0;
1008     VALUE len, str;
1009     rb_io_t *fptr;
1010
1011     rb_scan_args(argc, argv, "11", &len, &str);
1012     ilen = NUM2INT(len);
1013     if(NIL_P(str)) str = rb_str_new(0, ilen);
1014     else{
1015         StringValue(str);
1016         rb_str_modify(str);
1017         rb_str_resize(str, ilen);
1018     }
1019     if(ilen == 0) return str;
1020
1021     Data_Get_Struct(self, SSL, ssl);
1022     GetOpenFile(ossl_ssl_get_io(self), fptr);
1023     if (ssl) {
1024         if(SSL_pending(ssl) <= 0)
1025             rb_thread_wait_fd(FPTR_TO_FD(fptr));
1026         for (;;){
1027             nread = SSL_read(ssl, RSTRING_PTR(str), RSTRING_LEN(str));
1028             switch(ssl_get_error(ssl, nread)){
1029             case SSL_ERROR_NONE:
1030                 goto end;
1031             case SSL_ERROR_ZERO_RETURN:
1032                 rb_eof_error();
1033             case SSL_ERROR_WANT_WRITE:
1034                 rb_io_wait_writable(FPTR_TO_FD(fptr));
1035                 continue;
1036             case SSL_ERROR_WANT_READ:
1037                 rb_io_wait_readable(FPTR_TO_FD(fptr));
1038                 continue;
1039             case SSL_ERROR_SYSCALL:
1040                 if(ERR_peek_error() == 0 && nread == 0) rb_eof_error();
1041                 rb_sys_fail(0);
1042             default:
1043                 ossl_raise(eSSLError, "SSL_read:");
1044             }
1045         }
1046     }
1047     else {
1048         ID id_sysread = rb_intern("sysread");
1049         rb_warning("SSL session is not started yet.");
1050         return rb_funcall(ossl_ssl_get_io(self), id_sysread, 2, len, str);
1051     }
1052
1053   end:
1054     rb_str_set_len(str, nread);
1055     OBJ_TAINT(str);
1056
1057     return str;
1058 }
1059
1060 /*
1061  * call-seq:
1062  *    ssl.syswrite(string) => integer
1063  */
1064 static VALUE
1065 ossl_ssl_write(VALUE self, VALUE str)
1066 {
1067     SSL *ssl;
1068     int nwrite = 0;
1069     rb_io_t *fptr;
1070
1071     StringValue(str);
1072     Data_Get_Struct(self, SSL, ssl);
1073     GetOpenFile(ossl_ssl_get_io(self), fptr);
1074
1075     if (ssl) {
1076         for (;;){
1077             nwrite = SSL_write(ssl, RSTRING_PTR(str), RSTRING_LEN(str));
1078             switch(ssl_get_error(ssl, nwrite)){
1079             case SSL_ERROR_NONE:
1080                 goto end;
1081             case SSL_ERROR_WANT_WRITE:
1082                 rb_io_wait_writable(FPTR_TO_FD(fptr));
1083                 continue;
1084             case SSL_ERROR_WANT_READ:
1085                 rb_io_wait_readable(FPTR_TO_FD(fptr));
1086                 continue;
1087             case SSL_ERROR_SYSCALL:
1088                 if (errno) rb_sys_fail(0);
1089             default:
1090                 ossl_raise(eSSLError, "SSL_write:");
1091             }
1092         }
1093     }
1094     else {
1095         ID id_syswrite = rb_intern("syswrite");
1096         rb_warning("SSL session is not started yet.");
1097         return rb_funcall(ossl_ssl_get_io(self), id_syswrite, 1, str);
1098     }
1099
1100   end:
1101     return INT2NUM(nwrite);
1102 }
1103
1104 /*
1105  * call-seq:
1106  *    ssl.sysclose => nil
1107  */
1108 static VALUE
1109 ossl_ssl_close(VALUE self)
1110 {
1111     SSL *ssl;
1112
1113     Data_Get_Struct(self, SSL, ssl);
1114     ossl_ssl_shutdown(ssl);
1115     if (RTEST(ossl_ssl_get_sync_close(self)))
1116         rb_funcall(ossl_ssl_get_io(self), rb_intern("close"), 0);
1117
1118     return Qnil;
1119 }
1120
1121 /*
1122  * call-seq:
1123  *    ssl.cert => cert or nil
1124  */
1125 static VALUE
1126 ossl_ssl_get_cert(VALUE self)
1127 {
1128     SSL *ssl;
1129     X509 *cert = NULL;
1130
1131     Data_Get_Struct(self, SSL, ssl);
1132     if (ssl) {
1133         rb_warning("SSL session is not started yet.");
1134         return Qnil;
1135     }
1136
1137     /*
1138      * Is this OpenSSL bug? Should add a ref?
1139      * TODO: Ask for.
1140      */
1141     cert = SSL_get_certificate(ssl); /* NO DUPs => DON'T FREE. */
1142
1143     if (!cert) {
1144         return Qnil;
1145     }
1146     return ossl_x509_new(cert);
1147 }
1148
1149 /*
1150  * call-seq:
1151  *    ssl.peer_cert => cert or nil
1152  */
1153 static VALUE
1154 ossl_ssl_get_peer_cert(VALUE self)
1155 {
1156     SSL *ssl;
1157     X509 *cert = NULL;
1158     VALUE obj;
1159
1160     Data_Get_Struct(self, SSL, ssl);
1161
1162     if (!ssl){
1163         rb_warning("SSL session is not started yet.");
1164         return Qnil;
1165     }
1166
1167     cert = SSL_get_peer_certificate(ssl); /* Adds a ref => Safe to FREE. */
1168
1169     if (!cert) {
1170         return Qnil;
1171     }
1172     obj = ossl_x509_new(cert);
1173     X509_free(cert);
1174
1175     return obj;
1176 }
1177
1178 /*
1179  * call-seq:
1180  *    ssl.peer_cert_chain => [cert, ...] or nil
1181  */
1182 static VALUE
1183 ossl_ssl_get_peer_cert_chain(VALUE self)
1184 {
1185     SSL *ssl;
1186     STACK_OF(X509) *chain;
1187     X509 *cert;
1188     VALUE ary;
1189     int i, num;
1190
1191     Data_Get_Struct(self, SSL, ssl);
1192     if(!ssl){
1193         rb_warning("SSL session is not started yet.");
1194         return Qnil;
1195     }
1196     chain = SSL_get_peer_cert_chain(ssl);
1197     if(!chain) return Qnil;
1198     num = sk_num(chain);
1199     ary = rb_ary_new2(num);
1200     for (i = 0; i < num; i++){
1201         cert = (X509*)sk_value(chain, i);
1202         rb_ary_push(ary, ossl_x509_new(cert));
1203     }
1204
1205     return ary;
1206 }
1207
1208 /*
1209  * call-seq:
1210  *    ssl.cipher => [name, version, bits, alg_bits]
1211  */
1212 static VALUE
1213 ossl_ssl_get_cipher(VALUE self)
1214 {
1215     SSL *ssl;
1216     SSL_CIPHER *cipher;
1217
1218     Data_Get_Struct(self, SSL, ssl);
1219     if (!ssl) {
1220         rb_warning("SSL session is not started yet.");
1221         return Qnil;
1222     }
1223     cipher = SSL_get_current_cipher(ssl);
1224
1225     return ossl_ssl_cipher_to_ary(cipher);
1226 }
1227
1228 /*
1229  * call-seq:
1230  *    ssl.state => string
1231  */
1232 static VALUE
1233 ossl_ssl_get_state(VALUE self)
1234 {
1235     SSL *ssl;
1236     VALUE ret;
1237
1238     Data_Get_Struct(self, SSL, ssl);
1239     if (!ssl) {
1240         rb_warning("SSL session is not started yet.");
1241         return Qnil;
1242     }
1243     ret = rb_str_new2(SSL_state_string(ssl));
1244     if (ruby_verbose) {
1245         rb_str_cat2(ret, ": ");
1246         rb_str_cat2(ret, SSL_state_string_long(ssl));
1247     }
1248     return ret;
1249 }
1250
1251 /*
1252  * call-seq:
1253  *    ssl.pending => integer
1254  */
1255 static VALUE
1256 ossl_ssl_pending(VALUE self)
1257 {
1258     SSL *ssl;
1259
1260     Data_Get_Struct(self, SSL, ssl);
1261     if (!ssl) {
1262         rb_warning("SSL session is not started yet.");
1263         return Qnil;
1264     }
1265
1266     return INT2NUM(SSL_pending(ssl));
1267 }
1268
1269 /*
1270  *  call-seq:
1271  *     ssl.session_reused? -> true | false
1272  *
1273  */
1274 static VALUE
1275 ossl_ssl_session_reused(VALUE self)
1276 {
1277     SSL *ssl;
1278
1279     Data_Get_Struct(self, SSL, ssl);
1280     if (!ssl) {
1281         rb_warning("SSL session is not started yet.");
1282         return Qnil;
1283     }
1284
1285     switch(SSL_session_reused(ssl)) {
1286     case 1:     return Qtrue;
1287     case 0:     return Qfalse;
1288     default:    ossl_raise(eSSLError, "SSL_session_reused");
1289     }
1290 }
1291
1292 /*
1293  *  call-seq:
1294  *     ssl.session = session -> session
1295  *
1296  */
1297 static VALUE
1298 ossl_ssl_set_session(VALUE self, VALUE arg1)
1299 {
1300     SSL *ssl;
1301     SSL_SESSION *sess;
1302
1303 /* why is ossl_ssl_setup delayed? */
1304     ossl_ssl_setup(self);
1305
1306     Data_Get_Struct(self, SSL, ssl);
1307     if (!ssl) {
1308         rb_warning("SSL session is not started yet.");
1309         return Qnil;
1310     }
1311
1312     SafeGetSSLSession(arg1, sess);
1313
1314     if (SSL_set_session(ssl, sess) != 1)
1315         ossl_raise(eSSLError, "SSL_set_session");
1316
1317     return arg1;
1318 }
1319
1320 static VALUE
1321 ossl_ssl_get_verify_result(VALUE self)
1322 {
1323     SSL *ssl;
1324
1325     Data_Get_Struct(self, SSL, ssl);
1326     if (!ssl) {
1327         rb_warning("SSL session is not started yet.");
1328         return Qnil;
1329     }
1330
1331     return INT2FIX(SSL_get_verify_result(ssl));
1332 }
1333
1334 void
1335 Init_ossl_ssl()
1336 {
1337     int i;
1338     VALUE ary;
1339
1340 #if 0 /* let rdoc know about mOSSL */
1341     mOSSL = rb_define_module("OpenSSL");
1342 #endif
1343
1344     ID_callback_state = rb_intern("@callback_state");
1345
1346     ossl_ssl_ex_vcb_idx = SSL_get_ex_new_index(0,(void *)"ossl_ssl_ex_vcb_idx",0,0,0);
1347     ossl_ssl_ex_store_p = SSL_get_ex_new_index(0,(void *)"ossl_ssl_ex_store_p",0,0,0);
1348     ossl_ssl_ex_ptr_idx = SSL_get_ex_new_index(0,(void *)"ossl_ssl_ex_ptr_idx",0,0,0);
1349     ossl_ssl_ex_client_cert_cb_idx =
1350         SSL_get_ex_new_index(0,(void *)"ossl_ssl_ex_client_cert_cb_idx",0,0,0);
1351     ossl_ssl_ex_tmp_dh_callback_idx =
1352         SSL_get_ex_new_index(0,(void *)"ossl_ssl_ex_tmp_dh_callback_idx",0,0,0);
1353
1354     mSSL = rb_define_module_under(mOSSL, "SSL");
1355     eSSLError = rb_define_class_under(mSSL, "SSLError", eOSSLError);
1356
1357     Init_ossl_ssl_session();
1358
1359     /* class SSLContext
1360      *
1361      * The following attributes are available but don't show up in rdoc.
1362      * All attributes must be set before calling SSLSocket.new(io, ctx).
1363      * * ssl_version, cert, key, client_ca, ca_file, ca_path, timeout,
1364      * * verify_mode, verify_depth client_cert_cb, tmp_dh_callback,
1365      * * session_id_context, session_add_cb, session_new_cb, session_remove_cb
1366      */
1367     cSSLContext = rb_define_class_under(mSSL, "SSLContext", rb_cObject);
1368     rb_define_alloc_func(cSSLContext, ossl_sslctx_s_alloc);
1369     for(i = 0; i < numberof(ossl_sslctx_attrs); i++)
1370         rb_attr(cSSLContext, rb_intern(ossl_sslctx_attrs[i]), 1, 1, Qfalse);
1371     rb_define_alias(cSSLContext, "ssl_timeout", "timeout");
1372     rb_define_method(cSSLContext, "initialize",  ossl_sslctx_initialize, -1);
1373     rb_define_method(cSSLContext, "ssl_version=", ossl_sslctx_set_ssl_version, 1);
1374     rb_define_method(cSSLContext, "ciphers",     ossl_sslctx_get_ciphers, 0);
1375     rb_define_method(cSSLContext, "ciphers=",    ossl_sslctx_set_ciphers, 1);
1376
1377     rb_define_method(cSSLContext, "setup", ossl_sslctx_setup, 0);
1378
1379     
1380     rb_define_const(cSSLContext, "SESSION_CACHE_OFF", LONG2FIX(SSL_SESS_CACHE_OFF));
1381     rb_define_const(cSSLContext, "SESSION_CACHE_CLIENT", LONG2FIX(SSL_SESS_CACHE_CLIENT)); /* doesn't actually do anything in 0.9.8e */
1382     rb_define_const(cSSLContext, "SESSION_CACHE_SERVER", LONG2FIX(SSL_SESS_CACHE_SERVER));
1383     rb_define_const(cSSLContext, "SESSION_CACHE_BOTH", LONG2FIX(SSL_SESS_CACHE_BOTH)); /* no different than CACHE_SERVER in 0.9.8e */
1384     rb_define_const(cSSLContext, "SESSION_CACHE_NO_AUTO_CLEAR", LONG2FIX(SSL_SESS_CACHE_NO_AUTO_CLEAR));
1385     rb_define_const(cSSLContext, "SESSION_CACHE_NO_INTERNAL_LOOKUP", LONG2FIX(SSL_SESS_CACHE_NO_INTERNAL_LOOKUP));
1386     rb_define_const(cSSLContext, "SESSION_CACHE_NO_INTERNAL_STORE", LONG2FIX(SSL_SESS_CACHE_NO_INTERNAL_STORE));
1387     rb_define_const(cSSLContext, "SESSION_CACHE_NO_INTERNAL", LONG2FIX(SSL_SESS_CACHE_NO_INTERNAL));
1388     rb_define_method(cSSLContext, "session_add",     ossl_sslctx_session_add, 1);
1389     rb_define_method(cSSLContext, "session_remove",     ossl_sslctx_session_remove, 1);
1390     rb_define_method(cSSLContext, "session_cache_mode",     ossl_sslctx_get_session_cache_mode, 0);
1391     rb_define_method(cSSLContext, "session_cache_mode=",     ossl_sslctx_set_session_cache_mode, 1);
1392     rb_define_method(cSSLContext, "session_cache_size",     ossl_sslctx_get_session_cache_size, 0);
1393     rb_define_method(cSSLContext, "session_cache_size=",     ossl_sslctx_set_session_cache_size, 1);
1394     rb_define_method(cSSLContext, "session_cache_stats",     ossl_sslctx_get_session_cache_stats, 0);
1395     rb_define_method(cSSLContext, "flush_sessions",     ossl_sslctx_flush_sessions, -1);
1396
1397     ary = rb_ary_new2(numberof(ossl_ssl_method_tab));
1398     for (i = 0; i < numberof(ossl_ssl_method_tab); i++) {
1399         rb_ary_push(ary, ID2SYM(rb_intern(ossl_ssl_method_tab[i].name)));
1400     }
1401     rb_obj_freeze(ary);
1402     /* holds a list of available SSL/TLS methods */
1403     rb_define_const(cSSLContext, "METHODS", ary);
1404
1405     /* class SSLSocket
1406      *
1407      * The following attributes are available but don't show up in rdoc.
1408      * * io, context, sync_close
1409      *
1410      */
1411     cSSLSocket = rb_define_class_under(mSSL, "SSLSocket", rb_cObject);
1412     rb_define_alloc_func(cSSLSocket, ossl_ssl_s_alloc);
1413     for(i = 0; i < numberof(ossl_ssl_attr_readers); i++)
1414         rb_attr(cSSLSocket, rb_intern(ossl_ssl_attr_readers[i]), 1, 0, Qfalse);
1415     for(i = 0; i < numberof(ossl_ssl_attrs); i++)
1416         rb_attr(cSSLSocket, rb_intern(ossl_ssl_attrs[i]), 1, 1, Qfalse);
1417     rb_define_alias(cSSLSocket, "to_io", "io");
1418     rb_define_method(cSSLSocket, "initialize", ossl_ssl_initialize, -1);
1419     rb_define_method(cSSLSocket, "connect",    ossl_ssl_connect, 0);
1420     rb_define_method(cSSLSocket, "accept",     ossl_ssl_accept, 0);
1421     rb_define_method(cSSLSocket, "sysread",    ossl_ssl_read, -1);
1422     rb_define_method(cSSLSocket, "syswrite",   ossl_ssl_write, 1);
1423     rb_define_method(cSSLSocket, "sysclose",   ossl_ssl_close, 0);
1424     rb_define_method(cSSLSocket, "cert",       ossl_ssl_get_cert, 0);
1425     rb_define_method(cSSLSocket, "peer_cert",  ossl_ssl_get_peer_cert, 0);
1426     rb_define_method(cSSLSocket, "peer_cert_chain", ossl_ssl_get_peer_cert_chain, 0);
1427     rb_define_method(cSSLSocket, "cipher",     ossl_ssl_get_cipher, 0);
1428     rb_define_method(cSSLSocket, "state",      ossl_ssl_get_state, 0);
1429     rb_define_method(cSSLSocket, "pending",    ossl_ssl_pending, 0);
1430     rb_define_method(cSSLSocket, "session_reused?",    ossl_ssl_session_reused, 0);
1431     rb_define_method(cSSLSocket, "session=",    ossl_ssl_set_session, 1);
1432     rb_define_method(cSSLSocket, "verify_result", ossl_ssl_get_verify_result, 0);
1433
1434 #define ossl_ssl_def_const(x) rb_define_const(mSSL, #x, INT2FIX(SSL_##x))
1435
1436     ossl_ssl_def_const(VERIFY_NONE);
1437     ossl_ssl_def_const(VERIFY_PEER);
1438     ossl_ssl_def_const(VERIFY_FAIL_IF_NO_PEER_CERT);
1439     ossl_ssl_def_const(VERIFY_CLIENT_ONCE);
1440     /* Not introduce constants included in OP_ALL such as...
1441      * ossl_ssl_def_const(OP_MICROSOFT_SESS_ID_BUG);
1442      * ossl_ssl_def_const(OP_NETSCAPE_CHALLENGE_BUG);
1443      * ossl_ssl_def_const(OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG);
1444      * ossl_ssl_def_const(OP_SSLREF2_REUSE_CERT_TYPE_BUG);
1445      * ossl_ssl_def_const(OP_MICROSOFT_BIG_SSLV3_BUFFER);
1446      * ossl_ssl_def_const(OP_MSIE_SSLV2_RSA_PADDING);
1447      * ossl_ssl_def_const(OP_SSLEAY_080_CLIENT_DH_BUG);
1448      * ossl_ssl_def_const(OP_TLS_D5_BUG);
1449      * ossl_ssl_def_const(OP_TLS_BLOCK_PADDING_BUG);
1450      * ossl_ssl_def_const(OP_DONT_INSERT_EMPTY_FRAGMENTS);
1451      */
1452     ossl_ssl_def_const(OP_ALL);
1453 #if defined(SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION)
1454     ossl_ssl_def_const(OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
1455 #endif
1456 #if defined(SSL_OP_SINGLE_ECDH_USE)
1457     ossl_ssl_def_const(OP_SINGLE_ECDH_USE);
1458 #endif
1459     ossl_ssl_def_const(OP_SINGLE_DH_USE);
1460     ossl_ssl_def_const(OP_EPHEMERAL_RSA);
1461 #if defined(SSL_OP_CIPHER_SERVER_PREFERENCE)
1462     ossl_ssl_def_const(OP_CIPHER_SERVER_PREFERENCE);
1463 #endif
1464     ossl_ssl_def_const(OP_TLS_ROLLBACK_BUG);
1465     ossl_ssl_def_const(OP_NO_SSLv2);
1466     ossl_ssl_def_const(OP_NO_SSLv3);
1467     ossl_ssl_def_const(OP_NO_TLSv1);
1468 #if defined(SSL_OP_NO_TICKET)
1469     ossl_ssl_def_const(OP_NO_TICKET);
1470 #endif
1471     ossl_ssl_def_const(OP_PKCS1_CHECK_1);
1472     ossl_ssl_def_const(OP_PKCS1_CHECK_2);
1473     ossl_ssl_def_const(OP_NETSCAPE_CA_DN_BUG);
1474     ossl_ssl_def_const(OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG);
1475 }