• Main Page
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

ext/openssl/ossl_pkey_dsa.c

Go to the documentation of this file.
00001 /*
00002  * $Id: ossl_pkey_dsa.c 27440 2010-04-22 08:21:01Z nobu $
00003  * 'OpenSSL for Ruby' project
00004  * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
00005  * All rights reserved.
00006  */
00007 /*
00008  * This program is licenced under the same licence as Ruby.
00009  * (See the file 'LICENCE'.)
00010  */
00011 #if !defined(OPENSSL_NO_DSA)
00012 
00013 #include "ossl.h"
00014 
00015 #define GetPKeyDSA(obj, pkey) do { \
00016     GetPKey(obj, pkey); \
00017     if (EVP_PKEY_type(pkey->type) != EVP_PKEY_DSA) { /* PARANOIA? */ \
00018         ossl_raise(rb_eRuntimeError, "THIS IS NOT A DSA!"); \
00019     } \
00020 } while (0)
00021 
00022 #define DSA_HAS_PRIVATE(dsa) ((dsa)->priv_key)
00023 #define DSA_PRIVATE(obj,dsa) (DSA_HAS_PRIVATE(dsa)||OSSL_PKEY_IS_PRIVATE(obj))
00024 
00025 /*
00026  * Classes
00027  */
00028 VALUE cDSA;
00029 VALUE eDSAError;
00030 
00031 /*
00032  * Public
00033  */
00034 static VALUE
00035 dsa_instance(VALUE klass, DSA *dsa)
00036 {
00037     EVP_PKEY *pkey;
00038     VALUE obj;
00039 
00040     if (!dsa) {
00041         return Qfalse;
00042     }
00043     if (!(pkey = EVP_PKEY_new())) {
00044         return Qfalse;
00045     }
00046     if (!EVP_PKEY_assign_DSA(pkey, dsa)) {
00047         EVP_PKEY_free(pkey);
00048         return Qfalse;
00049     }
00050     WrapPKey(klass, obj, pkey);
00051 
00052     return obj;
00053 }
00054 
00055 VALUE
00056 ossl_dsa_new(EVP_PKEY *pkey)
00057 {
00058     VALUE obj;
00059 
00060     if (!pkey) {
00061         obj = dsa_instance(cDSA, DSA_new());
00062     } else {
00063         if (EVP_PKEY_type(pkey->type) != EVP_PKEY_DSA) {
00064             ossl_raise(rb_eTypeError, "Not a DSA key!");
00065         }
00066         WrapPKey(cDSA, obj, pkey);
00067     }
00068     if (obj == Qfalse) {
00069         ossl_raise(eDSAError, NULL);
00070     }
00071 
00072     return obj;
00073 }
00074 
00075 /*
00076  * Private
00077  */
00078 static DSA *
00079 dsa_generate(int size)
00080 {
00081     DSA *dsa;
00082     unsigned char seed[20];
00083     int seed_len = 20, counter;
00084     unsigned long h;
00085 
00086     if (!RAND_bytes(seed, seed_len)) {
00087         return 0;
00088     }
00089     dsa = DSA_generate_parameters(size, seed, seed_len, &counter, &h,
00090             rb_block_given_p() ? ossl_generate_cb : NULL,
00091             NULL);
00092     if(!dsa) return 0;
00093 
00094     if (!DSA_generate_key(dsa)) {
00095         DSA_free(dsa);
00096         return 0;
00097     }
00098 
00099     return dsa;
00100 }
00101 
00102 /*
00103  *  call-seq:
00104  *    DSA.generate(size) -> dsa
00105  *
00106  *  === Parameters
00107  *  * +size+ is an integer representing the desired key size.
00108  *
00109  */
00110 static VALUE
00111 ossl_dsa_s_generate(VALUE klass, VALUE size)
00112 {
00113     DSA *dsa = dsa_generate(NUM2INT(size)); /* err handled by dsa_instance */
00114     VALUE obj = dsa_instance(klass, dsa);
00115 
00116     if (obj == Qfalse) {
00117         DSA_free(dsa);
00118         ossl_raise(eDSAError, NULL);
00119     }
00120 
00121     return obj;
00122 }
00123 
00124 /*
00125  *  call-seq:
00126  *    DSA.new([size | string [, pass]) -> dsa
00127  *
00128  *  === Parameters
00129  *  * +size+ is an integer representing the desired key size.
00130  *  * +string+ contains a DER or PEM encoded key.
00131  *  * +pass+ is a string that contains a optional password.
00132  *
00133  *  === Examples
00134  *  * DSA.new -> dsa
00135  *  * DSA.new(1024) -> dsa
00136  *  * DSA.new(File.read('dsa.pem')) -> dsa
00137  *  * DSA.new(File.read('dsa.pem'), 'mypassword') -> dsa
00138  *
00139  */
00140 static VALUE
00141 ossl_dsa_initialize(int argc, VALUE *argv, VALUE self)
00142 {
00143     EVP_PKEY *pkey;
00144     DSA *dsa;
00145     BIO *in;
00146     char *passwd = NULL;
00147     VALUE arg, pass;
00148 
00149     GetPKey(self, pkey);
00150     if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) {
00151         dsa = DSA_new();
00152     }
00153     else if (FIXNUM_P(arg)) {
00154         if (!(dsa = dsa_generate(FIX2INT(arg)))) {
00155             ossl_raise(eDSAError, NULL);
00156         }
00157     }
00158     else {
00159         if (!NIL_P(pass)) passwd = StringValuePtr(pass);
00160         arg = ossl_to_der_if_possible(arg);
00161         in = ossl_obj2bio(arg);
00162         dsa = PEM_read_bio_DSAPrivateKey(in, NULL, ossl_pem_passwd_cb, passwd);
00163         if (!dsa) {
00164             (void)BIO_reset(in);
00165             dsa = PEM_read_bio_DSAPublicKey(in, NULL, NULL, NULL);
00166         }
00167         if (!dsa) {
00168             (void)BIO_reset(in);
00169             dsa = PEM_read_bio_DSA_PUBKEY(in, NULL, NULL, NULL);
00170         }
00171         if (!dsa) {
00172             (void)BIO_reset(in);
00173             dsa = d2i_DSAPrivateKey_bio(in, NULL);
00174         }
00175         if (!dsa) {
00176             (void)BIO_reset(in);
00177             dsa = d2i_DSA_PUBKEY_bio(in, NULL);
00178         }
00179         BIO_free(in);
00180         if (!dsa) ossl_raise(eDSAError, "Neither PUB key nor PRIV key:");
00181     }
00182     if (!EVP_PKEY_assign_DSA(pkey, dsa)) {
00183         DSA_free(dsa);
00184         ossl_raise(eDSAError, NULL);
00185     }
00186 
00187     return self;
00188 }
00189 
00190 /*
00191  *  call-seq:
00192  *    dsa.public? -> true | false
00193  *
00194  */
00195 static VALUE
00196 ossl_dsa_is_public(VALUE self)
00197 {
00198     EVP_PKEY *pkey;
00199 
00200     GetPKeyDSA(self, pkey);
00201 
00202     return (pkey->pkey.dsa->pub_key) ? Qtrue : Qfalse;
00203 }
00204 
00205 /*
00206  *  call-seq:
00207  *    dsa.private? -> true | false
00208  *
00209  */
00210 static VALUE
00211 ossl_dsa_is_private(VALUE self)
00212 {
00213     EVP_PKEY *pkey;
00214 
00215     GetPKeyDSA(self, pkey);
00216 
00217     return (DSA_PRIVATE(self, pkey->pkey.dsa)) ? Qtrue : Qfalse;
00218 }
00219 
00220 /*
00221  *  call-seq:
00222  *    dsa.to_pem([cipher, password]) -> aString
00223  *
00224  *  === Parameters
00225  *  +cipher+ is an OpenSSL::Cipher.
00226  *  +password+ is a string containing your password.
00227  *
00228  *  === Examples
00229  *  * DSA.to_pem -> aString
00230  *  * DSA.to_pem(cipher, 'mypassword') -> aString
00231  *
00232  */
00233 static VALUE
00234 ossl_dsa_export(int argc, VALUE *argv, VALUE self)
00235 {
00236     EVP_PKEY *pkey;
00237     BIO *out;
00238     const EVP_CIPHER *ciph = NULL;
00239     char *passwd = NULL;
00240     VALUE cipher, pass, str;
00241 
00242     GetPKeyDSA(self, pkey);
00243     rb_scan_args(argc, argv, "02", &cipher, &pass);
00244     if (!NIL_P(cipher)) {
00245         ciph = GetCipherPtr(cipher);
00246         if (!NIL_P(pass)) {
00247             passwd = StringValuePtr(pass);
00248         }
00249     }
00250     if (!(out = BIO_new(BIO_s_mem()))) {
00251         ossl_raise(eDSAError, NULL);
00252     }
00253     if (DSA_HAS_PRIVATE(pkey->pkey.dsa)) {
00254         if (!PEM_write_bio_DSAPrivateKey(out, pkey->pkey.dsa, ciph,
00255                                          NULL, 0, ossl_pem_passwd_cb, passwd)){
00256             BIO_free(out);
00257             ossl_raise(eDSAError, NULL);
00258         }
00259     } else {
00260         if (!PEM_write_bio_DSAPublicKey(out, pkey->pkey.dsa)) {
00261             BIO_free(out);
00262             ossl_raise(eDSAError, NULL);
00263         }
00264     }
00265     str = ossl_membio2str(out);
00266 
00267     return str;
00268 }
00269 
00270 /*
00271  *  call-seq:
00272  *    dsa.to_der -> aString
00273  *
00274  */
00275 static VALUE
00276 ossl_dsa_to_der(VALUE self)
00277 {
00278     EVP_PKEY *pkey;
00279     int (*i2d_func)_((DSA*, unsigned char**));
00280     unsigned char *p;
00281     long len;
00282     VALUE str;
00283 
00284     GetPKeyDSA(self, pkey);
00285     if(DSA_HAS_PRIVATE(pkey->pkey.dsa))
00286         i2d_func = (int(*)_((DSA*,unsigned char**)))i2d_DSAPrivateKey;
00287     else
00288         i2d_func = i2d_DSA_PUBKEY;
00289     if((len = i2d_func(pkey->pkey.dsa, NULL)) <= 0)
00290         ossl_raise(eDSAError, NULL);
00291     str = rb_str_new(0, len);
00292     p = (unsigned char *)RSTRING_PTR(str);
00293     if(i2d_func(pkey->pkey.dsa, &p) < 0)
00294         ossl_raise(eDSAError, NULL);
00295     ossl_str_adjust(str, p);
00296 
00297     return str;
00298 }
00299 
00300 /*
00301  *  call-seq:
00302  *    dsa.params -> hash
00303  *
00304  * Stores all parameters of key to the hash
00305  * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
00306  * Don't use :-)) (I's up to you)
00307  */
00308 static VALUE
00309 ossl_dsa_get_params(VALUE self)
00310 {
00311     EVP_PKEY *pkey;
00312     VALUE hash;
00313 
00314     GetPKeyDSA(self, pkey);
00315 
00316     hash = rb_hash_new();
00317 
00318     rb_hash_aset(hash, rb_str_new2("p"), ossl_bn_new(pkey->pkey.dsa->p));
00319     rb_hash_aset(hash, rb_str_new2("q"), ossl_bn_new(pkey->pkey.dsa->q));
00320     rb_hash_aset(hash, rb_str_new2("g"), ossl_bn_new(pkey->pkey.dsa->g));
00321     rb_hash_aset(hash, rb_str_new2("pub_key"), ossl_bn_new(pkey->pkey.dsa->pub_key));
00322     rb_hash_aset(hash, rb_str_new2("priv_key"), ossl_bn_new(pkey->pkey.dsa->priv_key));
00323 
00324     return hash;
00325 }
00326 
00327 /*
00328  *  call-seq:
00329  *    dsa.to_text -> aString
00330  *
00331  * Prints all parameters of key to buffer
00332  * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
00333  * Don't use :-)) (I's up to you)
00334  */
00335 static VALUE
00336 ossl_dsa_to_text(VALUE self)
00337 {
00338     EVP_PKEY *pkey;
00339     BIO *out;
00340     VALUE str;
00341 
00342     GetPKeyDSA(self, pkey);
00343     if (!(out = BIO_new(BIO_s_mem()))) {
00344         ossl_raise(eDSAError, NULL);
00345     }
00346     if (!DSA_print(out, pkey->pkey.dsa, 0)) { /* offset = 0 */
00347         BIO_free(out);
00348         ossl_raise(eDSAError, NULL);
00349     }
00350     str = ossl_membio2str(out);
00351 
00352     return str;
00353 }
00354 
00355 /*
00356  *  call-seq:
00357  *    dsa.public_key -> aDSA
00358  *
00359  * Makes new instance DSA PUBLIC_KEY from PRIVATE_KEY
00360  */
00361 static VALUE
00362 ossl_dsa_to_public_key(VALUE self)
00363 {
00364     EVP_PKEY *pkey;
00365     DSA *dsa;
00366     VALUE obj;
00367 
00368     GetPKeyDSA(self, pkey);
00369     /* err check performed by dsa_instance */
00370     dsa = DSAPublicKey_dup(pkey->pkey.dsa);
00371     obj = dsa_instance(CLASS_OF(self), dsa);
00372     if (obj == Qfalse) {
00373         DSA_free(dsa);
00374         ossl_raise(eDSAError, NULL);
00375     }
00376     return obj;
00377 }
00378 
00379 #define ossl_dsa_buf_size(pkey) (DSA_size((pkey)->pkey.dsa)+16)
00380 
00381 /*
00382  *  call-seq:
00383  *    dsa.syssign(string) -> aString
00384  *
00385  */
00386 static VALUE
00387 ossl_dsa_sign(VALUE self, VALUE data)
00388 {
00389     EVP_PKEY *pkey;
00390     unsigned int buf_len;
00391     VALUE str;
00392 
00393     GetPKeyDSA(self, pkey);
00394     StringValue(data);
00395     if (!DSA_PRIVATE(self, pkey->pkey.dsa)) {
00396         ossl_raise(eDSAError, "Private DSA key needed!");
00397     }
00398     str = rb_str_new(0, ossl_dsa_buf_size(pkey));
00399     if (!DSA_sign(0, (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data),
00400                   (unsigned char *)RSTRING_PTR(str),
00401                   &buf_len, pkey->pkey.dsa)) { /* type is ignored (0) */
00402         ossl_raise(eDSAError, NULL);
00403     }
00404     rb_str_set_len(str, buf_len);
00405 
00406     return str;
00407 }
00408 
00409 /*
00410  *  call-seq:
00411  *    dsa.sysverify(digest, sig) -> true | false
00412  *
00413  */
00414 static VALUE
00415 ossl_dsa_verify(VALUE self, VALUE digest, VALUE sig)
00416 {
00417     EVP_PKEY *pkey;
00418     int ret;
00419 
00420     GetPKeyDSA(self, pkey);
00421     StringValue(digest);
00422     StringValue(sig);
00423     /* type is ignored (0) */
00424     ret = DSA_verify(0, (unsigned char *)RSTRING_PTR(digest), RSTRING_LEN(digest),
00425                      (unsigned char *)RSTRING_PTR(sig), RSTRING_LEN(sig), pkey->pkey.dsa);
00426     if (ret < 0) {
00427         ossl_raise(eDSAError, NULL);
00428     }
00429     else if (ret == 1) {
00430         return Qtrue;
00431     }
00432 
00433     return Qfalse;
00434 }
00435 
00436 OSSL_PKEY_BN(dsa, p)
00437 OSSL_PKEY_BN(dsa, q)
00438 OSSL_PKEY_BN(dsa, g)
00439 OSSL_PKEY_BN(dsa, pub_key)
00440 OSSL_PKEY_BN(dsa, priv_key)
00441 
00442 /*
00443  * INIT
00444  */
00445 void
00446 Init_ossl_dsa()
00447 {
00448 #if 0 /* let rdoc know about mOSSL and mPKey */
00449     mOSSL = rb_define_module("OpenSSL");
00450     mPKey = rb_define_module_under(mOSSL, "PKey");
00451 #endif
00452 
00453     eDSAError = rb_define_class_under(mPKey, "DSAError", ePKeyError);
00454 
00455     cDSA = rb_define_class_under(mPKey, "DSA", cPKey);
00456 
00457     rb_define_singleton_method(cDSA, "generate", ossl_dsa_s_generate, 1);
00458     rb_define_method(cDSA, "initialize", ossl_dsa_initialize, -1);
00459 
00460     rb_define_method(cDSA, "public?", ossl_dsa_is_public, 0);
00461     rb_define_method(cDSA, "private?", ossl_dsa_is_private, 0);
00462     rb_define_method(cDSA, "to_text", ossl_dsa_to_text, 0);
00463     rb_define_method(cDSA, "export", ossl_dsa_export, -1);
00464     rb_define_alias(cDSA, "to_pem", "export");
00465     rb_define_alias(cDSA, "to_s", "export");
00466     rb_define_method(cDSA, "to_der", ossl_dsa_to_der, 0);
00467     rb_define_method(cDSA, "public_key", ossl_dsa_to_public_key, 0);
00468     rb_define_method(cDSA, "syssign", ossl_dsa_sign, 1);
00469     rb_define_method(cDSA, "sysverify", ossl_dsa_verify, 2);
00470 
00471     DEF_OSSL_PKEY_BN(cDSA, dsa, p);
00472     DEF_OSSL_PKEY_BN(cDSA, dsa, q);
00473     DEF_OSSL_PKEY_BN(cDSA, dsa, g);
00474     DEF_OSSL_PKEY_BN(cDSA, dsa, pub_key);
00475     DEF_OSSL_PKEY_BN(cDSA, dsa, priv_key);
00476 
00477     rb_define_method(cDSA, "params", ossl_dsa_get_params, 0);
00478 }
00479 
00480 #else /* defined NO_DSA */
00481 void
00482 Init_ossl_dsa()
00483 {
00484 }
00485 #endif /* NO_DSA */
00486 

Generated on Wed Sep 8 2010 21:54:07 for Ruby by  doxygen 1.7.1