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>
8 * This program is licenced under the same licence as Ruby.
9 * (See the file 'LICENCE'.)
12 #include <stdarg.h> /* for ossl_raise */
15 * String to HEXString conversion
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? */
26 if (!hexbuf
) { /* if no buf, return calculated len */
32 if (!(*hexbuf
= OPENSSL_malloc(len
+ 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';
51 ossl_x509_ary2sk0(VALUE ary
)
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
);
75 ossl_protect_x509_ary2sk(VALUE ary
, int *status
)
77 return (STACK_OF(X509
)*)rb_protect((VALUE(*)_((VALUE
)))ossl_x509_ary2sk0
,
82 ossl_x509_ary2sk(VALUE ary
)
87 sk
= ossl_protect_x509_ary2sk(ary
, &status
);
88 if(status
) rb_jump_tag(status
);
93 #define OSSL_IMPL_SK2ARY(name, type) \
95 ossl_##name##_sk2ary(STACK *sk) \
102 OSSL_Debug("empty sk!"); \
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)); \
118 OSSL_IMPL_SK2ARY(x509
, X509
)
119 OSSL_IMPL_SK2ARY(x509crl
, X509_CRL
)
122 ossl_str_new(int size
)
124 return rb_str_new(0, size
);
128 ossl_buf2str(char *buf
, int len
)
133 str
= rb_protect((VALUE(*)_((VALUE
)))ossl_str_new
, len
, &status
);
134 if(!NIL_P(str
)) memcpy(RSTRING(str
)->ptr
, buf
, len
);
136 if(status
) rb_jump_tag(status
);
142 * our default PEM callback
145 ossl_pem_passwd_cb0(VALUE flag
)
149 pass
= rb_yield(flag
);
150 SafeStringValue(pass
);
156 ossl_pem_passwd_cb(char *buf
, int max_len
, int flag
, void *pwd
)
161 if (pwd
|| !rb_block_given_p())
162 return PEM_def_callback(buf
, max_len
, flag
, pwd
);
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");
179 rb_warning("password must be shorter then %d bytes", max_len
-1);
182 memcpy(buf
, RSTRING(pass
)->ptr
, len
);
191 int ossl_verify_cb_idx
;
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
);
201 ossl_verify_cb(int ok
, X509_STORE_CTX
*ctx
)
203 VALUE proc
, rctx
, ret
;
204 struct ossl_verify_cb_args args
;
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)
213 rctx
= rb_protect((VALUE(*)(VALUE
))ossl_x509stctx_new
,
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
);
224 X509_STORE_CTX_set_error(ctx
, X509_V_OK
);
228 if (X509_STORE_CTX_get_error(ctx
) == X509_V_OK
) {
229 X509_STORE_CTX_set_error(ctx
, X509_V_ERR_CERT_REJECTED
);
244 * OpenSSLError < StandardError
249 * Convert to DER string
254 ossl_to_der(VALUE obj
)
258 tmp
= rb_funcall(obj
, ossl_s_to_der
, 0);
265 ossl_to_der_if_possible(VALUE obj
)
267 if(rb_respond_to(obj
, ossl_s_to_der
))
268 return ossl_to_der(obj
);
276 ossl_raise(VALUE exc
, const char *fmt
, ...)
284 #ifdef HAVE_ERR_PEEK_LAST_ERROR
285 e
= ERR_peek_last_error();
287 e
= ERR_peek_error();
291 len
= vsnprintf(buf
, BUFSIZ
, fmt
, args
);
294 if (len
< BUFSIZ
&& e
) {
295 if (dOSSL
== Qtrue
) /* FULL INFO */
296 msg
= ERR_error_string(e
, NULL
);
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
));
309 if(len
> BUFSIZ
) len
= strlen(buf
);
310 rb_exc_raise(rb_exc_new(exc
, buf
, len
));
320 while ((e
= ERR_get_error()) != 0){
321 rb_ary_push(ary
, rb_str_new2(ERR_error_string(e
, NULL
)));
332 #if !defined(HAVE_VA_ARGS_MACRO)
334 ossl_debug(const char *fmt
, ...)
338 if (dOSSL
== Qtrue
) {
339 fprintf(stderr
, "OSSL_DEBUG: ");
341 vfprintf(stderr
, fmt
, args
);
343 fprintf(stderr
, " [CONTEXT N/A]\n");
349 ossl_debug_get(VALUE self
)
355 ossl_debug_set(VALUE self
, VALUE val
)
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");
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();
400 CONF_modules_unload(1);
404 CRYPTO_cleanup_all_ex_data();
412 mOSSL
= rb_define_module("OpenSSL");
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
));
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
431 X509_STORE_CTX_get_ex_new_index(0, "ossl_verify_cb_idx", 0, 0, 0);
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);
444 ossl_s_to_der
= rb_intern("to_der");
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
[])
475 #endif /* OSSL_DEBUG */