Ruby 1.9.2p136(2010-12-25revision30365)

- 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