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