Change soft-fail to use the config, rather than env
[rbx.git] / stdlib / ext / openssl / ossl.c
blob1b8f76ad7a028fa09cafcf7a9d852431fce16459
1 /*
2 * $Id: ossl.c 11708 2007-02-12 23:01:19Z shyouhei $
3 * 'OpenSSL for Ruby' project
4 * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
5 * All rights reserved.
6 */
7 /*
8 * This program is licenced under the same licence as Ruby.
9 * (See the file 'LICENCE'.)
11 #include "ossl.h"
12 #include <stdarg.h> /* for ossl_raise */
15 * String to HEXString conversion
17 int
18 string2hex(char *buf, int buf_len, char **hexbuf, int *hexbuf_len)
20 static const char hex[]="0123456789abcdef";
21 int i, len = 2 * buf_len;
23 if (buf_len < 0 || len < buf_len) { /* PARANOIA? */
24 return -1;
26 if (!hexbuf) { /* if no buf, return calculated len */
27 if (hexbuf_len) {
28 *hexbuf_len = len;
30 return len;
32 if (!(*hexbuf = OPENSSL_malloc(len + 1))) {
33 return -1;
35 for (i = 0; i < buf_len; i++) {
36 (*hexbuf)[2 * i] = hex[((unsigned char)buf[i]) >> 4];
37 (*hexbuf)[2 * i + 1] = hex[buf[i] & 0x0f];
39 (*hexbuf)[2 * i] = '\0';
41 if (hexbuf_len) {
42 *hexbuf_len = len;
44 return len;
48 * Data Conversion
50 STACK_OF(X509) *
51 ossl_x509_ary2sk0(VALUE ary)
53 STACK_OF(X509) *sk;
54 VALUE val;
55 X509 *x509;
56 int i;
58 Check_Type(ary, T_ARRAY);
59 sk = sk_X509_new_null();
60 if (!sk) ossl_raise(eOSSLError, NULL);
62 for (i = 0; i < RARRAY(ary)->len; i++) {
63 val = rb_ary_entry(ary, i);
64 if (!rb_obj_is_kind_of(val, cX509Cert)) {
65 sk_X509_pop_free(sk, X509_free);
66 ossl_raise(eOSSLError, "object not X509 cert in array");
68 x509 = DupX509CertPtr(val); /* NEED TO DUP */
69 sk_X509_push(sk, x509);
71 return sk;
74 STACK_OF(X509) *
75 ossl_protect_x509_ary2sk(VALUE ary, int *status)
77 return (STACK_OF(X509)*)rb_protect((VALUE(*)_((VALUE)))ossl_x509_ary2sk0,
78 ary, status);
81 STACK_OF(X509) *
82 ossl_x509_ary2sk(VALUE ary)
84 STACK_OF(X509) *sk;
85 int status = 0;
87 sk = ossl_protect_x509_ary2sk(ary, &status);
88 if(status) rb_jump_tag(status);
90 return sk;
93 #define OSSL_IMPL_SK2ARY(name, type) \
94 VALUE \
95 ossl_##name##_sk2ary(STACK *sk) \
96 { \
97 type *t; \
98 int i, num; \
99 VALUE ary; \
101 if (!sk) { \
102 OSSL_Debug("empty sk!"); \
103 return Qnil; \
105 num = sk_num(sk); \
106 if (num < 0) { \
107 OSSL_Debug("items in sk < -1???"); \
108 return rb_ary_new(); \
110 ary = rb_ary_new2(num); \
112 for (i=0; i<num; i++) { \
113 t = (type *)sk_value(sk, i); \
114 rb_ary_push(ary, ossl_##name##_new(t)); \
116 return ary; \
118 OSSL_IMPL_SK2ARY(x509, X509)
119 OSSL_IMPL_SK2ARY(x509crl, X509_CRL)
121 static VALUE
122 ossl_str_new(int size)
124 return rb_str_new(0, size);
127 VALUE
128 ossl_buf2str(char *buf, int len)
130 VALUE str;
131 int status = 0;
133 str = rb_protect((VALUE(*)_((VALUE)))ossl_str_new, len, &status);
134 if(!NIL_P(str)) memcpy(RSTRING(str)->ptr, buf, len);
135 OPENSSL_free(buf);
136 if(status) rb_jump_tag(status);
138 return str;
142 * our default PEM callback
144 static VALUE
145 ossl_pem_passwd_cb0(VALUE flag)
147 VALUE pass;
149 pass = rb_yield(flag);
150 SafeStringValue(pass);
152 return pass;
156 ossl_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd)
158 int len, status = 0;
159 VALUE rflag, pass;
161 if (pwd || !rb_block_given_p())
162 return PEM_def_callback(buf, max_len, flag, pwd);
164 while (1) {
166 * when the flag is nonzero, this passphrase
167 * will be used to perform encryption; otherwise it will
168 * be used to perform decryption.
170 rflag = flag ? Qtrue : Qfalse;
171 pass = rb_protect(ossl_pem_passwd_cb0, rflag, &status);
172 if (status) return -1; /* exception was raised. */
173 len = RSTRING(pass)->len;
174 if (len < 4) { /* 4 is OpenSSL hardcoded limit */
175 rb_warning("password must be longer than 4 bytes");
176 continue;
178 if (len > max_len) {
179 rb_warning("password must be shorter then %d bytes", max_len-1);
180 continue;
182 memcpy(buf, RSTRING(pass)->ptr, len);
183 break;
185 return len;
189 * Verify callback
191 int ossl_verify_cb_idx;
193 VALUE
194 ossl_call_verify_cb_proc(struct ossl_verify_cb_args *args)
196 return rb_funcall(args->proc, rb_intern("call"), 2,
197 args->preverify_ok, args->store_ctx);
200 int
201 ossl_verify_cb(int ok, X509_STORE_CTX *ctx)
203 VALUE proc, rctx, ret;
204 struct ossl_verify_cb_args args;
205 int state = 0;
207 proc = (VALUE)X509_STORE_CTX_get_ex_data(ctx, ossl_verify_cb_idx);
208 if ((void*)proc == 0)
209 proc = (VALUE)X509_STORE_get_ex_data(ctx->ctx, ossl_verify_cb_idx);
210 if ((void*)proc == 0)
211 return ok;
212 if (!NIL_P(proc)) {
213 rctx = rb_protect((VALUE(*)(VALUE))ossl_x509stctx_new,
214 (VALUE)ctx, &state);
215 ret = Qfalse;
216 if (!state) {
217 args.proc = proc;
218 args.preverify_ok = ok ? Qtrue : Qfalse;
219 args.store_ctx = rctx;
220 ret = rb_ensure(ossl_call_verify_cb_proc, (VALUE)&args,
221 ossl_x509stctx_clear_ptr, rctx);
223 if (ret == Qtrue) {
224 X509_STORE_CTX_set_error(ctx, X509_V_OK);
225 ok = 1;
227 else{
228 if (X509_STORE_CTX_get_error(ctx) == X509_V_OK) {
229 X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REJECTED);
231 ok = 0;
235 return ok;
239 * main module
241 VALUE mOSSL;
244 * OpenSSLError < StandardError
246 VALUE eOSSLError;
249 * Convert to DER string
251 ID ossl_s_to_der;
253 VALUE
254 ossl_to_der(VALUE obj)
256 VALUE tmp;
258 tmp = rb_funcall(obj, ossl_s_to_der, 0);
259 StringValue(tmp);
261 return tmp;
264 VALUE
265 ossl_to_der_if_possible(VALUE obj)
267 if(rb_respond_to(obj, ossl_s_to_der))
268 return ossl_to_der(obj);
269 return obj;
273 * Errors
275 void
276 ossl_raise(VALUE exc, const char *fmt, ...)
278 va_list args;
279 char buf[BUFSIZ];
280 const char *msg;
281 long e;
282 int len = 0;
284 #ifdef HAVE_ERR_PEEK_LAST_ERROR
285 e = ERR_peek_last_error();
286 #else
287 e = ERR_peek_error();
288 #endif
289 if (fmt) {
290 va_start(args, fmt);
291 len = vsnprintf(buf, BUFSIZ, fmt, args);
292 va_end(args);
294 if (len < BUFSIZ && e) {
295 if (dOSSL == Qtrue) /* FULL INFO */
296 msg = ERR_error_string(e, NULL);
297 else
298 msg = ERR_reason_error_string(e);
299 fmt = len ? ": %s" : "%s";
300 len += snprintf(buf+len, BUFSIZ-len, fmt, msg);
302 if (dOSSL == Qtrue){ /* show all errors on the stack */
303 while ((e = ERR_get_error()) != 0){
304 rb_warn("error on stack: %s", ERR_error_string(e, NULL));
307 ERR_clear_error();
309 if(len > BUFSIZ) len = strlen(buf);
310 rb_exc_raise(rb_exc_new(exc, buf, len));
313 VALUE
314 ossl_get_errors()
316 VALUE ary;
317 long e;
319 ary = rb_ary_new();
320 while ((e = ERR_get_error()) != 0){
321 rb_ary_push(ary, rb_str_new2(ERR_error_string(e, NULL)));
324 return ary;
328 * Debug
330 VALUE dOSSL;
332 #if !defined(HAVE_VA_ARGS_MACRO)
333 void
334 ossl_debug(const char *fmt, ...)
336 va_list args;
338 if (dOSSL == Qtrue) {
339 fprintf(stderr, "OSSL_DEBUG: ");
340 va_start(args, fmt);
341 vfprintf(stderr, fmt, args);
342 va_end(args);
343 fprintf(stderr, " [CONTEXT N/A]\n");
346 #endif
348 static VALUE
349 ossl_debug_get(VALUE self)
351 return dOSSL;
354 static VALUE
355 ossl_debug_set(VALUE self, VALUE val)
357 VALUE old = dOSSL;
358 dOSSL = val;
360 if (old != dOSSL) {
361 if (dOSSL == Qtrue) {
362 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
363 fprintf(stderr, "OSSL_DEBUG: IS NOW ON!\n");
364 } else if (old == Qtrue) {
365 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_OFF);
366 fprintf(stderr, "OSSL_DEBUG: IS NOW OFF!\n");
369 return val;
373 * OSSL library init
375 void
376 Init_openssl()
379 * Init timezone info
381 #if 0
382 tzset();
383 #endif
386 * Init all digests, ciphers
388 /* CRYPTO_malloc_init(); */
389 /* ENGINE_load_builtin_engines(); */
390 OpenSSL_add_ssl_algorithms();
391 OpenSSL_add_all_algorithms();
392 ERR_load_crypto_strings();
393 SSL_load_error_strings();
396 * FIXME:
397 * On unload do:
399 #if 0
400 CONF_modules_unload(1);
401 destroy_ui_method();
402 EVP_cleanup();
403 ENGINE_cleanup();
404 CRYPTO_cleanup_all_ex_data();
405 ERR_remove_state(0);
406 ERR_free_strings();
407 #endif
410 * Init main module
412 mOSSL = rb_define_module("OpenSSL");
415 * Constants
417 rb_define_const(mOSSL, "VERSION", rb_str_new2(OSSL_VERSION));
418 rb_define_const(mOSSL, "OPENSSL_VERSION", rb_str_new2(OPENSSL_VERSION_TEXT));
419 rb_define_const(mOSSL, "OPENSSL_VERSION_NUMBER", INT2NUM(OPENSSL_VERSION_NUMBER));
422 * Generic error,
423 * common for all classes under OpenSSL module
425 eOSSLError = rb_define_class_under(mOSSL,"OpenSSLError",rb_eStandardError);
428 * Verify callback Proc index for ext-data
430 ossl_verify_cb_idx =
431 X509_STORE_CTX_get_ex_new_index(0, "ossl_verify_cb_idx", 0, 0, 0);
434 * Init debug core
436 dOSSL = Qfalse;
437 rb_define_module_function(mOSSL, "debug", ossl_debug_get, 0);
438 rb_define_module_function(mOSSL, "debug=", ossl_debug_set, 1);
439 rb_define_module_function(mOSSL, "errors", ossl_get_errors, 0);
442 * Get ID of to_der
444 ossl_s_to_der = rb_intern("to_der");
447 * Init components
449 Init_ossl_bn();
450 Init_ossl_cipher();
451 Init_ossl_config();
452 Init_ossl_digest();
453 Init_ossl_hmac();
454 Init_ossl_ns_spki();
455 Init_ossl_pkcs12();
456 Init_ossl_pkcs7();
457 Init_ossl_pkey();
458 Init_ossl_rand();
459 Init_ossl_ssl();
460 Init_ossl_x509();
461 Init_ossl_ocsp();
462 Init_ossl_engine();
463 Init_ossl_asn1();
466 #if defined(OSSL_DEBUG)
468 * Check if all symbols are OK with 'make LDSHARED=gcc all'
471 main(int argc, char *argv[], char *env[])
473 return 0;
475 #endif /* OSSL_DEBUG */