/source/ruby-1.9.2-p180/ext/openssl/ossl_pkey_dh.c
C | 532 lines | 344 code | 65 blank | 123 comment | 47 complexity | 6ef02b33af215af0914ccdde3f2714b7 MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause
1/*
2 * $Id: ossl_pkey_dh.c 27440 2010-04-22 08:21:01Z nobu $
3 * 'OpenSSL for Ruby' project
4 * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
5 * All rights reserved.
6 */
7/*
8 * This program is licenced under the same licence as Ruby.
9 * (See the file 'LICENCE'.)
10 */
11#if !defined(OPENSSL_NO_DH)
12
13#include "ossl.h"
14
15#define GetPKeyDH(obj, pkey) do { \
16 GetPKey(obj, pkey); \
17 if (EVP_PKEY_type(pkey->type) != EVP_PKEY_DH) { /* PARANOIA? */ \
18 ossl_raise(rb_eRuntimeError, "THIS IS NOT A DH!") ; \
19 } \
20} while (0)
21
22#define DH_HAS_PRIVATE(dh) ((dh)->priv_key)
23
24#ifdef OSSL_ENGINE_ENABLED
25# define DH_PRIVATE(dh) (DH_HAS_PRIVATE(dh) || (dh)->engine)
26#else
27# define DH_PRIVATE(dh) DH_HAS_PRIVATE(dh)
28#endif
29
30
31/*
32 * Classes
33 */
34VALUE cDH;
35VALUE eDHError;
36
37/*
38 * Public
39 */
40static VALUE
41dh_instance(VALUE klass, DH *dh)
42{
43 EVP_PKEY *pkey;
44 VALUE obj;
45
46 if (!dh) {
47 return Qfalse;
48 }
49 if (!(pkey = EVP_PKEY_new())) {
50 return Qfalse;
51 }
52 if (!EVP_PKEY_assign_DH(pkey, dh)) {
53 EVP_PKEY_free(pkey);
54 return Qfalse;
55 }
56 WrapPKey(klass, obj, pkey);
57
58 return obj;
59}
60
61VALUE
62ossl_dh_new(EVP_PKEY *pkey)
63{
64 VALUE obj;
65
66 if (!pkey) {
67 obj = dh_instance(cDH, DH_new());
68 } else {
69 if (EVP_PKEY_type(pkey->type) != EVP_PKEY_DH) {
70 ossl_raise(rb_eTypeError, "Not a DH key!");
71 }
72 WrapPKey(cDH, obj, pkey);
73 }
74 if (obj == Qfalse) {
75 ossl_raise(eDHError, NULL);
76 }
77
78 return obj;
79}
80
81/*
82 * Private
83 */
84static DH *
85dh_generate(int size, int gen)
86{
87 DH *dh;
88
89 dh = DH_generate_parameters(size, gen,
90 rb_block_given_p() ? ossl_generate_cb : NULL,
91 NULL);
92 if (!dh) return 0;
93
94 if (!DH_generate_key(dh)) {
95 DH_free(dh);
96 return 0;
97 }
98
99 return dh;
100}
101
102/*
103 * call-seq:
104 * DH.generate(size [, generator]) -> dh
105 *
106 * === Parameters
107 * * +size+ is an integer representing the desired key size. Keys smaller than 1024 should be considered insecure.
108 * * +generator+ is a small number > 1, typically 2 or 5.
109 *
110 */
111static VALUE
112ossl_dh_s_generate(int argc, VALUE *argv, VALUE klass)
113{
114 DH *dh ;
115 int g = 2;
116 VALUE size, gen, obj;
117
118 if (rb_scan_args(argc, argv, "11", &size, &gen) == 2) {
119 g = NUM2INT(gen);
120 }
121 dh = dh_generate(NUM2INT(size), g);
122 obj = dh_instance(klass, dh);
123 if (obj == Qfalse) {
124 DH_free(dh);
125 ossl_raise(eDHError, NULL);
126 }
127
128 return obj;
129}
130
131/*
132 * call-seq:
133 * DH.new([size [, generator] | string]) -> dh
134 *
135 * === Parameters
136 * * +size+ is an integer representing the desired key size. Keys smaller than 1024 should be considered insecure.
137 * * +generator+ is a small number > 1, typically 2 or 5.
138 * * +string+ contains the DER or PEM encoded key.
139 *
140 * === Examples
141 * * DH.new -> dh
142 * * DH.new(1024) -> dh
143 * * DH.new(1024, 5) -> dh
144 * * DH.new(File.read('key.pem')) -> dh
145 */
146static VALUE
147ossl_dh_initialize(int argc, VALUE *argv, VALUE self)
148{
149 EVP_PKEY *pkey;
150 DH *dh;
151 int g = 2;
152 BIO *in;
153 VALUE arg, gen;
154
155 GetPKey(self, pkey);
156 if(rb_scan_args(argc, argv, "02", &arg, &gen) == 0) {
157 dh = DH_new();
158 }
159 else if (FIXNUM_P(arg)) {
160 if (!NIL_P(gen)) {
161 g = NUM2INT(gen);
162 }
163 if (!(dh = dh_generate(FIX2INT(arg), g))) {
164 ossl_raise(eDHError, NULL);
165 }
166 }
167 else {
168 arg = ossl_to_der_if_possible(arg);
169 in = ossl_obj2bio(arg);
170 dh = PEM_read_bio_DHparams(in, NULL, NULL, NULL);
171 if (!dh){
172 (void)BIO_reset(in);
173 dh = d2i_DHparams_bio(in, NULL);
174 }
175 BIO_free(in);
176 if (!dh) ossl_raise(eDHError, NULL);
177 }
178 if (!EVP_PKEY_assign_DH(pkey, dh)) {
179 DH_free(dh);
180 ossl_raise(eDHError, NULL);
181 }
182 return self;
183}
184
185/*
186 * call-seq:
187 * dh.public? -> true | false
188 *
189 */
190static VALUE
191ossl_dh_is_public(VALUE self)
192{
193 EVP_PKEY *pkey;
194
195 GetPKeyDH(self, pkey);
196
197 return (pkey->pkey.dh->pub_key) ? Qtrue : Qfalse;
198}
199
200/*
201 * call-seq:
202 * dh.private? -> true | false
203 *
204 */
205static VALUE
206ossl_dh_is_private(VALUE self)
207{
208 EVP_PKEY *pkey;
209
210 GetPKeyDH(self, pkey);
211
212 return (DH_PRIVATE(pkey->pkey.dh)) ? Qtrue : Qfalse;
213}
214
215/*
216 * call-seq:
217 * dh.to_pem -> aString
218 *
219 */
220static VALUE
221ossl_dh_export(VALUE self)
222{
223 EVP_PKEY *pkey;
224 BIO *out;
225 VALUE str;
226
227 GetPKeyDH(self, pkey);
228 if (!(out = BIO_new(BIO_s_mem()))) {
229 ossl_raise(eDHError, NULL);
230 }
231 if (!PEM_write_bio_DHparams(out, pkey->pkey.dh)) {
232 BIO_free(out);
233 ossl_raise(eDHError, NULL);
234 }
235 str = ossl_membio2str(out);
236
237 return str;
238}
239
240/*
241 * call-seq:
242 * dh.to_der -> aString
243 *
244 */
245static VALUE
246ossl_dh_to_der(VALUE self)
247{
248 EVP_PKEY *pkey;
249 unsigned char *p;
250 long len;
251 VALUE str;
252
253 GetPKeyDH(self, pkey);
254 if((len = i2d_DHparams(pkey->pkey.dh, NULL)) <= 0)
255 ossl_raise(eDHError, NULL);
256 str = rb_str_new(0, len);
257 p = (unsigned char *)RSTRING_PTR(str);
258 if(i2d_DHparams(pkey->pkey.dh, &p) < 0)
259 ossl_raise(eDHError, NULL);
260 ossl_str_adjust(str, p);
261
262 return str;
263}
264
265/*
266 * call-seq:
267 * dh.params -> hash
268 *
269 * Stores all parameters of key to the hash
270 * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
271 * Don't use :-)) (I's up to you)
272 */
273static VALUE
274ossl_dh_get_params(VALUE self)
275{
276 EVP_PKEY *pkey;
277 VALUE hash;
278
279 GetPKeyDH(self, pkey);
280
281 hash = rb_hash_new();
282
283 rb_hash_aset(hash, rb_str_new2("p"), ossl_bn_new(pkey->pkey.dh->p));
284 rb_hash_aset(hash, rb_str_new2("g"), ossl_bn_new(pkey->pkey.dh->g));
285 rb_hash_aset(hash, rb_str_new2("pub_key"), ossl_bn_new(pkey->pkey.dh->pub_key));
286 rb_hash_aset(hash, rb_str_new2("priv_key"), ossl_bn_new(pkey->pkey.dh->priv_key));
287
288 return hash;
289}
290
291/*
292 * call-seq:
293 * dh.to_text -> aString
294 *
295 * Prints all parameters of key to buffer
296 * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
297 * Don't use :-)) (I's up to you)
298 */
299static VALUE
300ossl_dh_to_text(VALUE self)
301{
302 EVP_PKEY *pkey;
303 BIO *out;
304 VALUE str;
305
306 GetPKeyDH(self, pkey);
307 if (!(out = BIO_new(BIO_s_mem()))) {
308 ossl_raise(eDHError, NULL);
309 }
310 if (!DHparams_print(out, pkey->pkey.dh)) {
311 BIO_free(out);
312 ossl_raise(eDHError, NULL);
313 }
314 str = ossl_membio2str(out);
315
316 return str;
317}
318
319/*
320 * call-seq:
321 * dh.public_key -> aDH
322 *
323 * Makes new instance DH PUBLIC_KEY from PRIVATE_KEY
324 */
325static VALUE
326ossl_dh_to_public_key(VALUE self)
327{
328 EVP_PKEY *pkey;
329 DH *dh;
330 VALUE obj;
331
332 GetPKeyDH(self, pkey);
333 dh = DHparams_dup(pkey->pkey.dh); /* err check perfomed by dh_instance */
334 obj = dh_instance(CLASS_OF(self), dh);
335 if (obj == Qfalse) {
336 DH_free(dh);
337 ossl_raise(eDHError, NULL);
338 }
339
340 return obj;
341}
342
343/*
344 * call-seq:
345 * dh.check_params -> true | false
346 *
347 */
348static VALUE
349ossl_dh_check_params(VALUE self)
350{
351 DH *dh;
352 EVP_PKEY *pkey;
353 int codes;
354
355 GetPKeyDH(self, pkey);
356 dh = pkey->pkey.dh;
357
358 if (!DH_check(dh, &codes)) {
359 return Qfalse;
360 }
361
362 return codes == 0 ? Qtrue : Qfalse;
363}
364
365/*
366 * call-seq:
367 * dh.generate_key -> self
368 *
369 */
370static VALUE
371ossl_dh_generate_key(VALUE self)
372{
373 DH *dh;
374 EVP_PKEY *pkey;
375
376 GetPKeyDH(self, pkey);
377 dh = pkey->pkey.dh;
378
379 if (!DH_generate_key(dh))
380 ossl_raise(eDHError, "Failed to generate key");
381 return self;
382}
383
384/*
385 * call-seq:
386 * dh.compute_key(pub_bn) -> aString
387 *
388 * === Parameters
389 * * +pub_bn+ is a OpenSSL::BN.
390 *
391 * Returns aString containing a shared secret computed from the other parties public value.
392 *
393 * See DH_compute_key() for further information.
394 *
395 */
396static VALUE
397ossl_dh_compute_key(VALUE self, VALUE pub)
398{
399 DH *dh;
400 EVP_PKEY *pkey;
401 BIGNUM *pub_key;
402 VALUE str;
403 int len;
404
405 GetPKeyDH(self, pkey);
406 dh = pkey->pkey.dh;
407 pub_key = GetBNPtr(pub);
408 len = DH_size(dh);
409 str = rb_str_new(0, len);
410 if ((len = DH_compute_key((unsigned char *)RSTRING_PTR(str), pub_key, dh)) < 0) {
411 ossl_raise(eDHError, NULL);
412 }
413 rb_str_set_len(str, len);
414
415 return str;
416}
417
418OSSL_PKEY_BN(dh, p)
419OSSL_PKEY_BN(dh, g)
420OSSL_PKEY_BN(dh, pub_key)
421OSSL_PKEY_BN(dh, priv_key)
422
423/*
424 * -----BEGIN DH PARAMETERS-----
425 * MEYCQQD0zXHljRg/mJ9PYLACLv58Cd8VxBxxY7oEuCeURMiTqEhMym16rhhKgZG2
426 * zk2O9uUIBIxSj+NKMURHGaFKyIvLAgEC
427 * -----END DH PARAMETERS-----
428 */
429static unsigned char DEFAULT_DH_512_PRIM[] = {
430 0xf4, 0xcd, 0x71, 0xe5, 0x8d, 0x18, 0x3f, 0x98,
431 0x9f, 0x4f, 0x60, 0xb0, 0x02, 0x2e, 0xfe, 0x7c,
432 0x09, 0xdf, 0x15, 0xc4, 0x1c, 0x71, 0x63, 0xba,
433 0x04, 0xb8, 0x27, 0x94, 0x44, 0xc8, 0x93, 0xa8,
434 0x48, 0x4c, 0xca, 0x6d, 0x7a, 0xae, 0x18, 0x4a,
435 0x81, 0x91, 0xb6, 0xce, 0x4d, 0x8e, 0xf6, 0xe5,
436 0x08, 0x04, 0x8c, 0x52, 0x8f, 0xe3, 0x4a, 0x31,
437 0x44, 0x47, 0x19, 0xa1, 0x4a, 0xc8, 0x8b, 0xcb,
438};
439static unsigned char DEFAULT_DH_512_GEN[] = { 0x02 };
440DH *OSSL_DEFAULT_DH_512 = NULL;
441
442/*
443 * -----BEGIN DH PARAMETERS-----
444 * MIGHAoGBAJ0lOVy0VIr/JebWn0zDwY2h+rqITFOpdNr6ugsgvkDXuucdcChhYExJ
445 * AV/ZD2AWPbrTqV76mGRgJg4EddgT1zG0jq3rnFdMj2XzkBYx3BVvfR0Arnby0RHR
446 * T4h7KZ/2zmjvV+eF8kBUHBJAojUlzxKj4QeO2x20FP9X5xmNUXeDAgEC
447 * -----END DH PARAMETERS-----
448 */
449static unsigned char DEFAULT_DH_1024_PRIM[] = {
450 0x9d, 0x25, 0x39, 0x5c, 0xb4, 0x54, 0x8a, 0xff,
451 0x25, 0xe6, 0xd6, 0x9f, 0x4c, 0xc3, 0xc1, 0x8d,
452 0xa1, 0xfa, 0xba, 0x88, 0x4c, 0x53, 0xa9, 0x74,
453 0xda, 0xfa, 0xba, 0x0b, 0x20, 0xbe, 0x40, 0xd7,
454 0xba, 0xe7, 0x1d, 0x70, 0x28, 0x61, 0x60, 0x4c,
455 0x49, 0x01, 0x5f, 0xd9, 0x0f, 0x60, 0x16, 0x3d,
456 0xba, 0xd3, 0xa9, 0x5e, 0xfa, 0x98, 0x64, 0x60,
457 0x26, 0x0e, 0x04, 0x75, 0xd8, 0x13, 0xd7, 0x31,
458 0xb4, 0x8e, 0xad, 0xeb, 0x9c, 0x57, 0x4c, 0x8f,
459 0x65, 0xf3, 0x90, 0x16, 0x31, 0xdc, 0x15, 0x6f,
460 0x7d, 0x1d, 0x00, 0xae, 0x76, 0xf2, 0xd1, 0x11,
461 0xd1, 0x4f, 0x88, 0x7b, 0x29, 0x9f, 0xf6, 0xce,
462 0x68, 0xef, 0x57, 0xe7, 0x85, 0xf2, 0x40, 0x54,
463 0x1c, 0x12, 0x40, 0xa2, 0x35, 0x25, 0xcf, 0x12,
464 0xa3, 0xe1, 0x07, 0x8e, 0xdb, 0x1d, 0xb4, 0x14,
465 0xff, 0x57, 0xe7, 0x19, 0x8d, 0x51, 0x77, 0x83
466};
467static unsigned char DEFAULT_DH_1024_GEN[] = { 0x02 };
468DH *OSSL_DEFAULT_DH_1024 = NULL;
469
470static DH*
471ossl_create_dh(unsigned char *p, size_t plen, unsigned char *g, size_t glen)
472{
473 DH *dh;
474
475 if ((dh = DH_new()) == NULL) ossl_raise(eDHError, NULL);
476 dh->p = BN_bin2bn(p, plen, NULL);
477 dh->g = BN_bin2bn(g, glen, NULL);
478 if (dh->p == NULL || dh->g == NULL){
479 DH_free(dh);
480 ossl_raise(eDHError, NULL);
481 }
482
483 return dh;
484}
485
486/*
487 * INIT
488 */
489void
490Init_ossl_dh()
491{
492#if 0 /* let rdoc know about mOSSL and mPKey */
493 mOSSL = rb_define_module("OpenSSL");
494 mPKey = rb_define_module_under(mOSSL, "PKey");
495#endif
496
497 eDHError = rb_define_class_under(mPKey, "DHError", ePKeyError);
498 cDH = rb_define_class_under(mPKey, "DH", cPKey);
499 rb_define_singleton_method(cDH, "generate", ossl_dh_s_generate, -1);
500 rb_define_method(cDH, "initialize", ossl_dh_initialize, -1);
501 rb_define_method(cDH, "public?", ossl_dh_is_public, 0);
502 rb_define_method(cDH, "private?", ossl_dh_is_private, 0);
503 rb_define_method(cDH, "to_text", ossl_dh_to_text, 0);
504 rb_define_method(cDH, "export", ossl_dh_export, 0);
505 rb_define_alias(cDH, "to_pem", "export");
506 rb_define_alias(cDH, "to_s", "export");
507 rb_define_method(cDH, "to_der", ossl_dh_to_der, 0);
508 rb_define_method(cDH, "public_key", ossl_dh_to_public_key, 0);
509 rb_define_method(cDH, "params_ok?", ossl_dh_check_params, 0);
510 rb_define_method(cDH, "generate_key!", ossl_dh_generate_key, 0);
511 rb_define_method(cDH, "compute_key", ossl_dh_compute_key, 1);
512 DEF_OSSL_PKEY_BN(cDH, dh, p);
513 DEF_OSSL_PKEY_BN(cDH, dh, g);
514 DEF_OSSL_PKEY_BN(cDH, dh, pub_key);
515 DEF_OSSL_PKEY_BN(cDH, dh, priv_key);
516 rb_define_method(cDH, "params", ossl_dh_get_params, 0);
517
518 OSSL_DEFAULT_DH_512 = ossl_create_dh(
519 DEFAULT_DH_512_PRIM, sizeof(DEFAULT_DH_512_PRIM),
520 DEFAULT_DH_512_GEN, sizeof(DEFAULT_DH_512_GEN));
521 OSSL_DEFAULT_DH_1024 = ossl_create_dh(
522 DEFAULT_DH_1024_PRIM, sizeof(DEFAULT_DH_1024_PRIM),
523 DEFAULT_DH_1024_GEN, sizeof(DEFAULT_DH_1024_GEN));
524}
525
526#else /* defined NO_DH */
527void
528Init_ossl_dh()
529{
530}
531#endif /* NO_DH */
532