Ruby 1.9.2p136(2010-12-25revision30365)

- 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