/* * $Id$ * 'OpenSSL for Ruby' project * Copyright (C) 2001-2002 Michal Rokos * All rights reserved. */ /* * This program is licenced under the same licence as Ruby. * (See the file 'LICENCE'.) */ #if !defined(NO_DH) && !defined(OPENSSL_NO_DH) #include "ossl.h" #include "ossl_pkey.h" #define MakeDH(obj, dhp) do {\ obj = Data_Make_Struct(cDH, ossl_dh, 0, ossl_dh_free, dhp);\ dhp->pkey.get_EVP_PKEY = ossl_dh_get_EVP_PKEY;\ } while (0) #define GetDH(obj, dhp) do {\ Data_Get_Struct(obj, ossl_dh, dhp);\ if (!dhp->dh) rb_raise(eDHError, "not initialized!");\ } while (0) #define DH_PRIVATE(dh) ((dh)->priv_key) /* * Classes */ VALUE cDH; VALUE eDHError; /* * Struct */ typedef struct ossl_dh_st { ossl_pkey pkey; DH *dh; } ossl_dh; static void ossl_dh_free(ossl_dh *dhp) { if (dhp) { if (dhp->dh) DH_free(dhp->dh); dhp->dh = NULL; free(dhp); } } /* * Public */ VALUE ossl_dh_new(DH *dh) { ossl_dh *dhp = NULL; DH *new = NULL; VALUE obj; if (!dh) new = DH_new(); else new = DHparams_dup(dh); if (!new) OSSL_Raise(eDHError, ""); MakeDH(obj, dhp); dhp->dh = new; return obj; } DH * ossl_dh_get_DH(VALUE obj) { ossl_dh *dhp = NULL; DH *dh = NULL; OSSL_Check_Type(obj, cDH); GetDH(obj, dhp); dh = DHparams_dup(dhp->dh); if (!dh) OSSL_Raise(eDHError, ""); return dh; } EVP_PKEY * ossl_dh_get_EVP_PKEY(VALUE obj) { DH *dh = NULL; EVP_PKEY *pkey = NULL; dh = ossl_dh_get_DH(obj); if (!(pkey = EVP_PKEY_new())) { DH_free(dh); OSSL_Raise(eDHError, ""); } if (!EVP_PKEY_assign_DH(pkey, dh)) { /* NO DUP - don't free! */ DH_free(dh); EVP_PKEY_free(pkey); OSSL_Raise(eDHError, ""); } return pkey; } /* * Private */ static VALUE ossl_dh_s_new_from_pem(VALUE klass, VALUE buffer) { ossl_dh *dhp = NULL; DH *dh = NULL; BIO *in = NULL; VALUE obj; buffer = rb_String(buffer); if (!(in = BIO_new_mem_buf(RSTRING(buffer)->ptr, RSTRING(buffer)->len))) OSSL_Raise(eDHError, ""); if (!(dh = PEM_read_bio_DHparams(in, NULL, NULL, NULL))) { BIO_free(in); OSSL_Raise(eDHError, ""); } BIO_free(in); MakeDH(obj, dhp); dhp->dh = dh; return obj; } /* * CB for yielding when generating DH params */ static void MS_CALLBACK ossl_dh_generate_cb(int p, int n, void *arg) { VALUE ary; ary = rb_ary_new2(2); rb_ary_store(ary, 0, INT2NUM(p)); rb_ary_store(ary, 1, INT2NUM(n)); rb_yield(ary); } static VALUE ossl_dh_s_generate(VALUE klass, VALUE size, VALUE gen) { ossl_dh *dhp = NULL; DH *dh = NULL; void (*cb)(int, int, void *) = NULL; VALUE obj; Check_Type(size, T_FIXNUM); if (rb_block_given_p()) cb = ossl_dh_generate_cb; if (!(dh = DH_generate_parameters(FIX2INT(size), FIX2INT(gen), cb, NULL))) { /* arg to cb = NULL */ OSSL_Raise(eDHError, ""); } if (!DH_generate_key(dh)) { DH_free(dh); OSSL_Raise(eDHError, ""); } MakeDH(obj, dhp); dhp->dh = dh; return obj; } static VALUE ossl_dh_is_public(VALUE self) { ossl_dh *dhp = NULL; GetDH(self, dhp); /* * Do we need to check dhp->dh->public_pkey? * return Qtrue; */ return (dhp->dh->pub_key) ? Qtrue : Qfalse; } static VALUE ossl_dh_is_private(VALUE self) { ossl_dh *dhp = NULL; GetDH(self, dhp); return (DH_PRIVATE(dhp->dh)) ? Qtrue : Qfalse; } static VALUE ossl_dh_export(VALUE self) { ossl_dh *dhp = NULL; BIO *out = NULL; BUF_MEM *buf = NULL; VALUE str; GetDH(self, dhp); if (!(out = BIO_new(BIO_s_mem()))) { OSSL_Raise(eDHError, ""); } if (!PEM_write_bio_DHparams(out, dhp->dh)) { BIO_free(out); OSSL_Raise(eDHError, ""); } BIO_get_mem_ptr(out, &buf); str = rb_str_new(buf->data, buf->length); BIO_free(out); return str; } /* * Prints all parameters of key to buffer * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!! * Don't use :-)) (I's up to you) */ static VALUE ossl_dh_to_text(VALUE self) { ossl_dh *dhp = NULL; BIO *out = NULL; BUF_MEM *buf = NULL; VALUE str; GetDH(self, dhp); if (!(out = BIO_new(BIO_s_mem()))) { OSSL_Raise(eDHError, ""); } if (!DHparams_print(out, dhp->dh)) { BIO_free(out); OSSL_Raise(eDHError, ""); } BIO_get_mem_ptr(out, &buf); str = rb_str_new(buf->data, buf->length); BIO_free(out); return str; } /* * Makes new instance DH PUBLIC_KEY from PRIVATE_KEY */ static VALUE ossl_dh_to_public_key(VALUE self) { ossl_dh *dhp1 = NULL, *dhp2 = NULL; VALUE obj; GetDH(self, dhp1); MakeDH(obj, dhp2); if (!(dhp2->dh = DHparams_dup(dhp1->dh))) { OSSL_Raise(eDHError, ""); } return obj; } /* * INIT */ void Init_ossl_dh(VALUE mPKey, VALUE cPKey, VALUE ePKeyError) { eDHError = rb_define_class_under(mPKey, "DHError", ePKeyError); cDH = rb_define_class_under(mPKey, "DH", cPKey); rb_define_singleton_method(cDH, "new_from_pem", ossl_dh_s_new_from_pem, 1); rb_define_singleton_method(cDH, "generate", ossl_dh_s_generate, 2); rb_define_alias(CLASS_OF(cDH), "new_from_fixnum", "generate"); rb_define_method(cDH, "public?", ossl_dh_is_public, 0); rb_define_method(cDH, "private?", ossl_dh_is_private, 0); rb_define_method(cDH, "to_text", ossl_dh_to_text, 0); rb_define_method(cDH, "export", ossl_dh_export, 0); rb_define_alias(cDH, "to_pem", "export"); rb_define_method(cDH, "public_key", ossl_dh_to_public_key, 0); } #else /* defined NO_DH */ # warning >>> OpenSSL is compiled without DH support <<< void Init_ossl_dh(VALUE mPKey, VALUE cPKey, VALUE ePKeyError) { rb_warning("OpenSSL is compiled without DH support"); } #endif /* NO_DH */