|
Ruby 1.9.2p180(2011-02-18revision30909)
|
00001 /* 00002 * $Id: ossl_ssl.c 30334 2010-12-24 03:24:00Z yugui $ 00003 * 'OpenSSL for Ruby' project 00004 * Copyright (C) 2000-2002 GOTOU Yuuzou <gotoyuzo@notwork.org> 00005 * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> 00006 * Copyright (C) 2001-2007 Technorama Ltd. <oss-ruby@technorama.net> 00007 * All rights reserved. 00008 */ 00009 /* 00010 * This program is licenced under the same licence as Ruby. 00011 * (See the file 'LICENCE'.) 00012 */ 00013 #include "ossl.h" 00014 00015 #if defined(HAVE_UNISTD_H) 00016 # include <unistd.h> /* for read(), and write() */ 00017 #endif 00018 00019 #define numberof(ary) (int)(sizeof(ary)/sizeof(ary[0])) 00020 00021 #ifdef _WIN32 00022 # define TO_SOCKET(s) _get_osfhandle(s) 00023 #else 00024 # define TO_SOCKET(s) s 00025 #endif 00026 00027 VALUE mSSL; 00028 VALUE eSSLError; 00029 VALUE cSSLContext; 00030 VALUE cSSLSocket; 00031 00032 #define ossl_sslctx_set_cert(o,v) rb_iv_set((o),"@cert",(v)) 00033 #define ossl_sslctx_set_key(o,v) rb_iv_set((o),"@key",(v)) 00034 #define ossl_sslctx_set_client_ca(o,v) rb_iv_set((o),"@client_ca",(v)) 00035 #define ossl_sslctx_set_ca_file(o,v) rb_iv_set((o),"@ca_file",(v)) 00036 #define ossl_sslctx_set_ca_path(o,v) rb_iv_set((o),"@ca_path",(v)) 00037 #define ossl_sslctx_set_timeout(o,v) rb_iv_set((o),"@timeout",(v)) 00038 #define ossl_sslctx_set_verify_mode(o,v) rb_iv_set((o),"@verify_mode",(v)) 00039 #define ossl_sslctx_set_verify_dep(o,v) rb_iv_set((o),"@verify_depth",(v)) 00040 #define ossl_sslctx_set_verify_cb(o,v) rb_iv_set((o),"@verify_callback",(v)) 00041 #define ossl_sslctx_set_options(o,v) rb_iv_set((o),"@options",(v)) 00042 #define ossl_sslctx_set_cert_store(o,v) rb_iv_set((o),"@cert_store",(v)) 00043 #define ossl_sslctx_set_extra_cert(o,v) rb_iv_set((o),"@extra_chain_cert",(v)) 00044 #define ossl_sslctx_set_client_cert_cb(o,v) rb_iv_set((o),"@client_cert_cb",(v)) 00045 #define ossl_sslctx_set_tmp_dh_cb(o,v) rb_iv_set((o),"@tmp_dh_callback",(v)) 00046 #define ossl_sslctx_set_sess_id_ctx(o, v) rb_iv_get((o),"@session_id_context"(v)) 00047 00048 #define ossl_sslctx_get_cert(o) rb_iv_get((o),"@cert") 00049 #define ossl_sslctx_get_key(o) rb_iv_get((o),"@key") 00050 #define ossl_sslctx_get_client_ca(o) rb_iv_get((o),"@client_ca") 00051 #define ossl_sslctx_get_ca_file(o) rb_iv_get((o),"@ca_file") 00052 #define ossl_sslctx_get_ca_path(o) rb_iv_get((o),"@ca_path") 00053 #define ossl_sslctx_get_timeout(o) rb_iv_get((o),"@timeout") 00054 #define ossl_sslctx_get_verify_mode(o) rb_iv_get((o),"@verify_mode") 00055 #define ossl_sslctx_get_verify_dep(o) rb_iv_get((o),"@verify_depth") 00056 #define ossl_sslctx_get_verify_cb(o) rb_iv_get((o),"@verify_callback") 00057 #define ossl_sslctx_get_options(o) rb_iv_get((o),"@options") 00058 #define ossl_sslctx_get_cert_store(o) rb_iv_get((o),"@cert_store") 00059 #define ossl_sslctx_get_extra_cert(o) rb_iv_get((o),"@extra_chain_cert") 00060 #define ossl_sslctx_get_client_cert_cb(o) rb_iv_get((o),"@client_cert_cb") 00061 #define ossl_sslctx_get_tmp_dh_cb(o) rb_iv_get((o),"@tmp_dh_callback") 00062 #define ossl_sslctx_get_sess_id_ctx(o) rb_iv_get((o),"@session_id_context") 00063 00064 static const char *ossl_sslctx_attrs[] = { 00065 "cert", "key", "client_ca", "ca_file", "ca_path", 00066 "timeout", "verify_mode", "verify_depth", 00067 "verify_callback", "options", "cert_store", "extra_chain_cert", 00068 "client_cert_cb", "tmp_dh_callback", "session_id_context", 00069 "session_get_cb", "session_new_cb", "session_remove_cb", 00070 #ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME 00071 "servername_cb", 00072 #endif 00073 }; 00074 00075 #define ossl_ssl_get_io(o) rb_iv_get((o),"@io") 00076 #define ossl_ssl_get_ctx(o) rb_iv_get((o),"@context") 00077 #define ossl_ssl_get_sync_close(o) rb_iv_get((o),"@sync_close") 00078 #define ossl_ssl_get_x509(o) rb_iv_get((o),"@x509") 00079 #define ossl_ssl_get_key(o) rb_iv_get((o),"@key") 00080 #define ossl_ssl_get_tmp_dh(o) rb_iv_get((o),"@tmp_dh") 00081 00082 #define ossl_ssl_set_io(o,v) rb_iv_set((o),"@io",(v)) 00083 #define ossl_ssl_set_ctx(o,v) rb_iv_set((o),"@context",(v)) 00084 #define ossl_ssl_set_sync_close(o,v) rb_iv_set((o),"@sync_close",(v)) 00085 #define ossl_ssl_set_x509(o,v) rb_iv_set((o),"@x509",(v)) 00086 #define ossl_ssl_set_key(o,v) rb_iv_set((o),"@key",(v)) 00087 #define ossl_ssl_set_tmp_dh(o,v) rb_iv_set((o),"@tmp_dh",(v)) 00088 00089 static const char *ossl_ssl_attr_readers[] = { "io", "context", }; 00090 static const char *ossl_ssl_attrs[] = { 00091 #ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME 00092 "hostname", 00093 #endif 00094 "sync_close", 00095 }; 00096 00097 ID ID_callback_state; 00098 00099 /* 00100 * SSLContext class 00101 */ 00102 struct { 00103 const char *name; 00104 SSL_METHOD *(*func)(void); 00105 } ossl_ssl_method_tab[] = { 00106 #define OSSL_SSL_METHOD_ENTRY(name) { #name, (SSL_METHOD *(*)(void))name##_method } 00107 OSSL_SSL_METHOD_ENTRY(TLSv1), 00108 OSSL_SSL_METHOD_ENTRY(TLSv1_server), 00109 OSSL_SSL_METHOD_ENTRY(TLSv1_client), 00110 OSSL_SSL_METHOD_ENTRY(SSLv2), 00111 OSSL_SSL_METHOD_ENTRY(SSLv2_server), 00112 OSSL_SSL_METHOD_ENTRY(SSLv2_client), 00113 OSSL_SSL_METHOD_ENTRY(SSLv3), 00114 OSSL_SSL_METHOD_ENTRY(SSLv3_server), 00115 OSSL_SSL_METHOD_ENTRY(SSLv3_client), 00116 OSSL_SSL_METHOD_ENTRY(SSLv23), 00117 OSSL_SSL_METHOD_ENTRY(SSLv23_server), 00118 OSSL_SSL_METHOD_ENTRY(SSLv23_client), 00119 #undef OSSL_SSL_METHOD_ENTRY 00120 }; 00121 00122 int ossl_ssl_ex_vcb_idx; 00123 int ossl_ssl_ex_store_p; 00124 int ossl_ssl_ex_ptr_idx; 00125 int ossl_ssl_ex_client_cert_cb_idx; 00126 int ossl_ssl_ex_tmp_dh_callback_idx; 00127 00128 static void 00129 ossl_sslctx_free(SSL_CTX *ctx) 00130 { 00131 if(ctx && SSL_CTX_get_ex_data(ctx, ossl_ssl_ex_store_p)== (void*)1) 00132 ctx->cert_store = NULL; 00133 SSL_CTX_free(ctx); 00134 } 00135 00136 static VALUE 00137 ossl_sslctx_s_alloc(VALUE klass) 00138 { 00139 SSL_CTX *ctx; 00140 00141 ctx = SSL_CTX_new(SSLv23_method()); 00142 if (!ctx) { 00143 ossl_raise(eSSLError, "SSL_CTX_new:"); 00144 } 00145 SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); 00146 SSL_CTX_set_options(ctx, SSL_OP_ALL); 00147 return Data_Wrap_Struct(klass, 0, ossl_sslctx_free, ctx); 00148 } 00149 00150 static VALUE 00151 ossl_sslctx_set_ssl_version(VALUE self, VALUE ssl_method) 00152 { 00153 SSL_METHOD *method = NULL; 00154 const char *s; 00155 int i; 00156 00157 SSL_CTX *ctx; 00158 if(TYPE(ssl_method) == T_SYMBOL) 00159 s = rb_id2name(SYM2ID(ssl_method)); 00160 else 00161 s = StringValuePtr(ssl_method); 00162 for (i = 0; i < numberof(ossl_ssl_method_tab); i++) { 00163 if (strcmp(ossl_ssl_method_tab[i].name, s) == 0) { 00164 method = ossl_ssl_method_tab[i].func(); 00165 break; 00166 } 00167 } 00168 if (!method) { 00169 ossl_raise(rb_eArgError, "unknown SSL method `%s'.", s); 00170 } 00171 Data_Get_Struct(self, SSL_CTX, ctx); 00172 if (SSL_CTX_set_ssl_version(ctx, method) != 1) { 00173 ossl_raise(eSSLError, "SSL_CTX_set_ssl_version:"); 00174 } 00175 00176 return ssl_method; 00177 } 00178 00179 /* 00180 * call-seq: 00181 * SSLContext.new => ctx 00182 * SSLContext.new(:TLSv1) => ctx 00183 * SSLContext.new("SSLv23_client") => ctx 00184 * 00185 * You can get a list of valid methods with OpenSSL::SSL::SSLContext::METHODS 00186 */ 00187 static VALUE 00188 ossl_sslctx_initialize(int argc, VALUE *argv, VALUE self) 00189 { 00190 VALUE ssl_method; 00191 int i; 00192 00193 for(i = 0; i < numberof(ossl_sslctx_attrs); i++){ 00194 char buf[32]; 00195 snprintf(buf, sizeof(buf), "@%s", ossl_sslctx_attrs[i]); 00196 rb_iv_set(self, buf, Qnil); 00197 } 00198 if (rb_scan_args(argc, argv, "01", &ssl_method) == 0){ 00199 return self; 00200 } 00201 ossl_sslctx_set_ssl_version(self, ssl_method); 00202 00203 return self; 00204 } 00205 00206 static VALUE 00207 ossl_call_client_cert_cb(VALUE obj) 00208 { 00209 VALUE cb, ary, cert, key; 00210 SSL *ssl; 00211 00212 Data_Get_Struct(obj, SSL, ssl); 00213 cb = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_client_cert_cb_idx); 00214 if (NIL_P(cb)) return Qfalse; 00215 ary = rb_funcall(cb, rb_intern("call"), 1, obj); 00216 Check_Type(ary, T_ARRAY); 00217 GetX509CertPtr(cert = rb_ary_entry(ary, 0)); 00218 GetPKeyPtr(key = rb_ary_entry(ary, 1)); 00219 ossl_ssl_set_x509(obj, cert); 00220 ossl_ssl_set_key(obj, key); 00221 00222 return Qtrue; 00223 } 00224 00225 static int 00226 ossl_client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey) 00227 { 00228 VALUE obj; 00229 int status, success; 00230 00231 obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx); 00232 success = rb_protect((VALUE(*)_((VALUE)))ossl_call_client_cert_cb, 00233 obj, &status); 00234 if (status || !success) return 0; 00235 *x509 = DupX509CertPtr(ossl_ssl_get_x509(obj)); 00236 *pkey = DupPKeyPtr(ossl_ssl_get_key(obj)); 00237 00238 return 1; 00239 } 00240 00241 #if !defined(OPENSSL_NO_DH) 00242 static VALUE 00243 ossl_call_tmp_dh_callback(VALUE *args) 00244 { 00245 SSL *ssl; 00246 VALUE cb, dh; 00247 EVP_PKEY *pkey; 00248 00249 Data_Get_Struct(args[0], SSL, ssl); 00250 cb = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_tmp_dh_callback_idx); 00251 if (NIL_P(cb)) return Qfalse; 00252 dh = rb_funcall(cb, rb_intern("call"), 3, args[0], args[1], args[2]); 00253 pkey = GetPKeyPtr(dh); 00254 if (EVP_PKEY_type(pkey->type) != EVP_PKEY_DH) return Qfalse; 00255 ossl_ssl_set_tmp_dh(args[0], dh); 00256 00257 return Qtrue; 00258 } 00259 00260 static DH* 00261 ossl_tmp_dh_callback(SSL *ssl, int is_export, int keylength) 00262 { 00263 VALUE args[3]; 00264 int status, success; 00265 00266 args[0] = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx); 00267 args[1] = INT2FIX(is_export); 00268 args[2] = INT2FIX(keylength); 00269 success = rb_protect((VALUE(*)_((VALUE)))ossl_call_tmp_dh_callback, 00270 (VALUE)args, &status); 00271 if (status || !success) return NULL; 00272 00273 return GetPKeyPtr(ossl_ssl_get_tmp_dh(args[0]))->pkey.dh; 00274 } 00275 00276 static DH* 00277 ossl_default_tmp_dh_callback(SSL *ssl, int is_export, int keylength) 00278 { 00279 rb_warning("using default DH parameters."); 00280 00281 switch(keylength){ 00282 case 512: 00283 return OSSL_DEFAULT_DH_512; 00284 case 1024: 00285 return OSSL_DEFAULT_DH_1024; 00286 } 00287 return NULL; 00288 } 00289 #endif /* OPENSSL_NO_DH */ 00290 00291 static int 00292 ossl_ssl_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) 00293 { 00294 VALUE cb; 00295 SSL *ssl; 00296 00297 ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); 00298 cb = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_vcb_idx); 00299 X509_STORE_CTX_set_ex_data(ctx, ossl_verify_cb_idx, (void*)cb); 00300 return ossl_verify_cb(preverify_ok, ctx); 00301 } 00302 00303 static VALUE 00304 ossl_call_session_get_cb(VALUE ary) 00305 { 00306 VALUE ssl_obj, sslctx_obj, cb; 00307 00308 Check_Type(ary, T_ARRAY); 00309 ssl_obj = rb_ary_entry(ary, 0); 00310 00311 sslctx_obj = rb_iv_get(ssl_obj, "@context"); 00312 if (NIL_P(sslctx_obj)) return Qnil; 00313 cb = rb_iv_get(sslctx_obj, "@session_get_cb"); 00314 if (NIL_P(cb)) return Qnil; 00315 00316 return rb_funcall(cb, rb_intern("call"), 1, ary); 00317 } 00318 00319 /* this method is currently only called for servers (in OpenSSL <= 0.9.8e) */ 00320 static SSL_SESSION * 00321 ossl_sslctx_session_get_cb(SSL *ssl, unsigned char *buf, int len, int *copy) 00322 { 00323 VALUE ary, ssl_obj, ret_obj; 00324 SSL_SESSION *sess; 00325 void *ptr; 00326 int state = 0; 00327 00328 OSSL_Debug("SSL SESSION get callback entered"); 00329 if ((ptr = SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx)) == NULL) 00330 return NULL; 00331 ssl_obj = (VALUE)ptr; 00332 ary = rb_ary_new2(2); 00333 rb_ary_push(ary, ssl_obj); 00334 rb_ary_push(ary, rb_str_new((const char *)buf, len)); 00335 00336 ret_obj = rb_protect((VALUE(*)_((VALUE)))ossl_call_session_get_cb, ary, &state); 00337 if (state) { 00338 rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(state)); 00339 return NULL; 00340 } 00341 if (!rb_obj_is_instance_of(ret_obj, cSSLSession)) 00342 return NULL; 00343 00344 SafeGetSSLSession(ret_obj, sess); 00345 *copy = 1; 00346 00347 return sess; 00348 } 00349 00350 static VALUE 00351 ossl_call_session_new_cb(VALUE ary) 00352 { 00353 VALUE ssl_obj, sslctx_obj, cb; 00354 00355 Check_Type(ary, T_ARRAY); 00356 ssl_obj = rb_ary_entry(ary, 0); 00357 00358 sslctx_obj = rb_iv_get(ssl_obj, "@context"); 00359 if (NIL_P(sslctx_obj)) return Qnil; 00360 cb = rb_iv_get(sslctx_obj, "@session_new_cb"); 00361 if (NIL_P(cb)) return Qnil; 00362 00363 return rb_funcall(cb, rb_intern("call"), 1, ary); 00364 } 00365 00366 /* return 1 normal. return 0 removes the session */ 00367 static int 00368 ossl_sslctx_session_new_cb(SSL *ssl, SSL_SESSION *sess) 00369 { 00370 VALUE ary, ssl_obj, sess_obj, ret_obj; 00371 void *ptr; 00372 int state = 0; 00373 00374 OSSL_Debug("SSL SESSION new callback entered"); 00375 00376 if ((ptr = SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx)) == NULL) 00377 return 1; 00378 ssl_obj = (VALUE)ptr; 00379 sess_obj = rb_obj_alloc(cSSLSession); 00380 CRYPTO_add(&sess->references, 1, CRYPTO_LOCK_SSL_SESSION); 00381 DATA_PTR(sess_obj) = sess; 00382 00383 ary = rb_ary_new2(2); 00384 rb_ary_push(ary, ssl_obj); 00385 rb_ary_push(ary, sess_obj); 00386 00387 ret_obj = rb_protect((VALUE(*)_((VALUE)))ossl_call_session_new_cb, ary, &state); 00388 if (state) { 00389 rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(state)); 00390 return 0; /* what should be returned here??? */ 00391 } 00392 00393 return RTEST(ret_obj) ? 1 : 0; 00394 } 00395 00396 #if 0 /* unused */ 00397 static VALUE 00398 ossl_call_session_remove_cb(VALUE ary) 00399 { 00400 VALUE sslctx_obj, cb; 00401 00402 Check_Type(ary, T_ARRAY); 00403 sslctx_obj = rb_ary_entry(ary, 0); 00404 00405 cb = rb_iv_get(sslctx_obj, "@session_remove_cb"); 00406 if (NIL_P(cb)) return Qnil; 00407 00408 return rb_funcall(cb, rb_intern("call"), 1, ary); 00409 } 00410 #endif 00411 00412 static void 00413 ossl_sslctx_session_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess) 00414 { 00415 VALUE ary, sslctx_obj, sess_obj, ret_obj; 00416 void *ptr; 00417 int state = 0; 00418 00419 OSSL_Debug("SSL SESSION remove callback entered"); 00420 00421 if ((ptr = SSL_CTX_get_ex_data(ctx, ossl_ssl_ex_ptr_idx)) == NULL) 00422 return; 00423 sslctx_obj = (VALUE)ptr; 00424 sess_obj = rb_obj_alloc(cSSLSession); 00425 CRYPTO_add(&sess->references, 1, CRYPTO_LOCK_SSL_SESSION); 00426 DATA_PTR(sess_obj) = sess; 00427 00428 ary = rb_ary_new2(2); 00429 rb_ary_push(ary, sslctx_obj); 00430 rb_ary_push(ary, sess_obj); 00431 00432 ret_obj = rb_protect((VALUE(*)_((VALUE)))ossl_call_session_new_cb, ary, &state); 00433 if (state) { 00434 /* 00435 the SSL_CTX is frozen, nowhere to save state. 00436 there is no common accessor method to check it either. 00437 rb_ivar_set(sslctx_obj, ID_callback_state, INT2NUM(state)); 00438 */ 00439 } 00440 } 00441 00442 static VALUE 00443 ossl_sslctx_add_extra_chain_cert_i(VALUE i, VALUE arg) 00444 { 00445 X509 *x509; 00446 SSL_CTX *ctx; 00447 00448 Data_Get_Struct(arg, SSL_CTX, ctx); 00449 x509 = DupX509CertPtr(i); 00450 if(!SSL_CTX_add_extra_chain_cert(ctx, x509)){ 00451 ossl_raise(eSSLError, NULL); 00452 } 00453 00454 return i; 00455 } 00456 00457 static VALUE ossl_sslctx_setup(VALUE self); 00458 00459 #ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME 00460 static VALUE 00461 ossl_call_servername_cb(VALUE ary) 00462 { 00463 VALUE ssl_obj, sslctx_obj, cb, ret_obj; 00464 00465 Check_Type(ary, T_ARRAY); 00466 ssl_obj = rb_ary_entry(ary, 0); 00467 00468 sslctx_obj = rb_iv_get(ssl_obj, "@context"); 00469 if (NIL_P(sslctx_obj)) return Qnil; 00470 cb = rb_iv_get(sslctx_obj, "@servername_cb"); 00471 if (NIL_P(cb)) return Qnil; 00472 00473 ret_obj = rb_funcall(cb, rb_intern("call"), 1, ary); 00474 if (rb_obj_is_kind_of(ret_obj, cSSLContext)) { 00475 SSL *ssl; 00476 SSL_CTX *ctx2; 00477 00478 ossl_sslctx_setup(ret_obj); 00479 Data_Get_Struct(ssl_obj, SSL, ssl); 00480 Data_Get_Struct(ret_obj, SSL_CTX, ctx2); 00481 SSL_set_SSL_CTX(ssl, ctx2); 00482 } else if (!NIL_P(ret_obj)) { 00483 rb_raise(rb_eArgError, "servername_cb must return an OpenSSL::SSL::SSLContext object or nil"); 00484 } 00485 00486 return ret_obj; 00487 } 00488 00489 static int 00490 ssl_servername_cb(SSL *ssl, int *ad, void *arg) 00491 { 00492 VALUE ary, ssl_obj, ret_obj; 00493 void *ptr; 00494 int state = 0; 00495 const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); 00496 00497 if (!servername) 00498 return SSL_TLSEXT_ERR_OK; 00499 00500 if ((ptr = SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx)) == NULL) 00501 return SSL_TLSEXT_ERR_ALERT_FATAL; 00502 ssl_obj = (VALUE)ptr; 00503 ary = rb_ary_new2(2); 00504 rb_ary_push(ary, ssl_obj); 00505 rb_ary_push(ary, rb_str_new2(servername)); 00506 00507 ret_obj = rb_protect((VALUE(*)_((VALUE)))ossl_call_servername_cb, ary, &state); 00508 if (state) { 00509 rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(state)); 00510 return SSL_TLSEXT_ERR_ALERT_FATAL; 00511 } 00512 00513 return SSL_TLSEXT_ERR_OK; 00514 } 00515 #endif 00516 00517 /* 00518 * call-seq: 00519 * ctx.setup => Qtrue # first time 00520 * ctx.setup => nil # thereafter 00521 * 00522 * This method is called automatically when a new SSLSocket is created. 00523 * Normally you do not need to call this method (unless you are writing an extension in C). 00524 */ 00525 static VALUE 00526 ossl_sslctx_setup(VALUE self) 00527 { 00528 SSL_CTX *ctx; 00529 X509 *cert = NULL, *client_ca = NULL; 00530 X509_STORE *store; 00531 EVP_PKEY *key = NULL; 00532 char *ca_path = NULL, *ca_file = NULL; 00533 int i, verify_mode; 00534 VALUE val; 00535 00536 if(OBJ_FROZEN(self)) return Qnil; 00537 Data_Get_Struct(self, SSL_CTX, ctx); 00538 00539 #if !defined(OPENSSL_NO_DH) 00540 if (RTEST(ossl_sslctx_get_tmp_dh_cb(self))){ 00541 SSL_CTX_set_tmp_dh_callback(ctx, ossl_tmp_dh_callback); 00542 } 00543 else{ 00544 SSL_CTX_set_tmp_dh_callback(ctx, ossl_default_tmp_dh_callback); 00545 } 00546 #endif 00547 SSL_CTX_set_ex_data(ctx, ossl_ssl_ex_ptr_idx, (void*)self); 00548 00549 val = ossl_sslctx_get_cert_store(self); 00550 if(!NIL_P(val)){ 00551 /* 00552 * WORKAROUND: 00553 * X509_STORE can count references, but 00554 * X509_STORE_free() doesn't care it. 00555 * So we won't increment it but mark it by ex_data. 00556 */ 00557 store = GetX509StorePtr(val); /* NO NEED TO DUP */ 00558 SSL_CTX_set_cert_store(ctx, store); 00559 SSL_CTX_set_ex_data(ctx, ossl_ssl_ex_store_p, (void*)1); 00560 } 00561 00562 val = ossl_sslctx_get_extra_cert(self); 00563 if(!NIL_P(val)){ 00564 rb_block_call(val, rb_intern("each"), 0, 0, ossl_sslctx_add_extra_chain_cert_i, self); 00565 } 00566 00567 /* private key may be bundled in certificate file. */ 00568 val = ossl_sslctx_get_cert(self); 00569 cert = NIL_P(val) ? NULL : GetX509CertPtr(val); /* NO DUP NEEDED */ 00570 val = ossl_sslctx_get_key(self); 00571 key = NIL_P(val) ? NULL : GetPKeyPtr(val); /* NO DUP NEEDED */ 00572 if (cert && key) { 00573 if (!SSL_CTX_use_certificate(ctx, cert)) { 00574 /* Adds a ref => Safe to FREE */ 00575 ossl_raise(eSSLError, "SSL_CTX_use_certificate:"); 00576 } 00577 if (!SSL_CTX_use_PrivateKey(ctx, key)) { 00578 /* Adds a ref => Safe to FREE */ 00579 ossl_raise(eSSLError, "SSL_CTX_use_PrivateKey:"); 00580 } 00581 if (!SSL_CTX_check_private_key(ctx)) { 00582 ossl_raise(eSSLError, "SSL_CTX_check_private_key:"); 00583 } 00584 } 00585 00586 val = ossl_sslctx_get_client_ca(self); 00587 if(!NIL_P(val)){ 00588 if(TYPE(val) == T_ARRAY){ 00589 for(i = 0; i < RARRAY_LEN(val); i++){ 00590 client_ca = GetX509CertPtr(RARRAY_PTR(val)[i]); 00591 if (!SSL_CTX_add_client_CA(ctx, client_ca)){ 00592 /* Copies X509_NAME => FREE it. */ 00593 ossl_raise(eSSLError, "SSL_CTX_add_client_CA"); 00594 } 00595 } 00596 } 00597 else{ 00598 client_ca = GetX509CertPtr(val); /* NO DUP NEEDED. */ 00599 if (!SSL_CTX_add_client_CA(ctx, client_ca)){ 00600 /* Copies X509_NAME => FREE it. */ 00601 ossl_raise(eSSLError, "SSL_CTX_add_client_CA"); 00602 } 00603 } 00604 } 00605 00606 val = ossl_sslctx_get_ca_file(self); 00607 ca_file = NIL_P(val) ? NULL : StringValuePtr(val); 00608 val = ossl_sslctx_get_ca_path(self); 00609 ca_path = NIL_P(val) ? NULL : StringValuePtr(val); 00610 if(ca_file || ca_path){ 00611 if (!SSL_CTX_load_verify_locations(ctx, ca_file, ca_path)) 00612 rb_warning("can't set verify locations"); 00613 } 00614 00615 val = ossl_sslctx_get_verify_mode(self); 00616 verify_mode = NIL_P(val) ? SSL_VERIFY_NONE : NUM2INT(val); 00617 SSL_CTX_set_verify(ctx, verify_mode, ossl_ssl_verify_callback); 00618 if (RTEST(ossl_sslctx_get_client_cert_cb(self))) 00619 SSL_CTX_set_client_cert_cb(ctx, ossl_client_cert_cb); 00620 00621 val = ossl_sslctx_get_timeout(self); 00622 if(!NIL_P(val)) SSL_CTX_set_timeout(ctx, NUM2LONG(val)); 00623 00624 val = ossl_sslctx_get_verify_dep(self); 00625 if(!NIL_P(val)) SSL_CTX_set_verify_depth(ctx, NUM2LONG(val)); 00626 00627 val = ossl_sslctx_get_options(self); 00628 if(!NIL_P(val)) SSL_CTX_set_options(ctx, NUM2LONG(val)); 00629 rb_obj_freeze(self); 00630 00631 val = ossl_sslctx_get_sess_id_ctx(self); 00632 if (!NIL_P(val)){ 00633 StringValue(val); 00634 if (!SSL_CTX_set_session_id_context(ctx, (unsigned char *)RSTRING_PTR(val), 00635 RSTRING_LEN(val))){ 00636 ossl_raise(eSSLError, "SSL_CTX_set_session_id_context:"); 00637 } 00638 } 00639 00640 if (RTEST(rb_iv_get(self, "@session_get_cb"))) { 00641 SSL_CTX_sess_set_get_cb(ctx, ossl_sslctx_session_get_cb); 00642 OSSL_Debug("SSL SESSION get callback added"); 00643 } 00644 if (RTEST(rb_iv_get(self, "@session_new_cb"))) { 00645 SSL_CTX_sess_set_new_cb(ctx, ossl_sslctx_session_new_cb); 00646 OSSL_Debug("SSL SESSION new callback added"); 00647 } 00648 if (RTEST(rb_iv_get(self, "@session_remove_cb"))) { 00649 SSL_CTX_sess_set_remove_cb(ctx, ossl_sslctx_session_remove_cb); 00650 OSSL_Debug("SSL SESSION remove callback added"); 00651 } 00652 00653 #ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME 00654 val = rb_iv_get(self, "@servername_cb"); 00655 if (!NIL_P(val)) { 00656 SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb); 00657 OSSL_Debug("SSL TLSEXT servername callback added"); 00658 } 00659 #endif 00660 00661 return Qtrue; 00662 } 00663 00664 static VALUE 00665 ossl_ssl_cipher_to_ary(SSL_CIPHER *cipher) 00666 { 00667 VALUE ary; 00668 int bits, alg_bits; 00669 00670 ary = rb_ary_new2(4); 00671 rb_ary_push(ary, rb_str_new2(SSL_CIPHER_get_name(cipher))); 00672 rb_ary_push(ary, rb_str_new2(SSL_CIPHER_get_version(cipher))); 00673 bits = SSL_CIPHER_get_bits(cipher, &alg_bits); 00674 rb_ary_push(ary, INT2FIX(bits)); 00675 rb_ary_push(ary, INT2FIX(alg_bits)); 00676 00677 return ary; 00678 } 00679 00680 /* 00681 * call-seq: 00682 * ctx.ciphers => [[name, version, bits, alg_bits], ...] 00683 */ 00684 static VALUE 00685 ossl_sslctx_get_ciphers(VALUE self) 00686 { 00687 SSL_CTX *ctx; 00688 STACK_OF(SSL_CIPHER) *ciphers; 00689 SSL_CIPHER *cipher; 00690 VALUE ary; 00691 int i, num; 00692 00693 Data_Get_Struct(self, SSL_CTX, ctx); 00694 if(!ctx){ 00695 rb_warning("SSL_CTX is not initialized."); 00696 return Qnil; 00697 } 00698 ciphers = ctx->cipher_list; 00699 00700 if (!ciphers) 00701 return rb_ary_new(); 00702 00703 num = sk_num((STACK*)ciphers); 00704 ary = rb_ary_new2(num); 00705 for(i = 0; i < num; i++){ 00706 cipher = (SSL_CIPHER*)sk_value((STACK*)ciphers, i); 00707 rb_ary_push(ary, ossl_ssl_cipher_to_ary(cipher)); 00708 } 00709 return ary; 00710 } 00711 00712 /* 00713 * call-seq: 00714 * ctx.ciphers = "cipher1:cipher2:..." 00715 * ctx.ciphers = [name, ...] 00716 * ctx.ciphers = [[name, version, bits, alg_bits], ...] 00717 */ 00718 static VALUE 00719 ossl_sslctx_set_ciphers(VALUE self, VALUE v) 00720 { 00721 SSL_CTX *ctx; 00722 VALUE str, elem; 00723 int i; 00724 00725 rb_check_frozen(self); 00726 if (NIL_P(v)) 00727 return v; 00728 else if (TYPE(v) == T_ARRAY) { 00729 str = rb_str_new(0, 0); 00730 for (i = 0; i < RARRAY_LEN(v); i++) { 00731 elem = rb_ary_entry(v, i); 00732 if (TYPE(elem) == T_ARRAY) elem = rb_ary_entry(elem, 0); 00733 elem = rb_String(elem); 00734 rb_str_append(str, elem); 00735 if (i < RARRAY_LEN(v)-1) rb_str_cat2(str, ":"); 00736 } 00737 } else { 00738 str = v; 00739 StringValue(str); 00740 } 00741 00742 Data_Get_Struct(self, SSL_CTX, ctx); 00743 if(!ctx){ 00744 ossl_raise(eSSLError, "SSL_CTX is not initialized."); 00745 return Qnil; 00746 } 00747 if (!SSL_CTX_set_cipher_list(ctx, RSTRING_PTR(str))) { 00748 ossl_raise(eSSLError, "SSL_CTX_set_cipher_list:"); 00749 } 00750 00751 return v; 00752 } 00753 00754 00755 /* 00756 * call-seq: 00757 * ctx.session_add(session) -> true | false 00758 * 00759 */ 00760 static VALUE 00761 ossl_sslctx_session_add(VALUE self, VALUE arg) 00762 { 00763 SSL_CTX *ctx; 00764 SSL_SESSION *sess; 00765 00766 Data_Get_Struct(self, SSL_CTX, ctx); 00767 SafeGetSSLSession(arg, sess); 00768 00769 return SSL_CTX_add_session(ctx, sess) == 1 ? Qtrue : Qfalse; 00770 } 00771 00772 /* 00773 * call-seq: 00774 * ctx.session_remove(session) -> true | false 00775 * 00776 */ 00777 static VALUE 00778 ossl_sslctx_session_remove(VALUE self, VALUE arg) 00779 { 00780 SSL_CTX *ctx; 00781 SSL_SESSION *sess; 00782 00783 Data_Get_Struct(self, SSL_CTX, ctx); 00784 SafeGetSSLSession(arg, sess); 00785 00786 return SSL_CTX_remove_session(ctx, sess) == 1 ? Qtrue : Qfalse; 00787 } 00788 00789 /* 00790 * call-seq: 00791 * ctx.session_cache_mode -> integer 00792 * 00793 */ 00794 static VALUE 00795 ossl_sslctx_get_session_cache_mode(VALUE self) 00796 { 00797 SSL_CTX *ctx; 00798 00799 Data_Get_Struct(self, SSL_CTX, ctx); 00800 00801 return LONG2NUM(SSL_CTX_get_session_cache_mode(ctx)); 00802 } 00803 00804 /* 00805 * call-seq: 00806 * ctx.session_cache_mode=(integer) -> integer 00807 * 00808 */ 00809 static VALUE 00810 ossl_sslctx_set_session_cache_mode(VALUE self, VALUE arg) 00811 { 00812 SSL_CTX *ctx; 00813 00814 Data_Get_Struct(self, SSL_CTX, ctx); 00815 00816 SSL_CTX_set_session_cache_mode(ctx, NUM2LONG(arg)); 00817 00818 return arg; 00819 } 00820 00821 /* 00822 * call-seq: 00823 * ctx.session_cache_size -> integer 00824 * 00825 */ 00826 static VALUE 00827 ossl_sslctx_get_session_cache_size(VALUE self) 00828 { 00829 SSL_CTX *ctx; 00830 00831 Data_Get_Struct(self, SSL_CTX, ctx); 00832 00833 return LONG2NUM(SSL_CTX_sess_get_cache_size(ctx)); 00834 } 00835 00836 /* 00837 * call-seq: 00838 * ctx.session_cache_size=(integer) -> integer 00839 * 00840 */ 00841 static VALUE 00842 ossl_sslctx_set_session_cache_size(VALUE self, VALUE arg) 00843 { 00844 SSL_CTX *ctx; 00845 00846 Data_Get_Struct(self, SSL_CTX, ctx); 00847 00848 SSL_CTX_sess_set_cache_size(ctx, NUM2LONG(arg)); 00849 00850 return arg; 00851 } 00852 00853 /* 00854 * call-seq: 00855 * ctx.session_cache_stats -> Hash 00856 * 00857 */ 00858 static VALUE 00859 ossl_sslctx_get_session_cache_stats(VALUE self) 00860 { 00861 SSL_CTX *ctx; 00862 VALUE hash; 00863 00864 Data_Get_Struct(self, SSL_CTX, ctx); 00865 00866 hash = rb_hash_new(); 00867 rb_hash_aset(hash, ID2SYM(rb_intern("cache_num")), LONG2NUM(SSL_CTX_sess_number(ctx))); 00868 rb_hash_aset(hash, ID2SYM(rb_intern("connect")), LONG2NUM(SSL_CTX_sess_connect(ctx))); 00869 rb_hash_aset(hash, ID2SYM(rb_intern("connect_good")), LONG2NUM(SSL_CTX_sess_connect_good(ctx))); 00870 rb_hash_aset(hash, ID2SYM(rb_intern("connect_renegotiate")), LONG2NUM(SSL_CTX_sess_connect_renegotiate(ctx))); 00871 rb_hash_aset(hash, ID2SYM(rb_intern("accept")), LONG2NUM(SSL_CTX_sess_accept(ctx))); 00872 rb_hash_aset(hash, ID2SYM(rb_intern("accept_good")), LONG2NUM(SSL_CTX_sess_accept_good(ctx))); 00873 rb_hash_aset(hash, ID2SYM(rb_intern("accept_renegotiate")), LONG2NUM(SSL_CTX_sess_accept_renegotiate(ctx))); 00874 rb_hash_aset(hash, ID2SYM(rb_intern("cache_hits")), LONG2NUM(SSL_CTX_sess_hits(ctx))); 00875 rb_hash_aset(hash, ID2SYM(rb_intern("cb_hits")), LONG2NUM(SSL_CTX_sess_cb_hits(ctx))); 00876 rb_hash_aset(hash, ID2SYM(rb_intern("cache_misses")), LONG2NUM(SSL_CTX_sess_misses(ctx))); 00877 rb_hash_aset(hash, ID2SYM(rb_intern("cache_full")), LONG2NUM(SSL_CTX_sess_cache_full(ctx))); 00878 rb_hash_aset(hash, ID2SYM(rb_intern("timeouts")), LONG2NUM(SSL_CTX_sess_timeouts(ctx))); 00879 00880 return hash; 00881 } 00882 00883 00884 /* 00885 * call-seq: 00886 * ctx.flush_sessions(time | nil) -> self 00887 * 00888 */ 00889 static VALUE 00890 ossl_sslctx_flush_sessions(int argc, VALUE *argv, VALUE self) 00891 { 00892 VALUE arg1; 00893 SSL_CTX *ctx; 00894 time_t tm = 0; 00895 00896 rb_scan_args(argc, argv, "01", &arg1); 00897 00898 Data_Get_Struct(self, SSL_CTX, ctx); 00899 00900 if (NIL_P(arg1)) { 00901 tm = time(0); 00902 } else if (rb_obj_is_instance_of(arg1, rb_cTime)) { 00903 tm = NUM2LONG(rb_funcall(arg1, rb_intern("to_i"), 0)); 00904 } else { 00905 rb_raise(rb_eArgError, "arg must be Time or nil"); 00906 } 00907 00908 SSL_CTX_flush_sessions(ctx, (long)tm); 00909 00910 return self; 00911 } 00912 00913 /* 00914 * SSLSocket class 00915 */ 00916 static void 00917 ossl_ssl_shutdown(SSL *ssl) 00918 { 00919 if (ssl) { 00920 SSL_shutdown(ssl); 00921 SSL_clear(ssl); 00922 } 00923 } 00924 00925 static void 00926 ossl_ssl_free(SSL *ssl) 00927 { 00928 ossl_ssl_shutdown(ssl); 00929 SSL_free(ssl); 00930 } 00931 00932 static VALUE 00933 ossl_ssl_s_alloc(VALUE klass) 00934 { 00935 return Data_Wrap_Struct(klass, 0, ossl_ssl_free, NULL); 00936 } 00937 00938 /* 00939 * call-seq: 00940 * SSLSocket.new(io) => aSSLSocket 00941 * SSLSocket.new(io, ctx) => aSSLSocket 00942 * 00943 * === Parameters 00944 * * +io+ is a real ruby IO object. Not an IO like object that responds to read/write. 00945 * * +ctx+ is an OpenSSLSSL::SSLContext. 00946 * 00947 * The OpenSSL::Buffering module provides additional IO methods. 00948 * 00949 * This method will freeze the SSLContext if one is provided; 00950 * however, session management is still allowed in the frozen SSLContext. 00951 */ 00952 static VALUE 00953 ossl_ssl_initialize(int argc, VALUE *argv, VALUE self) 00954 { 00955 VALUE io, ctx; 00956 00957 if (rb_scan_args(argc, argv, "11", &io, &ctx) == 1) { 00958 ctx = rb_funcall(cSSLContext, rb_intern("new"), 0); 00959 } 00960 OSSL_Check_Kind(ctx, cSSLContext); 00961 Check_Type(io, T_FILE); 00962 ossl_ssl_set_io(self, io); 00963 ossl_ssl_set_ctx(self, ctx); 00964 ossl_ssl_set_sync_close(self, Qfalse); 00965 ossl_sslctx_setup(ctx); 00966 00967 rb_iv_set(self, "@hostname", Qnil); 00968 00969 rb_call_super(0, 0); 00970 00971 return self; 00972 } 00973 00974 static VALUE 00975 ossl_ssl_setup(VALUE self) 00976 { 00977 VALUE io, v_ctx, cb; 00978 SSL_CTX *ctx; 00979 SSL *ssl; 00980 rb_io_t *fptr; 00981 00982 Data_Get_Struct(self, SSL, ssl); 00983 if(!ssl){ 00984 #ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME 00985 VALUE hostname = rb_iv_get(self, "@hostname"); 00986 #endif 00987 00988 v_ctx = ossl_ssl_get_ctx(self); 00989 Data_Get_Struct(v_ctx, SSL_CTX, ctx); 00990 00991 ssl = SSL_new(ctx); 00992 if (!ssl) { 00993 ossl_raise(eSSLError, "SSL_new:"); 00994 } 00995 DATA_PTR(self) = ssl; 00996 00997 #ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME 00998 if (!NIL_P(hostname)) { 00999 if (SSL_set_tlsext_host_name(ssl, StringValuePtr(hostname)) != 1) 01000 ossl_raise(eSSLError, "SSL_set_tlsext_host_name:"); 01001 } 01002 #endif 01003 io = ossl_ssl_get_io(self); 01004 GetOpenFile(io, fptr); 01005 rb_io_check_readable(fptr); 01006 rb_io_check_writable(fptr); 01007 SSL_set_fd(ssl, TO_SOCKET(FPTR_TO_FD(fptr))); 01008 SSL_set_ex_data(ssl, ossl_ssl_ex_ptr_idx, (void*)self); 01009 cb = ossl_sslctx_get_verify_cb(v_ctx); 01010 SSL_set_ex_data(ssl, ossl_ssl_ex_vcb_idx, (void*)cb); 01011 cb = ossl_sslctx_get_client_cert_cb(v_ctx); 01012 SSL_set_ex_data(ssl, ossl_ssl_ex_client_cert_cb_idx, (void*)cb); 01013 cb = ossl_sslctx_get_tmp_dh_cb(v_ctx); 01014 SSL_set_ex_data(ssl, ossl_ssl_ex_tmp_dh_callback_idx, (void*)cb); 01015 } 01016 01017 return Qtrue; 01018 } 01019 01020 #ifdef _WIN32 01021 #define ssl_get_error(ssl, ret) (errno = rb_w32_map_errno(WSAGetLastError()), SSL_get_error(ssl, ret)) 01022 #else 01023 #define ssl_get_error(ssl, ret) SSL_get_error(ssl, ret) 01024 #endif 01025 01026 static void 01027 write_would_block(int nonblock) 01028 { 01029 if (nonblock) { 01030 VALUE exc = ossl_exc_new(eSSLError, "write would block"); 01031 rb_extend_object(exc, rb_mWaitWritable); 01032 rb_exc_raise(exc); 01033 } 01034 } 01035 01036 static void 01037 read_would_block(int nonblock) 01038 { 01039 if (nonblock) { 01040 VALUE exc = ossl_exc_new(eSSLError, "read would block"); 01041 rb_extend_object(exc, rb_mWaitReadable); 01042 rb_exc_raise(exc); 01043 } 01044 } 01045 01046 static VALUE 01047 ossl_start_ssl(VALUE self, int (*func)(), const char *funcname, int nonblock) 01048 { 01049 SSL *ssl; 01050 rb_io_t *fptr; 01051 int ret, ret2; 01052 VALUE cb_state; 01053 01054 rb_ivar_set(self, ID_callback_state, Qnil); 01055 01056 Data_Get_Struct(self, SSL, ssl); 01057 GetOpenFile(ossl_ssl_get_io(self), fptr); 01058 for(;;){ 01059 ret = func(ssl); 01060 01061 cb_state = rb_ivar_get(self, ID_callback_state); 01062 if (!NIL_P(cb_state)) 01063 rb_jump_tag(NUM2INT(cb_state)); 01064 01065 if (ret > 0) 01066 break; 01067 01068 switch((ret2 = ssl_get_error(ssl, ret))){ 01069 case SSL_ERROR_WANT_WRITE: 01070 write_would_block(nonblock); 01071 rb_io_wait_writable(FPTR_TO_FD(fptr)); 01072 continue; 01073 case SSL_ERROR_WANT_READ: 01074 read_would_block(nonblock); 01075 rb_io_wait_readable(FPTR_TO_FD(fptr)); 01076 continue; 01077 case SSL_ERROR_SYSCALL: 01078 if (errno) rb_sys_fail(funcname); 01079 ossl_raise(eSSLError, "%s SYSCALL returned=%d errno=%d state=%s", funcname, ret2, errno, SSL_state_string_long(ssl)); 01080 default: 01081 ossl_raise(eSSLError, "%s returned=%d errno=%d state=%s", funcname, ret2, errno, SSL_state_string_long(ssl)); 01082 } 01083 } 01084 01085 return self; 01086 } 01087 01088 /* 01089 * call-seq: 01090 * ssl.connect => self 01091 */ 01092 static VALUE 01093 ossl_ssl_connect(VALUE self) 01094 { 01095 ossl_ssl_setup(self); 01096 return ossl_start_ssl(self, SSL_connect, "SSL_connect", 0); 01097 } 01098 01099 /* 01100 * call-seq: 01101 * ssl.connect_nonblock => self 01102 * 01103 * initiate the TLS/SSL handshake as a client in non-blocking manner. 01104 * 01105 * # emulates blocking connect 01106 * begin 01107 * ssl.connect_nonblock 01108 * rescue IO::WaitReadable 01109 * IO.select([s2]) 01110 * retry 01111 * rescue IO::WaitWritable 01112 * IO.select(nil, [s2]) 01113 * retry 01114 * end 01115 * 01116 */ 01117 static VALUE 01118 ossl_ssl_connect_nonblock(VALUE self) 01119 { 01120 ossl_ssl_setup(self); 01121 return ossl_start_ssl(self, SSL_connect, "SSL_connect", 1); 01122 } 01123 01124 /* 01125 * call-seq: 01126 * ssl.accept => self 01127 */ 01128 static VALUE 01129 ossl_ssl_accept(VALUE self) 01130 { 01131 ossl_ssl_setup(self); 01132 return ossl_start_ssl(self, SSL_accept, "SSL_accept", 0); 01133 } 01134 01135 /* 01136 * call-seq: 01137 * ssl.accept_nonblock => self 01138 * 01139 * initiate the TLS/SSL handshake as a server in non-blocking manner. 01140 * 01141 * # emulates blocking accept 01142 * begin 01143 * ssl.accept_nonblock 01144 * rescue IO::WaitReadable 01145 * IO.select([s2]) 01146 * retry 01147 * rescue IO::WaitWritable 01148 * IO.select(nil, [s2]) 01149 * retry 01150 * end 01151 * 01152 */ 01153 static VALUE 01154 ossl_ssl_accept_nonblock(VALUE self) 01155 { 01156 ossl_ssl_setup(self); 01157 return ossl_start_ssl(self, SSL_accept, "SSL_accept", 1); 01158 } 01159 01160 static VALUE 01161 ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock) 01162 { 01163 SSL *ssl; 01164 int ilen, nread = 0; 01165 VALUE len, str; 01166 rb_io_t *fptr; 01167 01168 rb_scan_args(argc, argv, "11", &len, &str); 01169 ilen = NUM2INT(len); 01170 if(NIL_P(str)) str = rb_str_new(0, ilen); 01171 else{ 01172 StringValue(str); 01173 rb_str_modify(str); 01174 rb_str_resize(str, ilen); 01175 } 01176 if(ilen == 0) return str; 01177 01178 Data_Get_Struct(self, SSL, ssl); 01179 GetOpenFile(ossl_ssl_get_io(self), fptr); 01180 if (ssl) { 01181 if(!nonblock && SSL_pending(ssl) <= 0) 01182 rb_thread_wait_fd(FPTR_TO_FD(fptr)); 01183 for (;;){ 01184 nread = SSL_read(ssl, RSTRING_PTR(str), RSTRING_LEN(str)); 01185 switch(ssl_get_error(ssl, nread)){ 01186 case SSL_ERROR_NONE: 01187 goto end; 01188 case SSL_ERROR_ZERO_RETURN: 01189 rb_eof_error(); 01190 case SSL_ERROR_WANT_WRITE: 01191 write_would_block(nonblock); 01192 rb_io_wait_writable(FPTR_TO_FD(fptr)); 01193 continue; 01194 case SSL_ERROR_WANT_READ: 01195 read_would_block(nonblock); 01196 rb_io_wait_readable(FPTR_TO_FD(fptr)); 01197 continue; 01198 case SSL_ERROR_SYSCALL: 01199 if(ERR_peek_error() == 0 && nread == 0) rb_eof_error(); 01200 rb_sys_fail(0); 01201 default: 01202 ossl_raise(eSSLError, "SSL_read:"); 01203 } 01204 } 01205 } 01206 else { 01207 ID meth = nonblock ? rb_intern("read_nonblock") : rb_intern("sysread"); 01208 rb_warning("SSL session is not started yet."); 01209 return rb_funcall(ossl_ssl_get_io(self), meth, 2, len, str); 01210 } 01211 01212 end: 01213 rb_str_set_len(str, nread); 01214 OBJ_TAINT(str); 01215 01216 return str; 01217 } 01218 01219 01220 /* 01221 * call-seq: 01222 * ssl.sysread(length) => string 01223 * ssl.sysread(length, buffer) => buffer 01224 * 01225 * === Parameters 01226 * * +length+ is a positive integer. 01227 * * +buffer+ is a string used to store the result. 01228 */ 01229 static VALUE 01230 ossl_ssl_read(int argc, VALUE *argv, VALUE self) 01231 { 01232 return ossl_ssl_read_internal(argc, argv, self, 0); 01233 } 01234 01235 /* 01236 * call-seq: 01237 * ssl.sysread_nonblock(length) => string 01238 * ssl.sysread_nonblock(length, buffer) => buffer 01239 * 01240 * === Parameters 01241 * * +length+ is a positive integer. 01242 * * +buffer+ is a string used to store the result. 01243 */ 01244 static VALUE 01245 ossl_ssl_read_nonblock(int argc, VALUE *argv, VALUE self) 01246 { 01247 return ossl_ssl_read_internal(argc, argv, self, 1); 01248 } 01249 01250 static VALUE 01251 ossl_ssl_write_internal(VALUE self, VALUE str, int nonblock) 01252 { 01253 SSL *ssl; 01254 int nwrite = 0; 01255 rb_io_t *fptr; 01256 01257 StringValue(str); 01258 Data_Get_Struct(self, SSL, ssl); 01259 GetOpenFile(ossl_ssl_get_io(self), fptr); 01260 01261 if (ssl) { 01262 for (;;){ 01263 nwrite = SSL_write(ssl, RSTRING_PTR(str), RSTRING_LEN(str)); 01264 switch(ssl_get_error(ssl, nwrite)){ 01265 case SSL_ERROR_NONE: 01266 goto end; 01267 case SSL_ERROR_WANT_WRITE: 01268 write_would_block(nonblock); 01269 rb_io_wait_writable(FPTR_TO_FD(fptr)); 01270 continue; 01271 case SSL_ERROR_WANT_READ: 01272 read_would_block(nonblock); 01273 rb_io_wait_readable(FPTR_TO_FD(fptr)); 01274 continue; 01275 case SSL_ERROR_SYSCALL: 01276 if (errno) rb_sys_fail(0); 01277 default: 01278 ossl_raise(eSSLError, "SSL_write:"); 01279 } 01280 } 01281 } 01282 else { 01283 ID id_syswrite = rb_intern("syswrite"); 01284 rb_warning("SSL session is not started yet."); 01285 return rb_funcall(ossl_ssl_get_io(self), id_syswrite, 1, str); 01286 } 01287 01288 end: 01289 return INT2NUM(nwrite); 01290 } 01291 01292 /* 01293 * call-seq: 01294 * ssl.syswrite(string) => integer 01295 */ 01296 static VALUE 01297 ossl_ssl_write(VALUE self, VALUE str) 01298 { 01299 return ossl_ssl_write_internal(self, str, 0); 01300 } 01301 01302 /* 01303 * call-seq: 01304 * ssl.syswrite_nonblock(string) => integer 01305 */ 01306 static VALUE 01307 ossl_ssl_write_nonblock(VALUE self, VALUE str) 01308 { 01309 return ossl_ssl_write_internal(self, str, 1); 01310 } 01311 01312 /* 01313 * call-seq: 01314 * ssl.sysclose => nil 01315 */ 01316 static VALUE 01317 ossl_ssl_close(VALUE self) 01318 { 01319 SSL *ssl; 01320 01321 Data_Get_Struct(self, SSL, ssl); 01322 ossl_ssl_shutdown(ssl); 01323 if (RTEST(ossl_ssl_get_sync_close(self))) 01324 rb_funcall(ossl_ssl_get_io(self), rb_intern("close"), 0); 01325 01326 return Qnil; 01327 } 01328 01329 /* 01330 * call-seq: 01331 * ssl.cert => cert or nil 01332 */ 01333 static VALUE 01334 ossl_ssl_get_cert(VALUE self) 01335 { 01336 SSL *ssl; 01337 X509 *cert = NULL; 01338 01339 Data_Get_Struct(self, SSL, ssl); 01340 if (!ssl) { 01341 rb_warning("SSL session is not started yet."); 01342 return Qnil; 01343 } 01344 01345 /* 01346 * Is this OpenSSL bug? Should add a ref? 01347 * TODO: Ask for. 01348 */ 01349 cert = SSL_get_certificate(ssl); /* NO DUPs => DON'T FREE. */ 01350 01351 if (!cert) { 01352 return Qnil; 01353 } 01354 return ossl_x509_new(cert); 01355 } 01356 01357 /* 01358 * call-seq: 01359 * ssl.peer_cert => cert or nil 01360 */ 01361 static VALUE 01362 ossl_ssl_get_peer_cert(VALUE self) 01363 { 01364 SSL *ssl; 01365 X509 *cert = NULL; 01366 VALUE obj; 01367 01368 Data_Get_Struct(self, SSL, ssl); 01369 01370 if (!ssl){ 01371 rb_warning("SSL session is not started yet."); 01372 return Qnil; 01373 } 01374 01375 cert = SSL_get_peer_certificate(ssl); /* Adds a ref => Safe to FREE. */ 01376 01377 if (!cert) { 01378 return Qnil; 01379 } 01380 obj = ossl_x509_new(cert); 01381 X509_free(cert); 01382 01383 return obj; 01384 } 01385 01386 /* 01387 * call-seq: 01388 * ssl.peer_cert_chain => [cert, ...] or nil 01389 */ 01390 static VALUE 01391 ossl_ssl_get_peer_cert_chain(VALUE self) 01392 { 01393 SSL *ssl; 01394 STACK_OF(X509) *chain; 01395 X509 *cert; 01396 VALUE ary; 01397 int i, num; 01398 01399 Data_Get_Struct(self, SSL, ssl); 01400 if(!ssl){ 01401 rb_warning("SSL session is not started yet."); 01402 return Qnil; 01403 } 01404 chain = SSL_get_peer_cert_chain(ssl); 01405 if(!chain) return Qnil; 01406 num = sk_X509_num(chain); 01407 ary = rb_ary_new2(num); 01408 for (i = 0; i < num; i++){ 01409 cert = sk_X509_value(chain, i); 01410 rb_ary_push(ary, ossl_x509_new(cert)); 01411 } 01412 01413 return ary; 01414 } 01415 01416 /* 01417 * call-seq: 01418 * ssl.cipher => [name, version, bits, alg_bits] 01419 */ 01420 static VALUE 01421 ossl_ssl_get_cipher(VALUE self) 01422 { 01423 SSL *ssl; 01424 SSL_CIPHER *cipher; 01425 01426 Data_Get_Struct(self, SSL, ssl); 01427 if (!ssl) { 01428 rb_warning("SSL session is not started yet."); 01429 return Qnil; 01430 } 01431 cipher = (SSL_CIPHER *)SSL_get_current_cipher(ssl); 01432 01433 return ossl_ssl_cipher_to_ary(cipher); 01434 } 01435 01436 /* 01437 * call-seq: 01438 * ssl.state => string 01439 */ 01440 static VALUE 01441 ossl_ssl_get_state(VALUE self) 01442 { 01443 SSL *ssl; 01444 VALUE ret; 01445 01446 Data_Get_Struct(self, SSL, ssl); 01447 if (!ssl) { 01448 rb_warning("SSL session is not started yet."); 01449 return Qnil; 01450 } 01451 ret = rb_str_new2(SSL_state_string(ssl)); 01452 if (ruby_verbose) { 01453 rb_str_cat2(ret, ": "); 01454 rb_str_cat2(ret, SSL_state_string_long(ssl)); 01455 } 01456 return ret; 01457 } 01458 01459 /* 01460 * call-seq: 01461 * ssl.pending => integer 01462 */ 01463 static VALUE 01464 ossl_ssl_pending(VALUE self) 01465 { 01466 SSL *ssl; 01467 01468 Data_Get_Struct(self, SSL, ssl); 01469 if (!ssl) { 01470 rb_warning("SSL session is not started yet."); 01471 return Qnil; 01472 } 01473 01474 return INT2NUM(SSL_pending(ssl)); 01475 } 01476 01477 /* 01478 * call-seq: 01479 * ssl.session_reused? -> true | false 01480 * 01481 */ 01482 static VALUE 01483 ossl_ssl_session_reused(VALUE self) 01484 { 01485 SSL *ssl; 01486 01487 Data_Get_Struct(self, SSL, ssl); 01488 if (!ssl) { 01489 rb_warning("SSL session is not started yet."); 01490 return Qnil; 01491 } 01492 01493 switch(SSL_session_reused(ssl)) { 01494 case 1: return Qtrue; 01495 case 0: return Qfalse; 01496 default: ossl_raise(eSSLError, "SSL_session_reused"); 01497 } 01498 } 01499 01500 /* 01501 * call-seq: 01502 * ssl.session = session -> session 01503 * 01504 */ 01505 static VALUE 01506 ossl_ssl_set_session(VALUE self, VALUE arg1) 01507 { 01508 SSL *ssl; 01509 SSL_SESSION *sess; 01510 01511 /* why is ossl_ssl_setup delayed? */ 01512 ossl_ssl_setup(self); 01513 01514 Data_Get_Struct(self, SSL, ssl); 01515 if (!ssl) { 01516 rb_warning("SSL session is not started yet."); 01517 return Qnil; 01518 } 01519 01520 SafeGetSSLSession(arg1, sess); 01521 01522 if (SSL_set_session(ssl, sess) != 1) 01523 ossl_raise(eSSLError, "SSL_set_session"); 01524 01525 return arg1; 01526 } 01527 01528 static VALUE 01529 ossl_ssl_get_verify_result(VALUE self) 01530 { 01531 SSL *ssl; 01532 01533 Data_Get_Struct(self, SSL, ssl); 01534 if (!ssl) { 01535 rb_warning("SSL session is not started yet."); 01536 return Qnil; 01537 } 01538 01539 return INT2FIX(SSL_get_verify_result(ssl)); 01540 } 01541 01542 void 01543 Init_ossl_ssl() 01544 { 01545 int i; 01546 VALUE ary; 01547 01548 #if 0 /* let rdoc know about mOSSL */ 01549 mOSSL = rb_define_module("OpenSSL"); 01550 #endif 01551 01552 ID_callback_state = rb_intern("@callback_state"); 01553 01554 ossl_ssl_ex_vcb_idx = SSL_get_ex_new_index(0,(void *)"ossl_ssl_ex_vcb_idx",0,0,0); 01555 ossl_ssl_ex_store_p = SSL_get_ex_new_index(0,(void *)"ossl_ssl_ex_store_p",0,0,0); 01556 ossl_ssl_ex_ptr_idx = SSL_get_ex_new_index(0,(void *)"ossl_ssl_ex_ptr_idx",0,0,0); 01557 ossl_ssl_ex_client_cert_cb_idx = 01558 SSL_get_ex_new_index(0,(void *)"ossl_ssl_ex_client_cert_cb_idx",0,0,0); 01559 ossl_ssl_ex_tmp_dh_callback_idx = 01560 SSL_get_ex_new_index(0,(void *)"ossl_ssl_ex_tmp_dh_callback_idx",0,0,0); 01561 01562 mSSL = rb_define_module_under(mOSSL, "SSL"); 01563 eSSLError = rb_define_class_under(mSSL, "SSLError", eOSSLError); 01564 01565 Init_ossl_ssl_session(); 01566 01567 /* class SSLContext 01568 * 01569 * The following attributes are available but don't show up in rdoc. 01570 * All attributes must be set before calling SSLSocket.new(io, ctx). 01571 * * ssl_version, cert, key, client_ca, ca_file, ca_path, timeout, 01572 * * verify_mode, verify_depth client_cert_cb, tmp_dh_callback, 01573 * * session_id_context, session_add_cb, session_new_cb, session_remove_cb 01574 */ 01575 cSSLContext = rb_define_class_under(mSSL, "SSLContext", rb_cObject); 01576 rb_define_alloc_func(cSSLContext, ossl_sslctx_s_alloc); 01577 for(i = 0; i < numberof(ossl_sslctx_attrs); i++) 01578 rb_attr(cSSLContext, rb_intern(ossl_sslctx_attrs[i]), 1, 1, Qfalse); 01579 rb_define_alias(cSSLContext, "ssl_timeout", "timeout"); 01580 rb_define_alias(cSSLContext, "ssl_timeout=", "timeout="); 01581 rb_define_method(cSSLContext, "initialize", ossl_sslctx_initialize, -1); 01582 rb_define_method(cSSLContext, "ssl_version=", ossl_sslctx_set_ssl_version, 1); 01583 rb_define_method(cSSLContext, "ciphers", ossl_sslctx_get_ciphers, 0); 01584 rb_define_method(cSSLContext, "ciphers=", ossl_sslctx_set_ciphers, 1); 01585 01586 rb_define_method(cSSLContext, "setup", ossl_sslctx_setup, 0); 01587 01588 01589 rb_define_const(cSSLContext, "SESSION_CACHE_OFF", LONG2FIX(SSL_SESS_CACHE_OFF)); 01590 rb_define_const(cSSLContext, "SESSION_CACHE_CLIENT", LONG2FIX(SSL_SESS_CACHE_CLIENT)); /* doesn't actually do anything in 0.9.8e */ 01591 rb_define_const(cSSLContext, "SESSION_CACHE_SERVER", LONG2FIX(SSL_SESS_CACHE_SERVER)); 01592 rb_define_const(cSSLContext, "SESSION_CACHE_BOTH", LONG2FIX(SSL_SESS_CACHE_BOTH)); /* no different than CACHE_SERVER in 0.9.8e */ 01593 rb_define_const(cSSLContext, "SESSION_CACHE_NO_AUTO_CLEAR", LONG2FIX(SSL_SESS_CACHE_NO_AUTO_CLEAR)); 01594 rb_define_const(cSSLContext, "SESSION_CACHE_NO_INTERNAL_LOOKUP", LONG2FIX(SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)); 01595 rb_define_const(cSSLContext, "SESSION_CACHE_NO_INTERNAL_STORE", LONG2FIX(SSL_SESS_CACHE_NO_INTERNAL_STORE)); 01596 rb_define_const(cSSLContext, "SESSION_CACHE_NO_INTERNAL", LONG2FIX(SSL_SESS_CACHE_NO_INTERNAL)); 01597 rb_define_method(cSSLContext, "session_add", ossl_sslctx_session_add, 1); 01598 rb_define_method(cSSLContext, "session_remove", ossl_sslctx_session_remove, 1); 01599 rb_define_method(cSSLContext, "session_cache_mode", ossl_sslctx_get_session_cache_mode, 0); 01600 rb_define_method(cSSLContext, "session_cache_mode=", ossl_sslctx_set_session_cache_mode, 1); 01601 rb_define_method(cSSLContext, "session_cache_size", ossl_sslctx_get_session_cache_size, 0); 01602 rb_define_method(cSSLContext, "session_cache_size=", ossl_sslctx_set_session_cache_size, 1); 01603 rb_define_method(cSSLContext, "session_cache_stats", ossl_sslctx_get_session_cache_stats, 0); 01604 rb_define_method(cSSLContext, "flush_sessions", ossl_sslctx_flush_sessions, -1); 01605 01606 ary = rb_ary_new2(numberof(ossl_ssl_method_tab)); 01607 for (i = 0; i < numberof(ossl_ssl_method_tab); i++) { 01608 rb_ary_push(ary, ID2SYM(rb_intern(ossl_ssl_method_tab[i].name))); 01609 } 01610 rb_obj_freeze(ary); 01611 /* holds a list of available SSL/TLS methods */ 01612 rb_define_const(cSSLContext, "METHODS", ary); 01613 01614 /* class SSLSocket 01615 * 01616 * The following attributes are available but don't show up in rdoc. 01617 * * io, context, sync_close 01618 * 01619 */ 01620 cSSLSocket = rb_define_class_under(mSSL, "SSLSocket", rb_cObject); 01621 rb_define_alloc_func(cSSLSocket, ossl_ssl_s_alloc); 01622 for(i = 0; i < numberof(ossl_ssl_attr_readers); i++) 01623 rb_attr(cSSLSocket, rb_intern(ossl_ssl_attr_readers[i]), 1, 0, Qfalse); 01624 for(i = 0; i < numberof(ossl_ssl_attrs); i++) 01625 rb_attr(cSSLSocket, rb_intern(ossl_ssl_attrs[i]), 1, 1, Qfalse); 01626 rb_define_alias(cSSLSocket, "to_io", "io"); 01627 rb_define_method(cSSLSocket, "initialize", ossl_ssl_initialize, -1); 01628 rb_define_method(cSSLSocket, "connect", ossl_ssl_connect, 0); 01629 rb_define_method(cSSLSocket, "connect_nonblock", ossl_ssl_connect_nonblock, 0); 01630 rb_define_method(cSSLSocket, "accept", ossl_ssl_accept, 0); 01631 rb_define_method(cSSLSocket, "accept_nonblock", ossl_ssl_accept_nonblock, 0); 01632 rb_define_method(cSSLSocket, "sysread", ossl_ssl_read, -1); 01633 rb_define_private_method(cSSLSocket, "sysread_nonblock", ossl_ssl_read_nonblock, -1); 01634 rb_define_method(cSSLSocket, "syswrite", ossl_ssl_write, 1); 01635 rb_define_private_method(cSSLSocket, "syswrite_nonblock", ossl_ssl_write_nonblock, 1); 01636 rb_define_method(cSSLSocket, "sysclose", ossl_ssl_close, 0); 01637 rb_define_method(cSSLSocket, "cert", ossl_ssl_get_cert, 0); 01638 rb_define_method(cSSLSocket, "peer_cert", ossl_ssl_get_peer_cert, 0); 01639 rb_define_method(cSSLSocket, "peer_cert_chain", ossl_ssl_get_peer_cert_chain, 0); 01640 rb_define_method(cSSLSocket, "cipher", ossl_ssl_get_cipher, 0); 01641 rb_define_method(cSSLSocket, "state", ossl_ssl_get_state, 0); 01642 rb_define_method(cSSLSocket, "pending", ossl_ssl_pending, 0); 01643 rb_define_method(cSSLSocket, "session_reused?", ossl_ssl_session_reused, 0); 01644 rb_define_method(cSSLSocket, "session=", ossl_ssl_set_session, 1); 01645 rb_define_method(cSSLSocket, "verify_result", ossl_ssl_get_verify_result, 0); 01646 01647 #define ossl_ssl_def_const(x) rb_define_const(mSSL, #x, INT2NUM(SSL_##x)) 01648 01649 ossl_ssl_def_const(VERIFY_NONE); 01650 ossl_ssl_def_const(VERIFY_PEER); 01651 ossl_ssl_def_const(VERIFY_FAIL_IF_NO_PEER_CERT); 01652 ossl_ssl_def_const(VERIFY_CLIENT_ONCE); 01653 /* Not introduce constants included in OP_ALL such as... 01654 * ossl_ssl_def_const(OP_MICROSOFT_SESS_ID_BUG); 01655 * ossl_ssl_def_const(OP_NETSCAPE_CHALLENGE_BUG); 01656 * ossl_ssl_def_const(OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG); 01657 * ossl_ssl_def_const(OP_SSLREF2_REUSE_CERT_TYPE_BUG); 01658 * ossl_ssl_def_const(OP_MICROSOFT_BIG_SSLV3_BUFFER); 01659 * ossl_ssl_def_const(OP_MSIE_SSLV2_RSA_PADDING); 01660 * ossl_ssl_def_const(OP_SSLEAY_080_CLIENT_DH_BUG); 01661 * ossl_ssl_def_const(OP_TLS_D5_BUG); 01662 * ossl_ssl_def_const(OP_TLS_BLOCK_PADDING_BUG); 01663 * ossl_ssl_def_const(OP_DONT_INSERT_EMPTY_FRAGMENTS); 01664 */ 01665 ossl_ssl_def_const(OP_ALL); 01666 #if defined(SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION) 01667 ossl_ssl_def_const(OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); 01668 #endif 01669 #if defined(SSL_OP_SINGLE_ECDH_USE) 01670 ossl_ssl_def_const(OP_SINGLE_ECDH_USE); 01671 #endif 01672 ossl_ssl_def_const(OP_SINGLE_DH_USE); 01673 ossl_ssl_def_const(OP_EPHEMERAL_RSA); 01674 #if defined(SSL_OP_CIPHER_SERVER_PREFERENCE) 01675 ossl_ssl_def_const(OP_CIPHER_SERVER_PREFERENCE); 01676 #endif 01677 ossl_ssl_def_const(OP_TLS_ROLLBACK_BUG); 01678 ossl_ssl_def_const(OP_NO_SSLv2); 01679 ossl_ssl_def_const(OP_NO_SSLv3); 01680 ossl_ssl_def_const(OP_NO_TLSv1); 01681 #if defined(SSL_OP_NO_TICKET) 01682 ossl_ssl_def_const(OP_NO_TICKET); 01683 #endif 01684 ossl_ssl_def_const(OP_PKCS1_CHECK_1); 01685 ossl_ssl_def_const(OP_PKCS1_CHECK_2); 01686 ossl_ssl_def_const(OP_NETSCAPE_CA_DN_BUG); 01687 ossl_ssl_def_const(OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG); 01688 } 01689
1.7.3