Ruby
2.0.0p247(2013-06-27revision41674)
|
00001 /* 00002 * $Id: ossl_pkey_dsa.c 36355 2012-07-10 13:57:11Z 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 #if defined(HAVE_DSA_GENERATE_PARAMETERS_EX) && HAVE_BN_GENCB 00079 struct dsa_blocking_gen_arg { 00080 DSA *dsa; 00081 int size; 00082 unsigned char* seed; 00083 int seed_len; 00084 int *counter; 00085 unsigned long *h; 00086 BN_GENCB *cb; 00087 int result; 00088 }; 00089 00090 static void * 00091 dsa_blocking_gen(void *arg) 00092 { 00093 struct dsa_blocking_gen_arg *gen = (struct dsa_blocking_gen_arg *)arg; 00094 gen->result = DSA_generate_parameters_ex(gen->dsa, gen->size, gen->seed, gen->seed_len, gen->counter, gen->h, gen->cb); 00095 return 0; 00096 } 00097 #endif 00098 00099 static DSA * 00100 dsa_generate(int size) 00101 { 00102 #if defined(HAVE_DSA_GENERATE_PARAMETERS_EX) && HAVE_BN_GENCB 00103 BN_GENCB cb; 00104 struct ossl_generate_cb_arg cb_arg; 00105 struct dsa_blocking_gen_arg gen_arg; 00106 DSA *dsa = DSA_new(); 00107 unsigned char seed[20]; 00108 int seed_len = 20, counter; 00109 unsigned long h; 00110 00111 if (!dsa) return 0; 00112 if (!RAND_bytes(seed, seed_len)) { 00113 DSA_free(dsa); 00114 return 0; 00115 } 00116 00117 memset(&cb_arg, 0, sizeof(struct ossl_generate_cb_arg)); 00118 if (rb_block_given_p()) 00119 cb_arg.yield = 1; 00120 BN_GENCB_set(&cb, ossl_generate_cb_2, &cb_arg); 00121 gen_arg.dsa = dsa; 00122 gen_arg.size = size; 00123 gen_arg.seed = seed; 00124 gen_arg.seed_len = seed_len; 00125 gen_arg.counter = &counter; 00126 gen_arg.h = &h; 00127 gen_arg.cb = &cb; 00128 if (cb_arg.yield == 1) { 00129 /* we cannot release GVL when callback proc is supplied */ 00130 dsa_blocking_gen(&gen_arg); 00131 } else { 00132 /* there's a chance to unblock */ 00133 rb_thread_call_without_gvl(dsa_blocking_gen, &gen_arg, ossl_generate_cb_stop, &cb_arg); 00134 } 00135 if (!gen_arg.result) { 00136 DSA_free(dsa); 00137 if (cb_arg.state) rb_jump_tag(cb_arg.state); 00138 return 0; 00139 } 00140 #else 00141 DSA *dsa; 00142 unsigned char seed[20]; 00143 int seed_len = 20, counter; 00144 unsigned long h; 00145 00146 if (!RAND_bytes(seed, seed_len)) { 00147 return 0; 00148 } 00149 dsa = DSA_generate_parameters(size, seed, seed_len, &counter, &h, 00150 rb_block_given_p() ? ossl_generate_cb : NULL, NULL); 00151 if(!dsa) return 0; 00152 #endif 00153 00154 if (!DSA_generate_key(dsa)) { 00155 DSA_free(dsa); 00156 return 0; 00157 } 00158 00159 return dsa; 00160 } 00161 00162 /* 00163 * call-seq: 00164 * DSA.generate(size) -> dsa 00165 * 00166 * Creates a new DSA instance by generating a private/public key pair 00167 * from scratch. 00168 * 00169 * === Parameters 00170 * * +size+ is an integer representing the desired key size. 00171 * 00172 */ 00173 static VALUE 00174 ossl_dsa_s_generate(VALUE klass, VALUE size) 00175 { 00176 DSA *dsa = dsa_generate(NUM2INT(size)); /* err handled by dsa_instance */ 00177 VALUE obj = dsa_instance(klass, dsa); 00178 00179 if (obj == Qfalse) { 00180 DSA_free(dsa); 00181 ossl_raise(eDSAError, NULL); 00182 } 00183 00184 return obj; 00185 } 00186 00187 /* 00188 * call-seq: 00189 * DSA.new([size | string [, pass]) -> dsa 00190 * 00191 * Creates a new DSA instance by reading an existing key from +string+. 00192 * 00193 * === Parameters 00194 * * +size+ is an integer representing the desired key size. 00195 * * +string+ contains a DER or PEM encoded key. 00196 * * +pass+ is a string that contains an optional password. 00197 * 00198 * === Examples 00199 * DSA.new -> dsa 00200 * DSA.new(1024) -> dsa 00201 * DSA.new(File.read('dsa.pem')) -> dsa 00202 * DSA.new(File.read('dsa.pem'), 'mypassword') -> dsa 00203 * 00204 */ 00205 static VALUE 00206 ossl_dsa_initialize(int argc, VALUE *argv, VALUE self) 00207 { 00208 EVP_PKEY *pkey; 00209 DSA *dsa; 00210 BIO *in; 00211 char *passwd = NULL; 00212 VALUE arg, pass; 00213 00214 GetPKey(self, pkey); 00215 if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) { 00216 dsa = DSA_new(); 00217 } 00218 else if (FIXNUM_P(arg)) { 00219 if (!(dsa = dsa_generate(FIX2INT(arg)))) { 00220 ossl_raise(eDSAError, NULL); 00221 } 00222 } 00223 else { 00224 if (!NIL_P(pass)) passwd = StringValuePtr(pass); 00225 arg = ossl_to_der_if_possible(arg); 00226 in = ossl_obj2bio(arg); 00227 dsa = PEM_read_bio_DSAPrivateKey(in, NULL, ossl_pem_passwd_cb, passwd); 00228 if (!dsa) { 00229 OSSL_BIO_reset(in); 00230 dsa = PEM_read_bio_DSA_PUBKEY(in, NULL, NULL, NULL); 00231 } 00232 if (!dsa) { 00233 OSSL_BIO_reset(in); 00234 dsa = d2i_DSAPrivateKey_bio(in, NULL); 00235 } 00236 if (!dsa) { 00237 OSSL_BIO_reset(in); 00238 dsa = d2i_DSA_PUBKEY_bio(in, NULL); 00239 } 00240 if (!dsa) { 00241 OSSL_BIO_reset(in); 00242 dsa = PEM_read_bio_DSAPublicKey(in, NULL, NULL, NULL); 00243 } 00244 BIO_free(in); 00245 if (!dsa) { 00246 ERR_clear_error(); 00247 ossl_raise(eDSAError, "Neither PUB key nor PRIV key"); 00248 } 00249 } 00250 if (!EVP_PKEY_assign_DSA(pkey, dsa)) { 00251 DSA_free(dsa); 00252 ossl_raise(eDSAError, NULL); 00253 } 00254 00255 return self; 00256 } 00257 00258 /* 00259 * call-seq: 00260 * dsa.public? -> true | false 00261 * 00262 * Indicates whether this DSA instance has a public key associated with it or 00263 * not. The public key may be retrieved with DSA#public_key. 00264 */ 00265 static VALUE 00266 ossl_dsa_is_public(VALUE self) 00267 { 00268 EVP_PKEY *pkey; 00269 00270 GetPKeyDSA(self, pkey); 00271 00272 return (pkey->pkey.dsa->pub_key) ? Qtrue : Qfalse; 00273 } 00274 00275 /* 00276 * call-seq: 00277 * dsa.private? -> true | false 00278 * 00279 * Indicates whether this DSA instance has a private key associated with it or 00280 * not. The private key may be retrieved with DSA#private_key. 00281 */ 00282 static VALUE 00283 ossl_dsa_is_private(VALUE self) 00284 { 00285 EVP_PKEY *pkey; 00286 00287 GetPKeyDSA(self, pkey); 00288 00289 return (DSA_PRIVATE(self, pkey->pkey.dsa)) ? Qtrue : Qfalse; 00290 } 00291 00292 /* 00293 * call-seq: 00294 * dsa.to_pem([cipher, password]) -> aString 00295 * 00296 * Encodes this DSA to its PEM encoding. 00297 * 00298 * === Parameters 00299 * * +cipher+ is an OpenSSL::Cipher. 00300 * * +password+ is a string containing your password. 00301 * 00302 * === Examples 00303 * DSA.to_pem -> aString 00304 * DSA.to_pem(cipher, 'mypassword') -> aString 00305 * 00306 */ 00307 static VALUE 00308 ossl_dsa_export(int argc, VALUE *argv, VALUE self) 00309 { 00310 EVP_PKEY *pkey; 00311 BIO *out; 00312 const EVP_CIPHER *ciph = NULL; 00313 char *passwd = NULL; 00314 VALUE cipher, pass, str; 00315 00316 GetPKeyDSA(self, pkey); 00317 rb_scan_args(argc, argv, "02", &cipher, &pass); 00318 if (!NIL_P(cipher)) { 00319 ciph = GetCipherPtr(cipher); 00320 if (!NIL_P(pass)) { 00321 StringValue(pass); 00322 if (RSTRING_LENINT(pass) < OSSL_MIN_PWD_LEN) 00323 ossl_raise(eOSSLError, "OpenSSL requires passwords to be at least four characters long"); 00324 passwd = RSTRING_PTR(pass); 00325 } 00326 } 00327 if (!(out = BIO_new(BIO_s_mem()))) { 00328 ossl_raise(eDSAError, NULL); 00329 } 00330 if (DSA_HAS_PRIVATE(pkey->pkey.dsa)) { 00331 if (!PEM_write_bio_DSAPrivateKey(out, pkey->pkey.dsa, ciph, 00332 NULL, 0, ossl_pem_passwd_cb, passwd)){ 00333 BIO_free(out); 00334 ossl_raise(eDSAError, NULL); 00335 } 00336 } else { 00337 if (!PEM_write_bio_DSA_PUBKEY(out, pkey->pkey.dsa)) { 00338 BIO_free(out); 00339 ossl_raise(eDSAError, NULL); 00340 } 00341 } 00342 str = ossl_membio2str(out); 00343 00344 return str; 00345 } 00346 00347 /* 00348 * call-seq: 00349 * dsa.to_der -> aString 00350 * 00351 * Encodes this DSA to its DER encoding. 00352 * 00353 */ 00354 static VALUE 00355 ossl_dsa_to_der(VALUE self) 00356 { 00357 EVP_PKEY *pkey; 00358 int (*i2d_func)_((DSA*, unsigned char**)); 00359 unsigned char *p; 00360 long len; 00361 VALUE str; 00362 00363 GetPKeyDSA(self, pkey); 00364 if(DSA_HAS_PRIVATE(pkey->pkey.dsa)) 00365 i2d_func = (int(*)_((DSA*,unsigned char**)))i2d_DSAPrivateKey; 00366 else 00367 i2d_func = i2d_DSA_PUBKEY; 00368 if((len = i2d_func(pkey->pkey.dsa, NULL)) <= 0) 00369 ossl_raise(eDSAError, NULL); 00370 str = rb_str_new(0, len); 00371 p = (unsigned char *)RSTRING_PTR(str); 00372 if(i2d_func(pkey->pkey.dsa, &p) < 0) 00373 ossl_raise(eDSAError, NULL); 00374 ossl_str_adjust(str, p); 00375 00376 return str; 00377 } 00378 00379 /* 00380 * call-seq: 00381 * dsa.params -> hash 00382 * 00383 * Stores all parameters of key to the hash 00384 * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!! 00385 * Don't use :-)) (I's up to you) 00386 */ 00387 static VALUE 00388 ossl_dsa_get_params(VALUE self) 00389 { 00390 EVP_PKEY *pkey; 00391 VALUE hash; 00392 00393 GetPKeyDSA(self, pkey); 00394 00395 hash = rb_hash_new(); 00396 00397 rb_hash_aset(hash, rb_str_new2("p"), ossl_bn_new(pkey->pkey.dsa->p)); 00398 rb_hash_aset(hash, rb_str_new2("q"), ossl_bn_new(pkey->pkey.dsa->q)); 00399 rb_hash_aset(hash, rb_str_new2("g"), ossl_bn_new(pkey->pkey.dsa->g)); 00400 rb_hash_aset(hash, rb_str_new2("pub_key"), ossl_bn_new(pkey->pkey.dsa->pub_key)); 00401 rb_hash_aset(hash, rb_str_new2("priv_key"), ossl_bn_new(pkey->pkey.dsa->priv_key)); 00402 00403 return hash; 00404 } 00405 00406 /* 00407 * call-seq: 00408 * dsa.to_text -> aString 00409 * 00410 * Prints all parameters of key to buffer 00411 * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!! 00412 * Don't use :-)) (I's up to you) 00413 */ 00414 static VALUE 00415 ossl_dsa_to_text(VALUE self) 00416 { 00417 EVP_PKEY *pkey; 00418 BIO *out; 00419 VALUE str; 00420 00421 GetPKeyDSA(self, pkey); 00422 if (!(out = BIO_new(BIO_s_mem()))) { 00423 ossl_raise(eDSAError, NULL); 00424 } 00425 if (!DSA_print(out, pkey->pkey.dsa, 0)) { /* offset = 0 */ 00426 BIO_free(out); 00427 ossl_raise(eDSAError, NULL); 00428 } 00429 str = ossl_membio2str(out); 00430 00431 return str; 00432 } 00433 00434 /* 00435 * call-seq: 00436 * dsa.public_key -> aDSA 00437 * 00438 * Returns a new DSA instance that carries just the public key information. 00439 * If the current instance has also private key information, this will no 00440 * longer be present in the new instance. This feature is helpful for 00441 * publishing the public key information without leaking any of the private 00442 * information. 00443 * 00444 * === Example 00445 * dsa = OpenSSL::PKey::DSA.new(2048) # has public and private information 00446 * pub_key = dsa.public_key # has only the public part available 00447 * pub_key_der = pub_key.to_der # it's safe to publish this 00448 * 00449 * 00450 */ 00451 static VALUE 00452 ossl_dsa_to_public_key(VALUE self) 00453 { 00454 EVP_PKEY *pkey; 00455 DSA *dsa; 00456 VALUE obj; 00457 00458 GetPKeyDSA(self, pkey); 00459 /* err check performed by dsa_instance */ 00460 dsa = DSAPublicKey_dup(pkey->pkey.dsa); 00461 obj = dsa_instance(CLASS_OF(self), dsa); 00462 if (obj == Qfalse) { 00463 DSA_free(dsa); 00464 ossl_raise(eDSAError, NULL); 00465 } 00466 return obj; 00467 } 00468 00469 #define ossl_dsa_buf_size(pkey) (DSA_size((pkey)->pkey.dsa)+16) 00470 00471 /* 00472 * call-seq: 00473 * dsa.syssign(string) -> aString 00474 * 00475 * Computes and returns the DSA signature of +string+, where +string+ is 00476 * expected to be an already-computed message digest of the original input 00477 * data. The signature is issued using the private key of this DSA instance. 00478 * 00479 * === Parameters 00480 * * +string+ is a message digest of the original input data to be signed 00481 * 00482 * === Example 00483 * dsa = OpenSSL::PKey::DSA.new(2048) 00484 * doc = "Sign me" 00485 * digest = OpenSSL::Digest::SHA1.digest(doc) 00486 * sig = dsa.syssign(digest) 00487 * 00488 * 00489 */ 00490 static VALUE 00491 ossl_dsa_sign(VALUE self, VALUE data) 00492 { 00493 EVP_PKEY *pkey; 00494 unsigned int buf_len; 00495 VALUE str; 00496 00497 GetPKeyDSA(self, pkey); 00498 StringValue(data); 00499 if (!DSA_PRIVATE(self, pkey->pkey.dsa)) { 00500 ossl_raise(eDSAError, "Private DSA key needed!"); 00501 } 00502 str = rb_str_new(0, ossl_dsa_buf_size(pkey)); 00503 if (!DSA_sign(0, (unsigned char *)RSTRING_PTR(data), RSTRING_LENINT(data), 00504 (unsigned char *)RSTRING_PTR(str), 00505 &buf_len, pkey->pkey.dsa)) { /* type is ignored (0) */ 00506 ossl_raise(eDSAError, NULL); 00507 } 00508 rb_str_set_len(str, buf_len); 00509 00510 return str; 00511 } 00512 00513 /* 00514 * call-seq: 00515 * dsa.sysverify(digest, sig) -> true | false 00516 * 00517 * Verifies whether the signature is valid given the message digest input. It 00518 * does so by validating +sig+ using the public key of this DSA instance. 00519 * 00520 * === Parameters 00521 * * +digest+ is a message digest of the original input data to be signed 00522 * * +sig+ is a DSA signature value 00523 * 00524 * === Example 00525 * dsa = OpenSSL::PKey::DSA.new(2048) 00526 * doc = "Sign me" 00527 * digest = OpenSSL::Digest::SHA1.digest(doc) 00528 * sig = dsa.syssign(digest) 00529 * puts dsa.sysverify(digest, sig) # => true 00530 * 00531 */ 00532 static VALUE 00533 ossl_dsa_verify(VALUE self, VALUE digest, VALUE sig) 00534 { 00535 EVP_PKEY *pkey; 00536 int ret; 00537 00538 GetPKeyDSA(self, pkey); 00539 StringValue(digest); 00540 StringValue(sig); 00541 /* type is ignored (0) */ 00542 ret = DSA_verify(0, (unsigned char *)RSTRING_PTR(digest), RSTRING_LENINT(digest), 00543 (unsigned char *)RSTRING_PTR(sig), RSTRING_LENINT(sig), pkey->pkey.dsa); 00544 if (ret < 0) { 00545 ossl_raise(eDSAError, NULL); 00546 } 00547 else if (ret == 1) { 00548 return Qtrue; 00549 } 00550 00551 return Qfalse; 00552 } 00553 00554 OSSL_PKEY_BN(dsa, p) 00555 OSSL_PKEY_BN(dsa, q) 00556 OSSL_PKEY_BN(dsa, g) 00557 OSSL_PKEY_BN(dsa, pub_key) 00558 OSSL_PKEY_BN(dsa, priv_key) 00559 00560 /* 00561 * INIT 00562 */ 00563 void 00564 Init_ossl_dsa() 00565 { 00566 #if 0 00567 mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL and mPKey */ 00568 mPKey = rb_define_module_under(mOSSL, "PKey"); 00569 #endif 00570 00571 /* Document-class: OpenSSL::PKey::DSAError 00572 * 00573 * Generic exception that is raised if an operation on a DSA PKey 00574 * fails unexpectedly or in case an instantiation of an instance of DSA 00575 * fails due to non-conformant input data. 00576 */ 00577 eDSAError = rb_define_class_under(mPKey, "DSAError", ePKeyError); 00578 00579 /* Document-class: OpenSSL::PKey::DSA 00580 * 00581 * DSA, the Digital Signature Algorithm, is specified in NIST's 00582 * FIPS 186-3. It is an asymmetric public key algorithm that may be used 00583 * similar to e.g. RSA. 00584 * Please note that for OpenSSL versions prior to 1.0.0 the digest 00585 * algorithms OpenSSL::Digest::DSS (equivalent to SHA) or 00586 * OpenSSL::Digest::DSS1 (equivalent to SHA-1) must be used for issuing 00587 * signatures with a DSA key using OpenSSL::PKey#sign. 00588 * Starting with OpenSSL 1.0.0, digest algorithms are no longer restricted, 00589 * any Digest may be used for signing. 00590 */ 00591 cDSA = rb_define_class_under(mPKey, "DSA", cPKey); 00592 00593 rb_define_singleton_method(cDSA, "generate", ossl_dsa_s_generate, 1); 00594 rb_define_method(cDSA, "initialize", ossl_dsa_initialize, -1); 00595 00596 rb_define_method(cDSA, "public?", ossl_dsa_is_public, 0); 00597 rb_define_method(cDSA, "private?", ossl_dsa_is_private, 0); 00598 rb_define_method(cDSA, "to_text", ossl_dsa_to_text, 0); 00599 rb_define_method(cDSA, "export", ossl_dsa_export, -1); 00600 rb_define_alias(cDSA, "to_pem", "export"); 00601 rb_define_alias(cDSA, "to_s", "export"); 00602 rb_define_method(cDSA, "to_der", ossl_dsa_to_der, 0); 00603 rb_define_method(cDSA, "public_key", ossl_dsa_to_public_key, 0); 00604 rb_define_method(cDSA, "syssign", ossl_dsa_sign, 1); 00605 rb_define_method(cDSA, "sysverify", ossl_dsa_verify, 2); 00606 00607 DEF_OSSL_PKEY_BN(cDSA, dsa, p); 00608 DEF_OSSL_PKEY_BN(cDSA, dsa, q); 00609 DEF_OSSL_PKEY_BN(cDSA, dsa, g); 00610 DEF_OSSL_PKEY_BN(cDSA, dsa, pub_key); 00611 DEF_OSSL_PKEY_BN(cDSA, dsa, priv_key); 00612 00613 rb_define_method(cDSA, "params", ossl_dsa_get_params, 0); 00614 } 00615 00616 #else /* defined NO_DSA */ 00617 void 00618 Init_ossl_dsa() 00619 { 00620 } 00621 #endif /* NO_DSA */ 00622