diff options
author | technorama <technorama@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2007-06-08 15:02:04 +0000 |
---|---|---|
committer | technorama <technorama@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2007-06-08 15:02:04 +0000 |
commit | 18342ff8e00ebe27584786276a68d99767a2c38d (patch) | |
tree | 9e7f4f09dace24fe7af05763aa9dbb6ae67550b8 /ext | |
parent | f5be4ddc8d2d76f8d3543c5ecfd852199b20b7d2 (diff) |
import OpenSSL from trunk
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@12496 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext')
46 files changed, 3692 insertions, 362 deletions
diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb index 98921bc468..bc3f4fd2ed 100644 --- a/ext/openssl/extconf.rb +++ b/ext/openssl/extconf.rb @@ -59,6 +59,8 @@ unless have_header("openssl/conf_api.h") exit 1 end +%w"rb_str_set_len rb_block_call".each {|func| have_func(func, "ruby.h")} + message "=== Checking for OpenSSL features... ===\n" have_func("ERR_peek_last_error") have_func("BN_mod_add") @@ -81,6 +83,8 @@ have_func("HMAC_CTX_cleanup") have_func("HMAC_CTX_copy") have_func("HMAC_CTX_init") have_func("PEM_def_callback") +have_func("PKCS5_PBKDF2_HMAC") +have_func("PKCS5_PBKDF2_HMAC_SHA1") have_func("X509V3_set_nconf") have_func("X509V3_EXT_nconf_nid") have_func("X509_CRL_add0_revoked") diff --git a/ext/openssl/lib/openssl.rb b/ext/openssl/lib/openssl.rb index 24a9eed136..f10985ed2c 100644 --- a/ext/openssl/lib/openssl.rb +++ b/ext/openssl/lib/openssl.rb @@ -19,6 +19,7 @@ require 'openssl.so' require 'openssl/bn' require 'openssl/cipher' require 'openssl/digest' +require 'openssl/pkcs7' require 'openssl/ssl' require 'openssl/x509' diff --git a/ext/openssl/lib/openssl/buffering.rb b/ext/openssl/lib/openssl/buffering.rb index 761a017487..8800aa53cc 100644 --- a/ext/openssl/lib/openssl/buffering.rb +++ b/ext/openssl/lib/openssl/buffering.rb @@ -57,10 +57,10 @@ module Buffering if size == 0 if buf buf.clear + return buf else - buf = "" + return "" end - return @eof ? nil : buf end until @eof break if size && size <= @rbuffer.size @@ -78,10 +78,10 @@ module Buffering if maxlen == 0 if buf buf.clear + return buf else - buf = "" + return "" end - return @eof ? nil : buf end if @rbuffer.empty? begin diff --git a/ext/openssl/lib/openssl/cipher.rb b/ext/openssl/lib/openssl/cipher.rb index 049533d06b..290e9c1d2d 100644 --- a/ext/openssl/lib/openssl/cipher.rb +++ b/ext/openssl/lib/openssl/cipher.rb @@ -19,7 +19,7 @@ #require 'openssl' module OpenSSL - module Cipher + class Cipher %w(AES CAST5 BF DES IDEA RC2 RC4 RC5).each{|name| klass = Class.new(Cipher){ define_method(:initialize){|*args| @@ -41,18 +41,25 @@ module OpenSSL const_set("AES#{keylen}", klass) } - class Cipher - def random_key - str = OpenSSL::Random.random_bytes(self.key_len) - self.key = str - return str - end - - def random_iv - str = OpenSSL::Random.random_bytes(self.iv_len) - self.iv = str - return str - end + # Generate, set, and return a random key. + # You must call cipher.encrypt or cipher.decrypt before calling this method. + def random_key + str = OpenSSL::Random.random_bytes(self.key_len) + self.key = str + return str + end + + # Generate, set, and return a random iv. + # You must call cipher.encrypt or cipher.decrypt before calling this method. + def random_iv + str = OpenSSL::Random.random_bytes(self.iv_len) + self.iv = str + return str + end + + # This class is only provided for backwards compatibility. Use OpenSSL::Digest in the future. + class Cipher < Cipher + # add warning end end # Cipher end # OpenSSL diff --git a/ext/openssl/lib/openssl/digest.rb b/ext/openssl/lib/openssl/digest.rb index b3e4484805..8d7df73b54 100644 --- a/ext/openssl/lib/openssl/digest.rb +++ b/ext/openssl/lib/openssl/digest.rb @@ -19,7 +19,7 @@ #require 'openssl' module OpenSSL - module Digest + class Digest alg = %w(DSS DSS1 MD2 MD4 MD5 MDC2 RIPEMD160 SHA SHA1) if OPENSSL_VERSION_NUMBER > 0x00908000 @@ -44,6 +44,11 @@ module OpenSSL const_set(name, klass) } + # This class is only provided for backwards compatibility. Use OpenSSL::Digest in the future. + class Digest < Digest + # add warning + end + end # Digest end # OpenSSL diff --git a/ext/openssl/lib/openssl/pkcs7.rb b/ext/openssl/lib/openssl/pkcs7.rb new file mode 100644 index 0000000000..1f88c1de5e --- /dev/null +++ b/ext/openssl/lib/openssl/pkcs7.rb @@ -0,0 +1,25 @@ +=begin += $RCSfile$ -- PKCS7 + += Licence + This program is licenced under the same licence as Ruby. + (See the file 'LICENCE'.) + += Version + $Id: digest.rb 12148 2007-04-05 05:59:22Z technorama $ +=end + +module OpenSSL + class PKCS7 + # This class is only provided for backwards compatibility. Use OpenSSL::PKCS7 in the future. + class PKCS7 < PKCS7 + def initialize(*args) + super(*args) + + warn("Warning: OpenSSL::PKCS7::PKCS7 is deprecated after Ruby 1.9; use OpenSSL::PKCS7 instead") + end + end + + end # PKCS7 +end # OpenSSL + diff --git a/ext/openssl/lib/openssl/ssl.rb b/ext/openssl/lib/openssl/ssl.rb index ef7415f478..ab38aa2ab1 100644 --- a/ext/openssl/lib/openssl/ssl.rb +++ b/ext/openssl/lib/openssl/ssl.rb @@ -90,6 +90,12 @@ module OpenSSL end raise SSLError, "hostname not match" end + + def session + SSL::Session.new(self) + rescue SSL::Session::SessionError + nil + end end class SSLServer diff --git a/ext/openssl/ossl.c b/ext/openssl/ossl.c index a98f2641cc..53f476fd65 100644 --- a/ext/openssl/ossl.c +++ b/ext/openssl/ossl.c @@ -59,7 +59,7 @@ ossl_x509_ary2sk0(VALUE ary) sk = sk_X509_new_null(); if (!sk) ossl_raise(eOSSLError, NULL); - for (i = 0; i < RARRAY(ary)->len; i++) { + for (i = 0; i < RARRAY_LEN(ary); i++) { val = rb_ary_entry(ary, i); if (!rb_obj_is_kind_of(val, cX509Cert)) { sk_X509_pop_free(sk, X509_free); @@ -131,7 +131,7 @@ ossl_buf2str(char *buf, int len) int status = 0; str = rb_protect((VALUE(*)_((VALUE)))ossl_str_new, len, &status); - if(!NIL_P(str)) memcpy(RSTRING(str)->ptr, buf, len); + if(!NIL_P(str)) memcpy(RSTRING_PTR(str), buf, len); OPENSSL_free(buf); if(status) rb_jump_tag(status); @@ -170,7 +170,7 @@ ossl_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd) rflag = flag ? Qtrue : Qfalse; pass = rb_protect(ossl_pem_passwd_cb0, rflag, &status); if (status) return -1; /* exception was raised. */ - len = RSTRING(pass)->len; + len = RSTRING_LEN(pass); if (len < 4) { /* 4 is OpenSSL hardcoded limit */ rb_warning("password must be longer than 4 bytes"); continue; @@ -179,7 +179,7 @@ ossl_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd) rb_warning("password must be shorter then %d bytes", max_len-1); continue; } - memcpy(buf, RSTRING(pass)->ptr, len); + memcpy(buf, RSTRING_PTR(pass), len); break; } return len; @@ -310,6 +310,14 @@ ossl_raise(VALUE exc, const char *fmt, ...) rb_exc_raise(rb_exc_new(exc, buf, len)); } +/* + * call-seq: + * OpenSSL.errors -> [String...] + * + * See any remaining errors held in queue. + * + * Any errors you see here are probably due to a bug in ruby's OpenSSL implementation. + */ VALUE ossl_get_errors() { @@ -345,12 +353,23 @@ ossl_debug(const char *fmt, ...) } #endif +/* + * call-seq: + * OpenSSL.debug -> true | false + */ static VALUE ossl_debug_get(VALUE self) { return dOSSL; } +/* + * call-seq: + * OpenSSL.debug = boolean -> boolean + * + * Turns on or off CRYPTO_MEM_CHECK. + * Also shows some debugging message on stderr. + */ static VALUE ossl_debug_set(VALUE self, VALUE val) { @@ -427,8 +446,8 @@ Init_openssl() /* * Verify callback Proc index for ext-data */ - ossl_verify_cb_idx = - X509_STORE_CTX_get_ex_new_index(0, "ossl_verify_cb_idx", 0, 0, 0); + if ((ossl_verify_cb_idx = X509_STORE_CTX_get_ex_new_index(0, "ossl_verify_cb_idx", 0, 0, 0)) < 0) + ossl_raise(eOSSLError, "X509_STORE_CTX_get_ex_new_index"); /* * Init debug core @@ -454,6 +473,7 @@ Init_openssl() Init_ossl_ns_spki(); Init_ossl_pkcs12(); Init_ossl_pkcs7(); + Init_ossl_pkcs5(); Init_ossl_pkey(); Init_ossl_rand(); Init_ossl_ssl(); diff --git a/ext/openssl/ossl.h b/ext/openssl/ossl.h index c0325229c1..b11614560e 100644 --- a/ext/openssl/ossl.h +++ b/ext/openssl/ossl.h @@ -17,6 +17,11 @@ extern "C" { #endif +#if 0 + mOSSL = rb_define_module("OpenSSL"); + mX509 = rb_define_module_under(mOSSL, "X509"); +#endif + /* * OpenSSL has defined RFILE and Ruby has defined RFILE - so undef it! */ @@ -40,8 +45,8 @@ extern "C" { #endif #if defined(_WIN32) -# define OpenFile WINAPI_OpenFile # define OSSL_NO_CONF_API 1 +# include <winsock2.h> #endif #include <errno.h> #include <openssl/err.h> @@ -64,9 +69,6 @@ extern "C" { # define OSSL_OCSP_ENABLED # include <openssl/ocsp.h> #endif -#if defined(_WIN32) -# undef OpenFile -#endif /* * Common Module @@ -117,11 +119,10 @@ VALUE ossl_x509crl_sk2ary(STACK_OF(X509_CRL) *crl); VALUE ossl_buf2str(char *buf, int len); #define ossl_str_adjust(str, p) \ do{\ - int len = RSTRING(str)->len;\ - int newlen = (p) - (unsigned char*)RSTRING(str)->ptr;\ + int len = RSTRING_LEN(str);\ + int newlen = (p) - (unsigned char*)RSTRING_PTR(str);\ assert(newlen <= len);\ - RSTRING(str)->len = newlen;\ - RSTRING(str)->ptr[newlen] = 0;\ + rb_str_set_len(str, newlen);\ }while(0) /* diff --git a/ext/openssl/ossl_asn1.c b/ext/openssl/ossl_asn1.c index 3614f470d9..8ceea95021 100644 --- a/ext/openssl/ossl_asn1.c +++ b/ext/openssl/ossl_asn1.c @@ -214,7 +214,7 @@ obj_to_asn1bstr(VALUE obj, long unused_bits) StringValue(obj); if(!(bstr = ASN1_BIT_STRING_new())) ossl_raise(eASN1Error, NULL); - ASN1_BIT_STRING_set(bstr, RSTRING(obj)->ptr, RSTRING(obj)->len); + ASN1_BIT_STRING_set(bstr, RSTRING_PTR(obj), RSTRING_LEN(obj)); bstr->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07); /* clear */ bstr->flags |= ASN1_STRING_FLAG_BITS_LEFT|(unused_bits&0x07); @@ -229,7 +229,7 @@ obj_to_asn1str(VALUE obj) StringValue(obj); if(!(str = ASN1_STRING_new())) ossl_raise(eASN1Error, NULL); - ASN1_STRING_set(str, RSTRING(obj)->ptr, RSTRING(obj)->len); + ASN1_STRING_set(str, RSTRING_PTR(obj), RSTRING_LEN(obj)); return str; } @@ -253,8 +253,8 @@ obj_to_asn1obj(VALUE obj) ASN1_OBJECT *a1obj; StringValue(obj); - a1obj = OBJ_txt2obj(RSTRING(obj)->ptr, 0); - if(!a1obj) a1obj = OBJ_txt2obj(RSTRING(obj)->ptr, 1); + a1obj = OBJ_txt2obj(RSTRING_PTR(obj), 0); + if(!a1obj) a1obj = OBJ_txt2obj(RSTRING_PTR(obj), 1); if(!a1obj) ossl_raise(eASN1Error, "invalid OBJECT ID"); return a1obj; @@ -295,7 +295,7 @@ obj_to_asn1derstr(VALUE obj) str = ossl_to_der(obj); if(!(a1str = ASN1_STRING_new())) ossl_raise(eASN1Error, NULL); - ASN1_STRING_set(a1str, RSTRING(str)->ptr, RSTRING(str)->len); + ASN1_STRING_set(a1str, RSTRING_PTR(str), RSTRING_LEN(str)); return a1str; } @@ -445,7 +445,7 @@ decode_time(unsigned char* der, int length) /********/ typedef struct { - char *name; + const char *name; VALUE *klass; } ossl_asn1_info_t; @@ -678,7 +678,7 @@ static VALUE join_der(VALUE enumerable) { VALUE str = rb_str_new(0, 0); - rb_iterate(rb_each, enumerable, join_der_i, str); + rb_block_call(enumerable, rb_intern("each"), 0, 0, join_der_i, str); return str; } @@ -699,13 +699,13 @@ ossl_asn1data_to_der(VALUE self) tag = ossl_asn1_tag(self); tag_class = ossl_asn1_tag_class(self); - if((length = ASN1_object_size(1, RSTRING(value)->len, tag)) <= 0) + if((length = ASN1_object_size(1, RSTRING_LEN(value), tag)) <= 0) ossl_raise(eASN1Error, NULL); der = rb_str_new(0, length); - p = RSTRING(der)->ptr; - ASN1_put_object(&p, is_cons, RSTRING(value)->len, tag, tag_class); - memcpy(p, RSTRING(value)->ptr, RSTRING(value)->len); - p += RSTRING(value)->len; + p = RSTRING_PTR(der); + ASN1_put_object(&p, is_cons, RSTRING_LEN(value), tag, tag_class); + memcpy(p, RSTRING_PTR(value), RSTRING_LEN(value)); + p += RSTRING_LEN(value); ossl_str_adjust(der, p); return der; @@ -824,8 +824,8 @@ ossl_asn1_traverse(VALUE self, VALUE obj) obj = ossl_to_der_if_possible(obj); tmp = rb_str_new4(StringValue(obj)); - p = RSTRING(tmp)->ptr; - ossl_asn1_decode0(&p, RSTRING(tmp)->len, &offset, 0, 0, 1); + p = RSTRING_PTR(tmp); + ossl_asn1_decode0(&p, RSTRING_LEN(tmp), &offset, 0, 0, 1); return Qnil; } @@ -840,8 +840,8 @@ ossl_asn1_decode(VALUE self, VALUE obj) obj = ossl_to_der_if_possible(obj); tmp = rb_str_new4(StringValue(obj)); - p = RSTRING(tmp)->ptr; - ary = ossl_asn1_decode0(&p, RSTRING(tmp)->len, &offset, 0, 1, 0); + p = RSTRING_PTR(tmp); + ary = ossl_asn1_decode0(&p, RSTRING_LEN(tmp), &offset, 0, 1, 0); ret = rb_ary_entry(ary, 0); return ret; @@ -857,8 +857,8 @@ ossl_asn1_decode_all(VALUE self, VALUE obj) obj = ossl_to_der_if_possible(obj); tmp = rb_str_new4(StringValue(obj)); - p = RSTRING(tmp)->ptr; - ret = ossl_asn1_decode0(&p, RSTRING(tmp)->len, &offset, 0, 0, 0); + p = RSTRING_PTR(tmp); + ret = ossl_asn1_decode0(&p, RSTRING_LEN(tmp), &offset, 0, 0, 0); return ret; } @@ -973,21 +973,21 @@ ossl_asn1cons_to_der(VALUE self) explicit = ossl_asn1_is_explicit(self); value = join_der(ossl_asn1_get_value(self)); - seq_len = ASN1_object_size(1, RSTRING(value)->len, tag); + seq_len = ASN1_object_size(1, RSTRING_LEN(value), tag); length = ASN1_object_size(1, seq_len, tn); str = rb_str_new(0, length); - p = RSTRING(str)->ptr; + p = RSTRING_PTR(str); if(tc == V_ASN1_UNIVERSAL) - ASN1_put_object(&p, 1, RSTRING(value)->len, tn, tc); + ASN1_put_object(&p, 1, RSTRING_LEN(value), tn, tc); else{ if(explicit){ ASN1_put_object(&p, 1, seq_len, tn, tc); - ASN1_put_object(&p, 1, RSTRING(value)->len, tag, V_ASN1_UNIVERSAL); + ASN1_put_object(&p, 1, RSTRING_LEN(value), tag, V_ASN1_UNIVERSAL); } - else ASN1_put_object(&p, 1, RSTRING(value)->len, tn, tc); + else ASN1_put_object(&p, 1, RSTRING_LEN(value), tn, tc); } - memcpy(p, RSTRING(value)->ptr, RSTRING(value)->len); - p += RSTRING(value)->len; + memcpy(p, RSTRING_PTR(value), RSTRING_LEN(value)); + p += RSTRING_LEN(value); ossl_str_adjust(str, p); return str; @@ -1007,7 +1007,7 @@ ossl_asn1obj_s_register(VALUE self, VALUE oid, VALUE sn, VALUE ln) StringValue(sn); StringValue(ln); - if(!OBJ_create(RSTRING(oid)->ptr, RSTRING(sn)->ptr, RSTRING(ln)->ptr)) + if(!OBJ_create(RSTRING_PTR(oid), RSTRING_PTR(sn), RSTRING_PTR(ln))) ossl_raise(eASN1Error, NULL); return Qtrue; @@ -1112,9 +1112,9 @@ Init_ossl_asn1() } cASN1Data = rb_define_class_under(mASN1, "ASN1Data", rb_cObject); - rb_attr(cASN1Data, rb_intern("value"), 1, 1, Qtrue); - rb_attr(cASN1Data, rb_intern("tag"), 1, 1, Qtrue); - rb_attr(cASN1Data, rb_intern("tag_class"), 1, 1, Qtrue); + rb_attr(cASN1Data, rb_intern("value"), 1, 1, 0); + rb_attr(cASN1Data, rb_intern("tag"), 1, 1, 0); + rb_attr(cASN1Data, rb_intern("tag_class"), 1, 1, 0); rb_define_method(cASN1Data, "initialize", ossl_asn1data_initialize, 3); rb_define_method(cASN1Data, "to_der", ossl_asn1data_to_der, 0); @@ -1166,5 +1166,5 @@ do{\ rb_define_method(cASN1ObjectId, "oid", ossl_asn1obj_get_oid, 0); rb_define_alias(cASN1ObjectId, "short_name", "sn"); rb_define_alias(cASN1ObjectId, "long_name", "ln"); - rb_attr(cASN1BitString, rb_intern("unused_bits"), 1, 1, Qtrue); + rb_attr(cASN1BitString, rb_intern("unused_bits"), 1, 1, 0); } diff --git a/ext/openssl/ossl_bio.c b/ext/openssl/ossl_bio.c index 9c9aa24197..6db1fb9a62 100644 --- a/ext/openssl/ossl_bio.c +++ b/ext/openssl/ossl_bio.c @@ -19,16 +19,29 @@ ossl_obj2bio(VALUE obj) BIO *bio; if (TYPE(obj) == T_FILE) { - OpenFile *fptr; + rb_io_t *fptr; + FILE *fp; + int fd; + GetOpenFile(obj, fptr); rb_io_check_readable(fptr); - bio = BIO_new_fp(fptr->f, BIO_NOCLOSE); - } + if ((fd = dup(FPTR_TO_FD(fptr))) < 0){ + rb_sys_fail(0); + } + if (!(fp = fdopen(fd, "r"))){ + close(fd); + rb_sys_fail(0); + } + if (!(bio = BIO_new_fp(fp, BIO_CLOSE))){ + fclose(fp); + ossl_raise(eOSSLError, NULL); + } + } else { StringValue(obj); - bio = BIO_new_mem_buf(RSTRING(obj)->ptr, RSTRING(obj)->len); + bio = BIO_new_mem_buf(RSTRING_PTR(obj), RSTRING_LEN(obj)); + if (!bio) ossl_raise(eOSSLError, NULL); } - if (!bio) ossl_raise(eOSSLError, NULL); return bio; } diff --git a/ext/openssl/ossl_bn.c b/ext/openssl/ossl_bn.c index cc7689eef5..60d9e552a4 100644 --- a/ext/openssl/ossl_bn.c +++ b/ext/openssl/ossl_bn.c @@ -40,7 +40,7 @@ VALUE eBNError; * Public */ VALUE -ossl_bn_new(BIGNUM *bn) +ossl_bn_new(const BIGNUM *bn) { BIGNUM *newbn; VALUE obj; @@ -100,6 +100,13 @@ ossl_bn_alloc(VALUE klass) return obj; } +/* + * call-seq: + * BN.new => aBN + * BN.new(bn) => aBN + * BN.new(string) => aBN + * BN.new(string, 0 | 2 | 10 | 16) => aBN + */ static VALUE ossl_bn_initialize(int argc, VALUE *argv, VALUE self) { @@ -124,22 +131,22 @@ ossl_bn_initialize(int argc, VALUE *argv, VALUE self) switch (base) { case 0: - if (!BN_mpi2bn(RSTRING(str)->ptr, RSTRING(str)->len, bn)) { + if (!BN_mpi2bn(RSTRING_PTR(str), RSTRING_LEN(str), bn)) { ossl_raise(eBNError, NULL); } break; case 2: - if (!BN_bin2bn(RSTRING(str)->ptr, RSTRING(str)->len, bn)) { + if (!BN_bin2bn(RSTRING_PTR(str), RSTRING_LEN(str), bn)) { ossl_raise(eBNError, NULL); } break; case 10: - if (!BN_dec2bn(&bn, RSTRING(str)->ptr)) { + if (!BN_dec2bn(&bn, RSTRING_PTR(str))) { ossl_raise(eBNError, NULL); } break; case 16: - if (!BN_hex2bn(&bn, RSTRING(str)->ptr)) { + if (!BN_hex2bn(&bn, RSTRING_PTR(str))) { ossl_raise(eBNError, NULL); } break; @@ -149,6 +156,19 @@ ossl_bn_initialize(int argc, VALUE *argv, VALUE self) return self; } +/* + * call-seq: + * bn.to_s => string + * bn.to_s(base) => string + * + * === Parameters + * * +base+ - integer + * * * Valid values: + * * * * 0 - MPI + * * * * 2 - binary + * * * * 10 - the default + * * * * 16 - hex + */ static VALUE ossl_bn_to_s(int argc, VALUE *argv, VALUE self) { @@ -165,13 +185,13 @@ ossl_bn_to_s(int argc, VALUE *argv, VALUE self) case 0: len = BN_bn2mpi(bn, NULL); str = rb_str_new(0, len); - if (BN_bn2mpi(bn, RSTRING(str)->ptr) != len) + if (BN_bn2mpi(bn, RSTRING_PTR(str)) != len) ossl_raise(eBNError, NULL); break; case 2: len = BN_num_bytes(bn); str = rb_str_new(0, len); - if (BN_bn2bin(bn, RSTRING(str)->ptr) != len) + if (BN_bn2bin(bn, RSTRING_PTR(str)) != len) ossl_raise(eBNError, NULL); break; case 10: @@ -189,6 +209,10 @@ ossl_bn_to_s(int argc, VALUE *argv, VALUE self) return str; } +/* + * call-seq: + * bn.to_i => integer + */ static VALUE ossl_bn_to_i(VALUE self) { @@ -233,6 +257,11 @@ ossl_bn_coerce(VALUE self, VALUE other) } #define BIGNUM_BOOL1(func) \ + /* \ + * call-seq: \ + * bn.##func -> true | false \ + * \ + */ \ static VALUE \ ossl_bn_##func(VALUE self) \ { \ @@ -248,6 +277,11 @@ BIGNUM_BOOL1(is_one); BIGNUM_BOOL1(is_odd); #define BIGNUM_1c(func) \ + /* \ + * call-seq: \ + * bn.##func -> aBN \ + * \ + */ \ static VALUE \ ossl_bn_##func(VALUE self) \ { \ @@ -267,6 +301,11 @@ BIGNUM_BOOL1(is_odd); BIGNUM_1c(sqr); #define BIGNUM_2(func) \ + /* \ + * call-seq: \ + * bn.##func(bn2) -> aBN \ + * \ + */ \ static VALUE \ ossl_bn_##func(VALUE self, VALUE other) \ { \ @@ -287,6 +326,11 @@ BIGNUM_2(add); BIGNUM_2(sub); #define BIGNUM_2c(func) \ + /* \ + * call-seq: \ + * bn.##func(bn2) -> aBN \ + * \ + */ \ static VALUE \ ossl_bn_##func(VALUE self, VALUE other) \ { \ @@ -310,6 +354,10 @@ BIGNUM_2c(gcd); BIGNUM_2c(mod_sqr); BIGNUM_2c(mod_inverse); +/* + * call-seq: + * bn1 / bn2 => [result, remainder] + */ static VALUE ossl_bn_div(VALUE self, VALUE other) { @@ -337,6 +385,11 @@ ossl_bn_div(VALUE self, VALUE other) } #define BIGNUM_3c(func) \ + /* \ + * call-seq: \ + * bn.##func(bn1, bn2) -> aBN \ + * \ + */ \ static VALUE \ ossl_bn_##func(VALUE self, VALUE other1, VALUE other2) \ { \ @@ -360,6 +413,11 @@ BIGNUM_3c(mod_mul); BIGNUM_3c(mod_exp); #define BIGNUM_BIT(func) \ + /* \ + * call-seq: \ + * bn.##func(bit) -> self \ + * \ + */ \ static VALUE \ ossl_bn_##func(VALUE self, VALUE bit) \ { \ @@ -374,6 +432,10 @@ BIGNUM_BIT(set_bit); BIGNUM_BIT(clear_bit); BIGNUM_BIT(mask_bits); +/* + * call-seq: + * bn.bit_set?(bit) => true | false + */ static VALUE ossl_bn_is_bit_set(VALUE self, VALUE bit) { @@ -389,6 +451,11 @@ ossl_bn_is_bit_set(VALUE self, VALUE bit) } #define BIGNUM_SHIFT(func) \ + /* \ + * call-seq: \ + * bn.##func(bits) -> aBN \ + * \ + */ \ static VALUE \ ossl_bn_##func(VALUE self, VALUE bits) \ { \ @@ -410,7 +477,32 @@ ossl_bn_is_bit_set(VALUE self, VALUE bit) BIGNUM_SHIFT(lshift); BIGNUM_SHIFT(rshift); +#define BIGNUM_SELF_SHIFT(func) \ + /* \ + * call-seq: \ + * bn.##func!(bits) -> self \ + * \ + */ \ + static VALUE \ + ossl_bn_self_##func(VALUE self, VALUE bits) \ + { \ + BIGNUM *bn; \ + int b; \ + b = NUM2INT(bits); \ + GetBN(self, bn); \ + if (!BN_##func(bn, bn, b)) \ + ossl_raise(eBNError, NULL); \ + return self; \ + } +BIGNUM_SELF_SHIFT(lshift); +BIGNUM_SELF_SHIFT(rshift); + #define BIGNUM_RAND(func) \ + /* \ + * call-seq: \ + * BN.##func(bits [, fill [, odd]]) -> aBN \ + * \ + */ \ static VALUE \ ossl_bn_s_##func(int argc, VALUE *argv, VALUE klass) \ { \ @@ -440,6 +532,11 @@ BIGNUM_RAND(rand); BIGNUM_RAND(pseudo_rand); #define BIGNUM_RAND_RANGE(func) \ + /* \ + * call-seq: \ + * BN.##func(range) -> aBN \ + * \ + */ \ static VALUE \ ossl_bn_s_##func##_range(VALUE klass, VALUE range) \ { \ @@ -458,6 +555,16 @@ BIGNUM_RAND(pseudo_rand); BIGNUM_RAND_RANGE(rand); BIGNUM_RAND_RANGE(pseudo_rand); +/* + * call-seq: + * BN.generate_prime(bits, [, safe [, add [, rem]]]) => bn + * + * === Parameters + * * +bits+ - integer + * * +safe+ - boolean + * * +add+ - BN + * * +rem+ - BN + */ static VALUE ossl_bn_s_generate_prime(int argc, VALUE *argv, VALUE klass) { @@ -473,12 +580,8 @@ ossl_bn_s_generate_prime(int argc, VALUE *argv, VALUE klass) safe = 0; } if (!NIL_P(vadd)) { - if (NIL_P(vrem)) { - ossl_raise(rb_eArgError, - "if ADD is specified, REM must be also given"); - } add = GetBNPtr(vadd); - rem = GetBNPtr(vrem); + rem = NIL_P(vrem) ? NULL : GetBNPtr(vrem); } if (!(result = BN_new())) { ossl_raise(eBNError, NULL); @@ -489,10 +592,15 @@ ossl_bn_s_generate_prime(int argc, VALUE *argv, VALUE klass) } WrapBN(klass, obj, result); - return obj; + return obj; } #define BIGNUM_NUM(func) \ + /* \ + * call-seq: \ + * bn.##func -> integer \ + * \ + */ \ static VALUE \ ossl_bn_##func(VALUE self) \ { \ @@ -522,6 +630,11 @@ ossl_bn_copy(VALUE self, VALUE other) } #define BIGNUM_CMP(func) \ + /* \ + * call-seq: \ + * bn.##func(bn2) -> integer \ + * \ + */ \ static VALUE \ ossl_bn_##func(VALUE self, VALUE other) \ { \ @@ -541,6 +654,14 @@ ossl_bn_eql(VALUE self, VALUE other) return Qfalse; } +/* + * call-seq: + * bn.prime? => true | false + * bn.prime?(checks) => true | false + * + * === Parameters + * * +checks+ - integer + */ static VALUE ossl_bn_is_prime(int argc, VALUE *argv, VALUE self) { @@ -564,6 +685,16 @@ ossl_bn_is_prime(int argc, VALUE *argv, VALUE self) return Qnil; } +/* + * call-seq: + * bn.prime_fasttest? => true | false + * bn.prime_fasttest?(checks) => true | false + * bn.prime_fasttest?(checks, trial_div) => true | false + * + * === Parameters + * * +checks+ - integer + * * +trial_div+ - boolean + */ static VALUE ossl_bn_is_prime_fasttest(int argc, VALUE *argv, VALUE self) { @@ -676,8 +807,10 @@ Init_ossl_bn() rb_define_method(cBN, "bit_set?", ossl_bn_is_bit_set, 1); rb_define_method(cBN, "mask_bits!", ossl_bn_mask_bits, 1); rb_define_method(cBN, "<<", ossl_bn_lshift, 1); - /* lshift1 - DON'T IMPL. */ rb_define_method(cBN, ">>", ossl_bn_rshift, 1); + rb_define_method(cBN, "lshift!", ossl_bn_self_lshift, 1); + rb_define_method(cBN, "rshift!", ossl_bn_self_rshift, 1); + /* lshift1 - DON'T IMPL. */ /* rshift1 - DON'T IMPL. */ /* diff --git a/ext/openssl/ossl_bn.h b/ext/openssl/ossl_bn.h index 12aa484873..d6c396227b 100644 --- a/ext/openssl/ossl_bn.h +++ b/ext/openssl/ossl_bn.h @@ -14,9 +14,12 @@ extern VALUE cBN; extern VALUE eBNError; -VALUE ossl_bn_new(BIGNUM *); +extern BN_CTX *ossl_bn_ctx; + +VALUE ossl_bn_new(const BIGNUM *); BIGNUM *GetBNPtr(VALUE); void Init_ossl_bn(void); + #endif /* _OSS_BN_H_ */ diff --git a/ext/openssl/ossl_cipher.c b/ext/openssl/ossl_cipher.c index 57b7976617..b680dc6e64 100644 --- a/ext/openssl/ossl_cipher.c +++ b/ext/openssl/ossl_cipher.c @@ -26,7 +26,6 @@ /* * Classes */ -VALUE mCipher; VALUE cCipher; VALUE eCipherError; @@ -84,6 +83,14 @@ ossl_cipher_alloc(VALUE klass) return obj; } +/* + * call-seq: + * Cipher.new(string) -> cipher + * + * The string must contain a valid cipher name like "AES-128-CBC" or "3DES". + * + * A list of cipher names is available by calling OpenSSL::Cipher.ciphers. + */ static VALUE ossl_cipher_initialize(VALUE self, VALUE str) { @@ -124,6 +131,12 @@ add_cipher_name_to_ary(const OBJ_NAME *name, VALUE ary) return NULL; } +/* + * call-seq: + * Cipher.ciphers -> array[string...] + * + * Returns the names of all available ciphers in an array. + */ static VALUE ossl_s_ciphers(VALUE self) { @@ -141,6 +154,12 @@ ossl_s_ciphers(VALUE self) #endif } +/* + * call-seq: + * cipher.reset -> self + * + * Internally calls EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, -1). + */ static VALUE ossl_cipher_reset(VALUE self) { @@ -167,22 +186,23 @@ ossl_cipher_init(int argc, VALUE *argv, VALUE self, int mode) * We deprecated the arguments for this method, but we decided * keeping this behaviour for backward compatibility. */ + char *cname = rb_class2name(rb_obj_class(self)); + rb_warn("argumtents for %s#encrypt and %s#decrypt were deprecated; " + "use %s#pkcs5_keyivgen to derive key and IV", + cname, cname, cname); StringValue(pass); GetCipher(self, ctx); if (NIL_P(init_v)) memcpy(iv, "OpenSSL for Ruby rulez!", sizeof(iv)); else{ - char *cname = rb_class2name(rb_obj_class(self)); - rb_warning("key derivation by %s#encrypt is deprecated; " - "use %s::pkcs5_keyivgen instead", cname, cname); StringValue(init_v); - if (EVP_MAX_IV_LENGTH > RSTRING(init_v)->len) { + if (EVP_MAX_IV_LENGTH > RSTRING_LEN(init_v)) { memset(iv, 0, EVP_MAX_IV_LENGTH); - memcpy(iv, RSTRING(init_v)->ptr, RSTRING(init_v)->len); + memcpy(iv, RSTRING_PTR(init_v), RSTRING_LEN(init_v)); } - else memcpy(iv, RSTRING(init_v)->ptr, sizeof(iv)); + else memcpy(iv, RSTRING_PTR(init_v), sizeof(iv)); } EVP_BytesToKey(EVP_CIPHER_CTX_cipher(ctx), EVP_md5(), iv, - RSTRING(pass)->ptr, RSTRING(pass)->len, 1, key, NULL); + RSTRING_PTR(pass), RSTRING_LEN(pass), 1, key, NULL); p_key = key; p_iv = iv; } @@ -196,18 +216,54 @@ ossl_cipher_init(int argc, VALUE *argv, VALUE self, int mode) return self; } +/* + * call-seq: + * cipher.encrypt -> self + * + * Make sure to call .encrypt or .decrypt before using any of the following methods: + * * [key=, iv=, random_key, random_iv, pkcs5_keyivgen] + * + * Internally calls EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, 1). + */ static VALUE ossl_cipher_encrypt(int argc, VALUE *argv, VALUE self) { return ossl_cipher_init(argc, argv, self, 1); } +/* + * call-seq: + * cipher.decrypt -> self + * + * Make sure to call .encrypt or .decrypt before using any of the following methods: + * * [key=, iv=, random_key, random_iv, pkcs5_keyivgen] + * + * Internally calls EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, 0). + */ static VALUE ossl_cipher_decrypt(int argc, VALUE *argv, VALUE self) { return ossl_cipher_init(argc, argv, self, 0); } +/* + * call-seq: + * cipher.pkcs5_keyivgen(pass [, salt [, iterations [, digest]]] ) -> nil + * + * Generates and sets the key/iv based on a password. + * + * WARNING: This method is only PKCS5 v1.5 compliant when using RC2, RC4-40, or DES + * with MD5 or SHA1. Using anything else (like AES) will generate the key/iv using an + * OpenSSL specific method. Use a PKCS5 v2 key generation method instead. + * + * === Parameters + * +salt+ must be an 8 byte string if provided. + * +iterations+ is a integer with a default of 2048. + * +digest+ is a Digest object that defaults to 'MD5' + * + * A minimum of 1000 iterations is recommended. + * + */ static VALUE ossl_cipher_pkcs5_keyivgen(int argc, VALUE *argv, VALUE self) { @@ -221,15 +277,15 @@ ossl_cipher_pkcs5_keyivgen(int argc, VALUE *argv, VALUE self) StringValue(vpass); if(!NIL_P(vsalt)){ StringValue(vsalt); - if(RSTRING(vsalt)->len != PKCS5_SALT_LEN) + if(RSTRING_LEN(vsalt) != PKCS5_SALT_LEN) rb_raise(eCipherError, "salt must be an 8-octet string"); - salt = RSTRING(vsalt)->ptr; + salt = RSTRING_PTR(vsalt); } iter = NIL_P(viter) ? 2048 : NUM2INT(viter); digest = NIL_P(vdigest) ? EVP_md5() : GetDigestPtr(vdigest); GetCipher(self, ctx); EVP_BytesToKey(EVP_CIPHER_CTX_cipher(ctx), digest, salt, - RSTRING(vpass)->ptr, RSTRING(vpass)->len, iter, key, iv); + RSTRING_PTR(vpass), RSTRING_LEN(vpass), iter, key, iv); if (EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, -1) != 1) ossl_raise(eCipherError, NULL); OPENSSL_cleanse(key, sizeof key); @@ -238,39 +294,75 @@ ossl_cipher_pkcs5_keyivgen(int argc, VALUE *argv, VALUE self) return Qnil; } + +/* + * call-seq: + * cipher << data -> string + * + * === Parameters + * +data+ is a nonempty string. + * + * This method is deprecated and not available in 1.9.x or later. + */ +static VALUE +ossl_cipher_update_deprecated(VALUE self, VALUE data) +{ + char *cname; + + cname = rb_class2name(rb_obj_class(self)); + rb_warning("%s#<< is deprecated; use %s#update instead", cname, cname); + return rb_funcall(self, rb_intern("update"), 1, data); +} + + +/* + * call-seq: + * cipher.update(data [, buffer]) -> string or buffer + * + * === Parameters + * +data+ is a nonempty string. + * +buffer+ is an optional string to store the result. + */ static VALUE -ossl_cipher_update(VALUE self, VALUE data) +ossl_cipher_update(int argc, VALUE *argv, VALUE self) { EVP_CIPHER_CTX *ctx; char *in; int in_len, out_len; - VALUE str; + VALUE data, str; + + rb_scan_args(argc, argv, "11", &data, &str); StringValue(data); - in = RSTRING(data)->ptr; - if ((in_len = RSTRING(data)->len) == 0) + in = RSTRING_PTR(data); + if ((in_len = RSTRING_LEN(data)) == 0) rb_raise(rb_eArgError, "data must not be empty"); GetCipher(self, ctx); - str = rb_str_new(0, in_len+EVP_CIPHER_CTX_block_size(ctx)); - if (!EVP_CipherUpdate(ctx, RSTRING(str)->ptr, &out_len, in, in_len)) - ossl_raise(eCipherError, NULL); - assert(out_len < RSTRING(str)->len); - RSTRING(str)->len = out_len; - RSTRING(str)->ptr[out_len] = 0; + out_len = in_len+EVP_CIPHER_CTX_block_size(ctx); - return str; -} + if (NIL_P(str)) { + str = rb_str_new(0, out_len); + } else { + StringValue(str); + rb_str_resize(str, out_len); + } -static VALUE -ossl_cipher_update_deprecated(VALUE self, VALUE data) -{ - char *cname; + if (!EVP_CipherUpdate(ctx, RSTRING_PTR(str), &out_len, in, in_len)) + ossl_raise(eCipherError, NULL); + assert(out_len < RSTRING_LEN(str)); + rb_str_set_len(str, out_len); - cname = rb_class2name(rb_obj_class(self)); - rb_warning("%s#<< is deprecated; use %s#update instead", cname, cname); - return ossl_cipher_update(self, data); + return str; } +/* + * call-seq: + * cipher.final -> aString + * + * Returns the remaining data held in the cipher object. Further calls to update() or final() will return garbage. + * + * See EVP_CipherFinal_ex for further information. + */ static VALUE ossl_cipher_final(VALUE self) { @@ -280,15 +372,20 @@ ossl_cipher_final(VALUE self) GetCipher(self, ctx); str = rb_str_new(0, EVP_CIPHER_CTX_block_size(ctx)); - if (!EVP_CipherFinal_ex(ctx, RSTRING(str)->ptr, &out_len)) + if (!EVP_CipherFinal_ex(ctx, RSTRING_PTR(str), &out_len)) ossl_raise(eCipherError, NULL); - assert(out_len <= RSTRING(str)->len); - RSTRING(str)->len = out_len; - RSTRING(str)->ptr[out_len] = 0; + assert(out_len <= RSTRING_LEN(str)); + rb_str_set_len(str, out_len); return str; } +/* + * call-seq: + * cipher.name -> string + * + * Returns the name of the cipher which may differ slightly from the original name provided. + */ static VALUE ossl_cipher_name(VALUE self) { @@ -299,6 +396,14 @@ ossl_cipher_name(VALUE self) return rb_str_new2(EVP_CIPHER_name(EVP_CIPHER_CTX_cipher(ctx))); } +/* + * call-seq: + * cipher.key = string -> string + * + * Sets the cipher key. + * + * Only call this method after calling cipher.encrypt or cipher.decrypt. + */ static VALUE ossl_cipher_set_key(VALUE self, VALUE key) { @@ -307,15 +412,23 @@ ossl_cipher_set_key(VALUE self, VALUE key) StringValue(key); GetCipher(self, ctx); - if (RSTRING(key)->len < EVP_CIPHER_CTX_key_length(ctx)) + if (RSTRING_LEN(key) < EVP_CIPHER_CTX_key_length(ctx)) ossl_raise(eCipherError, "key length too short"); - if (EVP_CipherInit_ex(ctx, NULL, NULL, RSTRING(key)->ptr, NULL, -1) != 1) + if (EVP_CipherInit_ex(ctx, NULL, NULL, RSTRING_PTR(key), NULL, -1) != 1) ossl_raise(eCipherError, NULL); return key; } +/* + * call-seq: + * cipher.iv = string -> string + * + * Sets the cipher iv. + * + * Only call this method after calling cipher.encrypt or cipher.decrypt. + */ static VALUE ossl_cipher_set_iv(VALUE self, VALUE iv) { @@ -324,20 +437,32 @@ ossl_cipher_set_iv(VALUE self, VALUE iv) StringValue(iv); GetCipher(self, ctx); - if (RSTRING(iv)->len < EVP_CIPHER_CTX_iv_length(ctx)) + if (RSTRING_LEN(iv) < EVP_CIPHER_CTX_iv_length(ctx)) ossl_raise(eCipherError, "iv length too short"); - if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, RSTRING(iv)->ptr, -1) != 1) + if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, RSTRING_PTR(iv), -1) != 1) ossl_raise(eCipherError, NULL); return iv; } + +/* + * call-seq: + * cipher.key_length = integer -> integer + * + * Sets the key length of the cipher. If the cipher is a fixed length cipher then attempting to set the key + * length to any value other than the fixed value is an error. + * + * Under normal circumstances you do not need to call this method (and probably shouldn't). + * + * See EVP_CIPHER_CTX_set_key_length for further information. + */ static VALUE ossl_cipher_set_key_length(VALUE self, VALUE key_length) { - EVP_CIPHER_CTX *ctx; int len = NUM2INT(key_length); + EVP_CIPHER_CTX *ctx; GetCipher(self, ctx); if (EVP_CIPHER_CTX_set_key_length(ctx, len) != 1) @@ -346,6 +471,16 @@ ossl_cipher_set_key_length(VALUE self, VALUE key_length) return key_length; } +/* + * call-seq: + * cipher.padding = integer -> integer + * + * Enables or disables padding. By default encryption operations are padded using standard block padding and the + * padding is checked and removed when decrypting. If the pad parameter is zero then no padding is performed, the + * total amount of data encrypted or decrypted must then be a multiple of the block size or an error will occur. + * + * See EVP_CIPHER_CTX_set_padding for further information. + */ static VALUE ossl_cipher_set_padding(VALUE self, VALUE padding) { @@ -374,6 +509,27 @@ CIPHER_0ARG_INT(key_length) CIPHER_0ARG_INT(iv_length) CIPHER_0ARG_INT(block_size) +#if 0 +/* + * call-seq: + * cipher.key_length -> integer + * + */ +static VALUE ossl_cipher_key_length() { } +/* + * call-seq: + * cipher.iv_length -> integer + * + */ +static VALUE ossl_cipher_iv_length() { } +/* + * call-seq: + * cipher.block_size -> integer + * + */ +static VALUE ossl_cipher_block_size() { } +#endif + /* * INIT */ @@ -383,21 +539,21 @@ Init_ossl_cipher(void) #if 0 /* let rdoc know about mOSSL */ mOSSL = rb_define_module("OpenSSL"); #endif - - mCipher = rb_define_module_under(mOSSL, "Cipher"); - eCipherError = rb_define_class_under(mOSSL, "CipherError", eOSSLError); - cCipher = rb_define_class_under(mCipher, "Cipher", rb_cObject); + cCipher = rb_define_class_under(mOSSL, "Cipher", rb_cObject); + eCipherError = rb_define_class_under(cCipher, "CipherError", eOSSLError); rb_define_alloc_func(cCipher, ossl_cipher_alloc); rb_define_copy_func(cCipher, ossl_cipher_copy); - rb_define_module_function(mCipher, "ciphers", ossl_s_ciphers, 0); + rb_define_module_function(cCipher, "ciphers", ossl_s_ciphers, 0); rb_define_method(cCipher, "initialize", ossl_cipher_initialize, 1); rb_define_method(cCipher, "reset", ossl_cipher_reset, 0); rb_define_method(cCipher, "encrypt", ossl_cipher_encrypt, -1); rb_define_method(cCipher, "decrypt", ossl_cipher_decrypt, -1); rb_define_method(cCipher, "pkcs5_keyivgen", ossl_cipher_pkcs5_keyivgen, -1); - rb_define_method(cCipher, "update", ossl_cipher_update, 1); + rb_define_method(cCipher, "update", ossl_cipher_update, -1); +#if RUBY_VERSION_CODE < 190 rb_define_method(cCipher, "<<", ossl_cipher_update_deprecated, 1); +#endif rb_define_method(cCipher, "final", ossl_cipher_final, 0); rb_define_method(cCipher, "name", ossl_cipher_name, 0); rb_define_method(cCipher, "key=", ossl_cipher_set_key, 1); @@ -408,3 +564,4 @@ Init_ossl_cipher(void) rb_define_method(cCipher, "block_size", ossl_cipher_block_size, 0); rb_define_method(cCipher, "padding=", ossl_cipher_set_padding, 1); } + diff --git a/ext/openssl/ossl_cipher.h b/ext/openssl/ossl_cipher.h index 63c7a875e8..bed4fa853b 100644 --- a/ext/openssl/ossl_cipher.h +++ b/ext/openssl/ossl_cipher.h @@ -11,7 +11,6 @@ #if !defined(_OSSL_CIPHER_H_) #define _OSSL_CIPHER_H_ -extern VALUE mCipher; extern VALUE cCipher; extern VALUE eCipherError; diff --git a/ext/openssl/ossl_config.c b/ext/openssl/ossl_config.c index ef89fdfe0d..3dfe7f361c 100644 --- a/ext/openssl/ossl_config.c +++ b/ext/openssl/ossl_config.c @@ -171,16 +171,16 @@ ossl_config_add_value(VALUE self, VALUE section, VALUE name, VALUE value) StringValue(name); StringValue(value); GetConfig(self, conf); - if(!(sv = _CONF_get_section(conf, RSTRING(section)->ptr))){ - if(!(sv = _CONF_new_section(conf, RSTRING(section)->ptr))){ + if(!(sv = _CONF_get_section(conf, RSTRING_PTR(section)))){ + if(!(sv = _CONF_new_section(conf, RSTRING_PTR(section)))){ ossl_raise(eConfigError, NULL); } } if(!(cv = OPENSSL_malloc(sizeof(CONF_VALUE)))){ ossl_raise(eConfigError, NULL); } - cv->name = BUF_strdup(RSTRING(name)->ptr); - cv->value = BUF_strdup(RSTRING(value)->ptr); + cv->name = BUF_strdup(RSTRING_PTR(name)); + cv->value = BUF_strdup(RSTRING_PTR(value)); if(!cv->name || !cv->value || !_CONF_add_string(conf, sv, cv)){ OPENSSL_free(cv->name); OPENSSL_free(cv->value); @@ -201,7 +201,7 @@ ossl_config_get_value(VALUE self, VALUE section, VALUE name) StringValue(section); StringValue(name); GetConfig(self, conf); - str = NCONF_get_string(conf, RSTRING(section)->ptr, RSTRING(name)->ptr); + str = NCONF_get_string(conf, RSTRING_PTR(section), RSTRING_PTR(name)); if(!str){ ERR_clear_error(); return Qnil; @@ -246,7 +246,7 @@ static VALUE ossl_config_set_section(VALUE self, VALUE section, VALUE hash) { VALUE arg[2] = { self, section }; - rb_iterate(rb_each, hash, set_conf_section_i, (VALUE)arg); + rb_block_call(hash, rb_intern("each"), 0, 0, set_conf_section_i, (VALUE)arg); return hash; } diff --git a/ext/openssl/ossl_digest.c b/ext/openssl/ossl_digest.c index 4096b097a2..118626fd71 100644 --- a/ext/openssl/ossl_digest.c +++ b/ext/openssl/ossl_digest.c @@ -24,7 +24,6 @@ /* * Classes */ -VALUE mDigest; VALUE cDigest; VALUE eDigestError; @@ -36,11 +35,23 @@ static VALUE ossl_digest_alloc(VALUE klass); const EVP_MD * GetDigestPtr(VALUE obj) { - EVP_MD_CTX *ctx; + const EVP_MD *md; - SafeGetDigest(obj, ctx); + if (TYPE(obj) == T_STRING) { + const char *name = STR2CSTR(obj); + + md = EVP_get_digestbyname(name); + if (!md) + ossl_raise(rb_eRuntimeError, "Unsupported digest algorithm (%s).", name); + } else { + EVP_MD_CTX *ctx; + + SafeGetDigest(obj, ctx); + + md = EVP_MD_CTX_md(ctx); /*== ctx->digest*/ + } - return EVP_MD_CTX_md(ctx); /*== ctx->digest*/ + return md; } VALUE @@ -77,6 +88,11 @@ ossl_digest_alloc(VALUE klass) VALUE ossl_digest_update(VALUE, VALUE); +/* + * call-seq: + * Digest.new(string) -> digest + * + */ static VALUE ossl_digest_initialize(int argc, VALUE *argv, VALUE self) { @@ -118,6 +134,11 @@ ossl_digest_copy(VALUE self, VALUE other) return self; } +/* + * call-seq: + * digest.reset -> self + * + */ static VALUE ossl_digest_reset(VALUE self) { @@ -129,6 +150,11 @@ ossl_digest_reset(VALUE self) return self; } +/* + * call-seq: + * digest.update(string) -> aString + * + */ VALUE ossl_digest_update(VALUE self, VALUE data) { @@ -136,7 +162,7 @@ ossl_digest_update(VALUE self, VALUE data) StringValue(data); GetDigest(self, ctx); - EVP_DigestUpdate(ctx, RSTRING(data)->ptr, RSTRING(data)->len); + EVP_DigestUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)); return self; } @@ -157,6 +183,11 @@ digest_final(EVP_MD_CTX *ctx, char **buf, int *buf_len) EVP_MD_CTX_cleanup(&final); } +/* + * call-seq: + * digest.final -> aString + * + */ static VALUE ossl_digest_digest(VALUE self) { @@ -172,6 +203,11 @@ ossl_digest_digest(VALUE self) return digest; } +/* + * call-seq: + * digest.hexdigest -> aString + * + */ static VALUE ossl_digest_hexdigest(VALUE self) { @@ -212,6 +248,11 @@ ossl_digest_s_hexdigest(VALUE klass, VALUE str, VALUE data) return ossl_digest_hexdigest(obj); } +/* + * call-seq: + * digest1 == digest2 -> true | false + * + */ static VALUE ossl_digest_equal(VALUE self, VALUE other) { @@ -225,12 +266,12 @@ ossl_digest_equal(VALUE self, VALUE other) str2 = other; } GetDigest(self, ctx); - if (RSTRING(str2)->len == EVP_MD_CTX_size(ctx)) { + if (RSTRING_LEN(str2) == EVP_MD_CTX_size(ctx)) { str1 = ossl_digest_digest(self); } else { str1 = ossl_digest_hexdigest(self); } - if (RSTRING(str1)->len == RSTRING(str2)->len + if (RSTRING_LEN(str1) == RSTRING_LEN(str2) && rb_str_cmp(str1, str2) == 0) { return Qtrue; } @@ -238,6 +279,11 @@ ossl_digest_equal(VALUE self, VALUE other) return Qfalse; } +/* + * call-seq: + * digest.name -> string + * + */ static VALUE ossl_digest_name(VALUE self) { @@ -248,6 +294,12 @@ ossl_digest_name(VALUE self) return rb_str_new2(EVP_MD_name(EVP_MD_CTX_md(ctx))); } +/* + * call-seq: + * digest.size -> integer + * + * Returns the output size of the digest. + */ static VALUE ossl_digest_size(VALUE self) { @@ -268,11 +320,8 @@ Init_ossl_digest() mOSSL = rb_define_module("OpenSSL"); #endif - mDigest = rb_define_module_under(mOSSL, "Digest"); - - eDigestError = rb_define_class_under(mDigest, "DigestError", eOSSLError); - - cDigest = rb_define_class_under(mDigest, "Digest", rb_cObject); + cDigest = rb_define_class_under(mOSSL, "Digest", rb_cObject); + eDigestError = rb_define_class_under(cDigest, "DigestError", eOSSLError); rb_define_alloc_func(cDigest, ossl_digest_alloc); rb_define_singleton_method(cDigest, "digest", ossl_digest_s_digest, 2); diff --git a/ext/openssl/ossl_digest.h b/ext/openssl/ossl_digest.h index 8a1f7964f2..8cc5b1bc56 100644 --- a/ext/openssl/ossl_digest.h +++ b/ext/openssl/ossl_digest.h @@ -11,7 +11,6 @@ #if !defined(_OSSL_DIGEST_H_) #define _OSSL_DIGEST_H_ -extern VALUE mDigest; extern VALUE cDigest; extern VALUE eDigestError; diff --git a/ext/openssl/ossl_engine.c b/ext/openssl/ossl_engine.c index 71586e3620..cd835d1237 100644 --- a/ext/openssl/ossl_engine.c +++ b/ext/openssl/ossl_engine.c @@ -40,7 +40,7 @@ VALUE eEngineError; */ #define OSSL_ENGINE_LOAD_IF_MATCH(x) \ do{\ - if(!strcmp(#x, RSTRING(name)->ptr)){\ + if(!strcmp(#x, RSTRING_PTR(name))){\ ENGINE_load_##x();\ return Qtrue;\ }\ @@ -75,7 +75,7 @@ ossl_engine_s_load(int argc, VALUE *argv, VALUE klass) OSSL_ENGINE_LOAD_IF_MATCH(openbsd_dev_crypto); #endif OSSL_ENGINE_LOAD_IF_MATCH(openssl); - rb_warning("no such builtin loader for `%s'", RSTRING(name)->ptr); + rb_warning("no such builtin loader for `%s'", RSTRING_PTR(name)); return Qnil; #endif /* HAVE_ENGINE_LOAD_BUILTIN_ENGINES */ } @@ -112,7 +112,7 @@ ossl_engine_s_by_id(VALUE klass, VALUE id) StringValue(id); ossl_engine_s_load(1, &id, klass); - if(!(e = ENGINE_by_id(RSTRING(id)->ptr))) + if(!(e = ENGINE_by_id(RSTRING_PTR(id)))) ossl_raise(eEngineError, NULL); WrapEngine(klass, obj, e); if(rb_block_given_p()) rb_yield(obj); @@ -281,8 +281,8 @@ ossl_engine_ctrl_cmd(int argc, VALUE *argv, VALUE self) rb_scan_args(argc, argv, "11", &cmd, &val); StringValue(cmd); if (!NIL_P(val)) StringValue(val); - ret = ENGINE_ctrl_cmd_string(e, RSTRING(cmd)->ptr, - NIL_P(val) ? NULL : RSTRING(val)->ptr, 0); + ret = ENGINE_ctrl_cmd_string(e, RSTRING_PTR(cmd), + NIL_P(val) ? NULL : RSTRING_PTR(val), 0); if (!ret) ossl_raise(eEngineError, NULL); return self; diff --git a/ext/openssl/ossl_hmac.c b/ext/openssl/ossl_hmac.c index 312343e03d..ba85f521f7 100644 --- a/ext/openssl/ossl_hmac.c +++ b/ext/openssl/ossl_hmac.c @@ -57,6 +57,12 @@ ossl_hmac_alloc(VALUE klass) return obj; } + +/* + * call-seq: + * HMAC.new(key, digest) -> hmac + * + */ static VALUE ossl_hmac_initialize(VALUE self, VALUE key, VALUE digest) { @@ -64,7 +70,7 @@ ossl_hmac_initialize(VALUE self, VALUE key, VALUE digest) StringValue(key); GetHMAC(self, ctx); - HMAC_Init_ex(ctx, RSTRING(key)->ptr, RSTRING(key)->len, + HMAC_Init_ex(ctx, RSTRING_PTR(key), RSTRING_LEN(key), GetDigestPtr(digest), NULL); return self; @@ -87,6 +93,11 @@ ossl_hmac_copy(VALUE self, VALUE other) return self; } +/* + * call-seq: + * hmac.update(string) -> self + * + */ static VALUE ossl_hmac_update(VALUE self, VALUE data) { @@ -94,7 +105,7 @@ ossl_hmac_update(VALUE self, VALUE data) StringValue(data); GetHMAC(self, ctx); - HMAC_Update(ctx, RSTRING(data)->ptr, RSTRING(data)->len); + HMAC_Update(ctx, RSTRING_PTR(data), RSTRING_LEN(data)); return self; } @@ -116,6 +127,11 @@ hmac_final(HMAC_CTX *ctx, char **buf, int *buf_len) HMAC_CTX_cleanup(&final); } +/* + * call-seq: + * hmac.digest -> aString + * + */ static VALUE ossl_hmac_digest(VALUE self) { @@ -131,6 +147,11 @@ ossl_hmac_digest(VALUE self) return digest; } +/* + * call-seq: + * hmac.hexdigest -> aString + * + */ static VALUE ossl_hmac_hexdigest(VALUE self) { @@ -151,6 +172,27 @@ ossl_hmac_hexdigest(VALUE self) return hexdigest; } +/* + * call-seq: + * hmac.reset -> self + * + */ +static VALUE +ossl_hmac_reset(VALUE self) +{ + HMAC_CTX *ctx; + + GetHMAC(self, ctx); + HMAC_Init_ex(ctx, NULL, 0, NULL, NULL); + + return self; +} + +/* + * call-seq: + * HMAC.digest(digest, key, data) -> aString + * + */ static VALUE ossl_hmac_s_digest(VALUE klass, VALUE digest, VALUE key, VALUE data) { @@ -159,12 +201,17 @@ ossl_hmac_s_digest(VALUE klass, VALUE digest, VALUE key, VALUE data) StringValue(key); StringValue(data); - buf = HMAC(GetDigestPtr(digest), RSTRING(key)->ptr, RSTRING(key)->len, - RSTRING(data)->ptr, RSTRING(data)->len, NULL, &buf_len); + buf = HMAC(GetDigestPtr(digest), RSTRING_PTR(key), RSTRING_LEN(key), + RSTRING_PTR(data), RSTRING_LEN(data), NULL, &buf_len); return rb_str_new(buf, buf_len); } +/* + * call-seq: + * HMAC.digest(digest, key, data) -> aString + * + */ static VALUE ossl_hmac_s_hexdigest(VALUE klass, VALUE digest, VALUE key, VALUE data) { @@ -175,8 +222,8 @@ ossl_hmac_s_hexdigest(VALUE klass, VALUE digest, VALUE key, VALUE data) StringValue(key); StringValue(data); - buf = HMAC(GetDigestPtr(digest), RSTRING(key)->ptr, RSTRING(key)->len, - RSTRING(data)->ptr, RSTRING(data)->len, NULL, &buf_len); + buf = HMAC(GetDigestPtr(digest), RSTRING_PTR(key), RSTRING_LEN(key), + RSTRING_PTR(data), RSTRING_LEN(data), NULL, &buf_len); if (string2hex(buf, buf_len, &hexbuf, NULL) != 2 * buf_len) { ossl_raise(eHMACError, "Cannot convert buf to hexbuf"); } @@ -206,6 +253,7 @@ Init_ossl_hmac() rb_define_method(cHMAC, "initialize", ossl_hmac_initialize, 2); rb_define_copy_func(cHMAC, ossl_hmac_copy); + rb_define_method(cHMAC, "reset", ossl_hmac_reset, 0); rb_define_method(cHMAC, "update", ossl_hmac_update, 1); rb_define_alias(cHMAC, "<<", "update"); rb_define_method(cHMAC, "digest", ossl_hmac_digest, 0); diff --git a/ext/openssl/ossl_ns_spki.c b/ext/openssl/ossl_ns_spki.c index 66e28374cc..738a203d93 100644 --- a/ext/openssl/ossl_ns_spki.c +++ b/ext/openssl/ossl_ns_spki.c @@ -62,9 +62,9 @@ ossl_spki_initialize(int argc, VALUE *argv, VALUE self) return self; } StringValue(buffer); - if (!(spki = NETSCAPE_SPKI_b64_decode(RSTRING(buffer)->ptr, -1))) { - p = RSTRING(buffer)->ptr; - if (!(spki = d2i_NETSCAPE_SPKI(NULL, &p, RSTRING(buffer)->len))) { + if (!(spki = NETSCAPE_SPKI_b64_decode(RSTRING_PTR(buffer), -1))) { + p = RSTRING_PTR(buffer); + if (!(spki = d2i_NETSCAPE_SPKI(NULL, &p, RSTRING_LEN(buffer)))) { ossl_raise(eSPKIError, NULL); } } @@ -87,7 +87,7 @@ ossl_spki_to_der(VALUE self) if ((len = i2d_NETSCAPE_SPKI(spki, NULL)) <= 0) ossl_raise(eX509CertError, NULL); str = rb_str_new(0, len); - p = RSTRING(str)->ptr; + p = RSTRING_PTR(str); if (i2d_NETSCAPE_SPKI(spki, &p) <= 0) ossl_raise(eX509CertError, NULL); ossl_str_adjust(str, p); @@ -183,8 +183,8 @@ ossl_spki_set_challenge(VALUE self, VALUE str) StringValue(str); GetSPKI(self, spki); - if (!ASN1_STRING_set(spki->spkac->challenge, RSTRING(str)->ptr, - RSTRING(str)->len)) { + if (!ASN1_STRING_set(spki->spkac->challenge, RSTRING_PTR(str), + RSTRING_LEN(str))) { ossl_raise(eSPKIError, NULL); } diff --git a/ext/openssl/ossl_ocsp.c b/ext/openssl/ossl_ocsp.c index b5ea9dadf5..1e8e5903bd 100644 --- a/ext/openssl/ossl_ocsp.c +++ b/ext/openssl/ossl_ocsp.c @@ -109,9 +109,9 @@ ossl_ocspreq_initialize(int argc, VALUE *argv, VALUE self) if(!NIL_P(arg)){ arg = ossl_to_der_if_possible(arg); StringValue(arg); - p = (unsigned char*)RSTRING(arg)->ptr; + p = (unsigned char*)RSTRING_PTR(arg); if(!d2i_OCSP_REQUEST((OCSP_REQUEST**)&DATA_PTR(self), &p, - RSTRING(arg)->len)){ + RSTRING_LEN(arg))){ ossl_raise(eOCSPError, "cannot load DER encoded request"); } } @@ -134,7 +134,7 @@ ossl_ocspreq_add_nonce(int argc, VALUE *argv, VALUE self) else{ StringValue(val); GetOCSPReq(self, req); - ret = OCSP_request_add1_nonce(req, RSTRING(val)->ptr, RSTRING(val)->len); + ret = OCSP_request_add1_nonce(req, RSTRING_PTR(val), RSTRING_LEN(val)); } if(!ret) ossl_raise(eOCSPError, NULL); @@ -265,7 +265,7 @@ ossl_ocspreq_to_der(VALUE self) if((len = i2d_OCSP_REQUEST(req, NULL)) <= 0) ossl_raise(eOCSPError, NULL); str = rb_str_new(0, len); - p = RSTRING(str)->ptr; + p = RSTRING_PTR(str); if(i2d_OCSP_REQUEST(req, &p) <= 0) ossl_raise(eOCSPError, NULL); ossl_str_adjust(str, p); @@ -316,9 +316,9 @@ ossl_ocspres_initialize(int argc, VALUE *argv, VALUE self) if(!NIL_P(arg)){ arg = ossl_to_der_if_possible(arg); StringValue(arg); - p = RSTRING(arg)->ptr; + p = RSTRING_PTR(arg); if(!d2i_OCSP_RESPONSE((OCSP_RESPONSE**)&DATA_PTR(self), &p, - RSTRING(arg)->len)){ + RSTRING_LEN(arg))){ ossl_raise(eOCSPError, "cannot load DER encoded response"); } } @@ -377,7 +377,7 @@ ossl_ocspres_to_der(VALUE self) if((len = i2d_OCSP_RESPONSE(res, NULL)) <= 0) ossl_raise(eOCSPError, NULL); str = rb_str_new(0, len); - p = RSTRING(str)->ptr; + p = RSTRING_PTR(str); if(i2d_OCSP_RESPONSE(res, NULL) <= 0) ossl_raise(eOCSPError, NULL); ossl_str_adjust(str, p); @@ -436,7 +436,7 @@ ossl_ocspbres_add_nonce(int argc, VALUE *argv, VALUE self) else{ StringValue(val); GetOCSPBasicRes(self, bs); - ret = OCSP_basic_add1_nonce(bs, RSTRING(val)->ptr, RSTRING(val)->len); + ret = OCSP_basic_add1_nonce(bs, RSTRING_PTR(val), RSTRING_LEN(val)); } if(!ret) ossl_raise(eOCSPError, NULL); @@ -461,8 +461,8 @@ ossl_ocspbres_add_status(VALUE self, VALUE cid, VALUE status, if(!NIL_P(ext)){ /* All ary's members should be X509Extension */ Check_Type(ext, T_ARRAY); - for (i = 0; i < RARRAY(ext)->len; i++) - OSSL_Check_Kind(RARRAY(ext)->ptr[i], cX509Ext); + for (i = 0; i < RARRAY_LEN(ext); i++) + OSSL_Check_Kind(RARRAY_PTR(ext)[i], cX509Ext); } error = 0; @@ -490,8 +490,8 @@ ossl_ocspbres_add_status(VALUE self, VALUE cid, VALUE status, X509_EXTENSION *x509ext; sk_X509_EXTENSION_pop_free(single->singleExtensions, X509_EXTENSION_free); single->singleExtensions = NULL; - for(i = 0; i < RARRAY(ext)->len; i++){ - x509ext = DupX509ExtPtr(RARRAY(ext)->ptr[i]); + for(i = 0; i < RARRAY_LEN(ext); i++){ + x509ext = DupX509ExtPtr(RARRAY_PTR(ext)[i]); if(!OCSP_SINGLERESP_add_ext(single, x509ext, -1)){ X509_EXTENSION_free(x509ext); error = 1; diff --git a/ext/openssl/ossl_pkcs12.c b/ext/openssl/ossl_pkcs12.c index e7d9954c5a..2ec69ba8db 100644 --- a/ext/openssl/ossl_pkcs12.c +++ b/ext/openssl/ossl_pkcs12.c @@ -30,7 +30,6 @@ /* * Classes */ -VALUE mPKCS12; VALUE cPKCS12; VALUE ePKCS12Error; @@ -49,32 +48,85 @@ ossl_pkcs12_s_allocate(VALUE klass) return obj; } +/* + * call-seq: + * PKCS12.create(pass, name, key, cert [, ca, [, key_pbe [, cert_pbe [, key_iter [, mac_iter [, keytype]]]]]]) + * + * === Parameters + * * +pass+ - string + * * +name+ - A string describing the key. + * * +key+ - Any PKey. + * * +cert+ - A X509::Certificate. + * * * The public_key portion of the certificate must contain a valid public key. + * * * The not_before and not_after fields must be filled in. + * * +ca+ - An optional array of X509::Certificate's. + * * +key_pbe+ - string + * * +cert_pbe+ - string + * * +key_iter+ - integer + * * +mac_iter+ - integer + * * +keytype+ - An integer representing an MSIE specific extension. + * + * Any optional arguments may be supplied as nil to preserve the OpenSSL defaults. + * + * See the OpenSSL documentation for PKCS12_create(). + */ static VALUE ossl_pkcs12_s_create(int argc, VALUE *argv, VALUE self) { - VALUE pass, name, pkey, cert, ca; + VALUE pass, name, pkey, cert, ca, key_nid, cert_nid, key_iter, mac_iter, keytype; VALUE obj; char *passphrase, *friendlyname; EVP_PKEY *key; X509 *x509; STACK_OF(X509) *x509s; + int nkey = 0, ncert = 0, kiter = 0, miter = 0, ktype = 0; PKCS12 *p12; - rb_scan_args(argc, argv, "41", &pass, &name, &pkey, &cert, &ca); + rb_scan_args(argc, argv, "46", &pass, &name, &pkey, &cert, &ca, &key_nid, &cert_nid, &key_iter, &mac_iter, &keytype); passphrase = NIL_P(pass) ? NULL : StringValuePtr(pass); friendlyname = NIL_P(name) ? NULL : StringValuePtr(name); key = GetPKeyPtr(pkey); x509 = GetX509CertPtr(cert); x509s = NIL_P(ca) ? NULL : ossl_x509_ary2sk(ca); +/* TODO: make a VALUE to nid function */ + if (!NIL_P(key_nid)) { + if ((nkey = OBJ_txt2nid(StringValuePtr(key_nid))) == NID_undef) + rb_raise(rb_eArgError, "Unknown PBE algorithm %s", StringValuePtr(key_nid)); + } + if (!NIL_P(cert_nid)) { + if ((ncert = OBJ_txt2nid(StringValuePtr(cert_nid))) == NID_undef) + rb_raise(rb_eArgError, "Unknown PBE algorithm %s", StringValuePtr(cert_nid)); + } + if (!NIL_P(key_iter)) + kiter = NUM2INT(key_iter); + if (!NIL_P(mac_iter)) + miter = NUM2INT(mac_iter); + if (!NIL_P(keytype)) + ktype = NUM2INT(keytype); + p12 = PKCS12_create(passphrase, friendlyname, key, x509, x509s, - 0, 0, 0, 0, 0); + nkey, ncert, kiter, miter, ktype); sk_X509_pop_free(x509s, X509_free); if(!p12) ossl_raise(ePKCS12Error, NULL); WrapPKCS12(cPKCS12, obj, p12); + ossl_pkcs12_set_key(obj, pkey); + ossl_pkcs12_set_cert(obj, cert); + ossl_pkcs12_set_ca_certs(obj, ca); + return obj; } +/* + * call-seq: + * PKCS12.new -> pkcs12 + * PKCS12.new(str) -> pkcs12 + * PKCS12.new(str, pass) -> pkcs12 + * + * === Parameters + * * +str+ - Must be a DER encoded PKCS12 string. + * * +pass+ - string + */ static VALUE ossl_pkcs12_initialize(int argc, VALUE *argv, VALUE self) { @@ -94,7 +146,7 @@ ossl_pkcs12_initialize(int argc, VALUE *argv, VALUE self) pkey = cert = ca = Qnil; if(!PKCS12_parse((PKCS12*)DATA_PTR(self), passphrase, &key, &x509, &x509s)) - ossl_raise(ePKCS12Error, NULL); + ossl_raise(ePKCS12Error, "PKCS12_parse"); pkey = rb_protect((VALUE(*)_((VALUE)))ossl_pkey_new, (VALUE)key, &st); /* NO DUP */ if(st) goto err; @@ -129,7 +181,7 @@ ossl_pkcs12_to_der(VALUE self) if((len = i2d_PKCS12(p12, NULL)) <= 0) ossl_raise(ePKCS12Error, NULL); str = rb_str_new(0, len); - p = RSTRING(str)->ptr; + p = RSTRING_PTR(str); if(i2d_PKCS12(p12, &p) <= 0) ossl_raise(ePKCS12Error, NULL); ossl_str_adjust(str, p); @@ -140,10 +192,14 @@ ossl_pkcs12_to_der(VALUE self) void Init_ossl_pkcs12() { - mPKCS12 = rb_define_module_under(mOSSL, "PKCS12"); - cPKCS12 = rb_define_class_under(mPKCS12, "PKCS12", rb_cObject); - ePKCS12Error = rb_define_class_under(mPKCS12, "PKCS12Error", eOSSLError); - rb_define_module_function(mPKCS12, "create", ossl_pkcs12_s_create, -1); + /* + * Defines a file format commonly used to store private keys with + * accompanying public key certificates, protected with a password-based + * symmetric key. + */ + cPKCS12 = rb_define_class_under(mOSSL, "PKCS12", rb_cObject); + ePKCS12Error = rb_define_class_under(cPKCS12, "PKCS12Error", eOSSLError); + rb_define_singleton_method(cPKCS12, "create", ossl_pkcs12_s_create, -1); rb_define_alloc_func(cPKCS12, ossl_pkcs12_s_allocate); rb_attr(cPKCS12, rb_intern("key"), 1, 0, Qfalse); diff --git a/ext/openssl/ossl_pkcs12.h b/ext/openssl/ossl_pkcs12.h index 01dde2bc30..24d25d00bb 100644 --- a/ext/openssl/ossl_pkcs12.h +++ b/ext/openssl/ossl_pkcs12.h @@ -6,7 +6,6 @@ #if !defined(_OSSL_PKCS12_H_) #define _OSSL_PKCS12_H_ -extern VALUE mPKCS12; extern VALUE cPKCS12; extern VALUE ePKCS12Error; diff --git a/ext/openssl/ossl_pkcs5.c b/ext/openssl/ossl_pkcs5.c new file mode 100644 index 0000000000..ca02a18c67 --- /dev/null +++ b/ext/openssl/ossl_pkcs5.c @@ -0,0 +1,96 @@ +/* + * $Id$ + * Copyright (C) 2007 Technorama Ltd. <oss-ruby@technorama.net> + */ +#include "ossl.h" + +VALUE mPKCS5; +VALUE ePKCS5; + +/* + * call-seq: + * PKCS5.pbkdf2_hmac(pass, salt, iter, keylen, digest) => string + * + * === Parameters + * * +pass+ - string + * * +salt+ - string + * * +iter+ - integer - should be greater than 1000. 2000 is better. + * * +keylen+ - integer + * * +digest+ - a string or OpenSSL::Digest object. + * + * Available in OpenSSL 0.9.9?. + * + * Digests other than SHA1 may not be supported by other cryptography libraries. + */ +static VALUE +ossl_pkcs5_pbkdf2_hmac(VALUE self, VALUE pass, VALUE salt, VALUE iter, VALUE keylen, VALUE digest) +{ +#ifdef HAVE_PKCS5_PBKDF2_HMAC + VALUE str; + const EVP_MD md; + int len = NUM2INT(keylen); + + StringValue(pass); + StringValue(salt); + md = GetDigestPtr(digest); + + str = rb_str_new(0, len); + + if (PKCS5_PBKDF2_HMAC(RSTRING_PTR(pass), RSTRING_LEN(pass), RSTRING_PTR(salt), RSTRING_LEN(salt), NUM2INT(iter), md, len, RSTRING_PTR(str)) != 1) + ossl_raise(ePKCS5, "PKCS5_PBKDF2_HMAC"); + + return str; +#else + rb_notimplement(); +#endif +} + + +/* + * call-seq: + * PKCS5.pbkdf2_hmac_sha1(pass, salt, iter, keylen) => string + * + * === Parameters + * * +pass+ - string + * * +salt+ - string + * * +iter+ - integer - should be greater than 1000. 2000 is better. + * * +keylen+ - integer + * + * This method is available almost any version OpenSSL. + * + * Conforms to rfc2898. + */ +static VALUE +ossl_pkcs5_pbkdf2_hmac_sha1(VALUE self, VALUE pass, VALUE salt, VALUE iter, VALUE keylen) +{ +#ifdef HAVE_PKCS5_PBKDF2_HMAC_SHA1 + VALUE str; + int len = NUM2INT(keylen); + + StringValue(pass); + StringValue(salt); + + str = rb_str_new(0, len); + + if (PKCS5_PBKDF2_HMAC_SHA1(RSTRING_PTR(pass), RSTRING_LEN(pass), RSTRING_PTR(salt), RSTRING_LEN(salt), NUM2INT(iter), len, RSTRING_PTR(str)) != 1) + ossl_raise(ePKCS5, "PKCS5_PBKDF2_HMAC_SHA1"); + + return str; +#else + rb_notimplement(); +#endif +} + +void +Init_ossl_pkcs5() +{ + /* + * Password-based Encryption + * + */ + mPKCS5 = rb_define_module_under(mOSSL, "PKCS5"); + ePKCS5 = rb_define_class_under(mPKCS5, "PKCS5Error", eOSSLError); + + rb_define_module_function(mPKCS5, "pbkdf2_hmac", ossl_pkcs5_pbkdf2_hmac, 5); + rb_define_module_function(mPKCS5, "pbkdf2_hmac_sha1", ossl_pkcs5_pbkdf2_hmac_sha1, 4); +} diff --git a/ext/openssl/ossl_pkcs7.c b/ext/openssl/ossl_pkcs7.c index 0fcabd7777..6918844779 100644 --- a/ext/openssl/ossl_pkcs7.c +++ b/ext/openssl/ossl_pkcs7.c @@ -71,7 +71,6 @@ /* * Classes */ -VALUE mPKCS7; VALUE cPKCS7; VALUE cPKCS7Signer; VALUE cPKCS7Recipient; @@ -134,7 +133,8 @@ DupPKCS7RecipientPtr(VALUE obj) } /* - * Private + * call-seq: + * PKCS7.read_smime(string) => pkcs7 */ static VALUE ossl_pkcs7_s_read_smime(VALUE klass, VALUE arg) @@ -156,6 +156,10 @@ ossl_pkcs7_s_read_smime(VALUE klass, VALUE arg) return ret; } +/* + * call-seq: + * PKCS7.write_smime(pkcs7 [, data [, flags]]) => string + */ static VALUE ossl_pkcs7_s_write_smime(int argc, VALUE *argv, VALUE klass) { @@ -187,6 +191,10 @@ ossl_pkcs7_s_write_smime(int argc, VALUE *argv, VALUE klass) return str; } +/* + * call-seq: + * PKCS7.sign(cert, key, data, [, certs [, flags]]) => pkcs7 + */ static VALUE ossl_pkcs7_s_sign(int argc, VALUE *argv, VALUE klass) { @@ -226,6 +234,10 @@ ossl_pkcs7_s_sign(int argc, VALUE *argv, VALUE klass) return ret; } +/* + * call-seq: + * PKCS7.encrypt(certs, data, [, cipher [, flags]]) => pkcs7 + */ static VALUE ossl_pkcs7_s_encrypt(int argc, VALUE *argv, VALUE klass) { @@ -287,6 +299,13 @@ ossl_pkcs7_alloc(VALUE klass) return obj; } +/* + * call-seq: + * PKCS7.new => pkcs7 + * PKCS7.new(string) => pkcs7 + * + * Many methods in this class aren't documented. + */ static VALUE ossl_pkcs7_initialize(int argc, VALUE *argv, VALUE self) { @@ -335,7 +354,7 @@ static int ossl_pkcs7_sym2typeid(VALUE sym) { int i, ret = Qnil; - char *s; + const char *s; static struct { const char *name; @@ -364,6 +383,10 @@ ossl_pkcs7_sym2typeid(VALUE sym) return ret; } +/* + * call-seq: + * pkcs7.type = type => type + */ static VALUE ossl_pkcs7_set_type(VALUE self, VALUE type) { @@ -376,6 +399,10 @@ ossl_pkcs7_set_type(VALUE self, VALUE type) return type; } +/* + * call-seq: + * pkcs7.type => string or nil + */ static VALUE ossl_pkcs7_get_type(VALUE self) { @@ -583,7 +610,7 @@ ossl_pkcs7_set_certificates(VALUE self, VALUE ary) certs = pkcs7_get_certs_or_crls(self, 1); while((cert = sk_X509_pop(certs))) X509_free(cert); - rb_iterate(rb_each, ary, ossl_pkcs7_set_certs_i, self); + rb_block_call(ary, rb_intern("each"), 0, 0, ossl_pkcs7_set_certs_i, self); return ary; } @@ -623,7 +650,7 @@ ossl_pkcs7_set_crls(VALUE self, VALUE ary) crls = pkcs7_get_certs_or_crls(self, 0); while((crl = sk_X509_CRL_pop(crls))) X509_CRL_free(crl); - rb_iterate(rb_each, ary, ossl_pkcs7_set_crls_i, self); + rb_block_call(ary, rb_intern("each"), 0, 0, ossl_pkcs7_set_crls_i, self); return ary; } @@ -751,7 +778,7 @@ ossl_pkcs7_to_der(VALUE self) if((len = i2d_PKCS7(pkcs7, NULL)) <= 0) ossl_raise(ePKCS7Error, NULL); str = rb_str_new(0, len); - p = RSTRING(str)->ptr; + p = RSTRING_PTR(str); if(i2d_PKCS7(pkcs7, &p) <= 0) ossl_raise(ePKCS7Error, NULL); ossl_str_adjust(str, p); @@ -926,15 +953,12 @@ ossl_pkcs7ri_get_enc_key(VALUE self) void Init_ossl_pkcs7() { - mPKCS7 = rb_define_module_under(mOSSL, "PKCS7"); - - ePKCS7Error = rb_define_class_under(mPKCS7, "PKCS7Error", eOSSLError); - - cPKCS7 = rb_define_class_under(mPKCS7, "PKCS7", rb_cObject); - rb_define_singleton_method(mPKCS7, "read_smime", ossl_pkcs7_s_read_smime, 1); - rb_define_singleton_method(mPKCS7, "write_smime", ossl_pkcs7_s_write_smime, -1); - rb_define_singleton_method(mPKCS7, "sign", ossl_pkcs7_s_sign, -1); - rb_define_singleton_method(mPKCS7, "encrypt", ossl_pkcs7_s_encrypt, -1); + cPKCS7 = rb_define_class_under(mOSSL, "PKCS7", rb_cObject); + ePKCS7Error = rb_define_class_under(cPKCS7, "PKCS7Error", eOSSLError); + rb_define_singleton_method(cPKCS7, "read_smime", ossl_pkcs7_s_read_smime, 1); + rb_define_singleton_method(cPKCS7, "write_smime", ossl_pkcs7_s_write_smime, -1); + rb_define_singleton_method(cPKCS7, "sign", ossl_pkcs7_s_sign, -1); + rb_define_singleton_method(cPKCS7, "encrypt", ossl_pkcs7_s_encrypt, -1); rb_attr(cPKCS7, rb_intern("data"), 1, 0, Qfalse); rb_attr(cPKCS7, rb_intern("error_string"), 1, 1, Qfalse); rb_define_alloc_func(cPKCS7, ossl_pkcs7_alloc); @@ -964,8 +988,8 @@ Init_ossl_pkcs7() rb_define_alias(cPKCS7, "to_s", "to_pem"); rb_define_method(cPKCS7, "to_der", ossl_pkcs7_to_der, 0); - cPKCS7Signer = rb_define_class_under(mPKCS7, "SignerInfo", rb_cObject); - rb_define_const(mPKCS7, "Signer", cPKCS7Signer); + cPKCS7Signer = rb_define_class_under(cPKCS7, "SignerInfo", rb_cObject); + rb_define_const(cPKCS7, "Signer", cPKCS7Signer); rb_define_alloc_func(cPKCS7Signer, ossl_pkcs7si_alloc); rb_define_method(cPKCS7Signer, "initialize", ossl_pkcs7si_initialize,3); rb_define_method(cPKCS7Signer, "issuer", ossl_pkcs7si_get_issuer, 0); @@ -973,14 +997,14 @@ Init_ossl_pkcs7() rb_define_method(cPKCS7Signer, "serial", ossl_pkcs7si_get_serial,0); rb_define_method(cPKCS7Signer,"signed_time",ossl_pkcs7si_get_signed_time,0); - cPKCS7Recipient = rb_define_class_under(mPKCS7,"RecipientInfo",rb_cObject); + cPKCS7Recipient = rb_define_class_under(cPKCS7,"RecipientInfo",rb_cObject); rb_define_alloc_func(cPKCS7Recipient, ossl_pkcs7ri_alloc); rb_define_method(cPKCS7Recipient, "initialize", ossl_pkcs7ri_initialize,1); rb_define_method(cPKCS7Recipient, "issuer", ossl_pkcs7ri_get_issuer,0); rb_define_method(cPKCS7Recipient, "serial", ossl_pkcs7ri_get_serial,0); rb_define_method(cPKCS7Recipient, "enc_key", ossl_pkcs7ri_get_enc_key,0); -#define DefPKCS7Const(x) rb_define_const(mPKCS7, #x, INT2NUM(PKCS7_##x)) +#define DefPKCS7Const(x) rb_define_const(cPKCS7, #x, INT2NUM(PKCS7_##x)) DefPKCS7Const(TEXT); DefPKCS7Const(NOCERTS); diff --git a/ext/openssl/ossl_pkcs7.h b/ext/openssl/ossl_pkcs7.h index f5942d65db..371c421103 100644 --- a/ext/openssl/ossl_pkcs7.h +++ b/ext/openssl/ossl_pkcs7.h @@ -11,7 +11,6 @@ #if !defined(_OSSL_PKCS7_H_) #define _OSSL_PKCS7_H_ -extern VALUE mPKCS7; extern VALUE cPKCS7; extern VALUE cPKCS7Signer; extern VALUE cPKCS7Recipient; diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c index d54f5b938e..b295cfc25e 100644 --- a/ext/openssl/ossl_pkey.c +++ b/ext/openssl/ossl_pkey.c @@ -55,6 +55,10 @@ ossl_pkey_new(EVP_PKEY *pkey) case EVP_PKEY_DH: return ossl_dh_new(pkey); #endif +#if !defined(OPENSSL_NO_EC) && (OPENSSL_VERSION_NUMBER >= 0x0090802fL) + case EVP_PKEY_EC: + return ossl_ec_new(pkey); +#endif default: ossl_raise(ePKeyError, "unsupported key type"); } @@ -68,7 +72,7 @@ ossl_pkey_new_from_file(VALUE filename) EVP_PKEY *pkey; SafeStringValue(filename); - if (!(fp = fopen(RSTRING(filename)->ptr, "r"))) { + if (!(fp = fopen(RSTRING_PTR(filename), "r"))) { ossl_raise(ePKeyError, "%s", strerror(errno)); } @@ -108,7 +112,7 @@ EVP_PKEY * DupPKeyPtr(VALUE obj) { EVP_PKEY *pkey; - + SafeGetPKey(obj, pkey); CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY); @@ -169,13 +173,12 @@ ossl_pkey_sign(VALUE self, VALUE digest, VALUE data) GetPKey(self, pkey); EVP_SignInit(&ctx, GetDigestPtr(digest)); StringValue(data); - EVP_SignUpdate(&ctx, RSTRING(data)->ptr, RSTRING(data)->len); + EVP_SignUpdate(&ctx, RSTRING_PTR(data), RSTRING_LEN(data)); str = rb_str_new(0, EVP_PKEY_size(pkey)+16); - if (!EVP_SignFinal(&ctx, RSTRING(str)->ptr, &buf_len, pkey)) + if (!EVP_SignFinal(&ctx, RSTRING_PTR(str), &buf_len, pkey)) ossl_raise(ePKeyError, NULL); - assert(buf_len <= RSTRING(str)->len); - RSTRING(str)->len = buf_len; - RSTRING(str)->ptr[buf_len] = 0; + assert(buf_len <= RSTRING_LEN(str)); + rb_str_set_len(str, buf_len); return str; } @@ -190,8 +193,8 @@ ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data) EVP_VerifyInit(&ctx, GetDigestPtr(digest)); StringValue(sig); StringValue(data); - EVP_VerifyUpdate(&ctx, RSTRING(data)->ptr, RSTRING(data)->len); - switch (EVP_VerifyFinal(&ctx, RSTRING(sig)->ptr, RSTRING(sig)->len, pkey)) { + EVP_VerifyUpdate(&ctx, RSTRING_PTR(data), RSTRING_LEN(data)); + switch (EVP_VerifyFinal(&ctx, RSTRING_PTR(sig), RSTRING_LEN(sig), pkey)) { case 0: return Qfalse; case 1: @@ -227,10 +230,11 @@ Init_ossl_pkey() id_private_q = rb_intern("private?"); /* - * INIT rsa, dsa + * INIT rsa, dsa, dh, ec */ Init_ossl_rsa(); Init_ossl_dsa(); Init_ossl_dh(); + Init_ossl_ec(); } diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h index 880a104675..67ff1fddd0 100644 --- a/ext/openssl/ossl_pkey.h +++ b/ext/openssl/ossl_pkey.h @@ -77,7 +77,24 @@ extern DH *OSSL_DEFAULT_DH_1024; VALUE ossl_dh_new(EVP_PKEY *); void Init_ossl_dh(void); +/* + * EC + */ +extern VALUE cEC; +extern VALUE eECError; +extern VALUE cEC_GROUP; +extern VALUE eEC_GROUP; +extern VALUE cEC_POINT; +extern VALUE eEC_POINT; +VALUE ossl_ec_new(EVP_PKEY *); +void Init_ossl_ec(void); + + #define OSSL_PKEY_BN(keytype, name) \ +/* \ + * call-seq: \ + * key.##name -> aBN \ + */ \ static VALUE ossl_##keytype##_get_##name(VALUE self) \ { \ EVP_PKEY *pkey; \ @@ -89,6 +106,10 @@ static VALUE ossl_##keytype##_get_##name(VALUE self) \ return Qnil; \ return ossl_bn_new(bn); \ } \ +/* \ + * call-seq: \ + * key.##name = bn -> bn \ + */ \ static VALUE ossl_##keytype##_set_##name(VALUE self, VALUE bignum) \ { \ EVP_PKEY *pkey; \ diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c index e16ede8bba..a6924a6bb8 100644 --- a/ext/openssl/ossl_pkey_dh.c +++ b/ext/openssl/ossl_pkey_dh.c @@ -99,6 +99,15 @@ dh_generate(int size, int gen) return dh; } +/* + * call-seq: + * DH.generate(size [, generator]) -> dh + * + * === Parameters + * * +size+ is an integer representing the desired key size. Keys smaller than 1024 should be considered insecure. + * * +generator+ is a small number > 1, typically 2 or 5. + * + */ static VALUE ossl_dh_s_generate(int argc, VALUE *argv, VALUE klass) { @@ -119,6 +128,21 @@ ossl_dh_s_generate(int argc, VALUE *argv, VALUE klass) return obj; } +/* + * call-seq: + * DH.new([size [, generator] | string]) -> dh + * + * === Parameters + * * +size+ is an integer representing the desired key size. Keys smaller than 1024 should be considered insecure. + * * +generator+ is a small number > 1, typically 2 or 5. + * * +string+ contains the DER or PEM encoded key. + * + * === Examples + * * DH.new -> dh + * * DH.new(1024) -> dh + * * DH.new(1024, 5) -> dh + * * DH.new(File.read('key.pem')) -> dh + */ static VALUE ossl_dh_initialize(int argc, VALUE *argv, VALUE self) { @@ -158,19 +182,26 @@ ossl_dh_initialize(int argc, VALUE *argv, VALUE self) return self; } +/* + * call-seq: + * dh.public? -> true | false + * + */ static VALUE ossl_dh_is_public(VALUE self) { EVP_PKEY *pkey; GetPKeyDH(self, pkey); - /* - * Do we need to check dhp->dh->public_pkey? - * return Qtrue; - */ + return (pkey->pkey.dh->pub_key) ? Qtrue : Qfalse; } +/* + * call-seq: + * dh.private? -> true | false + * + */ static VALUE ossl_dh_is_private(VALUE self) { @@ -181,6 +212,11 @@ ossl_dh_is_private(VALUE self) return (DH_PRIVATE(pkey->pkey.dh)) ? Qtrue : Qfalse; } +/* + * call-seq: + * dh.to_pem -> aString + * + */ static VALUE ossl_dh_export(VALUE self) { @@ -201,6 +237,11 @@ ossl_dh_export(VALUE self) return str; } +/* + * call-seq: + * dh.to_der -> aString + * + */ static VALUE ossl_dh_to_der(VALUE self) { @@ -213,7 +254,7 @@ ossl_dh_to_der(VALUE self) if((len = i2d_DHparams(pkey->pkey.dh, NULL)) <= 0) ossl_raise(eDHError, NULL); str = rb_str_new(0, len); - p = RSTRING(str)->ptr; + p = RSTRING_PTR(str); if(i2d_DHparams(pkey->pkey.dh, &p) < 0) ossl_raise(eDHError, NULL); ossl_str_adjust(str, p); @@ -222,6 +263,9 @@ ossl_dh_to_der(VALUE self) } /* + * call-seq: + * dh.params -> hash + * * Stores all parameters of key to the hash * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!! * Don't use :-)) (I's up to you) @@ -245,6 +289,9 @@ ossl_dh_get_params(VALUE self) } /* + * call-seq: + * dh.to_text -> aString + * * Prints all parameters of key to buffer * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!! * Don't use :-)) (I's up to you) @@ -270,7 +317,10 @@ ossl_dh_to_text(VALUE self) } /* - * Makes new instance DH PUBLIC_KEY from PRIVATE_KEY + * call-seq: + * dh.public_key -> aDH + * + * Makes new instance DH PUBLIC_KEY from PRIVATE_KEY */ static VALUE ossl_dh_to_public_key(VALUE self) @@ -290,6 +340,11 @@ ossl_dh_to_public_key(VALUE self) return obj; } +/* + * call-seq: + * dh.check_params -> true | false + * + */ static VALUE ossl_dh_check_params(VALUE self) { @@ -307,6 +362,11 @@ ossl_dh_check_params(VALUE self) return codes == 0 ? Qtrue : Qfalse; } +/* + * call-seq: + * dh.generate_key -> self + * + */ static VALUE ossl_dh_generate_key(VALUE self) { @@ -321,6 +381,18 @@ ossl_dh_generate_key(VALUE self) return self; } +/* + * call-seq: + * dh.compute_key(pub_bn) -> aString + * + * === Parameters + * * +pub_bn+ is a OpenSSL::BN. + * + * Returns aString containing a shared secret computed from the other parties public value. + * + * See DH_compute_key() for further information. + * + */ static VALUE ossl_dh_compute_key(VALUE self, VALUE pub) { @@ -335,11 +407,10 @@ ossl_dh_compute_key(VALUE self, VALUE pub) pub_key = GetBNPtr(pub); len = DH_size(dh); str = rb_str_new(0, len); - if ((len = DH_compute_key(RSTRING(str)->ptr, pub_key, dh)) < 0) { + if ((len = DH_compute_key(RSTRING_PTR(str), pub_key, dh)) < 0) { ossl_raise(eDHError, NULL); } - RSTRING(str)->len = len; - RSTRING(str)->ptr[len] = 0; + rb_str_set_len(str, len); return str; } @@ -367,7 +438,7 @@ static unsigned char DEFAULT_DH_512_PRIM[] = { }; static unsigned char DEFAULT_DH_512_GEN[] = { 0x02 }; DH *OSSL_DEFAULT_DH_512 = NULL; - + /* * -----BEGIN DH PARAMETERS----- * MIGHAoGBAJ0lOVy0VIr/JebWn0zDwY2h+rqITFOpdNr6ugsgvkDXuucdcChhYExJ @@ -406,7 +477,7 @@ ossl_create_dh(unsigned char *p, size_t plen, unsigned char *g, size_t glen) dh->g = BN_bin2bn(g, glen, NULL); if (dh->p == NULL || dh->g == NULL){ DH_free(dh); - ossl_raise(eDHError, NULL); + ossl_raise(eDHError, NULL); } return dh; diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c index fdf23aa496..95dc426366 100644 --- a/ext/openssl/ossl_pkey_dsa.c +++ b/ext/openssl/ossl_pkey_dsa.c @@ -99,6 +99,14 @@ dsa_generate(int size) return dsa; } +/* + * call-seq: + * DSA.generate(size) -> dsa + * + * === Parameters + * * +size+ is an integer representing the desired key size. + * + */ static VALUE ossl_dsa_s_generate(VALUE klass, VALUE size) { @@ -113,6 +121,22 @@ ossl_dsa_s_generate(VALUE klass, VALUE size) return obj; } +/* + * call-seq: + * DSA.new([size | string [, pass]) -> dsa + * + * === Parameters + * * +size+ is an integer representing the desired key size. + * * +string+ contains a DER or PEM encoded key. + * * +pass+ is a string that contains a optional password. + * + * === Examples + * * DSA.new -> dsa + * * DSA.new(1024) -> dsa + * * DSA.new(File.read('dsa.pem')) -> dsa + * * DSA.new(File.read('dsa.pem'), 'mypassword') -> dsa + * + */ static VALUE ossl_dsa_initialize(int argc, VALUE *argv, VALUE self) { @@ -163,6 +187,11 @@ ossl_dsa_initialize(int argc, VALUE *argv, VALUE self) return self; } +/* + * call-seq: + * dsa.public? -> true | false + * + */ static VALUE ossl_dsa_is_public(VALUE self) { @@ -170,13 +199,14 @@ ossl_dsa_is_public(VALUE self) GetPKeyDSA(self, pkey); - /* - * Do we need to check dsap->dsa->public_pkey? - * return Qtrue; - */ return (pkey->pkey.dsa->pub_key) ? Qtrue : Qfalse; } +/* + * call-seq: + * dsa.private? -> true | false + * + */ static VALUE ossl_dsa_is_private(VALUE self) { @@ -187,6 +217,19 @@ ossl_dsa_is_private(VALUE self) return (DSA_PRIVATE(self, pkey->pkey.dsa)) ? Qtrue : Qfalse; } +/* + * call-seq: + * dsa.to_pem([cipher, password]) -> aString + * + * === Parameters + * +cipher+ is an OpenSSL::Cipher. + * +password+ is a string containing your password. + * + * === Examples + * * DSA.to_pem -> aString + * * DSA.to_pem(cipher, 'mypassword') -> aString + * + */ static VALUE ossl_dsa_export(int argc, VALUE *argv, VALUE self) { @@ -224,6 +267,11 @@ ossl_dsa_export(int argc, VALUE *argv, VALUE self) return str; } +/* + * call-seq: + * dsa.to_der -> aString + * + */ static VALUE ossl_dsa_to_der(VALUE self) { @@ -241,7 +289,7 @@ ossl_dsa_to_der(VALUE self) if((len = i2d_func(pkey->pkey.dsa, NULL)) <= 0) ossl_raise(eDSAError, NULL); str = rb_str_new(0, len); - p = RSTRING(str)->ptr; + p = RSTRING_PTR(str); if(i2d_func(pkey->pkey.dsa, &p) < 0) ossl_raise(eDSAError, NULL); ossl_str_adjust(str, p); @@ -250,6 +298,9 @@ ossl_dsa_to_der(VALUE self) } /* + * call-seq: + * dsa.params -> hash + * * Stores all parameters of key to the hash * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!! * Don't use :-)) (I's up to you) @@ -274,6 +325,9 @@ ossl_dsa_get_params(VALUE self) } /* + * call-seq: + * dsa.to_text -> aString + * * Prints all parameters of key to buffer * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!! * Don't use :-)) (I's up to you) @@ -299,6 +353,9 @@ ossl_dsa_to_text(VALUE self) } /* + * call-seq: + * dsa.public_key -> aDSA + * * Makes new instance DSA PUBLIC_KEY from PRIVATE_KEY */ static VALUE @@ -321,6 +378,11 @@ ossl_dsa_to_public_key(VALUE self) #define ossl_dsa_buf_size(pkey) (DSA_size((pkey)->pkey.dsa)+16) +/* + * call-seq: + * dsa.syssign(string) -> aString + * + */ static VALUE ossl_dsa_sign(VALUE self, VALUE data) { @@ -334,16 +396,20 @@ ossl_dsa_sign(VALUE self, VALUE data) ossl_raise(eDSAError, "Private DSA key needed!"); } str = rb_str_new(0, ossl_dsa_buf_size(pkey)); - if (!DSA_sign(0, RSTRING(data)->ptr, RSTRING(data)->len, RSTRING(str)->ptr, + if (!DSA_sign(0, RSTRING_PTR(data), RSTRING_LEN(data), RSTRING_PTR(str), &buf_len, pkey->pkey.dsa)) { /* type is ignored (0) */ ossl_raise(eDSAError, NULL); } - RSTRING(str)->len = buf_len; - RSTRING(str)->ptr[buf_len] = 0; + rb_str_set_len(str, buf_len); return str; } +/* + * call-seq: + * dsa.sysverify(digest, sig) -> true | false + * + */ static VALUE ossl_dsa_verify(VALUE self, VALUE digest, VALUE sig) { @@ -354,8 +420,8 @@ ossl_dsa_verify(VALUE self, VALUE digest, VALUE sig) StringValue(digest); StringValue(sig); /* type is ignored (0) */ - ret = DSA_verify(0, RSTRING(digest)->ptr, RSTRING(digest)->len, - RSTRING(sig)->ptr, RSTRING(sig)->len, pkey->pkey.dsa); + ret = DSA_verify(0, RSTRING_PTR(digest), RSTRING_LEN(digest), + RSTRING_PTR(sig), RSTRING_LEN(sig), pkey->pkey.dsa); if (ret < 0) { ossl_raise(eDSAError, NULL); } diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c new file mode 100644 index 0000000000..fbbd17843a --- /dev/null +++ b/ext/openssl/ossl_pkey_ec.c @@ -0,0 +1,1438 @@ +/* + * Copyright (C) 2006-2007 Technorama Ltd. <oss-ruby@technorama.net> + */ + +#include "ossl.h" + +#if !defined(OPENSSL_NO_EC) && (OPENSSL_VERSION_NUMBER >= 0x0090802fL) + +typedef struct { + EC_GROUP *group; + int dont_free; +} ossl_ec_group; + +typedef struct { + EC_POINT *point; + int dont_free; +} ossl_ec_point; + + +#define EXPORT_PEM 0 +#define EXPORT_DER 1 + + +#define GetPKeyEC(obj, pkey) do { \ + GetPKey(obj, pkey); \ + if (EVP_PKEY_type(pkey->type) != EVP_PKEY_EC) { \ + ossl_raise(rb_eRuntimeError, "THIS IS NOT A EC PKEY!"); \ + } \ +} while (0) + +#define SafeGet_ec_group(obj, group) do { \ + OSSL_Check_Kind(obj, cEC_GROUP); \ + Data_Get_Struct(obj, ossl_ec_group, group); \ +} while(0) + +#define Get_EC_KEY(obj, key) do { \ + EVP_PKEY *pkey; \ + GetPKeyEC(obj, pkey); \ + key = pkey->pkey.ec; \ +} while(0) + +#define Require_EC_KEY(obj, key) do { \ + Get_EC_KEY(obj, key); \ + if (key == NULL) \ + rb_raise(eECError, "EC_KEY is not initialized"); \ +} while(0) + +#define SafeRequire_EC_KEY(obj, key) do { \ + OSSL_Check_Kind(obj, cEC); \ + Require_EC_KEY(obj, key); \ +} while (0) + +#define Get_EC_GROUP(obj, g) do { \ + ossl_ec_group *ec_group; \ + Data_Get_Struct(obj, ossl_ec_group, ec_group); \ + if (ec_group == NULL) \ + rb_raise(eEC_GROUP, "missing ossl_ec_group structure"); \ + g = ec_group->group; \ +} while(0) + +#define Require_EC_GROUP(obj, group) do { \ + Get_EC_GROUP(obj, group); \ + if (group == NULL) \ + rb_raise(eEC_GROUP, "EC_GROUP is not initialized"); \ +} while(0) + +#define SafeRequire_EC_GROUP(obj, group) do { \ + OSSL_Check_Kind(obj, cEC_GROUP); \ + Require_EC_GROUP(obj, group); \ +} while(0) + +#define Get_EC_POINT(obj, p) do { \ + ossl_ec_point *ec_point; \ + Data_Get_Struct(obj, ossl_ec_point, ec_point); \ + if (ec_point == NULL) \ + rb_raise(eEC_POINT, "missing ossl_ec_point structure"); \ + p = ec_point->point; \ +} while(0) + +#define Require_EC_POINT(obj, point) do { \ + Get_EC_POINT(obj, point); \ + if (point == NULL) \ + rb_raise(eEC_POINT, "EC_POINT is not initialized"); \ +} while(0) + +#define SafeRequire_EC_POINT(obj, point) do { \ + OSSL_Check_Kind(obj, cEC_POINT); \ + Require_EC_POINT(obj, point); \ +} while(0) + +VALUE cEC; +VALUE eECError; +VALUE cEC_GROUP; +VALUE eEC_GROUP; +VALUE cEC_POINT; +VALUE eEC_POINT; + +static ID s_GFp; +static ID s_GFp_simple; +static ID s_GFp_mont; +static ID s_GFp_nist; +static ID s_GF2m; +static ID s_GF2m_simple; + +static ID ID_uncompressed; +static ID ID_compressed; +static ID ID_hybrid; + +static VALUE ec_instance(VALUE klass, EC_KEY *ec) +{ + EVP_PKEY *pkey; + VALUE obj; + + if (!ec) { + return Qfalse; + } + if (!(pkey = EVP_PKEY_new())) { + return Qfalse; + } + if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) { + EVP_PKEY_free(pkey); + return Qfalse; + } + WrapPKey(klass, obj, pkey); + + return obj; +} + +VALUE ossl_ec_new(EVP_PKEY *pkey) +{ + VALUE obj; + + if (!pkey) { + obj = ec_instance(cEC, EC_KEY_new()); + } else { + if (EVP_PKEY_type(pkey->type) != EVP_PKEY_EC) { + ossl_raise(rb_eTypeError, "Not a EC key!"); + } + WrapPKey(cEC, obj, pkey); + } + if (obj == Qfalse) { + ossl_raise(eECError, NULL); + } + + return obj; +} + + +/* call-seq: + * OpenSSL::PKey::EC.new() + * OpenSSL::PKey::EC.new(ec_key) + * OpenSSL::PKey::EC.new(ec_group) + * OpenSSL::PKey::EC.new("secp112r1") + * OpenSSL::PKey::EC.new(pem_string) + * OpenSSL::PKey::EC.new(der_string) + * + * See the OpenSSL documentation for: + * EC_KEY_* + */ +static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self) +{ + EVP_PKEY *pkey; + EC_KEY *ec = NULL; + VALUE arg, pass; + VALUE group = Qnil; + + GetPKey(self, pkey); + if (pkey->pkey.ec) + rb_raise(eECError, "EC_KEY already initialized"); + + rb_scan_args(argc, argv, "02", &arg, &pass); + + if (NIL_P(arg)) { + ec = EC_KEY_new(); + } else { + if (rb_obj_is_kind_of(arg, cEC)) { + EC_KEY *other_ec = NULL; + + SafeRequire_EC_KEY(arg, other_ec); + ec = EC_KEY_dup(other_ec); + } else if (rb_obj_is_kind_of(arg, cEC_GROUP)) { + ec = EC_KEY_new(); + group = arg; + } else { + BIO *in = ossl_obj2bio(arg); + + ec = PEM_read_bio_ECPrivateKey(in, NULL, NULL, NULL); + if (!ec) { + BIO_reset(in); + ec = PEM_read_bio_EC_PUBKEY(in, NULL, NULL, NULL); + } + if (!ec) { + BIO_reset(in); + ec = d2i_ECPrivateKey_bio(in, NULL); + } + if (!ec) { + BIO_reset(in); + ec = d2i_EC_PUBKEY_bio(in, NULL); + } + + BIO_free(in); + + if (ec == NULL) { + const char *name = STR2CSTR(arg); + int nid = OBJ_sn2nid(name); + + if (nid == NID_undef) + ossl_raise(eECError, "unknown curve name (%s)\n", name); + + if ((ec = EC_KEY_new_by_curve_name(nid)) == NULL) + ossl_raise(eECError, "unable to create curve (%s)\n", name); + } + } + } + + if (ec == NULL) + ossl_raise(eECError, NULL); + + if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) { + EC_KEY_free(ec); + ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY"); + } + + rb_iv_set(self, "@group", Qnil); + + if (!NIL_P(group)) + rb_funcall(self, rb_intern("group="), 1, arg); + + return self; +} + +/* + * call-seq: + * key.group => group + * + * Returns a constant <code>OpenSSL::EC::Group</code> that is tied to the key. + * Modifying the returned group can make the key invalid. + */ +static VALUE ossl_ec_key_get_group(VALUE self) +{ + VALUE group_v; + EC_KEY *ec; + ossl_ec_group *ec_group; + EC_GROUP *group; + + Require_EC_KEY(self, ec); + + group_v = rb_iv_get(self, "@group"); + if (!NIL_P(group_v)) + return group_v; + + if ((group = (EC_GROUP *)EC_KEY_get0_group(ec)) != NULL) { + group_v = rb_obj_alloc(cEC_GROUP); + SafeGet_ec_group(group_v, ec_group); + ec_group->group = group; + ec_group->dont_free = 1; + rb_iv_set(group_v, "@key", self); + rb_iv_set(self, "@group", group_v); + return group_v; + } + + return Qnil; +} + +/* + * call-seq: + * key.group = group => group + * + * Returns the same object passed, not the group object associated with the key. + * If you wish to access the group object tied to the key call key.group after setting + * the group. + * + * Setting the group will immediately destroy any previously assigned group object. + * The group is internally copied by OpenSSL. Modifying the original group after + * assignment will not effect the internal key structure. + * (your changes may be lost). BE CAREFUL. + * + * EC_KEY_set_group calls EC_GROUP_free(key->group) then EC_GROUP_dup(), not EC_GROUP_copy. + * This documentation is accurate for OpenSSL 0.9.8b. + */ +static VALUE ossl_ec_key_set_group(VALUE self, VALUE group_v) +{ + VALUE old_group_v; + EC_KEY *ec; + EC_GROUP *group; + + Require_EC_KEY(self, ec); + SafeRequire_EC_GROUP(group_v, group); + + old_group_v = rb_iv_get(self, "@group"); + if (!NIL_P(old_group_v)) { + ossl_ec_group *old_ec_group; + SafeGet_ec_group(old_group_v, old_ec_group); + + old_ec_group->group = NULL; + old_ec_group->dont_free = 0; + rb_iv_set(old_group_v, "@key", Qnil); + } + + rb_iv_set(self, "@group", Qnil); + + if (EC_KEY_set_group(ec, group) != 1) + ossl_raise(eECError, "EC_KEY_set_group"); + + return group_v; +} + +/* + * call-seq: + * key.private_key => OpenSSL::BN + * + * See the OpenSSL documentation for EC_KEY_get0_private_key() + */ +static VALUE ossl_ec_key_get_private_key(VALUE self) +{ + EC_KEY *ec; + const BIGNUM *bn; + + Require_EC_KEY(self, ec); + + if ((bn = EC_KEY_get0_private_key(ec)) == NULL) + return Qnil; + + return ossl_bn_new(bn); +} + +/* + * call-seq: + * key.private_key = openssl_bn + * + * See the OpenSSL documentation for EC_KEY_set_private_key() + */ +static VALUE ossl_ec_key_set_private_key(VALUE self, VALUE private_key) +{ + EC_KEY *ec; + BIGNUM *bn = NULL; + + Require_EC_KEY(self, ec); + if (!NIL_P(private_key)) + bn = GetBNPtr(private_key); + + switch (EC_KEY_set_private_key(ec, bn)) { + case 1: + break; + case 0: + if (bn == NULL) + break; + default: + ossl_raise(eECError, "EC_KEY_set_private_key"); + } + + return private_key; +} + + +static VALUE ossl_ec_point_dup(const EC_POINT *point, VALUE group_v) +{ + VALUE obj; + const EC_GROUP *group; + ossl_ec_point *new_point; + + obj = rb_obj_alloc(cEC_POINT); + Data_Get_Struct(obj, ossl_ec_point, new_point); + + SafeRequire_EC_GROUP(group_v, group); + + new_point->point = EC_POINT_dup(point, group); + if (new_point->point == NULL) + ossl_raise(eEC_POINT, "EC_POINT_dup"); + rb_iv_set(obj, "@group", group_v); + + return obj; +} + +/* + * call-seq: + * key.public_key => OpenSSL::PKey::EC::Point + * + * See the OpenSSL documentation for EC_KEY_get0_public_key() + */ +static VALUE ossl_ec_key_get_public_key(VALUE self) +{ + EC_KEY *ec; + const EC_POINT *point; + VALUE group; + + Require_EC_KEY(self, ec); + + if ((point = EC_KEY_get0_public_key(ec)) == NULL) + return Qnil; + + group = rb_funcall(self, rb_intern("group"), 0); + if (NIL_P(group)) + ossl_raise(eECError, "EC_KEY_get0_get0_group (has public_key but no group???"); + + return ossl_ec_point_dup(point, group); +} + +/* + * call-seq: + * key.public_key = ec_point + * + * See the OpenSSL documentation for EC_KEY_set_public_key() + */ +static VALUE ossl_ec_key_set_public_key(VALUE self, VALUE public_key) +{ + EC_KEY *ec; + EC_POINT *point = NULL; + + Require_EC_KEY(self, ec); + if (!NIL_P(public_key)) + SafeRequire_EC_POINT(public_key, point); + + switch (EC_KEY_set_public_key(ec, point)) { + case 1: + break; + case 0: + if (point == NULL) + break; + default: + ossl_raise(eECError, "EC_KEY_set_public_key"); + } + + return public_key; +} + +/* + * call-seq: + * key.public_key? => true or false + * + * Both public_key? and private_key? may return false at the same time unlike other PKey classes. + */ +static VALUE ossl_ec_key_is_public_key(VALUE self) +{ + EC_KEY *ec; + + Require_EC_KEY(self, ec); + + return (EC_KEY_get0_public_key(ec) ? Qtrue : Qfalse); +} + +/* + * call-seq: + * key.private_key? => true or false + * + * Both public_key? and private_key? may return false at the same time unlike other PKey classes. + */ +static VALUE ossl_ec_key_is_private_key(VALUE self) +{ + EC_KEY *ec; + + Require_EC_KEY(self, ec); + + return (EC_KEY_get0_private_key(ec) ? Qtrue : Qfalse); +} + +static VALUE ossl_ec_key_to_string(VALUE self, int format) +{ + EC_KEY *ec; + BIO *out; + int i = -1; + int private = 0; + EVP_CIPHER *cipher = NULL; + char *password = NULL; + VALUE str; + + Require_EC_KEY(self, ec); + + if (EC_KEY_get0_public_key(ec) == NULL) + rb_raise(eECError, "can't export - no public key set"); + + if (EC_KEY_check_key(ec) != 1) + ossl_raise(eECError, "can't export - EC_KEY_check_key failed"); + + if (EC_KEY_get0_private_key(ec)) + private = 1; + + if (!(out = BIO_new(BIO_s_mem()))) + ossl_raise(eECError, "BIO_new(BIO_s_mem())"); + + switch(format) { + case EXPORT_PEM: + if (private) { + if (cipher || password) +/* BUG: finish cipher/password key export */ + rb_notimplement(); + i = PEM_write_bio_ECPrivateKey(out, ec, cipher, NULL, 0, NULL, password); + } else { + if (cipher || password) + rb_raise(rb_eArgError, "encryption is not supported when exporting this key type"); + + i = PEM_write_bio_EC_PUBKEY(out, ec); + } + + break; + case EXPORT_DER: + if (private) { + if (cipher || password) + rb_raise(rb_eArgError, "encryption is not supported when exporting this key type"); + + i = i2d_ECPrivateKey_bio(out, ec); + } else { + if (cipher || password) + rb_raise(rb_eArgError, "encryption is not supported when exporting this key type"); + + i = i2d_EC_PUBKEY_bio(out, ec); + } + + break; + default: + BIO_free(out); + rb_raise(rb_eRuntimeError, "unknown format (internal error)"); + } + + if (i != 1) { + BIO_free(out); + ossl_raise(eECError, "outlen=%d", i); + } + + str = ossl_membio2str(out); + + return str; +} + +/* + * call-seq: + * key.to_pem => String + * + * See the OpenSSL documentation for PEM_write_bio_ECPrivateKey() + */ +static VALUE ossl_ec_key_to_pem(VALUE self) +{ + return ossl_ec_key_to_string(self, EXPORT_PEM); +} + +/* + * call-seq: + * key.to_der => String + * + * See the OpenSSL documentation for i2d_ECPrivateKey_bio() + */ +static VALUE ossl_ec_key_to_der(VALUE self) +{ + return ossl_ec_key_to_string(self, EXPORT_DER); +} + +/* + * call-seq: + * key.to_text => String + * + * See the OpenSSL documentation for EC_KEY_print() + */ +static VALUE ossl_ec_key_to_text(VALUE self) +{ + EC_KEY *ec; + BIO *out; + VALUE str; + + Require_EC_KEY(self, ec); + if (!(out = BIO_new(BIO_s_mem()))) { + ossl_raise(eECError, "BIO_new(BIO_s_mem())"); + } + if (!EC_KEY_print(out, ec, 0)) { + BIO_free(out); + ossl_raise(eECError, "EC_KEY_print"); + } + str = ossl_membio2str(out); + + return str; +} + +static VALUE ossl_ec_key_to_public_key(VALUE self) +{ + EC_KEY *ec; + + VALUE new_obj; + + Require_EC_KEY(self, ec); + + new_obj = rb_obj_alloc(cEC); + +/* BUG: finish .to_public_key */ +rb_notimplement(); + + + return new_obj; +} + +/* + * call-seq: + * key.generate_key => self + * + * See the OpenSSL documentation for EC_KEY_generate_key() + */ +static VALUE ossl_ec_key_generate_key(VALUE self) +{ + EC_KEY *ec; + + Require_EC_KEY(self, ec); + + if (EC_KEY_generate_key(ec) != 1) + ossl_raise(eECError, "EC_KEY_generate_key"); + + return self; +} + +/* + * call-seq: + * key.check_key => true + * + * Raises an exception if the key is invalid. + * + * See the OpenSSL documentation for EC_KEY_check_key() + */ +static VALUE ossl_ec_key_check_key(VALUE self) +{ + EC_KEY *ec; + + Require_EC_KEY(self, ec); + + if (EC_KEY_check_key(ec) != 1) + ossl_raise(eECError, "EC_KEY_check_key"); + + return Qtrue; +} + +/* + * call-seq: + * key.dh_compute_key(pubkey) => String + * + * See the OpenSSL documentation for ECDH_compute_key() + */ +static VALUE ossl_ec_key_dh_compute_key(VALUE self, VALUE pubkey) +{ + EC_KEY *ec; + EC_POINT *point; + int buf_len; + VALUE str; + + Require_EC_KEY(self, ec); + SafeRequire_EC_POINT(pubkey, point); + +/* BUG: need a way to figure out the maximum string size */ + buf_len = 1024; + str = rb_str_new(0, buf_len); +/* BUG: take KDF as a block */ + buf_len = ECDH_compute_key(RSTRING_PTR(str), buf_len, point, ec, NULL); + if (buf_len < 0) + ossl_raise(eECError, "ECDH_compute_key"); + + rb_str_resize(str, buf_len); + + return str; +} + +/* sign_setup */ + +/* + * call-seq: + * key.dsa_sign_asn1(data) => String + * + * See the OpenSSL documentation for ECDSA_sign() + */ +static VALUE ossl_ec_key_dsa_sign_asn1(VALUE self, VALUE data) +{ + EC_KEY *ec; + int buf_len; + VALUE str; + + Require_EC_KEY(self, ec); + StringValue(data); + + if (EC_KEY_get0_private_key(ec) == NULL) + ossl_raise(eECError, "Private EC key needed!"); + + str = rb_str_new(0, ECDSA_size(ec) + 16); + if (ECDSA_sign(0, RSTRING_PTR(data), RSTRING_LEN(data), RSTRING_PTR(str), &buf_len, ec) != 1) + ossl_raise(eECError, "ECDSA_sign"); + + rb_str_resize(str, buf_len); + + return str; +} + +/* + * call-seq: + * key.dsa_verify(data, sig) => true or false + * + * See the OpenSSL documentation for ECDSA_verify() + */ +static VALUE ossl_ec_key_dsa_verify_asn1(VALUE self, VALUE data, VALUE sig) +{ + EC_KEY *ec; + + Require_EC_KEY(self, ec); + StringValue(data); + StringValue(sig); + + switch (ECDSA_verify(0, RSTRING_PTR(data), RSTRING_LEN(data), RSTRING_PTR(sig), RSTRING_LEN(sig), ec)) { + case 1: return Qtrue; + case 0: return Qfalse; + default: break; + } + + ossl_raise(eECError, "ECDSA_verify"); +} + +static void ossl_ec_group_free(ossl_ec_group *ec_group) +{ + if (!ec_group->dont_free && ec_group->group) + EC_GROUP_clear_free(ec_group->group); + free(ec_group); +} + +static VALUE ossl_ec_group_alloc(VALUE klass) +{ + ossl_ec_group *ec_group; + VALUE obj; + + obj = Data_Make_Struct(klass, ossl_ec_group, 0, ossl_ec_group_free, ec_group); + + return obj; +} + +/* call-seq: + * OpenSSL::PKey::EC::Group.new("secp112r1") + * OpenSSL::PKey::EC::Group.new(ec_group) + * OpenSSL::PKey::EC::Group.new(pem_string) + * OpenSSL::PKey::EC::Group.new(der_string) + * OpenSSL::PKey::EC::Group.new(pem_file) + * OpenSSL::PKey::EC::Group.new(der_file) + * OpenSSL::PKey::EC::Group.new(:GFp_simple) + * OpenSSL::PKey::EC::Group.new(:GFp_mult) + * OpenSSL::PKey::EC::Group.new(:GFp_nist) + * OpenSSL::PKey::EC::Group.new(:GF2m_simple) + * OpenSSL::PKey::EC::Group.new(:GFp, bignum_p, bignum_a, bignum_b) + * OpenSSL::PKey::EC::Group.new(:GF2m, bignum_p, bignum_a, bignum_b) + * + * See the OpenSSL documentation for EC_GROUP_* + */ +static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self) +{ + VALUE arg1, arg2, arg3, arg4; + ossl_ec_group *ec_group; + EC_GROUP *group = NULL; + + Data_Get_Struct(self, ossl_ec_group, ec_group); + if (ec_group->group != NULL) + rb_raise(rb_eRuntimeError, "EC_GROUP is already initialized"); + + switch (rb_scan_args(argc, argv, "13", &arg1, &arg2, &arg3, &arg4)) { + case 1: + if (SYMBOL_P(arg1)) { + const EC_METHOD *method = NULL; + ID id = SYM2ID(arg1); + + if (id == s_GFp_simple) { + method = EC_GFp_simple_method(); + } else if (id == s_GFp_mont) { + method = EC_GFp_mont_method(); + } else if (id == s_GFp_nist) { + method = EC_GFp_nist_method(); + } else if (id == s_GF2m_simple) { + method = EC_GF2m_simple_method(); + } + + if (method) { + if ((group = EC_GROUP_new(method)) == NULL) + ossl_raise(eEC_GROUP, "EC_GROUP_new"); + } else { + rb_raise(rb_eArgError, "unknown symbol, must be :GFp_simple, :GFp_mont, :GFp_nist or :GF2m_simple"); + } + } else if (rb_obj_is_kind_of(arg1, cEC_GROUP)) { + const EC_GROUP *arg1_group; + + SafeRequire_EC_GROUP(arg1, arg1_group); + if ((group = EC_GROUP_dup(arg1_group)) == NULL) + ossl_raise(eEC_GROUP, "EC_GROUP_dup"); + } else { + BIO *in = ossl_obj2bio(arg1); + + group = PEM_read_bio_ECPKParameters(in, NULL, NULL, NULL); + if (!group) { + BIO_reset(in); + group = d2i_ECPKParameters_bio(in, NULL); + } + + BIO_free(in); + + if (!group) { + const char *name = STR2CSTR(arg1); + int nid = OBJ_sn2nid(name); + + if (nid == NID_undef) + ossl_raise(eEC_GROUP, "unknown curve name (%s)", name); + + group = EC_GROUP_new_by_curve_name(nid); + if (group == NULL) + ossl_raise(eEC_GROUP, "unable to create curve (%s)", name); + } + } + + break; + case 4: + if (SYMBOL_P(arg1)) { + ID id = SYM2ID(arg1); + EC_GROUP *(*new_curve)(const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *) = NULL; + const BIGNUM *p = GetBNPtr(arg2); + const BIGNUM *a = GetBNPtr(arg3); + const BIGNUM *b = GetBNPtr(arg4); + + if (id == s_GFp) { + new_curve = EC_GROUP_new_curve_GFp; + } else if (id == s_GF2m) { + new_curve = EC_GROUP_new_curve_GF2m; + } else { + rb_raise(rb_eArgError, "unknown symbol, must be :GFp or :GF2m"); + } + + if ((group = new_curve(p, a, b, ossl_bn_ctx)) == NULL) + ossl_raise(eEC_GROUP, "EC_GROUP_new_by_GF*"); + } else { + rb_raise(rb_eArgError, "unknown argument, must be :GFp or :GF2m"); + } + + break; + default: + rb_raise(rb_eArgError, "wrong number of arguments"); + } + + if (group == NULL) + ossl_raise(eEC_GROUP, ""); + + ec_group->group = group; + + return self; +} + +/* call-seq: + * group.generator => ec_point + * + * See the OpenSSL documentation for EC_GROUP_get0_generator() + */ +static VALUE ossl_ec_group_get_generator(VALUE self) +{ + VALUE point_obj; + EC_GROUP *group = NULL; + + Require_EC_GROUP(self, group); + + point_obj = ossl_ec_point_dup(EC_GROUP_get0_generator(group), self); + + return point_obj; +} + +/* call-seq: + * group.set_generator(generator, order, cofactor) => self + * + * See the OpenSSL documentation for EC_GROUP_set_generator() + */ +static VALUE ossl_ec_group_set_generator(VALUE self, VALUE generator, VALUE order, VALUE cofactor) +{ + EC_GROUP *group = NULL; + const EC_POINT *point; + const BIGNUM *o, *co; + + Require_EC_GROUP(self, group); + SafeRequire_EC_POINT(generator, point); + o = GetBNPtr(order); + co = GetBNPtr(cofactor); + + if (EC_GROUP_set_generator(group, point, o, co) != 1) + ossl_raise(eEC_GROUP, "EC_GROUP_set_generator"); + + return self; +} + +/* call-seq: + * group.get_order => order_bn + * + * See the OpenSSL documentation for EC_GROUP_get_order() + */ +static VALUE ossl_ec_group_get_order(VALUE self) +{ + VALUE bn_obj; + BIGNUM *bn; + EC_GROUP *group = NULL; + + Require_EC_GROUP(self, group); + + bn_obj = ossl_bn_new(NULL); + bn = GetBNPtr(bn_obj); + + if (EC_GROUP_get_order(group, bn, ossl_bn_ctx) != 1) + ossl_raise(eEC_GROUP, "EC_GROUP_get_order"); + + return bn_obj; +} + +/* call-seq: + * group.get_cofactor => cofactor_bn + * + * See the OpenSSL documentation for EC_GROUP_get_cofactor() + */ +static VALUE ossl_ec_group_get_cofactor(VALUE self) +{ + VALUE bn_obj; + BIGNUM *bn; + EC_GROUP *group = NULL; + + Require_EC_GROUP(self, group); + + bn_obj = ossl_bn_new(NULL); + bn = GetBNPtr(bn_obj); + + if (EC_GROUP_get_cofactor(group, bn, ossl_bn_ctx) != 1) + ossl_raise(eEC_GROUP, "EC_GROUP_get_cofactor"); + + return bn_obj; +} + +/* call-seq: + * group.curve_name => String + * + * See the OpenSSL documentation for EC_GROUP_get_curve_name() + */ +static VALUE ossl_ec_group_get_curve_name(VALUE self) +{ + EC_GROUP *group = NULL; + int nid; + + Get_EC_GROUP(self, group); + if (group == NULL) + return Qnil; + + nid = EC_GROUP_get_curve_name(group); + +/* BUG: an nid or asn1 object should be returned, maybe. */ + return rb_str_new2(OBJ_nid2sn(nid)); +} + +/* call-seq: + * EC.builtin_curves => [[name, comment], ...] + * + * See the OpenSSL documentation for EC_builtin_curves() + */ +static VALUE ossl_s_builtin_curves(VALUE self) +{ + EC_builtin_curve *curves = NULL; + int n; + int crv_len = EC_get_builtin_curves(NULL, 0); + VALUE ary, ret; + + curves = ALLOCA_N(EC_builtin_curve, crv_len); + if (curves == NULL) + return Qnil; + if (!EC_get_builtin_curves(curves, crv_len)) + ossl_raise(rb_eRuntimeError, "EC_get_builtin_curves"); + + ret = rb_ary_new2(crv_len); + + for (n = 0; n < crv_len; n++) { + const char *sname = OBJ_nid2sn(curves[n].nid); + const char *comment = curves[n].comment; + + ary = rb_ary_new2(2); + rb_ary_push(ary, rb_str_new2(sname)); + rb_ary_push(ary, comment ? rb_str_new2(comment) : Qnil); + rb_ary_push(ret, ary); + } + + return ret; +} + +/* call-seq: + * group.asn1_flag => Fixnum + * + * See the OpenSSL documentation for EC_GROUP_get_asn1_flag() + */ +static VALUE ossl_ec_group_get_asn1_flag(VALUE self) +{ + EC_GROUP *group = NULL; + int flag; + + Require_EC_GROUP(self, group); + + flag = EC_GROUP_get_asn1_flag(group); + + return INT2FIX(flag); +} + +/* call-seq: + * group.asn1_flag = Fixnum => Fixnum + * + * See the OpenSSL documentation for EC_GROUP_set_asn1_flag() + */ +static VALUE ossl_ec_group_set_asn1_flag(VALUE self, VALUE flag_v) +{ + EC_GROUP *group = NULL; + + Require_EC_GROUP(self, group); + + EC_GROUP_set_asn1_flag(group, NUM2INT(flag_v)); + + return flag_v; +} + +/* call-seq: + * group.point_conversion_form => :uncompressed | :compressed | :hybrid + * + * See the OpenSSL documentation for EC_GROUP_get_point_conversion_form() + */ +static VALUE ossl_ec_group_get_point_conversion_form(VALUE self) +{ + EC_GROUP *group = NULL; + point_conversion_form_t form; + VALUE ret; + + Require_EC_GROUP(self, group); + + form = EC_GROUP_get_point_conversion_form(group); + + switch (form) { + case POINT_CONVERSION_UNCOMPRESSED: ret = ID_uncompressed; break; + case POINT_CONVERSION_COMPRESSED: ret = ID_compressed; break; + case POINT_CONVERSION_HYBRID: ret = ID_hybrid; break; + default: rb_raise(eEC_GROUP, "unsupported point conversion form: %d, this module should be updated", form); + } + + return ID2SYM(ret); +} + +/* call-seq: + * group.point_conversion_form = form => form + * + * See the OpenSSL documentation for EC_GROUP_set_point_conversion_form() + */ +static VALUE ossl_ec_group_set_point_conversion_form(VALUE self, VALUE form_v) +{ + EC_GROUP *group = NULL; + point_conversion_form_t form; + ID form_id = SYM2ID(form_v); + + Require_EC_GROUP(self, group); + + if (form_id == ID_uncompressed) { + form = POINT_CONVERSION_UNCOMPRESSED; + } else if (form_id == ID_compressed) { + form = POINT_CONVERSION_COMPRESSED; + } else if (form_id == ID_hybrid) { + form = POINT_CONVERSION_HYBRID; + } else { + rb_raise(rb_eArgError, "form must be :compressed, :uncompressed, or :hybrid"); + } + + EC_GROUP_set_point_conversion_form(group, form); + + return form_v; +} + +/* call-seq: + * group.seed => String or nil + * + * See the OpenSSL documentation for EC_GROUP_get0_seed() + */ +static VALUE ossl_ec_group_get_seed(VALUE self) +{ + EC_GROUP *group = NULL; + size_t seed_len; + + Require_EC_GROUP(self, group); + + seed_len = EC_GROUP_get_seed_len(group); + + if (seed_len == 0) + return Qnil; + + return rb_str_new(EC_GROUP_get0_seed(group), seed_len); +} + +/* call-seq: + * group.seed = seed => seed + * + * See the OpenSSL documentation for EC_GROUP_set_seed() + */ +static VALUE ossl_ec_group_set_seed(VALUE self, VALUE seed) +{ + EC_GROUP *group = NULL; + + Require_EC_GROUP(self, group); + StringValue(seed); + + if (EC_GROUP_set_seed(group, RSTRING_PTR(seed), RSTRING_LEN(seed)) != RSTRING_LEN(seed)) + ossl_raise(eEC_GROUP, "EC_GROUP_set_seed"); + + return seed; +} + +/* get/set curve GFp, GF2m */ + +/* call-seq: + * group.degree => Fixnum + * + * See the OpenSSL documentation for EC_GROUP_get_degree() + */ +static VALUE ossl_ec_group_get_degree(VALUE self) +{ + EC_GROUP *group = NULL; + + Require_EC_GROUP(self, group); + + return INT2NUM(EC_GROUP_get_degree(group)); +} + +static VALUE ossl_ec_group_to_string(VALUE self, int format) +{ + EC_GROUP *group; + BIO *out; + int i = -1; + VALUE str; + + Get_EC_GROUP(self, group); + + if (!(out = BIO_new(BIO_s_mem()))) + ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())"); + + switch(format) { + case EXPORT_PEM: + i = PEM_write_bio_ECPKParameters(out, group); + break; + case EXPORT_DER: + i = i2d_ECPKParameters_bio(out, group); + break; + default: + BIO_free(out); + rb_raise(rb_eRuntimeError, "unknown format (internal error)"); + } + + if (i != 1) { + BIO_free(out); + ossl_raise(eECError, NULL); + } + + str = ossl_membio2str(out); + + return str; +} + +/* call-seq: + * group.to_pem => String + * + * See the OpenSSL documentation for PEM_write_bio_ECPKParameters() + */ +static VALUE ossl_ec_group_to_pem(VALUE self) +{ + return ossl_ec_group_to_string(self, EXPORT_PEM); +} + +/* call-seq: + * group.to_der => String + * + * See the OpenSSL documentation for i2d_ECPKParameters_bio() + */ +static VALUE ossl_ec_group_to_der(VALUE self) +{ + return ossl_ec_group_to_string(self, EXPORT_DER); +} + +/* call-seq: + * group.to_text => String + * + * See the OpenSSL documentation for ECPKParameters_print() + */ +static VALUE ossl_ec_group_to_text(VALUE self) +{ + EC_GROUP *group; + BIO *out; + VALUE str; + + Require_EC_GROUP(self, group); + if (!(out = BIO_new(BIO_s_mem()))) { + ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())"); + } + if (!ECPKParameters_print(out, group, 0)) { + BIO_free(out); + ossl_raise(eEC_GROUP, NULL); + } + str = ossl_membio2str(out); + + return str; +} + + +static void ossl_ec_point_free(ossl_ec_point *ec_point) +{ + if (!ec_point->dont_free && ec_point->point) + EC_POINT_clear_free(ec_point->point); + free(ec_point); +} + +static VALUE ossl_ec_point_alloc(VALUE klass) +{ + ossl_ec_point *ec_point; + VALUE obj; + + obj = Data_Make_Struct(klass, ossl_ec_point, 0, ossl_ec_point_free, ec_point); + + return obj; +} + +/* + * call-seq: + * OpenSSL::PKey::EC::Point.new(point) + * OpenSSL::PKey::EC::Point.new(group) + * OpenSSL::PKey::EC::Point.new(group, bn) + * + * See the OpenSSL documentation for EC_POINT_* + */ +static VALUE ossl_ec_point_initialize(int argc, VALUE *argv, VALUE self) +{ + ossl_ec_point *ec_point; + EC_POINT *point = NULL; + VALUE arg1, arg2; + VALUE group_v = Qnil; + const EC_GROUP *group = NULL; + + Data_Get_Struct(self, ossl_ec_point, ec_point); + if (ec_point->point) + rb_raise(eEC_POINT, "EC_POINT already initialized"); + + switch (rb_scan_args(argc, argv, "11", &arg1, &arg2)) { + case 1: + if (rb_obj_is_kind_of(arg1, cEC_POINT)) { + const EC_POINT *arg_point; + + group_v = rb_iv_get(arg1, "@group"); + SafeRequire_EC_GROUP(group_v, group); + SafeRequire_EC_POINT(arg1, arg_point); + + point = EC_POINT_dup(arg_point, group); + } else if (rb_obj_is_kind_of(arg1, cEC_GROUP)) { + group_v = arg1; + SafeRequire_EC_GROUP(group_v, group); + + point = EC_POINT_new(group); + } else { + rb_raise(eEC_POINT, "wrong argument type: must be OpenSSL::PKey::EC::Point or OpenSSL::Pkey::EC::Group"); + } + + break; + case 2: + if (!rb_obj_is_kind_of(arg1, cEC_GROUP)) + rb_raise(rb_eArgError, "1st argument must be OpenSSL::PKey::EC::Group"); + group_v = arg1; + SafeRequire_EC_GROUP(group_v, group); + + if (rb_obj_is_kind_of(arg2, cBN)) { + const BIGNUM *bn = GetBNPtr(arg2); + + point = EC_POINT_bn2point(group, bn, NULL, ossl_bn_ctx); + } else { + BIO *in = ossl_obj2bio(arg1); + +/* BUG: finish me */ + + BIO_free(in); + + if (point == NULL) { + ossl_raise(eEC_POINT, "unknown type for 2nd arg"); + } + } + break; + default: + rb_raise(rb_eArgError, "wrong number of arguments"); + } + + if (point == NULL) + ossl_raise(eEC_POINT, NULL); + + if (NIL_P(group_v)) + rb_raise(rb_eRuntimeError, "missing group (internal error)"); + + ec_point->point = point; + + rb_iv_set(self, "@group", group_v); + + return self; +} + +/* + * call-seq: + * point.to_bn => OpenSSL::BN + * + * See the OpenSSL documentation for EC_POINT_point2bn() + */ +static VALUE ossl_ec_point_to_bn(VALUE self) +{ + EC_POINT *point; + VALUE bn_obj; + VALUE group_v = rb_iv_get(self, "@group"); + const EC_GROUP *group; + point_conversion_form_t form; + BIGNUM *bn; + + Require_EC_POINT(self, point); + SafeRequire_EC_GROUP(group_v, group); + + form = EC_GROUP_get_point_conversion_form(group); + + bn_obj = rb_obj_alloc(cBN); + bn = GetBNPtr(bn_obj); + + if (EC_POINT_point2bn(group, point, form, bn, ossl_bn_ctx) == NULL) + ossl_raise(eEC_POINT, "EC_POINT_point2bn"); + + return bn_obj; +} + +static void no_copy(VALUE klass) +{ + rb_undef_method(klass, "copy"); + rb_undef_method(klass, "clone"); + rb_undef_method(klass, "dup"); + rb_undef_method(klass, "initialize_copy"); +} + +void Init_ossl_ec() +{ +#ifdef DONT_NEED_RDOC_WORKAROUND + mOSSL = rb_define_module("OpenSSL"); + mPKey = rb_define_module_under(mOSSL, "PKey"); +#endif + + eECError = rb_define_class_under(mPKey, "ECError", ePKeyError); + + cEC = rb_define_class_under(mPKey, "EC", cPKey); + cEC_GROUP = rb_define_class_under(cEC, "Group", rb_cObject); + cEC_POINT = rb_define_class_under(cEC, "Point", rb_cObject); + eEC_GROUP = rb_define_class_under(cEC_GROUP, "Error", eOSSLError); + eEC_POINT = rb_define_class_under(cEC_POINT, "Error", eOSSLError); + + s_GFp = rb_intern("GFp"); + s_GF2m = rb_intern("GF2m"); + s_GFp_simple = rb_intern("GFp_simple"); + s_GFp_mont = rb_intern("GFp_mont"); + s_GFp_nist = rb_intern("GFp_nist"); + s_GF2m_simple = rb_intern("GF2m_simple"); + + ID_uncompressed = rb_intern("uncompressed"); + ID_compressed = rb_intern("compressed"); + ID_hybrid = rb_intern("hybrid"); + + rb_define_singleton_method(cEC, "builtin_curves", ossl_s_builtin_curves, 0); + + rb_define_method(cEC, "initialize", ossl_ec_key_initialize, -1); +/* copy/dup/cmp */ + + rb_define_method(cEC, "group", ossl_ec_key_get_group, 0); + rb_define_method(cEC, "group=", ossl_ec_key_set_group, 1); + rb_define_method(cEC, "private_key", ossl_ec_key_get_private_key, 0); + rb_define_method(cEC, "private_key=", ossl_ec_key_set_private_key, 1); + rb_define_method(cEC, "public_key", ossl_ec_key_get_public_key, 0); + rb_define_method(cEC, "public_key=", ossl_ec_key_set_public_key, 1); + rb_define_method(cEC, "private_key?", ossl_ec_key_is_private_key, 0); + rb_define_method(cEC, "public_key?", ossl_ec_key_is_public_key, 0); +/* rb_define_method(cEC, "", ossl_ec_key_get_, 0); + rb_define_method(cEC, "=", ossl_ec_key_set_ 1); + set/get enc_flags + set/get _conv_from + set/get asn1_flag (can use ruby to call self.group.asn1_flag) + set/get precompute_mult +*/ + rb_define_method(cEC, "generate_key", ossl_ec_key_generate_key, 0); + rb_define_method(cEC, "check_key", ossl_ec_key_check_key, 0); + + rb_define_method(cEC, "dh_compute_key", ossl_ec_key_dh_compute_key, 1); + rb_define_method(cEC, "dsa_sign_asn1", ossl_ec_key_dsa_sign_asn1, 1); + rb_define_method(cEC, "dsa_verify_asn1", ossl_ec_key_dsa_verify_asn1, 2); +/* do_sign/do_verify */ + + rb_define_method(cEC, "to_pem", ossl_ec_key_to_pem, 0); + rb_define_method(cEC, "to_der", ossl_ec_key_to_der, 0); + rb_define_method(cEC, "to_text", ossl_ec_key_to_text, 0); + + + rb_define_alloc_func(cEC_GROUP, ossl_ec_group_alloc); + rb_define_method(cEC_GROUP, "initialize", ossl_ec_group_initialize, -1); +/* copy/dup/cmp */ + + rb_define_method(cEC_GROUP, "generator", ossl_ec_group_get_generator, 0); + rb_define_method(cEC_GROUP, "set_generator", ossl_ec_group_set_generator, 3); + rb_define_method(cEC_GROUP, "order", ossl_ec_group_get_order, 0); + rb_define_method(cEC_GROUP, "cofactor", ossl_ec_group_get_cofactor, 0); + + rb_define_method(cEC_GROUP, "curve_name", ossl_ec_group_get_curve_name, 0); +/* rb_define_method(cEC_GROUP, "curve_name=", ossl_ec_group_set_curve_name, 1); */ + + rb_define_method(cEC_GROUP, "asn1_flag", ossl_ec_group_get_asn1_flag, 0); + rb_define_method(cEC_GROUP, "asn1_flag=", ossl_ec_group_set_asn1_flag, 1); + + rb_define_method(cEC_GROUP, "point_conversion_form", ossl_ec_group_get_point_conversion_form, 0); + rb_define_method(cEC_GROUP, "point_conversion_form=", ossl_ec_group_set_point_conversion_form, 1); + + rb_define_method(cEC_GROUP, "seed", ossl_ec_group_get_seed, 0); + rb_define_method(cEC_GROUP, "seed=", ossl_ec_group_set_seed, 1); + +/* get/set GFp, GF2m */ + + rb_define_method(cEC_GROUP, "degree", ossl_ec_group_get_degree, 0); + +/* check* */ + + + rb_define_method(cEC_GROUP, "to_pem", ossl_ec_group_to_pem, 0); + rb_define_method(cEC_GROUP, "to_der", ossl_ec_group_to_der, 0); + rb_define_method(cEC_GROUP, "to_text", ossl_ec_group_to_text, 0); + + + rb_define_alloc_func(cEC_POINT, ossl_ec_point_alloc); + rb_define_method(cEC_POINT, "initialize", ossl_ec_point_initialize, -1); + rb_attr(cEC_POINT, rb_intern("group"), 1, 0, 0); +/* all the other methods */ + + rb_define_method(cEC_POINT, "to_bn", ossl_ec_point_to_bn, 0); + + no_copy(cEC); + no_copy(cEC_GROUP); + no_copy(cEC_POINT); +} + +#else /* defined NO_EC */ +# warning >>> OpenSSL is compiled without EC support <<< + +void Init_ossl_ec() +{ +} + +#endif /* NO_EC */ diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c index 0afdcf8d01..4a690a7cb5 100644 --- a/ext/openssl/ossl_pkey_rsa.c +++ b/ext/openssl/ossl_pkey_rsa.c @@ -84,9 +84,19 @@ rsa_generate(int size, int exp) NULL); } +/* + * call-seq: + * RSA.generate(size [, exponent]) -> rsa + * + * === Parameters + * * +size+ is an integer representing the desired key size. Keys smaller than 1024 should be considered insecure. + * * +exponent+ is an odd number normally 3, 17, or 65537. + * + */ static VALUE ossl_rsa_s_generate(int argc, VALUE *argv, VALUE klass) { +/* why does this method exist? why can't initialize take an optional exponent? */ RSA *rsa; VALUE size, exp; VALUE obj; @@ -104,6 +114,20 @@ ossl_rsa_s_generate(int argc, VALUE *argv, VALUE klass) return obj; } +/* + * call-seq: + * RSA.new([size | encoded_key] [, pass]) -> rsa + * + * === Parameters + * * +size+ is an integer representing the desired key size. + * * +encoded_key+ is a string containing PEM or DER encoded key. + * * +pass+ is an optional string with the password to decrypt the encoded key. + * + * === Examples + * * RSA.new(2048) -> rsa + * * RSA.new(File.read("rsa.pem")) -> rsa + * * RSA.new(File.read("rsa.pem"), "mypassword") -> rsa + */ static VALUE ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) { @@ -157,6 +181,13 @@ ossl_rsa_initialize(int argc, VALUE *argv, VALUE self) return self; } +/* + * call-seq: + * rsa.public? -> true + * + * The return value is always true since every private key is also a public key. + * + */ static VALUE ossl_rsa_is_public(VALUE self) { @@ -164,12 +195,16 @@ ossl_rsa_is_public(VALUE self) GetPKeyRSA(self, pkey); /* - * SURPRISE! :-)) - * Every key is public at the same time! + * This method should check for n and e. BUG. */ return Qtrue; } +/* + * call-seq: + * rsa.private? -> true | false + * + */ static VALUE ossl_rsa_is_private(VALUE self) { @@ -180,6 +215,18 @@ ossl_rsa_is_private(VALUE self) return (RSA_PRIVATE(self, pkey->pkey.rsa)) ? Qtrue : Qfalse; } +/* + * call-seq: + * rsa.to_pem([cipher, pass]) -> aString + * + * === Parameters + * * +cipher+ is a Cipher object. + * * +pass+ is a string. + * + * === Examples + * * rsa.to_pem -> aString + * * rsa.to_pem(cipher, pass) -> aString + */ static VALUE ossl_rsa_export(int argc, VALUE *argv, VALUE self) { @@ -219,6 +266,11 @@ ossl_rsa_export(int argc, VALUE *argv, VALUE self) return str; } +/* + * call-seq: + * rsa.to_der -> aString + * + */ static VALUE ossl_rsa_to_der(VALUE self) { @@ -236,7 +288,7 @@ ossl_rsa_to_der(VALUE self) if((len = i2d_func(pkey->pkey.rsa, NULL)) <= 0) ossl_raise(eRSAError, NULL); str = rb_str_new(0, len); - p = RSTRING(str)->ptr; + p = RSTRING_PTR(str); if(i2d_func(pkey->pkey.rsa, &p) < 0) ossl_raise(eRSAError, NULL); ossl_str_adjust(str, p); @@ -246,6 +298,11 @@ ossl_rsa_to_der(VALUE self) #define ossl_rsa_buf_size(pkey) (RSA_size((pkey)->pkey.rsa)+16) +/* + * call-seq: + * rsa.public_encrypt(string [, padding]) -> aString + * + */ static VALUE ossl_rsa_public_encrypt(int argc, VALUE *argv, VALUE self) { @@ -258,16 +315,20 @@ ossl_rsa_public_encrypt(int argc, VALUE *argv, VALUE self) pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding); StringValue(buffer); str = rb_str_new(0, ossl_rsa_buf_size(pkey)); - buf_len = RSA_public_encrypt(RSTRING(buffer)->len, RSTRING(buffer)->ptr, - RSTRING(str)->ptr, pkey->pkey.rsa, + buf_len = RSA_public_encrypt(RSTRING_LEN(buffer), RSTRING_PTR(buffer), + RSTRING_PTR(str), pkey->pkey.rsa, pad); if (buf_len < 0) ossl_raise(eRSAError, NULL); - RSTRING(str)->len = buf_len; - RSTRING(str)->ptr[buf_len] = 0; + rb_str_set_len(str, buf_len); return str; } +/* + * call-seq: + * rsa.public_decrypt(string [, padding]) -> aString + * + */ static VALUE ossl_rsa_public_decrypt(int argc, VALUE *argv, VALUE self) { @@ -280,16 +341,20 @@ ossl_rsa_public_decrypt(int argc, VALUE *argv, VALUE self) pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding); StringValue(buffer); str = rb_str_new(0, ossl_rsa_buf_size(pkey)); - buf_len = RSA_public_decrypt(RSTRING(buffer)->len, RSTRING(buffer)->ptr, - RSTRING(str)->ptr, pkey->pkey.rsa, + buf_len = RSA_public_decrypt(RSTRING_LEN(buffer), RSTRING_PTR(buffer), + RSTRING_PTR(str), pkey->pkey.rsa, pad); if (buf_len < 0) ossl_raise(eRSAError, NULL); - RSTRING(str)->len = buf_len; - RSTRING(str)->ptr[buf_len] = 0; + rb_str_set_len(str, buf_len); return str; } +/* + * call-seq: + * rsa.private_encrypt(string [, padding]) -> aString + * + */ static VALUE ossl_rsa_private_encrypt(int argc, VALUE *argv, VALUE self) { @@ -305,16 +370,21 @@ ossl_rsa_private_encrypt(int argc, VALUE *argv, VALUE self) pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding); StringValue(buffer); str = rb_str_new(0, ossl_rsa_buf_size(pkey)); - buf_len = RSA_private_encrypt(RSTRING(buffer)->len, RSTRING(buffer)->ptr, - RSTRING(str)->ptr, pkey->pkey.rsa, + buf_len = RSA_private_encrypt(RSTRING_LEN(buffer), RSTRING_PTR(buffer), + RSTRING_PTR(str), pkey->pkey.rsa, pad); if (buf_len < 0) ossl_raise(eRSAError, NULL); - RSTRING(str)->len = buf_len; - RSTRING(str)->ptr[buf_len] = 0; + rb_str_set_len(str, buf_len); return str; } + +/* + * call-seq: + * rsa.private_decrypt(string [, padding]) -> aString + * + */ static VALUE ossl_rsa_private_decrypt(int argc, VALUE *argv, VALUE self) { @@ -330,17 +400,19 @@ ossl_rsa_private_decrypt(int argc, VALUE *argv, VALUE self) pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding); StringValue(buffer); str = rb_str_new(0, ossl_rsa_buf_size(pkey)); - buf_len = RSA_private_decrypt(RSTRING(buffer)->len, RSTRING(buffer)->ptr, - RSTRING(str)->ptr, pkey->pkey.rsa, + buf_len = RSA_private_decrypt(RSTRING_LEN(buffer), RSTRING_PTR(buffer), + RSTRING_PTR(str), pkey->pkey.rsa, pad); if (buf_len < 0) ossl_raise(eRSAError, NULL); - RSTRING(str)->len = buf_len; - RSTRING(str)->ptr[buf_len] = 0; + rb_str_set_len(str, buf_len); return str; } /* + * call-seq: + * rsa.params -> hash + * * Stores all parameters of key to the hash * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!! * Don't use :-)) (I's up to you) @@ -368,6 +440,9 @@ ossl_rsa_get_params(VALUE self) } /* + * call-seq: + * rsa.to_text -> aString + * * Prints all parameters of key to buffer * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!! * Don't use :-)) (It's up to you) @@ -393,6 +468,9 @@ ossl_rsa_to_text(VALUE self) } /* + * call-seq: + * rsa.public_key -> aRSA + * * Makes new instance RSA PUBLIC_KEY from PRIVATE_KEY */ static VALUE @@ -415,7 +493,6 @@ ossl_rsa_to_public_key(VALUE self) /* * TODO: Test me -extern BN_CTX *ossl_bn_ctx; static VALUE ossl_rsa_blinding_on(VALUE self) diff --git a/ext/openssl/ossl_rand.c b/ext/openssl/ossl_rand.c index 71bb3bedd5..ca8c9a5ae9 100644 --- a/ext/openssl/ossl_rand.c +++ b/ext/openssl/ossl_rand.c @@ -31,75 +31,105 @@ static VALUE ossl_rand_seed(VALUE self, VALUE str) { StringValue(str); - RAND_seed(RSTRING(str)->ptr, RSTRING(str)->len); + RAND_seed(RSTRING_PTR(str), RSTRING_LEN(str)); return str; } +/* + * call-seq: + * load_random_file(filename) -> true + * + */ static VALUE ossl_rand_load_file(VALUE self, VALUE filename) { SafeStringValue(filename); - if(!RAND_load_file(RSTRING(filename)->ptr, -1)) { + if(!RAND_load_file(RSTRING_PTR(filename), -1)) { ossl_raise(eRandomError, NULL); } return Qtrue; } +/* + * call-seq: + * write_random_file(filename) -> true + * + */ static VALUE ossl_rand_write_file(VALUE self, VALUE filename) { SafeStringValue(filename); - if (RAND_write_file(RSTRING(filename)->ptr) == -1) { + if (RAND_write_file(RSTRING_PTR(filename)) == -1) { ossl_raise(eRandomError, NULL); } return Qtrue; } +/* + * call-seq: + * random_bytes(length) -> aString + * + */ static VALUE ossl_rand_bytes(VALUE self, VALUE len) { VALUE str; str = rb_str_new(0, FIX2INT(len)); - if (!RAND_bytes(RSTRING(str)->ptr, FIX2INT(len))) { + if (!RAND_bytes(RSTRING_PTR(str), FIX2INT(len))) { ossl_raise(eRandomError, NULL); } return str; } +/* + * call-seq: + * pseudo_bytes(length) -> aString + * + */ static VALUE ossl_rand_pseudo_bytes(VALUE self, VALUE len) { VALUE str; str = rb_str_new(0, FIX2INT(len)); - if (!RAND_pseudo_bytes(RSTRING(str)->ptr, FIX2INT(len))) { + if (!RAND_pseudo_bytes(RSTRING_PTR(str), FIX2INT(len))) { ossl_raise(eRandomError, NULL); } return str; } +/* + * call-seq: + * egd(filename) -> true + * + */ static VALUE ossl_rand_egd(VALUE self, VALUE filename) { SafeStringValue(filename); - if(!RAND_egd(RSTRING(filename)->ptr)) { + if(!RAND_egd(RSTRING_PTR(filename))) { ossl_raise(eRandomError, NULL); } return Qtrue; } +/* + * call-seq: + * egd_bytes(filename, length) -> true + * + */ static VALUE ossl_rand_egd_bytes(VALUE self, VALUE filename, VALUE len) { SafeStringValue(filename); - if (!RAND_egd_bytes(RSTRING(filename)->ptr, FIX2INT(len))) { + if (!RAND_egd_bytes(RSTRING_PTR(filename), FIX2INT(len))) { ossl_raise(eRandomError, NULL); } return Qtrue; diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c index 8e632b526b..76423b773b 100644 --- a/ext/openssl/ossl_ssl.c +++ b/ext/openssl/ossl_ssl.c @@ -3,6 +3,7 @@ * 'OpenSSL for Ruby' project * Copyright (C) 2000-2002 GOTOU Yuuzou <gotoyuzo@notwork.org> * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> + * Copyright (C) 2001-2007 Technorama Ltd. <oss-ruby@technorama.net> * All rights reserved. */ /* @@ -30,9 +31,6 @@ VALUE eSSLError; VALUE cSSLContext; VALUE cSSLSocket; -/* - * SSLContext class - */ #define ossl_sslctx_set_cert(o,v) rb_iv_set((o),"@cert",(v)) #define ossl_sslctx_set_key(o,v) rb_iv_set((o),"@key",(v)) #define ossl_sslctx_set_client_ca(o,v) rb_iv_set((o),"@client_ca",(v)) @@ -65,11 +63,12 @@ VALUE cSSLSocket; #define ossl_sslctx_get_tmp_dh_cb(o) rb_iv_get((o),"@tmp_dh_callback") #define ossl_sslctx_get_sess_id_ctx(o) rb_iv_get((o),"@session_id_context") -static char *ossl_sslctx_attrs[] = { +static const char *ossl_sslctx_attrs[] = { "cert", "key", "client_ca", "ca_file", "ca_path", "timeout", "verify_mode", "verify_depth", "verify_callback", "options", "cert_store", "extra_chain_cert", "client_cert_cb", "tmp_dh_callback", "session_id_context", + "session_get_cb", "session_new_cb", "session_remove_cb", }; #define ossl_ssl_get_io(o) rb_iv_get((o),"@io") @@ -86,8 +85,10 @@ static char *ossl_sslctx_attrs[] = { #define ossl_ssl_set_key(o,v) rb_iv_set((o),"@key",(v)) #define ossl_ssl_set_tmp_dh(o,v) rb_iv_set((o),"@tmp_dh",(v)) -static char *ossl_ssl_attr_readers[] = { "io", "context", }; -static char *ossl_ssl_attrs[] = { "sync_close", }; +static const char *ossl_ssl_attr_readers[] = { "io", "context", }; +static const char *ossl_ssl_attrs[] = { "sync_close", }; + +ID ID_callback_state; /* * SSLContext class @@ -140,6 +141,14 @@ ossl_sslctx_s_alloc(VALUE klass) return Data_Wrap_Struct(klass, 0, ossl_sslctx_free, ctx); } +/* + * call-seq: + * SSLContext.new => ctx + * SSLContext.new(:TLSv1) => ctx + * SSLContext.new("SSLv23_client") => ctx + * + * You can get a list of valid methods with OpenSSL::SSL::SSLContext::METHODS + */ static VALUE ossl_sslctx_initialize(int argc, VALUE *argv, VALUE self) { @@ -147,7 +156,7 @@ ossl_sslctx_initialize(int argc, VALUE *argv, VALUE self) SSL_METHOD *method = NULL; SSL_CTX *ctx; int i; - char *s; + const char *s; for(i = 0; i < numberof(ossl_sslctx_attrs); i++){ char buf[32]; @@ -274,6 +283,143 @@ ossl_ssl_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) } static VALUE +ossl_call_session_get_cb(VALUE ary) +{ + VALUE ssl_obj, sslctx_obj, cb, ret; + + Check_Type(ary, T_ARRAY); + ssl_obj = rb_ary_entry(ary, 0); + + sslctx_obj = rb_iv_get(ssl_obj, "@context"); + if (NIL_P(sslctx_obj)) return Qnil; + cb = rb_iv_get(sslctx_obj, "@session_get_cb"); + if (NIL_P(cb)) return Qnil; + + return rb_funcall(cb, rb_intern("call"), 1, ary); +} + +/* 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(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; +} + +static VALUE +ossl_call_session_new_cb(VALUE ary) +{ + VALUE ssl_obj, sslctx_obj, cb, ret; + + Check_Type(ary, T_ARRAY); + ssl_obj = rb_ary_entry(ary, 0); + + sslctx_obj = rb_iv_get(ssl_obj, "@context"); + if (NIL_P(sslctx_obj)) return Qnil; + cb = rb_iv_get(sslctx_obj, "@session_new_cb"); + if (NIL_P(cb)) return Qnil; + + return rb_funcall(cb, rb_intern("call"), 1, ary); +} + +/* 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; +} + +static VALUE +ossl_call_session_remove_cb(VALUE ary) +{ + VALUE sslctx_obj, cb, ret; + + Check_Type(ary, T_ARRAY); + sslctx_obj = rb_ary_entry(ary, 0); + + cb = rb_iv_get(sslctx_obj, "@session_remove_cb"); + if (NIL_P(cb)) return Qnil; + + return rb_funcall(cb, rb_intern("call"), 1, 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)); +*/ + } +} + +static VALUE ossl_sslctx_add_extra_chain_cert_i(VALUE i, VALUE arg) { X509 *x509; @@ -311,6 +457,7 @@ ossl_sslctx_setup(VALUE self) 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)){ @@ -327,7 +474,7 @@ ossl_sslctx_setup(VALUE self) val = ossl_sslctx_get_extra_cert(self); if(!NIL_P(val)){ - rb_iterate(rb_each, val, ossl_sslctx_add_extra_chain_cert_i, self); + 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. */ @@ -352,8 +499,8 @@ ossl_sslctx_setup(VALUE self) val = ossl_sslctx_get_client_ca(self); if(!NIL_P(val)){ if(TYPE(val) == T_ARRAY){ - for(i = 0; i < RARRAY(val)->len; i++){ - client_ca = GetX509CertPtr(RARRAY(val)->ptr[i]); + 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"); @@ -397,12 +544,24 @@ ossl_sslctx_setup(VALUE self) val = ossl_sslctx_get_sess_id_ctx(self); if (!NIL_P(val)){ StringValue(val); - if (!SSL_CTX_set_session_id_context(ctx, RSTRING(val)->ptr, - RSTRING(val)->len)){ - ossl_raise(eSSLError, "SSL_CTX_set_session_id_context:"); + if (!SSL_CTX_set_session_id_context(ctx, 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"); + } return Qtrue; } @@ -422,6 +581,10 @@ ossl_ssl_cipher_to_ary(SSL_CIPHER *cipher) return ary; } +/* + * call-seq: + * ctx.ciphers => [[name, version, bits, alg_bits], ...] + */ static VALUE ossl_sslctx_get_ciphers(VALUE self) { @@ -450,6 +613,12 @@ ossl_sslctx_get_ciphers(VALUE self) return ary; } +/* + * call-seq: + * ctx.ciphers = "cipher1:cipher2:..." + * ctx.ciphers = [name, ...] + * ctx.ciphers = [[name, version, bits, alg_bits], ...] + */ static VALUE ossl_sslctx_set_ciphers(VALUE self, VALUE v) { @@ -462,12 +631,12 @@ ossl_sslctx_set_ciphers(VALUE self, VALUE v) return v; else if (TYPE(v) == T_ARRAY) { str = rb_str_new(0, 0); - for (i = 0; i < RARRAY(v)->len; i++) { + for (i = 0; i < RARRAY_LEN(v); i++) { elem = rb_ary_entry(v, i); if (TYPE(elem) == T_ARRAY) elem = rb_ary_entry(elem, 0); elem = rb_String(elem); rb_str_append(str, elem); - if (i < RARRAY(v)->len-1) rb_str_cat2(str, ":"); + if (i < RARRAY_LEN(v)-1) rb_str_cat2(str, ":"); } } else { str = v; @@ -479,13 +648,173 @@ ossl_sslctx_set_ciphers(VALUE self, VALUE v) ossl_raise(eSSLError, "SSL_CTX is not initialized."); return Qnil; } - if (!SSL_CTX_set_cipher_list(ctx, RSTRING(str)->ptr)) { + if (!SSL_CTX_set_cipher_list(ctx, RSTRING_PTR(str))) { ossl_raise(eSSLError, "SSL_CTX_set_cipher_list:"); } return v; } + +/* + * call-seq: + * ctx.session_add(session) -> true | false + * + */ +static VALUE +ossl_sslctx_session_add(VALUE self, VALUE arg) +{ + SSL_CTX *ctx; + SSL_SESSION *sess; + + Data_Get_Struct(self, SSL_CTX, ctx); + SafeGetSSLSession(arg, sess); + + return SSL_CTX_add_session(ctx, sess) == 1 ? Qtrue : Qfalse; +} + +/* + * call-seq: + * ctx.session_remove(session) -> true | false + * + */ +static VALUE +ossl_sslctx_session_remove(VALUE self, VALUE arg) +{ + SSL_CTX *ctx; + SSL_SESSION *sess; + + Data_Get_Struct(self, SSL_CTX, ctx); + SafeGetSSLSession(arg, sess); + + return SSL_CTX_remove_session(ctx, sess) == 1 ? Qtrue : Qfalse; +} + +/* + * call-seq: + * ctx.session_cache_mode -> integer + * + */ +static VALUE +ossl_sslctx_get_session_cache_mode(VALUE self) +{ + SSL_CTX *ctx; + + Data_Get_Struct(self, SSL_CTX, ctx); + + return LONG2NUM(SSL_CTX_get_session_cache_mode(ctx)); +} + +/* + * call-seq: + * ctx.session_cache_mode=(integer) -> integer + * + */ +static VALUE +ossl_sslctx_set_session_cache_mode(VALUE self, VALUE arg) +{ + SSL_CTX *ctx; + + Data_Get_Struct(self, SSL_CTX, ctx); + + SSL_CTX_set_session_cache_mode(ctx, NUM2LONG(arg)); + + return arg; +} + +/* + * call-seq: + * ctx.session_cache_size -> integer + * + */ +static VALUE +ossl_sslctx_get_session_cache_size(VALUE self) +{ + SSL_CTX *ctx; + + Data_Get_Struct(self, SSL_CTX, ctx); + + return LONG2NUM(SSL_CTX_sess_get_cache_size(ctx)); +} + +/* + * call-seq: + * ctx.session_cache_size=(integer) -> integer + * + */ +static VALUE +ossl_sslctx_set_session_cache_size(VALUE self, VALUE arg) +{ + SSL_CTX *ctx; + + Data_Get_Struct(self, SSL_CTX, ctx); + + SSL_CTX_sess_set_cache_size(ctx, NUM2LONG(arg)); + + return arg; +} + +/* + * call-seq: + * ctx.session_cache_stats -> Hash + * + */ +static VALUE +ossl_sslctx_get_session_cache_stats(VALUE self) +{ + SSL_CTX *ctx; + VALUE hash; + + Data_Get_Struct(self, SSL_CTX, ctx); + + hash = rb_hash_new(); + rb_hash_aset(hash, rb_str_new2("cache_num"), LONG2NUM(SSL_CTX_sess_number(ctx))); + rb_hash_aset(hash, rb_str_new2("connect"), LONG2NUM(SSL_CTX_sess_connect(ctx))); + rb_hash_aset(hash, rb_str_new2("connect_good"), LONG2NUM(SSL_CTX_sess_connect_good(ctx))); + rb_hash_aset(hash, rb_str_new2("connect_renegotiate"), LONG2NUM(SSL_CTX_sess_connect_renegotiate(ctx))); + rb_hash_aset(hash, rb_str_new2("accept"), LONG2NUM(SSL_CTX_sess_accept(ctx))); + rb_hash_aset(hash, rb_str_new2("accept_good"), LONG2NUM(SSL_CTX_sess_accept_good(ctx))); + rb_hash_aset(hash, rb_str_new2("accept_renegotiate"), LONG2NUM(SSL_CTX_sess_accept_renegotiate(ctx))); + rb_hash_aset(hash, rb_str_new2("cache_hits"), LONG2NUM(SSL_CTX_sess_hits(ctx))); + rb_hash_aset(hash, rb_str_new2("cb_hits"), LONG2NUM(SSL_CTX_sess_cb_hits(ctx))); + rb_hash_aset(hash, rb_str_new2("cache_misses"), LONG2NUM(SSL_CTX_sess_misses(ctx))); + rb_hash_aset(hash, rb_str_new2("cache_full"), LONG2NUM(SSL_CTX_sess_cache_full(ctx))); + rb_hash_aset(hash, rb_str_new2("timeouts"), LONG2NUM(SSL_CTX_sess_timeouts(ctx))); + + return hash; +} + + +/* + * call-seq: + * ctx.flush_sessions(time | nil) -> self + * + */ +static VALUE +ossl_sslctx_flush_sessions(int argc, VALUE *argv, VALUE self) +{ + VALUE arg1; + SSL_CTX *ctx; + time_t tm = 0; + int cb_state; + + rb_scan_args(argc, argv, "01", &arg1); + + Data_Get_Struct(self, SSL_CTX, ctx); + + if (NIL_P(arg1)) { + tm = time(0); + } else if (rb_obj_is_instance_of(arg1, rb_cTime)) { + tm = NUM2LONG(rb_funcall(arg1, rb_intern("to_i"), 0)); + } else { + rb_raise(rb_eArgError, "arg must be Time or nil"); + } + + SSL_CTX_flush_sessions(ctx, tm); + + return self; +} + /* * SSLSocket class */ @@ -511,6 +840,20 @@ ossl_ssl_s_alloc(VALUE klass) return Data_Wrap_Struct(klass, 0, ossl_ssl_free, NULL); } +/* + * call-seq: + * SSLSocket.new(io) => aSSLSocket + * SSLSocket.new(io, ctx) => aSSLSocket + * + * === Parameters + * * +io+ is a real ruby IO object. Not an IO like object that responds to read/write. + * * +ctx+ is an OpenSSLSSL::SSLContext. + * + * The OpenSSL::Buffering module provides additional IO methods. + * + * This method will freeze the SSLContext if one is provided; + * however, session management is still allowed in the frozen SSLContext. + */ static VALUE ossl_ssl_initialize(int argc, VALUE *argv, VALUE self) { @@ -536,7 +879,7 @@ ossl_ssl_setup(VALUE self) VALUE io, v_ctx, cb; SSL_CTX *ctx; SSL *ssl; - OpenFile *fptr; + rb_io_t *fptr; Data_Get_Struct(self, SSL, ssl); if(!ssl){ @@ -553,7 +896,7 @@ ossl_ssl_setup(VALUE self) GetOpenFile(io, fptr); rb_io_check_readable(fptr); rb_io_check_writable(fptr); - SSL_set_fd(ssl, TO_SOCKET(fileno(fptr->f))); + SSL_set_fd(ssl, TO_SOCKET(FPTR_TO_FD(fptr))); SSL_set_ex_data(ssl, ossl_ssl_ex_ptr_idx, (void*)self); cb = ossl_sslctx_get_verify_cb(v_ctx); SSL_set_ex_data(ssl, ossl_ssl_ex_vcb_idx, (void*)cb); @@ -567,61 +910,85 @@ ossl_ssl_setup(VALUE self) } #ifdef _WIN32 -#define ssl_get_error(ssl, ret) \ - (errno = WSAGetLastError(), SSL_get_error(ssl, ret)) +#define ssl_get_error(ssl, ret) (errno = WSAGetLastError(), SSL_get_error(ssl, ret)) #else #define ssl_get_error(ssl, ret) SSL_get_error(ssl, ret) #endif static VALUE -ossl_start_ssl(VALUE self, int (*func)()) +ossl_start_ssl(VALUE self, int (*func)(), const char *funcname) { SSL *ssl; - OpenFile *fptr; - int ret; + rb_io_t *fptr; + int ret, ret2; + VALUE cb_state; + + rb_ivar_set(self, ID_callback_state, Qnil); Data_Get_Struct(self, SSL, ssl); GetOpenFile(ossl_ssl_get_io(self), fptr); for(;;){ if((ret = func(ssl)) > 0) break; - switch(ssl_get_error(ssl, ret)){ + switch((ret2 = ssl_get_error(ssl, ret))){ case SSL_ERROR_WANT_WRITE: - rb_io_wait_writable(fileno(fptr->f)); + rb_io_wait_writable(FPTR_TO_FD(fptr)); continue; case SSL_ERROR_WANT_READ: - rb_io_wait_readable(fileno(fptr->f)); + rb_io_wait_readable(FPTR_TO_FD(fptr)); continue; case SSL_ERROR_SYSCALL: - if (errno) rb_sys_fail(0); + if (errno) rb_sys_fail(funcname); + ossl_raise(eSSLError, "%s SYSCALL returned=%d errno=%d state=%s", funcname, ret2, errno, SSL_state_string_long(ssl)); default: - ossl_raise(eSSLError, NULL); + ossl_raise(eSSLError, "%s returned=%d errno=%d state=%s", funcname, ret2, errno, SSL_state_string_long(ssl)); } } + cb_state = rb_ivar_get(self, ID_callback_state); + if (!NIL_P(cb_state)) + rb_jump_tag(NUM2INT(cb_state)); + return self; } +/* + * call-seq: + * ssl.connect => self + */ static VALUE ossl_ssl_connect(VALUE self) { ossl_ssl_setup(self); - return ossl_start_ssl(self, SSL_connect); + return ossl_start_ssl(self, SSL_connect, "SSL_connect"); } +/* + * call-seq: + * ssl.accept => self + */ static VALUE ossl_ssl_accept(VALUE self) { ossl_ssl_setup(self); - return ossl_start_ssl(self, SSL_accept); + return ossl_start_ssl(self, SSL_accept, "SSL_accept"); } +/* + * call-seq: + * ssl.sysread(length) => string + * ssl.sysread(length, buffer) => buffer + * + * === Parameters + * * +length+ is a positive integer. + * * +buffer+ is a string used to store the result. + */ static VALUE ossl_ssl_read(int argc, VALUE *argv, VALUE self) { SSL *ssl; int ilen, nread = 0; VALUE len, str; - OpenFile *fptr; + rb_io_t *fptr; rb_scan_args(argc, argv, "11", &len, &str); ilen = NUM2INT(len); @@ -637,19 +1004,19 @@ ossl_ssl_read(int argc, VALUE *argv, VALUE self) GetOpenFile(ossl_ssl_get_io(self), fptr); if (ssl) { if(SSL_pending(ssl) <= 0) - rb_thread_wait_fd(fileno(fptr->f)); + rb_thread_wait_fd(FPTR_TO_FD(fptr)); for (;;){ - nread = SSL_read(ssl, RSTRING(str)->ptr, RSTRING(str)->len); + nread = SSL_read(ssl, RSTRING_PTR(str), RSTRING_LEN(str)); switch(ssl_get_error(ssl, nread)){ case SSL_ERROR_NONE: goto end; case SSL_ERROR_ZERO_RETURN: rb_eof_error(); case SSL_ERROR_WANT_WRITE: - rb_io_wait_writable(fileno(fptr->f)); + rb_io_wait_writable(FPTR_TO_FD(fptr)); continue; case SSL_ERROR_WANT_READ: - rb_io_wait_readable(fileno(fptr->f)); + rb_io_wait_readable(FPTR_TO_FD(fptr)); continue; case SSL_ERROR_SYSCALL: if(ERR_peek_error() == 0 && nread == 0) rb_eof_error(); @@ -666,19 +1033,22 @@ ossl_ssl_read(int argc, VALUE *argv, VALUE self) } end: - RSTRING(str)->len = nread; - RSTRING(str)->ptr[nread] = 0; + rb_str_set_len(str, nread); OBJ_TAINT(str); return str; } +/* + * call-seq: + * ssl.syswrite(string) => integer + */ static VALUE ossl_ssl_write(VALUE self, VALUE str) { SSL *ssl; int nwrite = 0; - OpenFile *fptr; + rb_io_t *fptr; StringValue(str); Data_Get_Struct(self, SSL, ssl); @@ -686,15 +1056,15 @@ ossl_ssl_write(VALUE self, VALUE str) if (ssl) { for (;;){ - nwrite = SSL_write(ssl, RSTRING(str)->ptr, RSTRING(str)->len); + nwrite = SSL_write(ssl, RSTRING_PTR(str), RSTRING_LEN(str)); switch(ssl_get_error(ssl, nwrite)){ case SSL_ERROR_NONE: goto end; case SSL_ERROR_WANT_WRITE: - rb_io_wait_writable(fileno(fptr->f)); + rb_io_wait_writable(FPTR_TO_FD(fptr)); continue; case SSL_ERROR_WANT_READ: - rb_io_wait_readable(fileno(fptr->f)); + rb_io_wait_readable(FPTR_TO_FD(fptr)); continue; case SSL_ERROR_SYSCALL: if (errno) rb_sys_fail(0); @@ -713,6 +1083,10 @@ ossl_ssl_write(VALUE self, VALUE str) return INT2NUM(nwrite); } +/* + * call-seq: + * ssl.sysclose => nil + */ static VALUE ossl_ssl_close(VALUE self) { @@ -726,6 +1100,10 @@ ossl_ssl_close(VALUE self) return Qnil; } +/* + * call-seq: + * ssl.cert => cert or nil + */ static VALUE ossl_ssl_get_cert(VALUE self) { @@ -750,6 +1128,10 @@ ossl_ssl_get_cert(VALUE self) return ossl_x509_new(cert); } +/* + * call-seq: + * ssl.peer_cert => cert or nil + */ static VALUE ossl_ssl_get_peer_cert(VALUE self) { @@ -775,6 +1157,10 @@ ossl_ssl_get_peer_cert(VALUE self) return obj; } +/* + * call-seq: + * ssl.peer_cert_chain => [cert, ...] or nil + */ static VALUE ossl_ssl_get_peer_cert_chain(VALUE self) { @@ -801,6 +1187,10 @@ ossl_ssl_get_peer_cert_chain(VALUE self) return ary; } +/* + * call-seq: + * ssl.cipher => [name, version, bits, alg_bits] + */ static VALUE ossl_ssl_get_cipher(VALUE self) { @@ -817,6 +1207,10 @@ ossl_ssl_get_cipher(VALUE self) return ossl_ssl_cipher_to_ary(cipher); } +/* + * call-seq: + * ssl.state => string + */ static VALUE ossl_ssl_get_state(VALUE self) { @@ -836,6 +1230,10 @@ ossl_ssl_get_state(VALUE self) return ret; } +/* + * call-seq: + * ssl.pending => integer + */ static VALUE ossl_ssl_pending(VALUE self) { @@ -850,15 +1248,70 @@ ossl_ssl_pending(VALUE self) return INT2NUM(SSL_pending(ssl)); } +/* + * call-seq: + * ssl.session_reused? -> true | false + * + */ +static VALUE +ossl_ssl_session_reused(VALUE self) +{ + SSL *ssl; + + Data_Get_Struct(self, SSL, ssl); + if (!ssl) { + rb_warning("SSL session is not started yet."); + return Qnil; + } + + switch(SSL_session_reused(ssl)) { + case 1: return Qtrue; + case 0: return Qfalse; + default: ossl_raise(eSSLError, "SSL_session_reused"); + } +} + +/* + * call-seq: + * ssl.session = session -> session + * + */ +static VALUE +ossl_ssl_set_session(VALUE self, VALUE arg1) +{ + SSL *ssl; + SSL_SESSION *sess; + +/* why is ossl_ssl_setup delayed? */ + ossl_ssl_setup(self); + + Data_Get_Struct(self, SSL, ssl); + if (!ssl) { + rb_warning("SSL session is not started yet."); + return Qnil; + } + + SafeGetSSLSession(arg1, sess); + + if (SSL_set_session(ssl, sess) != 1) + ossl_raise(eSSLError, "SSL_set_session"); + + return arg1; +} + + void Init_ossl_ssl() { int i; + VALUE ary; #if 0 /* let rdoc know about mOSSL */ mOSSL = rb_define_module("OpenSSL"); #endif + ID_callback_state = rb_intern("@callback_state"); + ossl_ssl_ex_vcb_idx = SSL_get_ex_new_index(0,"ossl_ssl_ex_vcb_idx",0,0,0); ossl_ssl_ex_store_p = SSL_get_ex_new_index(0,"ossl_ssl_ex_store_p",0,0,0); ossl_ssl_ex_ptr_idx = SSL_get_ex_new_index(0,"ossl_ssl_ex_ptr_idx",0,0,0); @@ -870,7 +1323,14 @@ Init_ossl_ssl() mSSL = rb_define_module_under(mOSSL, "SSL"); eSSLError = rb_define_class_under(mSSL, "SSLError", eOSSLError); - /* class SSLContext */ + /* class SSLContext + * + * The following attributes are available but don't show up in rdoc. + * All attributes must be set before calling SSLSocket.new(io, ctx). + * * cert, key, client_ca, ca_file, ca_path, timeout, verify_mode, verify_depth + * * client_cert_cb, tmp_dh_callback, session_id_context, + * * session_add_cb, session_new_cb, session_remove_cb + */ cSSLContext = rb_define_class_under(mSSL, "SSLContext", rb_cObject); rb_define_alloc_func(cSSLContext, ossl_sslctx_s_alloc); for(i = 0; i < numberof(ossl_sslctx_attrs); i++) @@ -879,7 +1339,38 @@ Init_ossl_ssl() rb_define_method(cSSLContext, "ciphers", ossl_sslctx_get_ciphers, 0); rb_define_method(cSSLContext, "ciphers=", ossl_sslctx_set_ciphers, 1); - /* class SSLSocket */ + + rb_define_const(cSSLContext, "SESSION_CACHE_OFF", LONG2FIX(SSL_SESS_CACHE_OFF)); + rb_define_const(cSSLContext, "SESSION_CACHE_CLIENT", LONG2FIX(SSL_SESS_CACHE_CLIENT)); /* doesn't actually do anything in 0.9.8e */ + rb_define_const(cSSLContext, "SESSION_CACHE_SERVER", LONG2FIX(SSL_SESS_CACHE_SERVER)); + rb_define_const(cSSLContext, "SESSION_CACHE_BOTH", LONG2FIX(SSL_SESS_CACHE_BOTH)); /* no different than CACHE_SERVER in 0.9.8e */ + rb_define_const(cSSLContext, "SESSION_CACHE_NO_AUTO_CLEAR", LONG2FIX(SSL_SESS_CACHE_NO_AUTO_CLEAR)); + rb_define_const(cSSLContext, "SESSION_CACHE_NO_INTERNAL_LOOKUP", LONG2FIX(SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)); + rb_define_const(cSSLContext, "SESSION_CACHE_NO_INTERNAL_STORE", LONG2FIX(SSL_SESS_CACHE_NO_INTERNAL_STORE)); + rb_define_const(cSSLContext, "SESSION_CACHE_NO_INTERNAL", LONG2FIX(SSL_SESS_CACHE_NO_INTERNAL)); + rb_define_method(cSSLContext, "session_add", ossl_sslctx_session_add, 1); + rb_define_method(cSSLContext, "session_remove", ossl_sslctx_session_remove, 1); + rb_define_method(cSSLContext, "session_cache_mode", ossl_sslctx_get_session_cache_mode, 0); + rb_define_method(cSSLContext, "session_cache_mode=", ossl_sslctx_set_session_cache_mode, 1); + rb_define_method(cSSLContext, "session_cache_size", ossl_sslctx_get_session_cache_size, 0); + rb_define_method(cSSLContext, "session_cache_size=", ossl_sslctx_set_session_cache_size, 1); + rb_define_method(cSSLContext, "session_cache_stats", ossl_sslctx_get_session_cache_stats, 0); + rb_define_method(cSSLContext, "flush_sessions", ossl_sslctx_flush_sessions, -1); + + ary = rb_ary_new2(numberof(ossl_ssl_method_tab)); + for (i = 0; i < numberof(ossl_ssl_method_tab); i++) { + rb_ary_push(ary, ID2SYM(rb_intern(ossl_ssl_method_tab[i].name))); + } + rb_obj_freeze(ary); + /* holds a list of available SSL/TLS methods */ + rb_define_const(cSSLContext, "METHODS", ary); + + /* class SSLSocket + * + * The following attributes are available but don't show up in rdoc. + * * io, context, sync_close + * + */ cSSLSocket = rb_define_class_under(mSSL, "SSLSocket", rb_cObject); rb_define_alloc_func(cSSLSocket, ossl_ssl_s_alloc); for(i = 0; i < numberof(ossl_ssl_attr_readers); i++) @@ -899,6 +1390,8 @@ Init_ossl_ssl() rb_define_method(cSSLSocket, "cipher", ossl_ssl_get_cipher, 0); rb_define_method(cSSLSocket, "state", ossl_ssl_get_state, 0); rb_define_method(cSSLSocket, "pending", ossl_ssl_pending, 0); + rb_define_method(cSSLSocket, "session_reused?", ossl_ssl_session_reused, 0); + rb_define_method(cSSLSocket, "session=", ossl_ssl_set_session, 1); #define ossl_ssl_def_const(x) rb_define_const(mSSL, #x, INT2FIX(SSL_##x)) diff --git a/ext/openssl/ossl_ssl.h b/ext/openssl/ossl_ssl.h index 5929eef856..487f41216c 100644 --- a/ext/openssl/ossl_ssl.h +++ b/ext/openssl/ossl_ssl.h @@ -11,11 +11,26 @@ #if !defined(_OSSL_SSL_H_) #define _OSSL_SSL_H_ +#define GetSSLSession(obj, sess) do { \ + Data_Get_Struct(obj, SSL_SESSION, sess); \ + if (!sess) { \ + ossl_raise(rb_eRuntimeError, "SSL Session wasn't initialized."); \ + } \ +} while (0) + +#define SafeGetSSLSession(obj, sess) do { \ + OSSL_Check_Kind(obj, cSSLSession); \ + GetSSLSession(obj, sess); \ +} while (0) + extern VALUE mSSL; extern VALUE eSSLError; extern VALUE cSSLSocket; extern VALUE cSSLContext; +extern VALUE cSSLSession; void Init_ossl_ssl(void); +void Init_ossl_ssl_session(void); #endif /* _OSSL_SSL_H_ */ + diff --git a/ext/openssl/ossl_ssl_session.c b/ext/openssl/ossl_ssl_session.c new file mode 100644 index 0000000000..b21cd1535e --- /dev/null +++ b/ext/openssl/ossl_ssl_session.c @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2004-2007 Technorama Ltd. <oss-ruby@technorama.net> + */ + +#include "ossl.h" + +#define GetSSLSession(obj, sess) do { \ + Data_Get_Struct(obj, SSL_SESSION, sess); \ + if (!sess) { \ + ossl_raise(rb_eRuntimeError, "SSL Session wasn't initialized."); \ + } \ +} while (0) + +#define SafeGetSSLSession(obj, sess) do { \ + OSSL_Check_Kind(obj, cSSLSession); \ + GetSSLSession(obj, sess); \ +} while (0) + + +VALUE cSSLSession; +static VALUE eSSLSession; + +static VALUE ossl_ssl_session_alloc(VALUE klass) +{ + return Data_Wrap_Struct(klass, 0, SSL_SESSION_free, NULL); +} + +/* + * call-seq: + * Session.new(SSLSocket | string) => session + * + * === Parameters + * +SSLSocket+ is an OpenSSL::SSL::SSLSocket + * +string+ must be a DER or PEM encoded Session. +*/ +static VALUE ossl_ssl_session_initialize(VALUE self, VALUE arg1) +{ + SSL_SESSION *ctx = NULL; + VALUE obj; + unsigned char *p; + + if (RDATA(self)->data) + ossl_raise(eSSLSession, "SSL Session already initialized"); + + if (rb_obj_is_instance_of(arg1, cSSLSocket)) { + SSL *ssl; + + Data_Get_Struct(arg1, SSL, ssl); + + if ((ctx = SSL_get1_session(ssl)) == NULL) + ossl_raise(eSSLSession, "no session available"); + } else { + BIO *in = ossl_obj2bio(arg1); + + ctx = PEM_read_bio_SSL_SESSION(in, NULL, NULL, NULL); + + if (!ctx) { + BIO_reset(in); + ctx = d2i_SSL_SESSION_bio(in, NULL); + } + + BIO_free(in); + + if (!ctx) + ossl_raise(rb_eArgError, "unknown type"); + } + + /* should not happen */ + if (ctx == NULL) + ossl_raise(eSSLSession, "ctx not set - internal error"); + + RDATA(self)->data = ctx; + + return self; +} + +/* + * call-seq: + * session1 == session2 -> boolean + * +*/ +static VALUE ossl_ssl_session_eq(VALUE val1, VALUE val2) +{ + SSL_SESSION *ctx1, *ctx2; + + GetSSLSession(val1, ctx1); + SafeGetSSLSession(val2, ctx2); + + switch (SSL_SESSION_cmp(ctx1, ctx2)) { + case 0: return Qtrue; + default: return Qfalse; + } +} + +/* + * call-seq: + * session.time -> Time + * +*/ +static VALUE ossl_ssl_session_get_time(VALUE self) +{ + SSL_SESSION *ctx; + time_t t; + + GetSSLSession(self, ctx); + + t = SSL_SESSION_get_time(ctx); + + if (t == 0) + return Qnil; + + return rb_funcall(rb_cTime, rb_intern("at"), 1, LONG2NUM(t)); +} + +/* + * call-seq: + * session.timeout -> integer + * + * How long until the session expires in seconds. + * +*/ +static VALUE ossl_ssl_session_get_timeout(VALUE self) +{ + SSL_SESSION *ctx; + time_t t; + + GetSSLSession(self, ctx); + + t = SSL_SESSION_get_timeout(ctx); + + return ULONG2NUM(t); +} + +#define SSLSESSION_SET_TIME(func) \ + static VALUE ossl_ssl_session_set_##func(VALUE self, VALUE time_v) \ + { \ + SSL_SESSION *ctx; \ + time_t t; \ + \ + GetSSLSession(self, ctx); \ + \ + if (rb_obj_is_instance_of(time_v, rb_cTime)) { \ + time_v = rb_funcall(time_v, rb_intern("to_i"), 0); \ + } else if (FIXNUM_P(time_v)) { \ + ; \ + } else { \ + rb_raise(rb_eArgError, "unknown type"); \ + } \ + \ + t = NUM2ULONG(time_v); \ + \ + SSL_SESSION_set_##func(ctx, t); \ + \ + return ossl_ssl_session_get_##func(self); \ + } + +SSLSESSION_SET_TIME(time) +SSLSESSION_SET_TIME(timeout) + +/* + * call-seq: + * session.id -> aString + * + * Returns the Session ID. +*/ +static VALUE ossl_ssl_session_get_id(VALUE self) +{ + SSL_SESSION *ctx; + const unsigned char *p = NULL; + unsigned int i = 0; + + GetSSLSession(self, ctx); + + p = SSL_SESSION_get_id(ctx, &i); + + return rb_str_new(p, i); +} + +/* + * call-seq: + * session.to_der -> aString + * + * Returns an ASN1 encoded String that contains the Session object. +*/ +static VALUE ossl_ssl_session_to_der(VALUE self) +{ + SSL_SESSION *ctx; + unsigned char buf[1024*10], *p; + int len; + + GetSSLSession(self, ctx); + + p = buf; + len = i2d_SSL_SESSION(ctx, &p); + + if (len <= 0) + ossl_raise(eSSLSession, "i2d_SSL_SESSION"); + else if (len >= sizeof(buf)) + ossl_raise(eSSLSession, "i2d_SSL_SESSION too large"); + + return rb_str_new(p, len); +} + +/* + * call-seq: + * session.to_pem -> String + * + * Returns a PEM encoded String that contains the Session object. +*/ +static VALUE ossl_ssl_session_to_pem(VALUE self) +{ + SSL_SESSION *ctx; + BIO *out; + BUF_MEM *buf; + VALUE str; + int i; + + GetSSLSession(self, ctx); + + if (!(out = BIO_new(BIO_s_mem()))) { + ossl_raise(eSSLSession, "BIO_s_mem()"); + } + + if (!(i=PEM_write_bio_SSL_SESSION(out, ctx))) { + BIO_free(out); + ossl_raise(eSSLSession, "SSL_SESSION_print()"); + } + + BIO_get_mem_ptr(out, &buf); + str = rb_str_new(buf->data, buf->length); + BIO_free(out); + + return str; +} + + +/* + * call-seq: + * session.to_text -> String + * + * Shows everything in the Session object. +*/ +static VALUE ossl_ssl_session_to_text(VALUE self) +{ + SSL_SESSION *ctx; + BIO *out; + BUF_MEM *buf; + VALUE str; + + GetSSLSession(self, ctx); + + if (!(out = BIO_new(BIO_s_mem()))) { + ossl_raise(eSSLSession, "BIO_s_mem()"); + } + + if (!SSL_SESSION_print(out, ctx)) { + BIO_free(out); + ossl_raise(eSSLSession, "SSL_SESSION_print()"); + } + + BIO_get_mem_ptr(out, &buf); + str = rb_str_new(buf->data, buf->length); + BIO_free(out); + + return str; +} + + +void Init_ossl_ssl_session(void) +{ +#if 0 /* let rdoc know about mOSSL */ + mOSSL = rb_define_module("OpenSSL"); + mSSL = rb_define_module_under(mOSSL, "SSL"); +#endif + cSSLSession = rb_define_class_under(mSSL, "Session", rb_cObject); + eSSLSession = rb_define_class_under(cSSLSession, "SessionError", eOSSLError); + + rb_define_alloc_func(cSSLSession, ossl_ssl_session_alloc); + rb_define_method(cSSLSession, "initialize", ossl_ssl_session_initialize, 1); + + rb_define_method(cSSLSession, "==", ossl_ssl_session_eq, 1); + + rb_define_method(cSSLSession, "time", ossl_ssl_session_get_time, 0); + rb_define_method(cSSLSession, "time=", ossl_ssl_session_set_time, 1); + rb_define_method(cSSLSession, "timeout", ossl_ssl_session_get_timeout, 0); + rb_define_method(cSSLSession, "timeout=", ossl_ssl_session_set_timeout, 1); + + rb_define_method(cSSLSession, "id", ossl_ssl_session_get_id, 0); + rb_define_method(cSSLSession, "to_der", ossl_ssl_session_to_der, 0); + rb_define_method(cSSLSession, "to_pem", ossl_ssl_session_to_pem, 0); + rb_define_method(cSSLSession, "to_text", ossl_ssl_session_to_text, 0); +} diff --git a/ext/openssl/ossl_x509attr.c b/ext/openssl/ossl_x509attr.c index 7b88e294a9..ca1c59aba9 100644 --- a/ext/openssl/ossl_x509attr.c +++ b/ext/openssl/ossl_x509attr.c @@ -84,6 +84,10 @@ ossl_x509attr_alloc(VALUE klass) return obj; } +/* + * call-seq: + * Attribute.new(oid [, value]) => attr + */ static VALUE ossl_x509attr_initialize(int argc, VALUE *argv, VALUE self) { @@ -95,9 +99,9 @@ ossl_x509attr_initialize(int argc, VALUE *argv, VALUE self) if(rb_scan_args(argc, argv, "11", &oid, &value) == 1){ oid = ossl_to_der_if_possible(oid); StringValue(oid); - p = RSTRING(oid)->ptr; + p = RSTRING_PTR(oid); if(!d2i_X509_ATTRIBUTE((X509_ATTRIBUTE**)&DATA_PTR(self), - &p, RSTRING(oid)->len)){ + &p, RSTRING_LEN(oid))){ ossl_raise(eX509AttrError, NULL); } return self; @@ -108,6 +112,10 @@ ossl_x509attr_initialize(int argc, VALUE *argv, VALUE self) return self; } +/* + * call-seq: + * attr.oid = string => string + */ static VALUE ossl_x509attr_set_oid(VALUE self, VALUE oid) { @@ -125,6 +133,10 @@ ossl_x509attr_set_oid(VALUE self, VALUE oid) return oid; } +/* + * call-seq: + * attr.oid => string + */ static VALUE ossl_x509attr_get_oid(VALUE self) { @@ -156,6 +168,10 @@ ossl_x509attr_get_oid(VALUE self) # define OSSL_X509ATTR_SET_SINGLE(attr) ((attr)->set = 0) #endif +/* + * call-seq: + * attr.value = asn1 => asn1 + */ static VALUE ossl_x509attr_set_value(VALUE self, VALUE value) { @@ -179,6 +195,10 @@ ossl_x509attr_set_value(VALUE self, VALUE value) return value; } +/* + * call-seq: + * attr.value => asn1 + */ static VALUE ossl_x509attr_get_value(VALUE self) { @@ -192,7 +212,7 @@ ossl_x509attr_get_value(VALUE self) if(OSSL_X509ATTR_IS_SINGLE(attr)){ length = i2d_ASN1_TYPE(attr->value.single, NULL); str = rb_str_new(0, length); - p = RSTRING(str)->ptr; + p = RSTRING_PTR(str); i2d_ASN1_TYPE(attr->value.single, &p); ossl_str_adjust(str, p); } @@ -200,7 +220,7 @@ ossl_x509attr_get_value(VALUE self) length = i2d_ASN1_SET_OF_ASN1_TYPE(attr->value.set, NULL, i2d_ASN1_TYPE, V_ASN1_SET, V_ASN1_UNIVERSAL, 0); str = rb_str_new(0, length); - p = RSTRING(str)->ptr; + p = RSTRING_PTR(str); i2d_ASN1_SET_OF_ASN1_TYPE(attr->value.set, &p, i2d_ASN1_TYPE, V_ASN1_SET, V_ASN1_UNIVERSAL, 0); ossl_str_adjust(str, p); @@ -210,6 +230,10 @@ ossl_x509attr_get_value(VALUE self) return asn1; } +/* + * call-seq: + * attr.to_der => string + */ static VALUE ossl_x509attr_to_der(VALUE self) { @@ -222,10 +246,10 @@ ossl_x509attr_to_der(VALUE self) if((len = i2d_X509_ATTRIBUTE(attr, NULL)) <= 0) ossl_raise(eX509AttrError, NULL); str = rb_str_new(0, len); - p = RSTRING(str)->ptr; + p = RSTRING_PTR(str); if(i2d_X509_ATTRIBUTE(attr, &p) <= 0) ossl_raise(eX509AttrError, NULL); - RSTRING(str)->len = p - (unsigned char*)RSTRING(str)->ptr; + rb_str_set_len(str, p - (unsigned char*)RSTRING_PTR(str)); return str; } diff --git a/ext/openssl/ossl_x509cert.c b/ext/openssl/ossl_x509cert.c index fc587a31f3..b97f27ffa9 100644 --- a/ext/openssl/ossl_x509cert.c +++ b/ext/openssl/ossl_x509cert.c @@ -63,7 +63,7 @@ ossl_x509_new_from_file(VALUE filename) VALUE obj; SafeStringValue(filename); - if (!(fp = fopen(RSTRING(filename)->ptr, "r"))) { + if (!(fp = fopen(RSTRING_PTR(filename), "r"))) { ossl_raise(eX509CertError, "%s", strerror(errno)); } x509 = PEM_read_X509(fp, NULL, NULL, NULL); @@ -125,6 +125,11 @@ ossl_x509_alloc(VALUE klass) return obj; } +/* + * call-seq: + * Certificate.new => cert + * Certificate.new(string) => cert + */ static VALUE ossl_x509_initialize(int argc, VALUE *argv, VALUE self) { @@ -169,6 +174,10 @@ ossl_x509_copy(VALUE self, VALUE other) return self; } +/* + * call-seq: + * cert.to_der => string + */ static VALUE ossl_x509_to_der(VALUE self) { @@ -181,7 +190,7 @@ ossl_x509_to_der(VALUE self) if ((len = i2d_X509(x509, NULL)) <= 0) ossl_raise(eX509CertError, NULL); str = rb_str_new(0, len); - p = RSTRING(str)->ptr; + p = RSTRING_PTR(str); if (i2d_X509(x509, &p) <= 0) ossl_raise(eX509CertError, NULL); ossl_str_adjust(str, p); @@ -189,6 +198,10 @@ ossl_x509_to_der(VALUE self) return str; } +/* + * call-seq: + * cert.to_pem => string + */ static VALUE ossl_x509_to_pem(VALUE self) { @@ -209,6 +222,10 @@ ossl_x509_to_pem(VALUE self) return str; } +/* + * call-seq: + * cert.to_text => string + */ static VALUE ossl_x509_to_text(VALUE self) { @@ -252,6 +269,10 @@ ossl_x509_to_req(VALUE self) } #endif +/* + * call-seq: + * cert.version => integer + */ static VALUE ossl_x509_get_version(VALUE self) { @@ -262,6 +283,10 @@ ossl_x509_get_version(VALUE self) return LONG2NUM(X509_get_version(x509)); } +/* + * call-seq: + * cert.version = integer => integer + */ static VALUE ossl_x509_set_version(VALUE self, VALUE version) { @@ -279,6 +304,10 @@ ossl_x509_set_version(VALUE self, VALUE version) return version; } +/* + * call-seq: + * cert.serial => integer + */ static VALUE ossl_x509_get_serial(VALUE self) { @@ -289,6 +318,10 @@ ossl_x509_get_serial(VALUE self) return asn1integer_to_num(X509_get_serialNumber(x509)); } +/* + * call-seq: + * cert.serial = integer => integer + */ static VALUE ossl_x509_set_serial(VALUE self, VALUE num) { @@ -302,6 +335,10 @@ ossl_x509_set_serial(VALUE self, VALUE num) return num; } +/* + * call-seq: + * cert.signature_algorithm => string + */ static VALUE ossl_x509_get_signature_algorithm(VALUE self) { @@ -322,6 +359,10 @@ ossl_x509_get_signature_algorithm(VALUE self) return str; } +/* + * call-seq: + * cert.subject => name + */ static VALUE ossl_x509_get_subject(VALUE self) { @@ -336,6 +377,10 @@ ossl_x509_get_subject(VALUE self) return ossl_x509name_new(name); } +/* + * call-seq: + * cert.subject = name => name + */ static VALUE ossl_x509_set_subject(VALUE self, VALUE subject) { @@ -349,6 +394,10 @@ ossl_x509_set_subject(VALUE self, VALUE subject) return subject; } +/* + * call-seq: + * cert.issuer => name + */ static VALUE ossl_x509_get_issuer(VALUE self) { @@ -363,6 +412,10 @@ ossl_x509_get_issuer(VALUE self) return ossl_x509name_new(name); } +/* + * call-seq: + * cert.issuer = name => name + */ static VALUE ossl_x509_set_issuer(VALUE self, VALUE issuer) { @@ -376,6 +429,10 @@ ossl_x509_set_issuer(VALUE self, VALUE issuer) return issuer; } +/* + * call-seq: + * cert.not_before => time + */ static VALUE ossl_x509_get_not_before(VALUE self) { @@ -390,6 +447,10 @@ ossl_x509_get_not_before(VALUE self) return asn1time_to_time(asn1time); } +/* + * call-seq: + * cert.not_before = time => time + */ static VALUE ossl_x509_set_not_before(VALUE self, VALUE time) { @@ -405,6 +466,10 @@ ossl_x509_set_not_before(VALUE self, VALUE time) return time; } +/* + * call-seq: + * cert.not_after => time + */ static VALUE ossl_x509_get_not_after(VALUE self) { @@ -419,6 +484,10 @@ ossl_x509_get_not_after(VALUE self) return asn1time_to_time(asn1time); } +/* + * call-seq: + * cert.not_before = time => time + */ static VALUE ossl_x509_set_not_after(VALUE self, VALUE time) { @@ -434,6 +503,10 @@ ossl_x509_set_not_after(VALUE self, VALUE time) return time; } +/* + * call-seq: + * cert.public_key => key + */ static VALUE ossl_x509_get_public_key(VALUE self) { @@ -448,6 +521,10 @@ ossl_x509_get_public_key(VALUE self) return ossl_pkey_new(pkey); /* NO DUP - OK */ } +/* + * call-seq: + * cert.public_key = key => key + */ static VALUE ossl_x509_set_public_key(VALUE self, VALUE key) { @@ -461,6 +538,10 @@ ossl_x509_set_public_key(VALUE self, VALUE key) return key; } +/* + * call-seq: + * cert.sign(key, digest) => self + */ static VALUE ossl_x509_sign(VALUE self, VALUE key, VALUE digest) { @@ -479,6 +560,9 @@ ossl_x509_sign(VALUE self, VALUE key, VALUE digest) } /* + * call-seq: + * cert.verify(key) => true | false + * * Checks that cert signature is made with PRIVversion of this PUBLIC 'key' */ static VALUE @@ -501,6 +585,9 @@ ossl_x509_verify(VALUE self, VALUE key) } /* + * call-seq: + * cert.check_private_key(key) + * * Checks if 'key' is PRIV key for this cert */ static VALUE @@ -521,7 +608,8 @@ ossl_x509_check_private_key(VALUE self, VALUE key) } /* - * Gets X509v3 extensions as array of X509Ext objects + * call-seq: + * cert.extensions => [extension...] */ static VALUE ossl_x509_get_extensions(VALUE self) @@ -546,7 +634,8 @@ ossl_x509_get_extensions(VALUE self) } /* - * Sets X509_EXTENSIONs + * call-seq: + * cert.extensions = [ext...] => [ext...] */ static VALUE ossl_x509_set_extensions(VALUE self, VALUE ary) @@ -557,14 +646,14 @@ ossl_x509_set_extensions(VALUE self, VALUE ary) Check_Type(ary, T_ARRAY); /* All ary's members should be X509Extension */ - for (i=0; i<RARRAY(ary)->len; i++) { - OSSL_Check_Kind(RARRAY(ary)->ptr[i], cX509Ext); + for (i=0; i<RARRAY_LEN(ary); i++) { + OSSL_Check_Kind(RARRAY_PTR(ary)[i], cX509Ext); } GetX509(self, x509); sk_X509_EXTENSION_pop_free(x509->cert_info->extensions, X509_EXTENSION_free); x509->cert_info->extensions = NULL; - for (i=0; i<RARRAY(ary)->len; i++) { - ext = DupX509ExtPtr(RARRAY(ary)->ptr[i]); + for (i=0; i<RARRAY_LEN(ary); i++) { + ext = DupX509ExtPtr(RARRAY_PTR(ary)[i]); if (!X509_add_ext(x509, ext, -1)) { /* DUPs ext - FREE it */ X509_EXTENSION_free(ext); @@ -576,6 +665,10 @@ ossl_x509_set_extensions(VALUE self, VALUE ary) return ary; } +/* + * call-seq: + * cert.add_extension(extension) => extension + */ static VALUE ossl_x509_add_extension(VALUE self, VALUE extension) { diff --git a/ext/openssl/ossl_x509crl.c b/ext/openssl/ossl_x509crl.c index 0dc22416e7..be9ddacf48 100644 --- a/ext/openssl/ossl_x509crl.c +++ b/ext/openssl/ossl_x509crl.c @@ -287,14 +287,14 @@ ossl_x509crl_set_revoked(VALUE self, VALUE ary) Check_Type(ary, T_ARRAY); /* All ary members should be X509 Revoked */ - for (i=0; i<RARRAY(ary)->len; i++) { - OSSL_Check_Kind(RARRAY(ary)->ptr[i], cX509Rev); + for (i=0; i<RARRAY_LEN(ary); i++) { + OSSL_Check_Kind(RARRAY_PTR(ary)[i], cX509Rev); } GetX509CRL(self, crl); sk_X509_REVOKED_pop_free(crl->crl->revoked, X509_REVOKED_free); crl->crl->revoked = NULL; - for (i=0; i<RARRAY(ary)->len; i++) { - rev = DupX509RevokedPtr(RARRAY(ary)->ptr[i]); + for (i=0; i<RARRAY_LEN(ary); i++) { + rev = DupX509RevokedPtr(RARRAY_PTR(ary)[i]); if (!X509_CRL_add0_revoked(crl, rev)) { /* NO DUP - don't free! */ ossl_raise(eX509CRLError, NULL); } @@ -461,14 +461,14 @@ ossl_x509crl_set_extensions(VALUE self, VALUE ary) Check_Type(ary, T_ARRAY); /* All ary members should be X509 Extensions */ - for (i=0; i<RARRAY(ary)->len; i++) { - OSSL_Check_Kind(RARRAY(ary)->ptr[i], cX509Ext); + for (i=0; i<RARRAY_LEN(ary); i++) { + OSSL_Check_Kind(RARRAY_PTR(ary)[i], cX509Ext); } GetX509CRL(self, crl); sk_X509_EXTENSION_pop_free(crl->crl->extensions, X509_EXTENSION_free); crl->crl->extensions = NULL; - for (i=0; i<RARRAY(ary)->len; i++) { - ext = DupX509ExtPtr(RARRAY(ary)->ptr[i]); + for (i=0; i<RARRAY_LEN(ary); i++) { + ext = DupX509ExtPtr(RARRAY_PTR(ary)[i]); if(!X509_CRL_add_ext(crl, ext, -1)) { /* DUPs ext - FREE it */ X509_EXTENSION_free(ext); ossl_raise(eX509CRLError, NULL); diff --git a/ext/openssl/ossl_x509ext.c b/ext/openssl/ossl_x509ext.c index 31ffec48fa..aa9366f901 100644 --- a/ext/openssl/ossl_x509ext.c +++ b/ext/openssl/ossl_x509ext.c @@ -229,23 +229,23 @@ ossl_x509extfactory_create_ext(int argc, VALUE *argv, VALUE self) StringValue(value); if(NIL_P(critical)) critical = Qfalse; - nid = OBJ_ln2nid(RSTRING(oid)->ptr); - if(!nid) nid = OBJ_sn2nid(RSTRING(oid)->ptr); - if(!nid) ossl_raise(eX509ExtError, "unknown OID `%s'", RSTRING(oid)->ptr); + nid = OBJ_ln2nid(RSTRING_PTR(oid)); + if(!nid) nid = OBJ_sn2nid(RSTRING_PTR(oid)); + if(!nid) ossl_raise(eX509ExtError, "unknown OID `%s'", RSTRING_PTR(oid)); valstr = rb_str_new2(RTEST(critical) ? "critical," : ""); rb_str_append(valstr, value); GetX509ExtFactory(self, ctx); #ifdef HAVE_X509V3_EXT_NCONF_NID rconf = rb_iv_get(self, "@config"); conf = NIL_P(rconf) ? NULL : GetConfigPtr(rconf); - ext = X509V3_EXT_nconf_nid(conf, ctx, nid, RSTRING(valstr)->ptr); + ext = X509V3_EXT_nconf_nid(conf, ctx, nid, RSTRING_PTR(valstr)); #else if (!empty_lhash) empty_lhash = lh_new(NULL, NULL); - ext = X509V3_EXT_conf_nid(empty_lhash, ctx, nid, RSTRING(valstr)->ptr); + ext = X509V3_EXT_conf_nid(empty_lhash, ctx, nid, RSTRING_PTR(valstr)); #endif if (!ext){ ossl_raise(eX509ExtError, "%s = %s", - RSTRING(oid)->ptr, RSTRING(value)->ptr); + RSTRING_PTR(oid), RSTRING_PTR(value)); } WrapX509Ext(cX509Ext, obj, ext); @@ -280,9 +280,9 @@ ossl_x509ext_initialize(int argc, VALUE *argv, VALUE self) if(rb_scan_args(argc, argv, "12", &oid, &value, &critical) == 1){ oid = ossl_to_der_if_possible(oid); StringValue(oid); - p = RSTRING(oid)->ptr; + p = RSTRING_PTR(oid); if(!d2i_X509_EXTENSION((X509_EXTENSION**)&DATA_PTR(self), - &p, RSTRING(oid)->len)) + &p, RSTRING_LEN(oid))) ossl_raise(eX509ExtError, NULL); return self; } @@ -319,14 +319,14 @@ ossl_x509ext_set_value(VALUE self, VALUE data) data = ossl_to_der_if_possible(data); StringValue(data); - if(!(s = OPENSSL_malloc(RSTRING(data)->len))) + if(!(s = OPENSSL_malloc(RSTRING_LEN(data)))) ossl_raise(eX509ExtError, "malloc error"); - memcpy(s, RSTRING(data)->ptr, RSTRING(data)->len); + memcpy(s, RSTRING_PTR(data), RSTRING_LEN(data)); if(!(asn1s = ASN1_OCTET_STRING_new())){ free(s); ossl_raise(eX509ExtError, NULL); } - if(!M_ASN1_OCTET_STRING_set(asn1s, s, RSTRING(data)->len)){ + if(!M_ASN1_OCTET_STRING_set(asn1s, s, RSTRING_LEN(data))){ free(s); ASN1_OCTET_STRING_free(asn1s); ossl_raise(eX509ExtError, NULL); @@ -409,7 +409,7 @@ ossl_x509ext_to_der(VALUE obj) if((len = i2d_X509_EXTENSION(ext, NULL)) <= 0) ossl_raise(eX509ExtError, NULL); str = rb_str_new(0, len); - p = RSTRING(str)->ptr; + p = RSTRING_PTR(str); if(i2d_X509_EXTENSION(ext, &p) < 0) ossl_raise(eX509ExtError, NULL); ossl_str_adjust(str, p); diff --git a/ext/openssl/ossl_x509name.c b/ext/openssl/ossl_x509name.c index c5ed8b5457..c1164644e4 100644 --- a/ext/openssl/ossl_x509name.c +++ b/ext/openssl/ossl_x509name.c @@ -109,6 +109,13 @@ ossl_x509name_init_i(VALUE i, VALUE args) return Qnil; } +/* + * call-seq: + * X509::Name.new => name + * X509::Name.new(string) => name + * X509::Name.new(dn) => name + * X509::Name.new(dn, template) => name + */ static VALUE ossl_x509name_initialize(int argc, VALUE *argv, VALUE self) { @@ -125,14 +132,14 @@ ossl_x509name_initialize(int argc, VALUE *argv, VALUE self) VALUE args; if(NIL_P(template)) template = OBJECT_TYPE_TEMPLATE; args = rb_ary_new3(2, self, template); - rb_iterate(rb_each, tmp, ossl_x509name_init_i, args); + rb_block_call(tmp, rb_intern("each"), 0, 0, ossl_x509name_init_i, args); } else{ unsigned char *p; VALUE str = ossl_to_der_if_possible(arg); StringValue(str); - p = RSTRING(str)->ptr; - if(!d2i_X509_NAME((X509_NAME**)&DATA_PTR(self), &p, RSTRING(str)->len)){ + p = RSTRING_PTR(str); + if(!d2i_X509_NAME((X509_NAME**)&DATA_PTR(self), &p, RSTRING_LEN(str))){ ossl_raise(eX509NameError, NULL); } } @@ -141,6 +148,10 @@ ossl_x509name_initialize(int argc, VALUE *argv, VALUE self) return self; } +/* + * call-seq: + * name.add_entry(oid, value [, type]) => self + */ static VALUE ossl_x509name_add_entry(int argc, VALUE *argv, VALUE self) { @@ -152,8 +163,8 @@ VALUE ossl_x509name_add_entry(int argc, VALUE *argv, VALUE self) StringValue(value); if(NIL_P(type)) type = rb_aref(OBJECT_TYPE_TEMPLATE, oid); GetX509Name(self, name); - if (!X509_NAME_add_entry_by_txt(name, RSTRING(oid)->ptr, NUM2INT(type), - RSTRING(value)->ptr, RSTRING(value)->len, -1, 0)) { + if (!X509_NAME_add_entry_by_txt(name, RSTRING_PTR(oid), NUM2INT(type), + RSTRING_PTR(value), RSTRING_LEN(value), -1, 0)) { ossl_raise(eX509NameError, NULL); } @@ -175,9 +186,14 @@ ossl_x509name_to_s_old(VALUE self) return str; } +/* + * call-seq: + * name.to_s => string + * name.to_s(integer) => string + */ static VALUE ossl_x509name_to_s(int argc, VALUE *argv, VALUE self) -{ +{ X509_NAME *name; VALUE flag, str; BIO *out; @@ -199,6 +215,10 @@ ossl_x509name_to_s(int argc, VALUE *argv, VALUE self) return str; } +/* + * call-seq: + * name.to_a => [[name, data, type], ...] + */ static VALUE ossl_x509name_to_a(VALUE self) { @@ -266,6 +286,10 @@ ossl_x509name_eql(VALUE self, VALUE other) return (result == 0) ? Qtrue : Qfalse; } +/* + * call-seq: + * name.hash => integer + */ static VALUE ossl_x509name_hash(VALUE self) { @@ -279,6 +303,10 @@ ossl_x509name_hash(VALUE self) return ULONG2NUM(hash); } +/* + * call-seq: + * name.to_der => string + */ static VALUE ossl_x509name_to_der(VALUE self) { @@ -291,7 +319,7 @@ ossl_x509name_to_der(VALUE self) if((len = i2d_X509_NAME(name, NULL)) <= 0) ossl_raise(eX509NameError, NULL); str = rb_str_new(0, len); - p = RSTRING(str)->ptr; + p = RSTRING_PTR(str); if(i2d_X509_NAME(name, &p) <= 0) ossl_raise(eX509NameError, NULL); ossl_str_adjust(str, p); diff --git a/ext/openssl/ossl_x509req.c b/ext/openssl/ossl_x509req.c index d644250433..13a42dddaf 100644 --- a/ext/openssl/ossl_x509req.c +++ b/ext/openssl/ossl_x509req.c @@ -171,7 +171,7 @@ ossl_x509req_to_der(VALUE self) if ((len = i2d_X509_REQ(req, NULL)) <= 0) ossl_raise(eX509CertError, NULL); str = rb_str_new(0, len); - p = RSTRING(str)->ptr; + p = RSTRING_PTR(str); if (i2d_X509_REQ(req, &p) <= 0) ossl_raise(eX509ReqError, NULL); ossl_str_adjust(str, p); @@ -403,14 +403,14 @@ ossl_x509req_set_attributes(VALUE self, VALUE ary) VALUE item; Check_Type(ary, T_ARRAY); - for (i=0;i<RARRAY(ary)->len; i++) { - OSSL_Check_Kind(RARRAY(ary)->ptr[i], cX509Attr); + for (i=0;i<RARRAY_LEN(ary); i++) { + OSSL_Check_Kind(RARRAY_PTR(ary)[i], cX509Attr); } GetX509Req(self, req); sk_X509_ATTRIBUTE_pop_free(req->req_info->attributes, X509_ATTRIBUTE_free); req->req_info->attributes = NULL; - for (i=0;i<RARRAY(ary)->len; i++) { - item = RARRAY(ary)->ptr[i]; + for (i=0;i<RARRAY_LEN(ary); i++) { + item = RARRAY_PTR(ary)[i]; attr = DupX509AttrPtr(item); if (!X509_REQ_add1_attr(req, attr)) { ossl_raise(eX509ReqError, NULL); diff --git a/ext/openssl/ossl_x509revoked.c b/ext/openssl/ossl_x509revoked.c index 3ccac8d26a..d0f816bad4 100644 --- a/ext/openssl/ossl_x509revoked.c +++ b/ext/openssl/ossl_x509revoked.c @@ -175,14 +175,14 @@ ossl_x509revoked_set_extensions(VALUE self, VALUE ary) VALUE item; Check_Type(ary, T_ARRAY); - for (i=0; i<RARRAY(ary)->len; i++) { - OSSL_Check_Kind(RARRAY(ary)->ptr[i], cX509Ext); + for (i=0; i<RARRAY_LEN(ary); i++) { + OSSL_Check_Kind(RARRAY_PTR(ary)[i], cX509Ext); } GetX509Rev(self, rev); sk_X509_EXTENSION_pop_free(rev->extensions, X509_EXTENSION_free); rev->extensions = NULL; - for (i=0; i<RARRAY(ary)->len; i++) { - item = RARRAY(ary)->ptr[i]; + for (i=0; i<RARRAY_LEN(ary); i++) { + item = RARRAY_PTR(ary)[i]; ext = DupX509ExtPtr(item); if(!X509_REVOKED_add_ext(rev, ext, -1)) { ossl_raise(eX509RevError, NULL); diff --git a/ext/openssl/ossl_x509store.c b/ext/openssl/ossl_x509store.c index cea845a1cc..24a6625ee4 100644 --- a/ext/openssl/ossl_x509store.c +++ b/ext/openssl/ossl_x509store.c @@ -118,11 +118,18 @@ ossl_x509store_set_vfy_cb(VALUE self, VALUE cb) return cb; } + +/* + * call-seq: + * X509::Store.new => store + * + */ static VALUE ossl_x509store_initialize(int argc, VALUE *argv, VALUE self) { X509_STORE *store; +/* BUG: This method takes any number of arguments but appears to ignore them. */ GetX509Store(self, store); X509_STORE_set_verify_cb_func(store, ossl_verify_cb); ossl_x509store_set_vfy_cb(self, Qnil); @@ -206,7 +213,7 @@ ossl_x509store_add_file(VALUE self, VALUE file) if(file != Qnil){ Check_SafeStr(file); - path = RSTRING(file)->ptr; + path = RSTRING_PTR(file); } GetX509Store(self, store); lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); @@ -227,7 +234,7 @@ ossl_x509store_add_path(VALUE self, VALUE dir) if(dir != Qnil){ Check_SafeStr(dir); - path = RSTRING(dir)->ptr; + path = RSTRING_PTR(dir); } GetX509Store(self, store); lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir()); @@ -550,6 +557,10 @@ ossl_x509stctx_set_trust(VALUE self, VALUE trust) return trust; } +/* + * call-seq: + * storectx.time = time => time + */ static VALUE ossl_x509stctx_set_time(VALUE self, VALUE time) { diff --git a/ext/openssl/ruby_missing.h b/ext/openssl/ruby_missing.h index 4bd08890f8..64b76f26b4 100644 --- a/ext/openssl/ruby_missing.h +++ b/ext/openssl/ruby_missing.h @@ -9,10 +9,33 @@ * (See the file 'LICENCE'.) */ #if !defined(_OSSL_RUBY_MISSING_H_) -#define _OSS_RUBY_MISSING_H_ +#define _OSSL_RUBY_MISSING_H_ #define rb_define_copy_func(klass, func) \ rb_define_method(klass, "initialize_copy", func, 1) -#endif /* _OSS_RUBY_MISSING_H_ */ +#ifndef GetReadFile +#define FPTR_TO_FD(fptr) (fptr->fd) +#else +#define FPTR_TO_FD(fptr) (fileno(GetReadFile(fptr))) +#endif + +#ifndef HAVE_RB_IO_T +#define rb_io_t OpenFile +#endif + +#ifndef HAVE_RB_STR_SET_LEN +/* these methods should probably be backported to 1.8 */ +#define rb_str_set_len(str, length) do { \ + RSTRING(str)->ptr[length] = 0; \ + RSTRING(str)->len = length; \ +} while(0) +#endif /* ! HAVE_RB_STR_SET_LEN */ + +#ifndef HAVE_RB_BLOCK_CALL +/* the openssl module doesn't use arg[3-4] and arg2 is always rb_each */ +#define rb_block_call(arg1, arg2, arg3, arg4, arg5, arg6) rb_iterate(rb_each, arg1, arg5, arg6) +#endif /* ! HAVE_RB_BLOCK_CALL */ + +#endif /* _OSSL_RUBY_MISSING_H_ */ |