|
Ruby 1.9.2p290(2011-07-09revision32553)
|
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
1.7.3