Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# ext/openssl/ossl_pkey_dh.c

Go to the documentation of this file.

    00001 /*
    00002  * $Id: ossl_pkey_dh.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_DH)
    00012
    00013 #include "ossl.h"
    00014
    00015 #define GetPKeyDH(obj, pkey) do { \
    00016     GetPKey(obj, pkey); \
    00017     if (EVP_PKEY_type(pkey->type) != EVP_PKEY_DH) { /* PARANOIA? */ \
    00018         ossl_raise(rb_eRuntimeError, "THIS IS NOT A DH!") ; \
    00019     } \
    00020 } while (0)
    00021
    00022 #define DH_HAS_PRIVATE(dh) ((dh)->priv_key)
    00023
    00024 #ifdef OSSL_ENGINE_ENABLED
    00025 #  define DH_PRIVATE(dh) (DH_HAS_PRIVATE(dh) || (dh)->engine)
    00026 #else
    00027 #  define DH_PRIVATE(dh) DH_HAS_PRIVATE(dh)
    00028 #endif
    00029
    00030
    00031 /*
    00032  * Classes
    00033  */
    00034 VALUE cDH;
    00035 VALUE eDHError;
    00036
    00037 /*
    00038  * Public
    00039  */
    00040 static VALUE
    00041 dh_instance(VALUE klass, DH *dh)
    00042 {
    00043     EVP_PKEY *pkey;
    00044     VALUE obj;
    00045
    00046     if (!dh) {
    00047         return Qfalse;
    00048     }
    00049     if (!(pkey = EVP_PKEY_new())) {
    00050         return Qfalse;
    00051     }
    00052     if (!EVP_PKEY_assign_DH(pkey, dh)) {
    00053         EVP_PKEY_free(pkey);
    00054         return Qfalse;
    00055     }
    00056     WrapPKey(klass, obj, pkey);
    00057
    00058     return obj;
    00059 }
    00060
    00061 VALUE
    00062 ossl_dh_new(EVP_PKEY *pkey)
    00063 {
    00064     VALUE obj;
    00065
    00066     if (!pkey) {
    00067         obj = dh_instance(cDH, DH_new());
    00068     } else {
    00069         if (EVP_PKEY_type(pkey->type) != EVP_PKEY_DH) {
    00070             ossl_raise(rb_eTypeError, "Not a DH key!");
    00071         }
    00072         WrapPKey(cDH, obj, pkey);
    00073     }
    00074     if (obj == Qfalse) {
    00075         ossl_raise(eDHError, NULL);
    00076     }
    00077
    00078     return obj;
    00079 }
    00080
    00081 /*
    00082  * Private
    00083  */
    00084 static DH *
    00085 dh_generate(int size, int gen)
    00086 {
    00087     DH *dh;
    00088
    00089     dh = DH_generate_parameters(size, gen,
    00090             rb_block_given_p() ? ossl_generate_cb : NULL,
    00091             NULL);
    00092     if (!dh) return 0;
    00093
    00094     if (!DH_generate_key(dh)) {
    00095         DH_free(dh);
    00096         return 0;
    00097     }
    00098
    00099     return dh;
    00100 }
    00101
    00102 /*
    00103  *  call-seq:
    00104  *     DH.generate(size [, generator]) -> dh
    00105  *
    00106  *  === Parameters
    00107  *  * +size+ is an integer representing the desired key size.  Keys smaller than 1024 should be considered insecure.
    00108  *  * +generator+ is a small number > 1, typically 2 or 5.
    00109  *
    00110  */
    00111 static VALUE
    00112 ossl_dh_s_generate(int argc, VALUE *argv, VALUE klass)
    00113 {
    00114     DH *dh ;
    00115     int g = 2;
    00116     VALUE size, gen, obj;
    00117
    00118     if (rb_scan_args(argc, argv, "11", &size, &gen) == 2) {
    00119         g = NUM2INT(gen);
    00120     }
    00121     dh = dh_generate(NUM2INT(size), g);
    00122     obj = dh_instance(klass, dh);
    00123     if (obj == Qfalse) {
    00124         DH_free(dh);
    00125         ossl_raise(eDHError, NULL);
    00126     }
    00127
    00128     return obj;
    00129 }
    00130
    00131 /*
    00132  *  call-seq:
    00133  *     DH.new([size [, generator] | string]) -> dh
    00134  *
    00135  *  === Parameters
    00136  *  * +size+ is an integer representing the desired key size.  Keys smaller than 1024 should be considered insecure.
    00137  *  * +generator+ is a small number > 1, typically 2 or 5.
    00138  *  * +string+ contains the DER or PEM encoded key.
    00139  *
    00140  *  === Examples
    00141  *  * DH.new -> dh
    00142  *  * DH.new(1024) -> dh
    00143  *  * DH.new(1024, 5) -> dh
    00144  *  * DH.new(File.read('key.pem')) -> dh
    00145  */
    00146 static VALUE
    00147 ossl_dh_initialize(int argc, VALUE *argv, VALUE self)
    00148 {
    00149     EVP_PKEY *pkey;
    00150     DH *dh;
    00151     int g = 2;
    00152     BIO *in;
    00153     VALUE arg, gen;
    00154
    00155     GetPKey(self, pkey);
    00156     if(rb_scan_args(argc, argv, "02", &arg, &gen) == 0) {
    00157       dh = DH_new();
    00158     }
    00159     else if (FIXNUM_P(arg)) {
    00160         if (!NIL_P(gen)) {
    00161             g = NUM2INT(gen);
    00162         }
    00163         if (!(dh = dh_generate(FIX2INT(arg), g))) {
    00164             ossl_raise(eDHError, NULL);
    00165         }
    00166     }
    00167     else {
    00168         arg = ossl_to_der_if_possible(arg);
    00169         in = ossl_obj2bio(arg);
    00170         dh = PEM_read_bio_DHparams(in, NULL, NULL, NULL);
    00171         if (!dh){
    00172             (void)BIO_reset(in);
    00173             dh = d2i_DHparams_bio(in, NULL);
    00174         }
    00175         BIO_free(in);
    00176         if (!dh) ossl_raise(eDHError, NULL);
    00177     }
    00178     if (!EVP_PKEY_assign_DH(pkey, dh)) {
    00179         DH_free(dh);
    00180         ossl_raise(eDHError, NULL);
    00181     }
    00182     return self;
    00183 }
    00184
    00185 /*
    00186  *  call-seq:
    00187  *     dh.public? -> true | false
    00188  *
    00189  */
    00190 static VALUE
    00191 ossl_dh_is_public(VALUE self)
    00192 {
    00193     EVP_PKEY *pkey;
    00194
    00195     GetPKeyDH(self, pkey);
    00196
    00197     return (pkey->pkey.dh->pub_key) ? Qtrue : Qfalse;
    00198 }
    00199
    00200 /*
    00201  *  call-seq:
    00202  *     dh.private? -> true | false
    00203  *
    00204  */
    00205 static VALUE
    00206 ossl_dh_is_private(VALUE self)
    00207 {
    00208     EVP_PKEY *pkey;
    00209
    00210     GetPKeyDH(self, pkey);
    00211
    00212     return (DH_PRIVATE(pkey->pkey.dh)) ? Qtrue : Qfalse;
    00213 }
    00214
    00215 /*
    00216  *  call-seq:
    00217  *     dh.to_pem -> aString
    00218  *
    00219  */
    00220 static VALUE
    00221 ossl_dh_export(VALUE self)
    00222 {
    00223     EVP_PKEY *pkey;
    00224     BIO *out;
    00225     VALUE str;
    00226
    00227     GetPKeyDH(self, pkey);
    00228     if (!(out = BIO_new(BIO_s_mem()))) {
    00229         ossl_raise(eDHError, NULL);
    00230     }
    00231     if (!PEM_write_bio_DHparams(out, pkey->pkey.dh)) {
    00232         BIO_free(out);
    00233         ossl_raise(eDHError, NULL);
    00234     }
    00235     str = ossl_membio2str(out);
    00236
    00237     return str;
    00238 }
    00239
    00240 /*
    00241  *  call-seq:
    00242  *     dh.to_der -> aString
    00243  *
    00244  */
    00245 static VALUE
    00246 ossl_dh_to_der(VALUE self)
    00247 {
    00248     EVP_PKEY *pkey;
    00249     unsigned char *p;
    00250     long len;
    00251     VALUE str;
    00252
    00253     GetPKeyDH(self, pkey);
    00254     if((len = i2d_DHparams(pkey->pkey.dh, NULL)) <= 0)
    00255         ossl_raise(eDHError, NULL);
    00256     str = rb_str_new(0, len);
    00257     p = (unsigned char *)RSTRING_PTR(str);
    00258     if(i2d_DHparams(pkey->pkey.dh, &p) < 0)
    00259         ossl_raise(eDHError, NULL);
    00260     ossl_str_adjust(str, p);
    00261
    00262     return str;
    00263 }
    00264
    00265 /*
    00266  *  call-seq:
    00267  *     dh.params -> hash
    00268  *
    00269  * Stores all parameters of key to the hash
    00270  * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
    00271  * Don't use :-)) (I's up to you)
    00272  */
    00273 static VALUE
    00274 ossl_dh_get_params(VALUE self)
    00275 {
    00276     EVP_PKEY *pkey;
    00277     VALUE hash;
    00278
    00279     GetPKeyDH(self, pkey);
    00280
    00281     hash = rb_hash_new();
    00282
    00283     rb_hash_aset(hash, rb_str_new2("p"), ossl_bn_new(pkey->pkey.dh->p));
    00284     rb_hash_aset(hash, rb_str_new2("g"), ossl_bn_new(pkey->pkey.dh->g));
    00285     rb_hash_aset(hash, rb_str_new2("pub_key"), ossl_bn_new(pkey->pkey.dh->pub_key));
    00286     rb_hash_aset(hash, rb_str_new2("priv_key"), ossl_bn_new(pkey->pkey.dh->priv_key));
    00287
    00288     return hash;
    00289 }
    00290
    00291 /*
    00292  *  call-seq:
    00293  *     dh.to_text -> aString
    00294  *
    00295  * Prints all parameters of key to buffer
    00296  * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
    00297  * Don't use :-)) (I's up to you)
    00298  */
    00299 static VALUE
    00300 ossl_dh_to_text(VALUE self)
    00301 {
    00302     EVP_PKEY *pkey;
    00303     BIO *out;
    00304     VALUE str;
    00305
    00306     GetPKeyDH(self, pkey);
    00307     if (!(out = BIO_new(BIO_s_mem()))) {
    00308         ossl_raise(eDHError, NULL);
    00309     }
    00310     if (!DHparams_print(out, pkey->pkey.dh)) {
    00311         BIO_free(out);
    00312         ossl_raise(eDHError, NULL);
    00313     }
    00314     str = ossl_membio2str(out);
    00315
    00316     return str;
    00317 }
    00318
    00319 /*
    00320  *  call-seq:
    00321  *     dh.public_key -> aDH
    00322  *
    00323  *  Makes new instance DH PUBLIC_KEY from PRIVATE_KEY
    00324  */
    00325 static VALUE
    00326 ossl_dh_to_public_key(VALUE self)
    00327 {
    00328     EVP_PKEY *pkey;
    00329     DH *dh;
    00330     VALUE obj;
    00331
    00332     GetPKeyDH(self, pkey);
    00333     dh = DHparams_dup(pkey->pkey.dh); /* err check perfomed by dh_instance */
    00334     obj = dh_instance(CLASS_OF(self), dh);
    00335     if (obj == Qfalse) {
    00336         DH_free(dh);
    00337         ossl_raise(eDHError, NULL);
    00338     }
    00339
    00340     return obj;
    00341 }
    00342
    00343 /*
    00344  *  call-seq:
    00345  *     dh.check_params -> true | false
    00346  *
    00347  */
    00348 static VALUE
    00349 ossl_dh_check_params(VALUE self)
    00350 {
    00351     DH *dh;
    00352     EVP_PKEY *pkey;
    00353     int codes;
    00354
    00355     GetPKeyDH(self, pkey);
    00356     dh = pkey->pkey.dh;
    00357
    00358     if (!DH_check(dh, &codes)) {
    00359         return Qfalse;
    00360     }
    00361
    00362     return codes == 0 ? Qtrue : Qfalse;
    00363 }
    00364
    00365 /*
    00366  *  call-seq:
    00367  *     dh.generate_key -> self
    00368  *
    00369  */
    00370 static VALUE
    00371 ossl_dh_generate_key(VALUE self)
    00372 {
    00373     DH *dh;
    00374     EVP_PKEY *pkey;
    00375
    00376     GetPKeyDH(self, pkey);
    00377     dh = pkey->pkey.dh;
    00378
    00379     if (!DH_generate_key(dh))
    00380         ossl_raise(eDHError, "Failed to generate key");
    00381     return self;
    00382 }
    00383
    00384 /*
    00385  *  call-seq:
    00386  *     dh.compute_key(pub_bn) -> aString
    00387  *
    00388  *  === Parameters
    00389  *  * +pub_bn+ is a OpenSSL::BN.
    00390  *
    00391  *  Returns aString containing a shared secret computed from the other parties public value.
    00392  *
    00393  *  See DH_compute_key() for further information.
    00394  *
    00395  */
    00396 static VALUE
    00397 ossl_dh_compute_key(VALUE self, VALUE pub)
    00398 {
    00399     DH *dh;
    00400     EVP_PKEY *pkey;
    00401     BIGNUM *pub_key;
    00402     VALUE str;
    00403     int len;
    00404
    00405     GetPKeyDH(self, pkey);
    00406     dh = pkey->pkey.dh;
    00407     pub_key = GetBNPtr(pub);
    00408     len = DH_size(dh);
    00409     str = rb_str_new(0, len);
    00410     if ((len = DH_compute_key((unsigned char *)RSTRING_PTR(str), pub_key, dh)) < 0) {
    00411         ossl_raise(eDHError, NULL);
    00412     }
    00413     rb_str_set_len(str, len);
    00414
    00415     return str;
    00416 }
    00417
    00418 OSSL_PKEY_BN(dh, p)
    00419 OSSL_PKEY_BN(dh, g)
    00420 OSSL_PKEY_BN(dh, pub_key)
    00421 OSSL_PKEY_BN(dh, priv_key)
    00422
    00423 /*
    00424  * -----BEGIN DH PARAMETERS-----
    00425  * MEYCQQD0zXHljRg/mJ9PYLACLv58Cd8VxBxxY7oEuCeURMiTqEhMym16rhhKgZG2
    00426  * zk2O9uUIBIxSj+NKMURHGaFKyIvLAgEC
    00427  * -----END DH PARAMETERS-----
    00428  */
    00429 static unsigned char DEFAULT_DH_512_PRIM[] = {
    00430     0xf4, 0xcd, 0x71, 0xe5, 0x8d, 0x18, 0x3f, 0x98,
    00431     0x9f, 0x4f, 0x60, 0xb0, 0x02, 0x2e, 0xfe, 0x7c,
    00432     0x09, 0xdf, 0x15, 0xc4, 0x1c, 0x71, 0x63, 0xba,
    00433     0x04, 0xb8, 0x27, 0x94, 0x44, 0xc8, 0x93, 0xa8,
    00434     0x48, 0x4c, 0xca, 0x6d, 0x7a, 0xae, 0x18, 0x4a,
    00435     0x81, 0x91, 0xb6, 0xce, 0x4d, 0x8e, 0xf6, 0xe5,
    00436     0x08, 0x04, 0x8c, 0x52, 0x8f, 0xe3, 0x4a, 0x31,
    00437     0x44, 0x47, 0x19, 0xa1, 0x4a, 0xc8, 0x8b, 0xcb,
    00438 };
    00439 static unsigned char DEFAULT_DH_512_GEN[] = { 0x02 };
    00440 DH *OSSL_DEFAULT_DH_512 = NULL;
    00441
    00442 /*
    00443  * -----BEGIN DH PARAMETERS-----
    00444  * MIGHAoGBAJ0lOVy0VIr/JebWn0zDwY2h+rqITFOpdNr6ugsgvkDXuucdcChhYExJ
    00445  * AV/ZD2AWPbrTqV76mGRgJg4EddgT1zG0jq3rnFdMj2XzkBYx3BVvfR0Arnby0RHR
    00446  * T4h7KZ/2zmjvV+eF8kBUHBJAojUlzxKj4QeO2x20FP9X5xmNUXeDAgEC
    00447  * -----END DH PARAMETERS-----
    00448  */
    00449 static unsigned char DEFAULT_DH_1024_PRIM[] = {
    00450     0x9d, 0x25, 0x39, 0x5c, 0xb4, 0x54, 0x8a, 0xff,
    00451     0x25, 0xe6, 0xd6, 0x9f, 0x4c, 0xc3, 0xc1, 0x8d,
    00452     0xa1, 0xfa, 0xba, 0x88, 0x4c, 0x53, 0xa9, 0x74,
    00453     0xda, 0xfa, 0xba, 0x0b, 0x20, 0xbe, 0x40, 0xd7,
    00454     0xba, 0xe7, 0x1d, 0x70, 0x28, 0x61, 0x60, 0x4c,
    00455     0x49, 0x01, 0x5f, 0xd9, 0x0f, 0x60, 0x16, 0x3d,
    00456     0xba, 0xd3, 0xa9, 0x5e, 0xfa, 0x98, 0x64, 0x60,
    00457     0x26, 0x0e, 0x04, 0x75, 0xd8, 0x13, 0xd7, 0x31,
    00458     0xb4, 0x8e, 0xad, 0xeb, 0x9c, 0x57, 0x4c, 0x8f,
    00459     0x65, 0xf3, 0x90, 0x16, 0x31, 0xdc, 0x15, 0x6f,
    00460     0x7d, 0x1d, 0x00, 0xae, 0x76, 0xf2, 0xd1, 0x11,
    00461     0xd1, 0x4f, 0x88, 0x7b, 0x29, 0x9f, 0xf6, 0xce,
    00462     0x68, 0xef, 0x57, 0xe7, 0x85, 0xf2, 0x40, 0x54,
    00463     0x1c, 0x12, 0x40, 0xa2, 0x35, 0x25, 0xcf, 0x12,
    00464     0xa3, 0xe1, 0x07, 0x8e, 0xdb, 0x1d, 0xb4, 0x14,
    00465     0xff, 0x57, 0xe7, 0x19, 0x8d, 0x51, 0x77, 0x83
    00466 };
    00467 static unsigned char DEFAULT_DH_1024_GEN[] = { 0x02 };
    00468 DH *OSSL_DEFAULT_DH_1024 = NULL;
    00469
    00470 static DH*
    00471 ossl_create_dh(unsigned char *p, size_t plen, unsigned char *g, size_t glen)
    00472 {
    00473     DH *dh;
    00474
    00475     if ((dh = DH_new()) == NULL) ossl_raise(eDHError, NULL);
    00476     dh->p = BN_bin2bn(p, plen, NULL);
    00477     dh->g = BN_bin2bn(g, glen, NULL);
    00478     if (dh->p == NULL || dh->g == NULL){
    00479         DH_free(dh);
    00480         ossl_raise(eDHError, NULL);
    00481     }
    00482
    00483     return dh;
    00484 }
    00485
    00486 /*
    00487  * INIT
    00488  */
    00489 void
    00490 Init_ossl_dh()
    00491 {
    00492 #if 0 /* let rdoc know about mOSSL and mPKey */
    00493     mOSSL = rb_define_module("OpenSSL");
    00494     mPKey = rb_define_module_under(mOSSL, "PKey");
    00495 #endif
    00496
    00497     eDHError = rb_define_class_under(mPKey, "DHError", ePKeyError);
    00498     cDH = rb_define_class_under(mPKey, "DH", cPKey);
    00499     rb_define_singleton_method(cDH, "generate", ossl_dh_s_generate, -1);
    00500     rb_define_method(cDH, "initialize", ossl_dh_initialize, -1);
    00501     rb_define_method(cDH, "public?", ossl_dh_is_public, 0);
    00502     rb_define_method(cDH, "private?", ossl_dh_is_private, 0);
    00503     rb_define_method(cDH, "to_text", ossl_dh_to_text, 0);
    00504     rb_define_method(cDH, "export", ossl_dh_export, 0);
    00505     rb_define_alias(cDH, "to_pem", "export");
    00506     rb_define_alias(cDH, "to_s", "export");
    00507     rb_define_method(cDH, "to_der", ossl_dh_to_der, 0);
    00508     rb_define_method(cDH, "public_key", ossl_dh_to_public_key, 0);
    00509     rb_define_method(cDH, "params_ok?", ossl_dh_check_params, 0);
    00510     rb_define_method(cDH, "generate_key!", ossl_dh_generate_key, 0);
    00511     rb_define_method(cDH, "compute_key", ossl_dh_compute_key, 1);
    00512     DEF_OSSL_PKEY_BN(cDH, dh, p);
    00513     DEF_OSSL_PKEY_BN(cDH, dh, g);
    00514     DEF_OSSL_PKEY_BN(cDH, dh, pub_key);
    00515     DEF_OSSL_PKEY_BN(cDH, dh, priv_key);
    00516     rb_define_method(cDH, "params", ossl_dh_get_params, 0);
    00517
    00518     OSSL_DEFAULT_DH_512 = ossl_create_dh(
    00519         DEFAULT_DH_512_PRIM, sizeof(DEFAULT_DH_512_PRIM),
    00520         DEFAULT_DH_512_GEN, sizeof(DEFAULT_DH_512_GEN));
    00521     OSSL_DEFAULT_DH_1024 = ossl_create_dh(
    00522         DEFAULT_DH_1024_PRIM, sizeof(DEFAULT_DH_1024_PRIM),
    00523         DEFAULT_DH_1024_GEN, sizeof(DEFAULT_DH_1024_GEN));
    00524 }
    00525
    00526 #else /* defined NO_DH */
    00527 void
    00528 Init_ossl_dh()
    00529 {
    00530 }
    00531 #endif /* NO_DH */
    00532
    00533