• 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 31796 2011-05-29 22:49:10Z yugui $
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             (void)ERR_get_error();
00166             dsa = PEM_read_bio_DSAPublicKey(in, NULL, NULL, NULL);
00167         }
00168         if (!dsa) {
00169             (void)BIO_reset(in);
00170             (void)ERR_get_error();
00171             dsa = PEM_read_bio_DSA_PUBKEY(in, NULL, NULL, NULL);
00172         }
00173         if (!dsa) {
00174             (void)BIO_reset(in);
00175             (void)ERR_get_error();
00176             dsa = d2i_DSAPrivateKey_bio(in, NULL);
00177         }
00178         if (!dsa) {
00179             (void)BIO_reset(in);
00180             (void)ERR_get_error();
00181             dsa = d2i_DSA_PUBKEY_bio(in, NULL);
00182         }
00183         BIO_free(in);
00184         if (!dsa) {
00185             (void)ERR_get_error();
00186             ossl_raise(eDSAError, "Neither PUB key nor PRIV key:");
00187         }
00188     }
00189     if (!EVP_PKEY_assign_DSA(pkey, dsa)) {
00190         DSA_free(dsa);
00191         ossl_raise(eDSAError, NULL);
00192     }
00193 
00194     return self;
00195 }
00196 
00197 /*
00198  *  call-seq:
00199  *    dsa.public? -> true | false
00200  *
00201  */
00202 static VALUE
00203 ossl_dsa_is_public(VALUE self)
00204 {
00205     EVP_PKEY *pkey;
00206 
00207     GetPKeyDSA(self, pkey);
00208 
00209     return (pkey->pkey.dsa->pub_key) ? Qtrue : Qfalse;
00210 }
00211 
00212 /*
00213  *  call-seq:
00214  *    dsa.private? -> true | false
00215  *
00216  */
00217 static VALUE
00218 ossl_dsa_is_private(VALUE self)
00219 {
00220     EVP_PKEY *pkey;
00221 
00222     GetPKeyDSA(self, pkey);
00223 
00224     return (DSA_PRIVATE(self, pkey->pkey.dsa)) ? Qtrue : Qfalse;
00225 }
00226 
00227 /*
00228  *  call-seq:
00229  *    dsa.to_pem([cipher, password]) -> aString
00230  *
00231  *  === Parameters
00232  *  +cipher+ is an OpenSSL::Cipher.
00233  *  +password+ is a string containing your password.
00234  *
00235  *  === Examples
00236  *  * DSA.to_pem -> aString
00237  *  * DSA.to_pem(cipher, 'mypassword') -> aString
00238  *
00239  */
00240 static VALUE
00241 ossl_dsa_export(int argc, VALUE *argv, VALUE self)
00242 {
00243     EVP_PKEY *pkey;
00244     BIO *out;
00245     const EVP_CIPHER *ciph = NULL;
00246     char *passwd = NULL;
00247     VALUE cipher, pass, str;
00248 
00249     GetPKeyDSA(self, pkey);
00250     rb_scan_args(argc, argv, "02", &cipher, &pass);
00251     if (!NIL_P(cipher)) {
00252         ciph = GetCipherPtr(cipher);
00253         if (!NIL_P(pass)) {
00254             passwd = StringValuePtr(pass);
00255         }
00256     }
00257     if (!(out = BIO_new(BIO_s_mem()))) {
00258         ossl_raise(eDSAError, NULL);
00259     }
00260     if (DSA_HAS_PRIVATE(pkey->pkey.dsa)) {
00261         if (!PEM_write_bio_DSAPrivateKey(out, pkey->pkey.dsa, ciph,
00262                                          NULL, 0, ossl_pem_passwd_cb, passwd)){
00263             BIO_free(out);
00264             ossl_raise(eDSAError, NULL);
00265         }
00266     } else {
00267         if (!PEM_write_bio_DSAPublicKey(out, pkey->pkey.dsa)) {
00268             BIO_free(out);
00269             ossl_raise(eDSAError, NULL);
00270         }
00271     }
00272     str = ossl_membio2str(out);
00273 
00274     return str;
00275 }
00276 
00277 /*
00278  *  call-seq:
00279  *    dsa.to_der -> aString
00280  *
00281  */
00282 static VALUE
00283 ossl_dsa_to_der(VALUE self)
00284 {
00285     EVP_PKEY *pkey;
00286     int (*i2d_func)_((DSA*, unsigned char**));
00287     unsigned char *p;
00288     long len;
00289     VALUE str;
00290 
00291     GetPKeyDSA(self, pkey);
00292     if(DSA_HAS_PRIVATE(pkey->pkey.dsa))
00293         i2d_func = (int(*)_((DSA*,unsigned char**)))i2d_DSAPrivateKey;
00294     else
00295         i2d_func = i2d_DSA_PUBKEY;
00296     if((len = i2d_func(pkey->pkey.dsa, NULL)) <= 0)
00297         ossl_raise(eDSAError, NULL);
00298     str = rb_str_new(0, len);
00299     p = (unsigned char *)RSTRING_PTR(str);
00300     if(i2d_func(pkey->pkey.dsa, &p) < 0)
00301         ossl_raise(eDSAError, NULL);
00302     ossl_str_adjust(str, p);
00303 
00304     return str;
00305 }
00306 
00307 /*
00308  *  call-seq:
00309  *    dsa.params -> hash
00310  *
00311  * Stores all parameters of key to the hash
00312  * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
00313  * Don't use :-)) (I's up to you)
00314  */
00315 static VALUE
00316 ossl_dsa_get_params(VALUE self)
00317 {
00318     EVP_PKEY *pkey;
00319     VALUE hash;
00320 
00321     GetPKeyDSA(self, pkey);
00322 
00323     hash = rb_hash_new();
00324 
00325     rb_hash_aset(hash, rb_str_new2("p"), ossl_bn_new(pkey->pkey.dsa->p));
00326     rb_hash_aset(hash, rb_str_new2("q"), ossl_bn_new(pkey->pkey.dsa->q));
00327     rb_hash_aset(hash, rb_str_new2("g"), ossl_bn_new(pkey->pkey.dsa->g));
00328     rb_hash_aset(hash, rb_str_new2("pub_key"), ossl_bn_new(pkey->pkey.dsa->pub_key));
00329     rb_hash_aset(hash, rb_str_new2("priv_key"), ossl_bn_new(pkey->pkey.dsa->priv_key));
00330 
00331     return hash;
00332 }
00333 
00334 /*
00335  *  call-seq:
00336  *    dsa.to_text -> aString
00337  *
00338  * Prints all parameters of key to buffer
00339  * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
00340  * Don't use :-)) (I's up to you)
00341  */
00342 static VALUE
00343 ossl_dsa_to_text(VALUE self)
00344 {
00345     EVP_PKEY *pkey;
00346     BIO *out;
00347     VALUE str;
00348 
00349     GetPKeyDSA(self, pkey);
00350     if (!(out = BIO_new(BIO_s_mem()))) {
00351         ossl_raise(eDSAError, NULL);
00352     }
00353     if (!DSA_print(out, pkey->pkey.dsa, 0)) { /* offset = 0 */
00354         BIO_free(out);
00355         ossl_raise(eDSAError, NULL);
00356     }
00357     str = ossl_membio2str(out);
00358 
00359     return str;
00360 }
00361 
00362 /*
00363  *  call-seq:
00364  *    dsa.public_key -> aDSA
00365  *
00366  * Makes new instance DSA PUBLIC_KEY from PRIVATE_KEY
00367  */
00368 static VALUE
00369 ossl_dsa_to_public_key(VALUE self)
00370 {
00371     EVP_PKEY *pkey;
00372     DSA *dsa;
00373     VALUE obj;
00374 
00375     GetPKeyDSA(self, pkey);
00376     /* err check performed by dsa_instance */
00377     dsa = DSAPublicKey_dup(pkey->pkey.dsa);
00378     obj = dsa_instance(CLASS_OF(self), dsa);
00379     if (obj == Qfalse) {
00380         DSA_free(dsa);
00381         ossl_raise(eDSAError, NULL);
00382     }
00383     return obj;
00384 }
00385 
00386 #define ossl_dsa_buf_size(pkey) (DSA_size((pkey)->pkey.dsa)+16)
00387 
00388 /*
00389  *  call-seq:
00390  *    dsa.syssign(string) -> aString
00391  *
00392  */
00393 static VALUE
00394 ossl_dsa_sign(VALUE self, VALUE data)
00395 {
00396     EVP_PKEY *pkey;
00397     unsigned int buf_len;
00398     VALUE str;
00399 
00400     GetPKeyDSA(self, pkey);
00401     StringValue(data);
00402     if (!DSA_PRIVATE(self, pkey->pkey.dsa)) {
00403         ossl_raise(eDSAError, "Private DSA key needed!");
00404     }
00405     str = rb_str_new(0, ossl_dsa_buf_size(pkey));
00406     if (!DSA_sign(0, (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data),
00407                   (unsigned char *)RSTRING_PTR(str),
00408                   &buf_len, pkey->pkey.dsa)) { /* type is ignored (0) */
00409         ossl_raise(eDSAError, NULL);
00410     }
00411     rb_str_set_len(str, buf_len);
00412 
00413     return str;
00414 }
00415 
00416 /*
00417  *  call-seq:
00418  *    dsa.sysverify(digest, sig) -> true | false
00419  *
00420  */
00421 static VALUE
00422 ossl_dsa_verify(VALUE self, VALUE digest, VALUE sig)
00423 {
00424     EVP_PKEY *pkey;
00425     int ret;
00426 
00427     GetPKeyDSA(self, pkey);
00428     StringValue(digest);
00429     StringValue(sig);
00430     /* type is ignored (0) */
00431     ret = DSA_verify(0, (unsigned char *)RSTRING_PTR(digest), RSTRING_LEN(digest),
00432                      (unsigned char *)RSTRING_PTR(sig), RSTRING_LEN(sig), pkey->pkey.dsa);
00433     if (ret < 0) {
00434         ossl_raise(eDSAError, NULL);
00435     }
00436     else if (ret == 1) {
00437         return Qtrue;
00438     }
00439 
00440     return Qfalse;
00441 }
00442 
00443 OSSL_PKEY_BN(dsa, p)
00444 OSSL_PKEY_BN(dsa, q)
00445 OSSL_PKEY_BN(dsa, g)
00446 OSSL_PKEY_BN(dsa, pub_key)
00447 OSSL_PKEY_BN(dsa, priv_key)
00448 
00449 /*
00450  * INIT
00451  */
00452 void
00453 Init_ossl_dsa()
00454 {
00455 #if 0 /* let rdoc know about mOSSL and mPKey */
00456     mOSSL = rb_define_module("OpenSSL");
00457     mPKey = rb_define_module_under(mOSSL, "PKey");
00458 #endif
00459 
00460     eDSAError = rb_define_class_under(mPKey, "DSAError", ePKeyError);
00461 
00462     cDSA = rb_define_class_under(mPKey, "DSA", cPKey);
00463 
00464     rb_define_singleton_method(cDSA, "generate", ossl_dsa_s_generate, 1);
00465     rb_define_method(cDSA, "initialize", ossl_dsa_initialize, -1);
00466 
00467     rb_define_method(cDSA, "public?", ossl_dsa_is_public, 0);
00468     rb_define_method(cDSA, "private?", ossl_dsa_is_private, 0);
00469     rb_define_method(cDSA, "to_text", ossl_dsa_to_text, 0);
00470     rb_define_method(cDSA, "export", ossl_dsa_export, -1);
00471     rb_define_alias(cDSA, "to_pem", "export");
00472     rb_define_alias(cDSA, "to_s", "export");
00473     rb_define_method(cDSA, "to_der", ossl_dsa_to_der, 0);
00474     rb_define_method(cDSA, "public_key", ossl_dsa_to_public_key, 0);
00475     rb_define_method(cDSA, "syssign", ossl_dsa_sign, 1);
00476     rb_define_method(cDSA, "sysverify", ossl_dsa_verify, 2);
00477 
00478     DEF_OSSL_PKEY_BN(cDSA, dsa, p);
00479     DEF_OSSL_PKEY_BN(cDSA, dsa, q);
00480     DEF_OSSL_PKEY_BN(cDSA, dsa, g);
00481     DEF_OSSL_PKEY_BN(cDSA, dsa, pub_key);
00482     DEF_OSSL_PKEY_BN(cDSA, dsa, priv_key);
00483 
00484     rb_define_method(cDSA, "params", ossl_dsa_get_params, 0);
00485 }
00486 
00487 #else /* defined NO_DSA */
00488 void
00489 Init_ossl_dsa()
00490 {
00491 }
00492 #endif /* NO_DSA */
00493 

Generated on Thu Sep 8 2011 03:50:35 for Ruby by  doxygen 1.7.1