Ruby  2.0.0p247(2013-06-27revision41674)
ext/openssl/ossl_pkey_dh.c
Go to the documentation of this file.
00001 /*
00002  * $Id: ossl_pkey_dh.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_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 #if defined(HAVE_DH_GENERATE_PARAMETERS_EX) && HAVE_BN_GENCB
00085 struct dh_blocking_gen_arg {
00086     DH *dh;
00087     int size;
00088     int gen;
00089     BN_GENCB *cb;
00090     int result;
00091 };
00092 
00093 static void *
00094 dh_blocking_gen(void *arg)
00095 {
00096     struct dh_blocking_gen_arg *gen = (struct dh_blocking_gen_arg *)arg;
00097     gen->result = DH_generate_parameters_ex(gen->dh, gen->size, gen->gen, gen->cb);
00098     return 0;
00099 }
00100 #endif
00101 
00102 static DH *
00103 dh_generate(int size, int gen)
00104 {
00105 #if defined(HAVE_DH_GENERATE_PARAMETERS_EX) && HAVE_BN_GENCB
00106     BN_GENCB cb;
00107     struct ossl_generate_cb_arg cb_arg;
00108     struct dh_blocking_gen_arg gen_arg;
00109     DH *dh = DH_new();
00110 
00111     if (!dh) return 0;
00112 
00113     memset(&cb_arg, 0, sizeof(struct ossl_generate_cb_arg));
00114     if (rb_block_given_p())
00115         cb_arg.yield = 1;
00116     BN_GENCB_set(&cb, ossl_generate_cb_2, &cb_arg);
00117     gen_arg.dh = dh;
00118     gen_arg.size = size;
00119     gen_arg.gen = gen;
00120     gen_arg.cb = &cb;
00121     if (cb_arg.yield == 1) {
00122         /* we cannot release GVL when callback proc is supplied */
00123         dh_blocking_gen(&gen_arg);
00124     } else {
00125         /* there's a chance to unblock */
00126         rb_thread_call_without_gvl(dh_blocking_gen, &gen_arg, ossl_generate_cb_stop, &cb_arg);
00127     }
00128 
00129     if (!gen_arg.result) {
00130         DH_free(dh);
00131         if (cb_arg.state) rb_jump_tag(cb_arg.state);
00132         return 0;
00133     }
00134 #else
00135     DH *dh;
00136 
00137     dh = DH_generate_parameters(size, gen, rb_block_given_p() ? ossl_generate_cb : NULL, NULL);
00138     if (!dh) return 0;
00139 #endif
00140 
00141     if (!DH_generate_key(dh)) {
00142         DH_free(dh);
00143         return 0;
00144     }
00145 
00146     return dh;
00147 }
00148 
00149 /*
00150  *  call-seq:
00151  *     DH.generate(size [, generator]) -> dh
00152  *
00153  * Creates a new DH instance from scratch by generating the private and public
00154  * components alike.
00155  *
00156  * === Parameters
00157  * * +size+ is an integer representing the desired key size. Keys smaller than 1024 bits should be considered insecure.
00158  * * +generator+ is a small number > 1, typically 2 or 5.
00159  *
00160  */
00161 static VALUE
00162 ossl_dh_s_generate(int argc, VALUE *argv, VALUE klass)
00163 {
00164     DH *dh ;
00165     int g = 2;
00166     VALUE size, gen, obj;
00167 
00168     if (rb_scan_args(argc, argv, "11", &size, &gen) == 2) {
00169         g = NUM2INT(gen);
00170     }
00171     dh = dh_generate(NUM2INT(size), g);
00172     obj = dh_instance(klass, dh);
00173     if (obj == Qfalse) {
00174         DH_free(dh);
00175         ossl_raise(eDHError, NULL);
00176     }
00177 
00178     return obj;
00179 }
00180 
00181 /*
00182  *  call-seq:
00183  *     DH.new([size [, generator] | string]) -> dh
00184  *
00185  * Either generates a DH instance from scratch or by reading already existing
00186  * DH parameters from +string+. Note that when reading a DH instance from
00187  * data that was encoded from a DH instance by using DH#to_pem or DH#to_der
00188  * the result will *not* contain a public/private key pair yet. This needs to
00189  * be generated using DH#generate_key! first.
00190  *
00191  * === Parameters
00192  * * +size+ is an integer representing the desired key size. Keys smaller than 1024 bits should be considered insecure.
00193  * * +generator+ is a small number > 1, typically 2 or 5.
00194  * * +string+ contains the DER or PEM encoded key.
00195  *
00196  * === Examples
00197  *  DH.new # -> dh
00198  *  DH.new(1024) # -> dh
00199  *  DH.new(1024, 5) # -> dh
00200  *  #Reading DH parameters
00201  *  dh = DH.new(File.read('parameters.pem')) # -> dh, but no public/private key yet
00202  *  dh.generate_key! # -> dh with public and private key
00203  */
00204 static VALUE
00205 ossl_dh_initialize(int argc, VALUE *argv, VALUE self)
00206 {
00207     EVP_PKEY *pkey;
00208     DH *dh;
00209     int g = 2;
00210     BIO *in;
00211     VALUE arg, gen;
00212 
00213     GetPKey(self, pkey);
00214     if(rb_scan_args(argc, argv, "02", &arg, &gen) == 0) {
00215       dh = DH_new();
00216     }
00217     else if (FIXNUM_P(arg)) {
00218         if (!NIL_P(gen)) {
00219             g = NUM2INT(gen);
00220         }
00221         if (!(dh = dh_generate(FIX2INT(arg), g))) {
00222             ossl_raise(eDHError, NULL);
00223         }
00224     }
00225     else {
00226         arg = ossl_to_der_if_possible(arg);
00227         in = ossl_obj2bio(arg);
00228         dh = PEM_read_bio_DHparams(in, NULL, NULL, NULL);
00229         if (!dh){
00230             OSSL_BIO_reset(in);
00231             dh = d2i_DHparams_bio(in, NULL);
00232         }
00233         BIO_free(in);
00234         if (!dh) {
00235             ossl_raise(eDHError, NULL);
00236         }
00237     }
00238     if (!EVP_PKEY_assign_DH(pkey, dh)) {
00239         DH_free(dh);
00240         ossl_raise(eDHError, NULL);
00241     }
00242     return self;
00243 }
00244 
00245 /*
00246  *  call-seq:
00247  *     dh.public? -> true | false
00248  *
00249  * Indicates whether this DH instance has a public key associated with it or
00250  * not. The public key may be retrieved with DH#pub_key.
00251  */
00252 static VALUE
00253 ossl_dh_is_public(VALUE self)
00254 {
00255     EVP_PKEY *pkey;
00256 
00257     GetPKeyDH(self, pkey);
00258 
00259     return (pkey->pkey.dh->pub_key) ? Qtrue : Qfalse;
00260 }
00261 
00262 /*
00263  *  call-seq:
00264  *     dh.private? -> true | false
00265  *
00266  * Indicates whether this DH instance has a private key associated with it or
00267  * not. The private key may be retrieved with DH#priv_key.
00268  */
00269 static VALUE
00270 ossl_dh_is_private(VALUE self)
00271 {
00272     EVP_PKEY *pkey;
00273 
00274     GetPKeyDH(self, pkey);
00275 
00276     return (DH_PRIVATE(pkey->pkey.dh)) ? Qtrue : Qfalse;
00277 }
00278 
00279 /*
00280  *  call-seq:
00281  *     dh.to_pem -> aString
00282  *
00283  * Encodes this DH to its PEM encoding. Note that any existing per-session
00284  * public/private keys will *not* get encoded, just the Diffie-Hellman
00285  * parameters will be encoded.
00286  */
00287 static VALUE
00288 ossl_dh_export(VALUE self)
00289 {
00290     EVP_PKEY *pkey;
00291     BIO *out;
00292     VALUE str;
00293 
00294     GetPKeyDH(self, pkey);
00295     if (!(out = BIO_new(BIO_s_mem()))) {
00296         ossl_raise(eDHError, NULL);
00297     }
00298     if (!PEM_write_bio_DHparams(out, pkey->pkey.dh)) {
00299         BIO_free(out);
00300         ossl_raise(eDHError, NULL);
00301     }
00302     str = ossl_membio2str(out);
00303 
00304     return str;
00305 }
00306 
00307 /*
00308  *  call-seq:
00309  *     dh.to_der -> aString
00310  *
00311  * Encodes this DH to its DER encoding. Note that any existing per-session
00312  * public/private keys will *not* get encoded, just the Diffie-Hellman
00313  * parameters will be encoded.
00314 
00315  */
00316 static VALUE
00317 ossl_dh_to_der(VALUE self)
00318 {
00319     EVP_PKEY *pkey;
00320     unsigned char *p;
00321     long len;
00322     VALUE str;
00323 
00324     GetPKeyDH(self, pkey);
00325     if((len = i2d_DHparams(pkey->pkey.dh, NULL)) <= 0)
00326         ossl_raise(eDHError, NULL);
00327     str = rb_str_new(0, len);
00328     p = (unsigned char *)RSTRING_PTR(str);
00329     if(i2d_DHparams(pkey->pkey.dh, &p) < 0)
00330         ossl_raise(eDHError, NULL);
00331     ossl_str_adjust(str, p);
00332 
00333     return str;
00334 }
00335 
00336 /*
00337  *  call-seq:
00338  *     dh.params -> hash
00339  *
00340  * Stores all parameters of key to the hash
00341  * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
00342  * Don't use :-)) (I's up to you)
00343  */
00344 static VALUE
00345 ossl_dh_get_params(VALUE self)
00346 {
00347     EVP_PKEY *pkey;
00348     VALUE hash;
00349 
00350     GetPKeyDH(self, pkey);
00351 
00352     hash = rb_hash_new();
00353 
00354     rb_hash_aset(hash, rb_str_new2("p"), ossl_bn_new(pkey->pkey.dh->p));
00355     rb_hash_aset(hash, rb_str_new2("g"), ossl_bn_new(pkey->pkey.dh->g));
00356     rb_hash_aset(hash, rb_str_new2("pub_key"), ossl_bn_new(pkey->pkey.dh->pub_key));
00357     rb_hash_aset(hash, rb_str_new2("priv_key"), ossl_bn_new(pkey->pkey.dh->priv_key));
00358 
00359     return hash;
00360 }
00361 
00362 /*
00363  *  call-seq:
00364  *     dh.to_text -> aString
00365  *
00366  * Prints all parameters of key to buffer
00367  * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
00368  * Don't use :-)) (I's up to you)
00369  */
00370 static VALUE
00371 ossl_dh_to_text(VALUE self)
00372 {
00373     EVP_PKEY *pkey;
00374     BIO *out;
00375     VALUE str;
00376 
00377     GetPKeyDH(self, pkey);
00378     if (!(out = BIO_new(BIO_s_mem()))) {
00379         ossl_raise(eDHError, NULL);
00380     }
00381     if (!DHparams_print(out, pkey->pkey.dh)) {
00382         BIO_free(out);
00383         ossl_raise(eDHError, NULL);
00384     }
00385     str = ossl_membio2str(out);
00386 
00387     return str;
00388 }
00389 
00390 /*
00391  *  call-seq:
00392  *     dh.public_key -> aDH
00393  *
00394  * Returns a new DH instance that carries just the public information, i.e.
00395  * the prime +p+ and the generator +g+, but no public/private key yet. Such
00396  * a pair may be generated using DH#generate_key!. The "public key" needed
00397  * for a key exchange with DH#compute_key is considered as per-session
00398  * information and may be retrieved with DH#pub_key once a key pair has
00399  * been generated.
00400  * If the current instance already contains private information (and thus a
00401  * valid public/private key pair), this information will no longer be present
00402  * in the new instance generated by DH#public_key. This feature is helpful for
00403  * publishing the Diffie-Hellman parameters without leaking any of the private
00404  * per-session information.
00405  *
00406  * === Example
00407  *  dh = OpenSSL::PKey::DH.new(2048) # has public and private key set
00408  *  public_key = dh.public_key # contains only prime and generator
00409  *  parameters = public_key.to_der # it's safe to publish this
00410  */
00411 static VALUE
00412 ossl_dh_to_public_key(VALUE self)
00413 {
00414     EVP_PKEY *pkey;
00415     DH *dh;
00416     VALUE obj;
00417 
00418     GetPKeyDH(self, pkey);
00419     dh = DHparams_dup(pkey->pkey.dh); /* err check perfomed by dh_instance */
00420     obj = dh_instance(CLASS_OF(self), dh);
00421     if (obj == Qfalse) {
00422         DH_free(dh);
00423         ossl_raise(eDHError, NULL);
00424     }
00425 
00426     return obj;
00427 }
00428 
00429 /*
00430  *  call-seq:
00431  *     dh.check_params -> true | false
00432  *
00433  * Validates the Diffie-Hellman parameters associated with this instance.
00434  * It checks whether a safe prime and a suitable generator are used. If this
00435  * is not the case, +false+ is returned.
00436  */
00437 static VALUE
00438 ossl_dh_check_params(VALUE self)
00439 {
00440     DH *dh;
00441     EVP_PKEY *pkey;
00442     int codes;
00443 
00444     GetPKeyDH(self, pkey);
00445     dh = pkey->pkey.dh;
00446 
00447     if (!DH_check(dh, &codes)) {
00448         return Qfalse;
00449     }
00450 
00451     return codes == 0 ? Qtrue : Qfalse;
00452 }
00453 
00454 /*
00455  *  call-seq:
00456  *     dh.generate_key! -> self
00457  *
00458  * Generates a private and public key unless a private key already exists.
00459  * If this DH instance was generated from public DH parameters (e.g. by
00460  * encoding the result of DH#public_key), then this method needs to be
00461  * called first in order to generate the per-session keys before performing
00462  * the actual key exchange.
00463  *
00464  * === Example
00465  *   dh = OpenSSL::PKey::DH.new(2048)
00466  *   public_key = dh.public_key #contains no private/public key yet
00467  *   public_key.generate_key!
00468  *   puts public_key.private? # => true
00469  */
00470 static VALUE
00471 ossl_dh_generate_key(VALUE self)
00472 {
00473     DH *dh;
00474     EVP_PKEY *pkey;
00475 
00476     GetPKeyDH(self, pkey);
00477     dh = pkey->pkey.dh;
00478 
00479     if (!DH_generate_key(dh))
00480         ossl_raise(eDHError, "Failed to generate key");
00481     return self;
00482 }
00483 
00484 /*
00485  *  call-seq:
00486  *     dh.compute_key(pub_bn) -> aString
00487  *
00488  * Returns a String containing a shared secret computed from the other party's public value.
00489  * See DH_compute_key() for further information.
00490  *
00491  * === Parameters
00492  * * +pub_bn+ is a OpenSSL::BN, *not* the DH instance returned by
00493  * DH#public_key as that contains the DH parameters only.
00494  */
00495 static VALUE
00496 ossl_dh_compute_key(VALUE self, VALUE pub)
00497 {
00498     DH *dh;
00499     EVP_PKEY *pkey;
00500     BIGNUM *pub_key;
00501     VALUE str;
00502     int len;
00503 
00504     GetPKeyDH(self, pkey);
00505     dh = pkey->pkey.dh;
00506     pub_key = GetBNPtr(pub);
00507     len = DH_size(dh);
00508     str = rb_str_new(0, len);
00509     if ((len = DH_compute_key((unsigned char *)RSTRING_PTR(str), pub_key, dh)) < 0) {
00510         ossl_raise(eDHError, NULL);
00511     }
00512     rb_str_set_len(str, len);
00513 
00514     return str;
00515 }
00516 
00517 OSSL_PKEY_BN(dh, p)
00518 OSSL_PKEY_BN(dh, g)
00519 OSSL_PKEY_BN(dh, pub_key)
00520 OSSL_PKEY_BN(dh, priv_key)
00521 
00522 /*
00523  * -----BEGIN DH PARAMETERS-----
00524  * MEYCQQD0zXHljRg/mJ9PYLACLv58Cd8VxBxxY7oEuCeURMiTqEhMym16rhhKgZG2
00525  * zk2O9uUIBIxSj+NKMURHGaFKyIvLAgEC
00526  * -----END DH PARAMETERS-----
00527  */
00528 static unsigned char DEFAULT_DH_512_PRIM[] = {
00529     0xf4, 0xcd, 0x71, 0xe5, 0x8d, 0x18, 0x3f, 0x98,
00530     0x9f, 0x4f, 0x60, 0xb0, 0x02, 0x2e, 0xfe, 0x7c,
00531     0x09, 0xdf, 0x15, 0xc4, 0x1c, 0x71, 0x63, 0xba,
00532     0x04, 0xb8, 0x27, 0x94, 0x44, 0xc8, 0x93, 0xa8,
00533     0x48, 0x4c, 0xca, 0x6d, 0x7a, 0xae, 0x18, 0x4a,
00534     0x81, 0x91, 0xb6, 0xce, 0x4d, 0x8e, 0xf6, 0xe5,
00535     0x08, 0x04, 0x8c, 0x52, 0x8f, 0xe3, 0x4a, 0x31,
00536     0x44, 0x47, 0x19, 0xa1, 0x4a, 0xc8, 0x8b, 0xcb,
00537 };
00538 static unsigned char DEFAULT_DH_512_GEN[] = { 0x02 };
00539 DH *OSSL_DEFAULT_DH_512 = NULL;
00540 
00541 /*
00542  * -----BEGIN DH PARAMETERS-----
00543  * MIGHAoGBAJ0lOVy0VIr/JebWn0zDwY2h+rqITFOpdNr6ugsgvkDXuucdcChhYExJ
00544  * AV/ZD2AWPbrTqV76mGRgJg4EddgT1zG0jq3rnFdMj2XzkBYx3BVvfR0Arnby0RHR
00545  * T4h7KZ/2zmjvV+eF8kBUHBJAojUlzxKj4QeO2x20FP9X5xmNUXeDAgEC
00546  * -----END DH PARAMETERS-----
00547  */
00548 static unsigned char DEFAULT_DH_1024_PRIM[] = {
00549     0x9d, 0x25, 0x39, 0x5c, 0xb4, 0x54, 0x8a, 0xff,
00550     0x25, 0xe6, 0xd6, 0x9f, 0x4c, 0xc3, 0xc1, 0x8d,
00551     0xa1, 0xfa, 0xba, 0x88, 0x4c, 0x53, 0xa9, 0x74,
00552     0xda, 0xfa, 0xba, 0x0b, 0x20, 0xbe, 0x40, 0xd7,
00553     0xba, 0xe7, 0x1d, 0x70, 0x28, 0x61, 0x60, 0x4c,
00554     0x49, 0x01, 0x5f, 0xd9, 0x0f, 0x60, 0x16, 0x3d,
00555     0xba, 0xd3, 0xa9, 0x5e, 0xfa, 0x98, 0x64, 0x60,
00556     0x26, 0x0e, 0x04, 0x75, 0xd8, 0x13, 0xd7, 0x31,
00557     0xb4, 0x8e, 0xad, 0xeb, 0x9c, 0x57, 0x4c, 0x8f,
00558     0x65, 0xf3, 0x90, 0x16, 0x31, 0xdc, 0x15, 0x6f,
00559     0x7d, 0x1d, 0x00, 0xae, 0x76, 0xf2, 0xd1, 0x11,
00560     0xd1, 0x4f, 0x88, 0x7b, 0x29, 0x9f, 0xf6, 0xce,
00561     0x68, 0xef, 0x57, 0xe7, 0x85, 0xf2, 0x40, 0x54,
00562     0x1c, 0x12, 0x40, 0xa2, 0x35, 0x25, 0xcf, 0x12,
00563     0xa3, 0xe1, 0x07, 0x8e, 0xdb, 0x1d, 0xb4, 0x14,
00564     0xff, 0x57, 0xe7, 0x19, 0x8d, 0x51, 0x77, 0x83
00565 };
00566 static unsigned char DEFAULT_DH_1024_GEN[] = { 0x02 };
00567 DH *OSSL_DEFAULT_DH_1024 = NULL;
00568 
00569 static DH*
00570 ossl_create_dh(unsigned char *p, size_t plen, unsigned char *g, size_t glen)
00571 {
00572     DH *dh;
00573 
00574     if ((dh = DH_new()) == NULL) ossl_raise(eDHError, NULL);
00575     dh->p = BN_bin2bn(p, rb_long2int(plen), NULL);
00576     dh->g = BN_bin2bn(g, rb_long2int(glen), NULL);
00577     if (dh->p == NULL || dh->g == NULL){
00578         DH_free(dh);
00579         ossl_raise(eDHError, NULL);
00580     }
00581 
00582     return dh;
00583 }
00584 
00585 /*
00586  * INIT
00587  */
00588 void
00589 Init_ossl_dh()
00590 {
00591 #if 0
00592     mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL and mPKey */
00593     mPKey = rb_define_module_under(mOSSL, "PKey");
00594 #endif
00595 
00596     /* Document-class: OpenSSL::PKey::DHError
00597      *
00598      * Generic exception that is raised if an operation on a DH PKey
00599      * fails unexpectedly or in case an instantiation of an instance of DH
00600      * fails due to non-conformant input data.
00601      */
00602     eDHError = rb_define_class_under(mPKey, "DHError", ePKeyError);
00603     /* Document-class: OpenSSL::PKey::DH
00604      *
00605      * An implementation of the Diffie-Hellman key exchange protocol based on
00606      * discrete logarithms in finite fields, the same basis that DSA is built
00607      * on.
00608      *
00609      * === Accessor methods for the Diffie-Hellman parameters
00610      * * DH#p
00611      * The prime (an OpenSSL::BN) of the Diffie-Hellman parameters.
00612      * * DH#g
00613      * The generator (an OpenSSL::BN) g of the Diffie-Hellman parameters.
00614      * * DH#pub_key
00615      * The per-session public key (an OpenSSL::BN) matching the private key.
00616      * This needs to be passed to DH#compute_key.
00617      * * DH#priv_key
00618      * The per-session private key, an OpenSSL::BN.
00619      *
00620      * === Example of a key exchange
00621      *  dh1 = OpenSSL::PKey::DH.new(2048)
00622      *  params = dh1.public_key.to_der #you may send this publicly to the participating party
00623      *  dh2 = OpenSSL::PKey::DH.new(der)
00624      *  dh2.generate_key! #generate the per-session key pair
00625      *  symm_key1 = dh1.compute_key(dh2.pub_key)
00626      *  symm_key2 = dh2.compute_key(dh1.pub_key)
00627      *
00628      *  puts symm_key1 == symm_key2 # => true
00629      */
00630     cDH = rb_define_class_under(mPKey, "DH", cPKey);
00631     rb_define_singleton_method(cDH, "generate", ossl_dh_s_generate, -1);
00632     rb_define_method(cDH, "initialize", ossl_dh_initialize, -1);
00633     rb_define_method(cDH, "public?", ossl_dh_is_public, 0);
00634     rb_define_method(cDH, "private?", ossl_dh_is_private, 0);
00635     rb_define_method(cDH, "to_text", ossl_dh_to_text, 0);
00636     rb_define_method(cDH, "export", ossl_dh_export, 0);
00637     rb_define_alias(cDH, "to_pem", "export");
00638     rb_define_alias(cDH, "to_s", "export");
00639     rb_define_method(cDH, "to_der", ossl_dh_to_der, 0);
00640     rb_define_method(cDH, "public_key", ossl_dh_to_public_key, 0);
00641     rb_define_method(cDH, "params_ok?", ossl_dh_check_params, 0);
00642     rb_define_method(cDH, "generate_key!", ossl_dh_generate_key, 0);
00643     rb_define_method(cDH, "compute_key", ossl_dh_compute_key, 1);
00644 
00645     DEF_OSSL_PKEY_BN(cDH, dh, p);
00646     DEF_OSSL_PKEY_BN(cDH, dh, g);
00647     DEF_OSSL_PKEY_BN(cDH, dh, pub_key);
00648     DEF_OSSL_PKEY_BN(cDH, dh, priv_key);
00649     rb_define_method(cDH, "params", ossl_dh_get_params, 0);
00650 
00651     OSSL_DEFAULT_DH_512 = ossl_create_dh(
00652         DEFAULT_DH_512_PRIM, sizeof(DEFAULT_DH_512_PRIM),
00653         DEFAULT_DH_512_GEN, sizeof(DEFAULT_DH_512_GEN));
00654     OSSL_DEFAULT_DH_1024 = ossl_create_dh(
00655         DEFAULT_DH_1024_PRIM, sizeof(DEFAULT_DH_1024_PRIM),
00656         DEFAULT_DH_1024_GEN, sizeof(DEFAULT_DH_1024_GEN));
00657 }
00658 
00659 #else /* defined NO_DH */
00660 void
00661 Init_ossl_dh()
00662 {
00663 }
00664 #endif /* NO_DH */
00665 
00666