• Main Page
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

ext/openssl/ossl.c

Go to the documentation of this file.
00001 /*
00002  * $Id: ossl.c 27440 2010-04-22 08:21:01Z nobu $
00003  * 'OpenSSL for Ruby' project
00004  * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
00005  * All rights reserved.
00006  */
00007 /*
00008  * This program is licenced under the same licence as Ruby.
00009  * (See the file 'LICENCE'.)
00010  */
00011 #include "ossl.h"
00012 #include <stdarg.h> /* for ossl_raise */
00013 
00014 /*
00015  * String to HEXString conversion
00016  */
00017 int
00018 string2hex(const unsigned char *buf, int buf_len, char **hexbuf, int *hexbuf_len)
00019 {
00020     static const char hex[]="0123456789abcdef";
00021     int i, len = 2 * buf_len;
00022 
00023     if (buf_len < 0 || len < buf_len) { /* PARANOIA? */
00024         return -1;
00025     }
00026     if (!hexbuf) { /* if no buf, return calculated len */
00027         if (hexbuf_len) {
00028             *hexbuf_len = len;
00029         }
00030         return len;
00031     }
00032     if (!(*hexbuf = OPENSSL_malloc(len + 1))) {
00033         return -1;
00034     }
00035     for (i = 0; i < buf_len; i++) {
00036         (*hexbuf)[2 * i] = hex[((unsigned char)buf[i]) >> 4];
00037         (*hexbuf)[2 * i + 1] = hex[buf[i] & 0x0f];
00038     }
00039     (*hexbuf)[2 * i] = '\0';
00040 
00041     if (hexbuf_len) {
00042         *hexbuf_len = len;
00043     }
00044     return len;
00045 }
00046 
00047 /*
00048  * Data Conversion
00049  */
00050 STACK_OF(X509) *
00051 ossl_x509_ary2sk0(VALUE ary)
00052 {
00053     STACK_OF(X509) *sk;
00054     VALUE val;
00055     X509 *x509;
00056     int i;
00057 
00058     Check_Type(ary, T_ARRAY);
00059     sk = sk_X509_new_null();
00060     if (!sk) ossl_raise(eOSSLError, NULL);
00061 
00062     for (i = 0; i < RARRAY_LEN(ary); i++) {
00063         val = rb_ary_entry(ary, i);
00064         if (!rb_obj_is_kind_of(val, cX509Cert)) {
00065             sk_X509_pop_free(sk, X509_free);
00066             ossl_raise(eOSSLError, "object not X509 cert in array");
00067         }
00068         x509 = DupX509CertPtr(val); /* NEED TO DUP */
00069         sk_X509_push(sk, x509);
00070     }
00071     return sk;
00072 }
00073 
00074 STACK_OF(X509) *
00075 ossl_protect_x509_ary2sk(VALUE ary, int *status)
00076 {
00077     return (STACK_OF(X509)*)rb_protect((VALUE(*)_((VALUE)))ossl_x509_ary2sk0,
00078                                        ary, status);
00079 }
00080 
00081 STACK_OF(X509) *
00082 ossl_x509_ary2sk(VALUE ary)
00083 {
00084     STACK_OF(X509) *sk;
00085     int status = 0;
00086 
00087     sk = ossl_protect_x509_ary2sk(ary, &status);
00088     if(status) rb_jump_tag(status);
00089 
00090     return sk;
00091 }
00092 
00093 #define OSSL_IMPL_SK2ARY(name, type)            \
00094 VALUE                                           \
00095 ossl_##name##_sk2ary(STACK_OF(type) *sk)        \
00096 {                                               \
00097     type *t;                                    \
00098     int i, num;                                 \
00099     VALUE ary;                                  \
00100                                                 \
00101     if (!sk) {                                  \
00102         OSSL_Debug("empty sk!");                \
00103         return Qnil;                            \
00104     }                                           \
00105     num = sk_##type##_num(sk);                  \
00106     if (num < 0) {                              \
00107         OSSL_Debug("items in sk < -1???");      \
00108         return rb_ary_new();                    \
00109     }                                           \
00110     ary = rb_ary_new2(num);                     \
00111                                                 \
00112     for (i=0; i<num; i++) {                     \
00113         t = sk_##type##_value(sk, i);           \
00114         rb_ary_push(ary, ossl_##name##_new(t)); \
00115     }                                           \
00116     return ary;                                 \
00117 }
00118 OSSL_IMPL_SK2ARY(x509, X509)
00119 OSSL_IMPL_SK2ARY(x509crl, X509_CRL)
00120 
00121 static VALUE
00122 ossl_str_new(int size)
00123 {
00124     return rb_str_new(0, size);
00125 }
00126 
00127 VALUE
00128 ossl_buf2str(char *buf, int len)
00129 {
00130     VALUE str;
00131     int status = 0;
00132 
00133     str = rb_protect((VALUE(*)_((VALUE)))ossl_str_new, len, &status);
00134     if(!NIL_P(str)) memcpy(RSTRING_PTR(str), buf, len);
00135     OPENSSL_free(buf);
00136     if(status) rb_jump_tag(status);
00137 
00138     return str;
00139 }
00140 
00141 /*
00142  * our default PEM callback
00143  */
00144 static VALUE
00145 ossl_pem_passwd_cb0(VALUE flag)
00146 {
00147     VALUE pass;
00148 
00149     pass = rb_yield(flag);
00150     SafeStringValue(pass);
00151 
00152     return pass;
00153 }
00154 
00155 int
00156 ossl_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd)
00157 {
00158     int len, status = 0;
00159     VALUE rflag, pass;
00160 
00161     if (pwd || !rb_block_given_p())
00162         return PEM_def_callback(buf, max_len, flag, pwd);
00163 
00164     while (1) {
00165         /*
00166          * when the flag is nonzero, this passphrase
00167          * will be used to perform encryption; otherwise it will
00168          * be used to perform decryption.
00169          */
00170         rflag = flag ? Qtrue : Qfalse;
00171         pass  = rb_protect(ossl_pem_passwd_cb0, rflag, &status);
00172         if (status) return -1; /* exception was raised. */
00173         len = RSTRING_LEN(pass);
00174         if (len < 4) { /* 4 is OpenSSL hardcoded limit */
00175             rb_warning("password must be longer than 4 bytes");
00176             continue;
00177         }
00178         if (len > max_len) {
00179             rb_warning("password must be shorter then %d bytes", max_len-1);
00180             continue;
00181         }
00182         memcpy(buf, RSTRING_PTR(pass), len);
00183         break;
00184     }
00185     return len;
00186 }
00187 
00188 /*
00189  * Verify callback
00190  */
00191 int ossl_verify_cb_idx;
00192 
00193 VALUE
00194 ossl_call_verify_cb_proc(struct ossl_verify_cb_args *args)
00195 {
00196     return rb_funcall(args->proc, rb_intern("call"), 2,
00197                       args->preverify_ok, args->store_ctx);
00198 }
00199 
00200 int
00201 ossl_verify_cb(int ok, X509_STORE_CTX *ctx)
00202 {
00203     VALUE proc, rctx, ret;
00204     struct ossl_verify_cb_args args;
00205     int state = 0;
00206 
00207     proc = (VALUE)X509_STORE_CTX_get_ex_data(ctx, ossl_verify_cb_idx);
00208     if ((void*)proc == 0)
00209         proc = (VALUE)X509_STORE_get_ex_data(ctx->ctx, ossl_verify_cb_idx);
00210     if ((void*)proc == 0)
00211         return ok;
00212     if (!NIL_P(proc)) {
00213         rctx = rb_protect((VALUE(*)(VALUE))ossl_x509stctx_new,
00214                           (VALUE)ctx, &state);
00215         ret = Qfalse;
00216         if (!state) {
00217             args.proc = proc;
00218             args.preverify_ok = ok ? Qtrue : Qfalse;
00219             args.store_ctx = rctx;
00220             ret = rb_ensure(ossl_call_verify_cb_proc, (VALUE)&args,
00221                             ossl_x509stctx_clear_ptr, rctx);
00222         }
00223         if (ret == Qtrue) {
00224             X509_STORE_CTX_set_error(ctx, X509_V_OK);
00225             ok = 1;
00226         }
00227         else{
00228             if (X509_STORE_CTX_get_error(ctx) == X509_V_OK) {
00229                 X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REJECTED);
00230             }
00231             ok = 0;
00232         }
00233     }
00234 
00235     return ok;
00236 }
00237 
00238 /*
00239  * main module
00240  */
00241 VALUE mOSSL;
00242 
00243 /*
00244  * OpenSSLError < StandardError
00245  */
00246 VALUE eOSSLError;
00247 
00248 /*
00249  * Convert to DER string
00250  */
00251 ID ossl_s_to_der;
00252 
00253 VALUE
00254 ossl_to_der(VALUE obj)
00255 {
00256     VALUE tmp;
00257 
00258     tmp = rb_funcall(obj, ossl_s_to_der, 0);
00259     StringValue(tmp);
00260 
00261     return tmp;
00262 }
00263 
00264 VALUE
00265 ossl_to_der_if_possible(VALUE obj)
00266 {
00267     if(rb_respond_to(obj, ossl_s_to_der))
00268         return ossl_to_der(obj);
00269     return obj;
00270 }
00271 
00272 /*
00273  * Errors
00274  */
00275 static VALUE
00276 ossl_make_error(VALUE exc, const char *fmt, va_list args)
00277 {
00278     char buf[BUFSIZ];
00279     const char *msg;
00280     long e;
00281     int len = 0;
00282 
00283 #ifdef HAVE_ERR_PEEK_LAST_ERROR
00284     e = ERR_peek_last_error();
00285 #else
00286     e = ERR_peek_error();
00287 #endif
00288     if (fmt) {
00289         len = vsnprintf(buf, BUFSIZ, fmt, args);
00290     }
00291     if (len < BUFSIZ && e) {
00292         if (dOSSL == Qtrue) /* FULL INFO */
00293             msg = ERR_error_string(e, NULL);
00294         else
00295             msg = ERR_reason_error_string(e);
00296         len += snprintf(buf+len, BUFSIZ-len, "%s%s", (len ? ": " : ""), msg);
00297     }
00298     if (dOSSL == Qtrue){ /* show all errors on the stack */
00299         while ((e = ERR_get_error()) != 0){
00300             rb_warn("error on stack: %s", ERR_error_string(e, NULL));
00301         }
00302     }
00303     ERR_clear_error();
00304 
00305     if(len > BUFSIZ) len = strlen(buf);
00306     return rb_exc_new(exc, buf, len);
00307 }
00308 
00309 void
00310 ossl_raise(VALUE exc, const char *fmt, ...)
00311 {
00312     va_list args;
00313     VALUE err;
00314     va_start(args, fmt);
00315     err = ossl_make_error(exc, fmt, args);
00316     va_end(args);
00317     rb_exc_raise(err);
00318 }
00319 
00320 VALUE
00321 ossl_exc_new(VALUE exc, const char *fmt, ...)
00322 {
00323     va_list args;
00324     VALUE err;
00325     va_start(args, fmt);
00326     err = ossl_make_error(exc, fmt, args);
00327     va_end(args);
00328     return err;
00329 }
00330 
00331 /*
00332  * call-seq:
00333  *   OpenSSL.errors -> [String...]
00334  *
00335  * See any remaining errors held in queue.
00336  *
00337  * Any errors you see here are probably due to a bug in ruby's OpenSSL implementation.
00338  */
00339 VALUE
00340 ossl_get_errors()
00341 {
00342     VALUE ary;
00343     long e;
00344 
00345     ary = rb_ary_new();
00346     while ((e = ERR_get_error()) != 0){
00347         rb_ary_push(ary, rb_str_new2(ERR_error_string(e, NULL)));
00348     }
00349 
00350     return ary;
00351 }
00352 
00353 /*
00354  * Debug
00355  */
00356 VALUE dOSSL;
00357 
00358 #if !defined(HAVE_VA_ARGS_MACRO)
00359 void
00360 ossl_debug(const char *fmt, ...)
00361 {
00362     va_list args;
00363 
00364     if (dOSSL == Qtrue) {
00365         fprintf(stderr, "OSSL_DEBUG: ");
00366         va_start(args, fmt);
00367         vfprintf(stderr, fmt, args);
00368         va_end(args);
00369         fprintf(stderr, " [CONTEXT N/A]\n");
00370     }
00371 }
00372 #endif
00373 
00374 /*
00375  * call-seq:
00376  *   OpenSSL.debug -> true | false
00377  */
00378 static VALUE
00379 ossl_debug_get(VALUE self)
00380 {
00381     return dOSSL;
00382 }
00383 
00384 /*
00385  * call-seq:
00386  *   OpenSSL.debug = boolean -> boolean
00387  *
00388  * Turns on or off CRYPTO_MEM_CHECK.
00389  * Also shows some debugging message on stderr.
00390  */
00391 static VALUE
00392 ossl_debug_set(VALUE self, VALUE val)
00393 {
00394     VALUE old = dOSSL;
00395     dOSSL = val;
00396 
00397     if (old != dOSSL) {
00398         if (dOSSL == Qtrue) {
00399             CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
00400             fprintf(stderr, "OSSL_DEBUG: IS NOW ON!\n");
00401         } else if (old == Qtrue) {
00402             CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_OFF);
00403             fprintf(stderr, "OSSL_DEBUG: IS NOW OFF!\n");
00404         }
00405     }
00406     return val;
00407 }
00408 
00409 /*
00410  * OSSL library init
00411  */
00412 void
00413 Init_openssl()
00414 {
00415     /*
00416      * Init timezone info
00417      */
00418 #if 0
00419     tzset();
00420 #endif
00421 
00422     /*
00423      * Init all digests, ciphers
00424      */
00425     /* CRYPTO_malloc_init(); */
00426     /* ENGINE_load_builtin_engines(); */
00427     OpenSSL_add_ssl_algorithms();
00428     OpenSSL_add_all_algorithms();
00429     ERR_load_crypto_strings();
00430     SSL_load_error_strings();
00431 
00432     /*
00433      * FIXME:
00434      * On unload do:
00435      */
00436 #if 0
00437     CONF_modules_unload(1);
00438     destroy_ui_method();
00439     EVP_cleanup();
00440     ENGINE_cleanup();
00441     CRYPTO_cleanup_all_ex_data();
00442     ERR_remove_state(0);
00443     ERR_free_strings();
00444 #endif
00445 
00446     /*
00447      * Init main module
00448      */
00449     mOSSL = rb_define_module("OpenSSL");
00450 
00451     /*
00452      * Constants
00453      */
00454     rb_define_const(mOSSL, "VERSION", rb_str_new2(OSSL_VERSION));
00455     rb_define_const(mOSSL, "OPENSSL_VERSION", rb_str_new2(OPENSSL_VERSION_TEXT));
00456     rb_define_const(mOSSL, "OPENSSL_VERSION_NUMBER", INT2NUM(OPENSSL_VERSION_NUMBER));
00457 
00458     /*
00459      * Generic error,
00460      * common for all classes under OpenSSL module
00461      */
00462     eOSSLError = rb_define_class_under(mOSSL,"OpenSSLError",rb_eStandardError);
00463 
00464     /*
00465      * Verify callback Proc index for ext-data
00466      */
00467     if ((ossl_verify_cb_idx = X509_STORE_CTX_get_ex_new_index(0, (void *)"ossl_verify_cb_idx", 0, 0, 0)) < 0)
00468         ossl_raise(eOSSLError, "X509_STORE_CTX_get_ex_new_index");
00469 
00470     /*
00471      * Init debug core
00472      */
00473     dOSSL = Qfalse;
00474     rb_define_module_function(mOSSL, "debug", ossl_debug_get, 0);
00475     rb_define_module_function(mOSSL, "debug=", ossl_debug_set, 1);
00476     rb_define_module_function(mOSSL, "errors", ossl_get_errors, 0);
00477 
00478     /*
00479      * Get ID of to_der
00480      */
00481     ossl_s_to_der = rb_intern("to_der");
00482 
00483     /*
00484      * Init components
00485      */
00486     Init_ossl_bn();
00487     Init_ossl_cipher();
00488     Init_ossl_config();
00489     Init_ossl_digest();
00490     Init_ossl_hmac();
00491     Init_ossl_ns_spki();
00492     Init_ossl_pkcs12();
00493     Init_ossl_pkcs7();
00494     Init_ossl_pkcs5();
00495     Init_ossl_pkey();
00496     Init_ossl_rand();
00497     Init_ossl_ssl();
00498     Init_ossl_x509();
00499     Init_ossl_ocsp();
00500     Init_ossl_engine();
00501     Init_ossl_asn1();
00502 }
00503 
00504 #if defined(OSSL_DEBUG)
00505 /*
00506  * Check if all symbols are OK with 'make LDSHARED=gcc all'
00507  */
00508 int
00509 main(int argc, char *argv[])
00510 {
00511     return 0;
00512 }
00513 #endif /* OSSL_DEBUG */
00514 
00515 

Generated on Thu Sep 8 2011 03:50:34 for Ruby by  doxygen 1.7.1