static VALUE ossl_pkcs7_get_signer(VALUE self) { PKCS7 *pkcs7; STACK_OF(PKCS7_SIGNER_INFO) *sk; PKCS7_SIGNER_INFO *si; int num, i; VALUE ary; GetPKCS7(self, pkcs7); if (!(sk = PKCS7_get_signer_info(pkcs7))) { OSSL_Debug("OpenSSL::PKCS7#get_signer_info == NULL!"); return rb_ary_new(); } if ((num = sk_PKCS7_SIGNER_INFO_num(sk)) < 0) { ossl_raise(ePKCS7Error, "Negative number of signers!"); } ary = rb_ary_new2(num); for (i=0; i<num; i++) { si = sk_PKCS7_SIGNER_INFO_value(sk, i); rb_ary_push(ary, ossl_pkcs7si_new(si)); } return ary; }
static VALUE ossl_x509stctx_get_chain(VALUE self) { X509_STORE_CTX *ctx; STACK_OF(X509) *chain; X509 *x509; int i, num; VALUE ary; GetX509StCtx(self, ctx); if((chain = X509_STORE_CTX_get_chain(ctx)) == NULL){ return Qnil; } if((num = sk_X509_num(chain)) < 0){ OSSL_Debug("certs in chain < 0???"); return rb_ary_new(); } ary = rb_ary_new2(num); for(i = 0; i < num; i++) { x509 = sk_X509_value(chain, i); rb_ary_push(ary, ossl_x509_new(x509)); } return ary; }
static void ossl_sslctx_session_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess) { VALUE ary, sslctx_obj, sess_obj, ret_obj; void *ptr; int state = 0; OSSL_Debug("SSL SESSION remove callback entered"); if ((ptr = SSL_CTX_get_ex_data(ctx, ossl_ssl_ex_ptr_idx)) == NULL) return; sslctx_obj = (VALUE)ptr; sess_obj = rb_obj_alloc(cSSLSession); CRYPTO_add(&sess->references, 1, CRYPTO_LOCK_SSL_SESSION); DATA_PTR(sess_obj) = sess; ary = rb_ary_new2(2); rb_ary_push(ary, sslctx_obj); rb_ary_push(ary, sess_obj); ret_obj = rb_protect((VALUE(*)_((VALUE)))ossl_call_session_new_cb, ary, &state); if (state) { /* the SSL_CTX is frozen, nowhere to save state. there is no common accessor method to check it either. rb_ivar_set(sslctx_obj, ID_callback_state, INT2NUM(state)); */ } }
/* return 1 normal. return 0 removes the session */ static int ossl_sslctx_session_new_cb(SSL *ssl, SSL_SESSION *sess) { VALUE ary, ssl_obj, sess_obj, ret_obj; void *ptr; int state = 0; OSSL_Debug("SSL SESSION new callback entered"); if ((ptr = SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx)) == NULL) return 1; ssl_obj = (VALUE)ptr; sess_obj = rb_obj_alloc(cSSLSession); CRYPTO_add(&sess->references, 1, CRYPTO_LOCK_SSL_SESSION); DATA_PTR(sess_obj) = sess; ary = rb_ary_new2(2); rb_ary_push(ary, ssl_obj); rb_ary_push(ary, sess_obj); ret_obj = rb_protect((VALUE(*)_((VALUE)))ossl_call_session_new_cb, ary, &state); if (state) { rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(state)); return 0; /* what should be returned here??? */ } return RTEST(ret_obj) ? 1 : 0; }
/* this method is currently only called for servers (in OpenSSL <= 0.9.8e) */ static SSL_SESSION * ossl_sslctx_session_get_cb(SSL *ssl, unsigned char *buf, int len, int *copy) { VALUE ary, ssl_obj, ret_obj; SSL_SESSION *sess; void *ptr; int state = 0; OSSL_Debug("SSL SESSION get callback entered"); if ((ptr = SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx)) == NULL) return NULL; ssl_obj = (VALUE)ptr; ary = rb_ary_new2(2); rb_ary_push(ary, ssl_obj); rb_ary_push(ary, rb_str_new((const char *)buf, len)); ret_obj = rb_protect((VALUE(*)_((VALUE)))ossl_call_session_get_cb, ary, &state); if (state) { rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(state)); return NULL; } if (!rb_obj_is_instance_of(ret_obj, cSSLSession)) return NULL; SafeGetSSLSession(ret_obj, sess); *copy = 1; return sess; }
int ossl_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd_) { long len; int status; VALUE rflag, pass = (VALUE)pwd_; if (RTEST(pass)) { /* PEM_def_callback(buf, max_len, flag, StringValueCStr(pass)) does not * work because it does not allow NUL characters and truncates to 1024 * bytes silently if the input is over 1024 bytes */ if (RB_TYPE_P(pass, T_STRING)) { len = RSTRING_LEN(pass); if (len <= max_len) { memcpy(buf, RSTRING_PTR(pass), len); return (int)len; } } OSSL_Debug("passed data is not valid String???"); return -1; } if (!rb_block_given_p()) { return PEM_def_callback(buf, max_len, flag, NULL); } while (1) { /* * when the flag is nonzero, this passphrase * will be used to perform encryption; otherwise it will * be used to perform decryption. */ rflag = flag ? Qtrue : Qfalse; pass = rb_protect(ossl_pem_passwd_cb0, rflag, &status); if (status) { /* ignore an exception raised. */ rb_set_errinfo(Qnil); return -1; } if (NIL_P(pass)) return -1; len = RSTRING_LEN(pass); if (len > max_len) { rb_warning("password must not be longer than %d bytes", max_len); continue; } memcpy(buf, RSTRING_PTR(pass), len); break; } return (int)len; }
/* * call-seq: * spki.challenge => string * * Returns the challenge string associated with this SPKI. */ static VALUE ossl_spki_get_challenge(VALUE self) { NETSCAPE_SPKI *spki; GetSPKI(self, spki); if (spki->spkac->challenge->length <= 0) { OSSL_Debug("Challenge.length <= 0?"); return rb_str_new(0, 0); } return rb_str_new((const char *)spki->spkac->challenge->data, spki->spkac->challenge->length); }
/* * Gets X509v3 extensions as array of X509Ext objects */ static VALUE ossl_x509crl_get_extensions(VALUE self) { X509_CRL *crl; int count, i; X509_EXTENSION *ext; VALUE ary; GetX509CRL(self, crl); count = X509_CRL_get_ext_count(crl); if (count < 0) { OSSL_Debug("count < 0???"); return rb_ary_new(); } ary = rb_ary_new2(count); for (i=0; i<count; i++) { ext = X509_CRL_get_ext(crl, i); /* NO DUP - don't free! */ rb_ary_push(ary, ossl_x509ext_new(ext)); } return ary; }
static VALUE ossl_x509crl_get_revoked(VALUE self) { X509_CRL *crl; int i, num; X509_REVOKED *rev; VALUE ary, revoked; GetX509CRL(self, crl); num = sk_X509_CRL_num(X509_CRL_get_REVOKED(crl)); if (num < 0) { OSSL_Debug("num < 0???"); return rb_ary_new(); } ary = rb_ary_new2(num); for(i=0; i<num; i++) { /* NO DUP - don't free! */ rev = (X509_REVOKED *)sk_X509_CRL_value(X509_CRL_get_REVOKED(crl), i); revoked = ossl_x509revoked_new(rev); rb_ary_push(ary, revoked); } return ary; }
/* * call-seq: * ctx.setup => Qtrue # first time * ctx.setup => nil # thereafter * * This method is called automatically when a new SSLSocket is created. * Normally you do not need to call this method (unless you are writing an extension in C). */ static VALUE ossl_sslctx_setup(VALUE self) { SSL_CTX *ctx; X509 *cert = NULL, *client_ca = NULL; X509_STORE *store; EVP_PKEY *key = NULL; char *ca_path = NULL, *ca_file = NULL; int i, verify_mode; VALUE val; if(OBJ_FROZEN(self)) return Qnil; Data_Get_Struct(self, SSL_CTX, ctx); #if !defined(OPENSSL_NO_DH) if (RTEST(ossl_sslctx_get_tmp_dh_cb(self))){ SSL_CTX_set_tmp_dh_callback(ctx, ossl_tmp_dh_callback); } else{ SSL_CTX_set_tmp_dh_callback(ctx, ossl_default_tmp_dh_callback); } #endif SSL_CTX_set_ex_data(ctx, ossl_ssl_ex_ptr_idx, (void*)self); val = ossl_sslctx_get_cert_store(self); if(!NIL_P(val)){ /* * WORKAROUND: * X509_STORE can count references, but * X509_STORE_free() doesn't care it. * So we won't increment it but mark it by ex_data. */ store = GetX509StorePtr(val); /* NO NEED TO DUP */ SSL_CTX_set_cert_store(ctx, store); SSL_CTX_set_ex_data(ctx, ossl_ssl_ex_store_p, (void*)1); } val = ossl_sslctx_get_extra_cert(self); if(!NIL_P(val)){ rb_block_call(val, rb_intern("each"), 0, 0, ossl_sslctx_add_extra_chain_cert_i, self); } /* private key may be bundled in certificate file. */ val = ossl_sslctx_get_cert(self); cert = NIL_P(val) ? NULL : GetX509CertPtr(val); /* NO DUP NEEDED */ val = ossl_sslctx_get_key(self); key = NIL_P(val) ? NULL : GetPKeyPtr(val); /* NO DUP NEEDED */ if (cert && key) { if (!SSL_CTX_use_certificate(ctx, cert)) { /* Adds a ref => Safe to FREE */ ossl_raise(eSSLError, "SSL_CTX_use_certificate:"); } if (!SSL_CTX_use_PrivateKey(ctx, key)) { /* Adds a ref => Safe to FREE */ ossl_raise(eSSLError, "SSL_CTX_use_PrivateKey:"); } if (!SSL_CTX_check_private_key(ctx)) { ossl_raise(eSSLError, "SSL_CTX_check_private_key:"); } } val = ossl_sslctx_get_client_ca(self); if(!NIL_P(val)){ if(TYPE(val) == T_ARRAY){ for(i = 0; i < RARRAY_LEN(val); i++){ client_ca = GetX509CertPtr(RARRAY_PTR(val)[i]); if (!SSL_CTX_add_client_CA(ctx, client_ca)){ /* Copies X509_NAME => FREE it. */ ossl_raise(eSSLError, "SSL_CTX_add_client_CA"); } } } else{ client_ca = GetX509CertPtr(val); /* NO DUP NEEDED. */ if (!SSL_CTX_add_client_CA(ctx, client_ca)){ /* Copies X509_NAME => FREE it. */ ossl_raise(eSSLError, "SSL_CTX_add_client_CA"); } } } val = ossl_sslctx_get_ca_file(self); ca_file = NIL_P(val) ? NULL : StringValuePtr(val); val = ossl_sslctx_get_ca_path(self); ca_path = NIL_P(val) ? NULL : StringValuePtr(val); if(ca_file || ca_path){ if (!SSL_CTX_load_verify_locations(ctx, ca_file, ca_path)) rb_warning("can't set verify locations"); } val = ossl_sslctx_get_verify_mode(self); verify_mode = NIL_P(val) ? SSL_VERIFY_NONE : NUM2INT(val); SSL_CTX_set_verify(ctx, verify_mode, ossl_ssl_verify_callback); if (RTEST(ossl_sslctx_get_client_cert_cb(self))) SSL_CTX_set_client_cert_cb(ctx, ossl_client_cert_cb); val = ossl_sslctx_get_timeout(self); if(!NIL_P(val)) SSL_CTX_set_timeout(ctx, NUM2LONG(val)); val = ossl_sslctx_get_verify_dep(self); if(!NIL_P(val)) SSL_CTX_set_verify_depth(ctx, NUM2LONG(val)); val = ossl_sslctx_get_options(self); if(!NIL_P(val)) SSL_CTX_set_options(ctx, NUM2LONG(val)); rb_obj_freeze(self); val = ossl_sslctx_get_sess_id_ctx(self); if (!NIL_P(val)){ StringValue(val); if (!SSL_CTX_set_session_id_context(ctx, (unsigned char *)RSTRING_PTR(val), RSTRING_LEN(val))){ ossl_raise(eSSLError, "SSL_CTX_set_session_id_context:"); } } if (RTEST(rb_iv_get(self, "@session_get_cb"))) { SSL_CTX_sess_set_get_cb(ctx, ossl_sslctx_session_get_cb); OSSL_Debug("SSL SESSION get callback added"); } if (RTEST(rb_iv_get(self, "@session_new_cb"))) { SSL_CTX_sess_set_new_cb(ctx, ossl_sslctx_session_new_cb); OSSL_Debug("SSL SESSION new callback added"); } if (RTEST(rb_iv_get(self, "@session_remove_cb"))) { SSL_CTX_sess_set_remove_cb(ctx, ossl_sslctx_session_remove_cb); OSSL_Debug("SSL SESSION remove callback added"); } #ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME val = rb_iv_get(self, "@servername_cb"); if (!NIL_P(val)) { SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb); OSSL_Debug("SSL TLSEXT servername callback added"); } #endif return Qtrue; }