|
Ruby 1.9.2p180(2011-02-18revision30909)
|
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
1.7.3