diff options
author | gotoyuzo <gotoyuzo@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2003-07-23 16:12:24 +0000 |
---|---|---|
committer | gotoyuzo <gotoyuzo@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2003-07-23 16:12:24 +0000 |
commit | 231247c010acba191b78ed2d1310c935e63ad919 (patch) | |
tree | 10591a106bc2f3eff53eff8e440f58495ff517c9 /ext/openssl/ossl_pkey.c | |
parent | fd46a1da0a41b7939424bc5a393027be7940908e (diff) | |
download | ruby-231247c010acba191b78ed2d1310c935e63ad919.tar.gz |
* ext/openssl: imported.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@4128 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext/openssl/ossl_pkey.c')
-rw-r--r-- | ext/openssl/ossl_pkey.c | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c new file mode 100644 index 0000000000..cd73355d66 --- /dev/null +++ b/ext/openssl/ossl_pkey.c @@ -0,0 +1,238 @@ +/* + * $Id$ + * 'OpenSSL for Ruby' project + * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> + * All rights reserved. + */ +/* + * This program is licenced under the same licence as Ruby. + * (See the file 'LICENCE'.) + */ +#include "ossl.h" + +/* + * Classes + */ +VALUE mPKey; +VALUE cPKey; +VALUE ePKeyError; +ID id_private_q; + +/* + * Public + */ +VALUE +ossl_pkey_new(EVP_PKEY *pkey) +{ + if (!pkey) { + ossl_raise(ePKeyError, "Cannot make new key from NULL."); + } + switch (EVP_PKEY_type(pkey->type)) { +#if !defined(OPENSSL_NO_RSA) + case EVP_PKEY_RSA: + return ossl_rsa_new(pkey); +#endif +#if !defined(OPENSSL_NO_DSA) + case EVP_PKEY_DSA: + return ossl_dsa_new(pkey); +#endif +#if !defined(OPENSSL_NO_DH) + case EVP_PKEY_DH: + return ossl_dh_new(pkey); +#endif + default: + ossl_raise(ePKeyError, "unsupported key type"); + } + return Qnil; /* not reached */ +} + +VALUE +ossl_pkey_new_from_file(VALUE filename) +{ + FILE *fp; + EVP_PKEY *pkey; + + SafeStringValue(filename); + if (!(fp = fopen(RSTRING(filename)->ptr, "r"))) { + ossl_raise(ePKeyError, "%s", strerror(errno)); + } + + pkey = PEM_read_PrivateKey(fp, NULL, ossl_pem_passwd_cb, NULL); + fclose(fp); + if (!pkey) { + ossl_raise(ePKeyError, NULL); + } + + return ossl_pkey_new(pkey); +} + +EVP_PKEY * +GetPKeyPtr(VALUE obj) +{ + EVP_PKEY *pkey; + + SafeGetPKey(obj, pkey); + + return pkey; +} + +EVP_PKEY * +GetPrivPKeyPtr(VALUE obj) +{ + EVP_PKEY *pkey; + + SafeGetPKey(obj, pkey); + if (rb_funcall(obj, id_private_q, 0, NULL) != Qtrue) { /* returns Qtrue */ + ossl_raise(rb_eArgError, "Private key is needed."); + } + + return pkey; +} + +EVP_PKEY * +DupPrivPKeyPtr(VALUE obj) +{ + EVP_PKEY *pkey; + + SafeGetPKey(obj, pkey); + if (rb_funcall(obj, id_private_q, 0, NULL) != Qtrue) { /* returns Qtrue */ + ossl_raise(rb_eArgError, "Private key is needed."); + } + CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY); + + return pkey; +} + +/* + * Private + */ +static VALUE +ossl_pkey_alloc(VALUE klass) +{ + EVP_PKEY *pkey; + VALUE obj; + + if (!(pkey = EVP_PKEY_new())) { + ossl_raise(ePKeyError, NULL); + } + WrapPKey(klass, obj, pkey); + + return obj; +} +DEFINE_ALLOC_WRAPPER(ossl_pkey_alloc) + +static VALUE +ossl_pkey_initialize(VALUE self) +{ + if (rb_obj_is_instance_of(self, cPKey)) { + ossl_raise(rb_eNotImpError, "OpenSSL::PKey::PKey is an abstract class."); + } + return self; +} + +static VALUE +ossl_pkey_to_der(VALUE self) +{ + EVP_PKEY *pkey; + VALUE str; + BIO *out; + BUF_MEM *buf; + + GetPKey(self, pkey); + + out = BIO_new(BIO_s_mem()); + if (!out) ossl_raise(ePKeyError, NULL); + + if (!i2d_PUBKEY_bio(out, pkey)) { + BIO_free(out); + ossl_raise(ePKeyError, NULL); + } + + BIO_get_mem_ptr(out, &buf); + str = rb_str_new(buf->data, buf->length); + + BIO_free(out); + + return str; +} + +static VALUE +ossl_pkey_sign(VALUE self, VALUE digest, VALUE data) +{ + EVP_PKEY *pkey; + EVP_MD_CTX ctx; + char *buf; + int buf_len; + VALUE str; + + GetPKey(self, pkey); + if (rb_funcall(self, id_private_q, 0, NULL) != Qtrue) { + ossl_raise(rb_eArgError, "Private key is needed."); + } + EVP_SignInit(&ctx, GetDigestPtr(digest)); + StringValue(data); + EVP_SignUpdate(&ctx, RSTRING(data)->ptr, RSTRING(data)->len); + if (!(buf = OPENSSL_malloc(EVP_PKEY_size(pkey) + 16))) { + ossl_raise(ePKeyError, NULL); + } + if (!EVP_SignFinal(&ctx, buf, &buf_len, pkey)) { + OPENSSL_free(buf); + ossl_raise(ePKeyError, NULL); + } + str = rb_str_new(buf, buf_len); + OPENSSL_free(buf); + + return str; +} + +static VALUE +ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data) +{ + EVP_PKEY *pkey; + EVP_MD_CTX ctx; + + GetPKey(self, pkey); + 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)) { + case 0: + return Qfalse; + case 1: + return Qtrue; + default: + ossl_raise(ePKeyError, NULL); + } + return Qnil; /* dummy */ +} + +/* + * INIT + */ +void +Init_ossl_pkey() +{ + mPKey = rb_define_module_under(mOSSL, "PKey"); + + ePKeyError = rb_define_class_under(mPKey, "PKeyError", eOSSLError); + + cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject); + + rb_define_alloc_func(cPKey, ossl_pkey_alloc); + rb_define_method(cPKey, "initialize", ossl_pkey_initialize, 0); + + rb_define_method(cPKey, "to_der", ossl_pkey_to_der, 0); + rb_define_method(cPKey, "sign", ossl_pkey_sign, 2); + rb_define_method(cPKey, "verify", ossl_pkey_verify, 3); + + id_private_q = rb_intern("private?"); + + /* + * INIT rsa, dsa + */ + Init_ossl_rsa(); + Init_ossl_dsa(); + Init_ossl_dh(); +} + |