2 * $Id: ossl_pkey_dsa.c 12043 2007-03-12 04:12:32Z knu $
3 * 'OpenSSL for Ruby' project
4 * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
8 * This program is licenced under the same licence as Ruby.
9 * (See the file 'LICENCE'.)
11 #if !defined(OPENSSL_NO_DSA)
15 #define GetPKeyDSA(obj, pkey) do { \
17 if (EVP_PKEY_type(pkey->type) != EVP_PKEY_DSA) { /* PARANOIA? */ \
18 ossl_raise(rb_eRuntimeError, "THIS IS NOT A DSA!"); \
22 #define DSA_HAS_PRIVATE(dsa) ((dsa)->priv_key)
23 #define DSA_PRIVATE(obj,dsa) (DSA_HAS_PRIVATE(dsa)||OSSL_PKEY_IS_PRIVATE(obj))
35 dsa_instance(VALUE klass
, DSA
*dsa
)
43 if (!(pkey
= EVP_PKEY_new())) {
46 if (!EVP_PKEY_assign_DSA(pkey
, dsa
)) {
50 WrapPKey(klass
, obj
, pkey
);
56 ossl_dsa_new(EVP_PKEY
*pkey
)
61 obj
= dsa_instance(cDSA
, DSA_new());
63 if (EVP_PKEY_type(pkey
->type
) != EVP_PKEY_DSA
) {
64 ossl_raise(rb_eTypeError
, "Not a DSA key!");
66 WrapPKey(cDSA
, obj
, pkey
);
69 ossl_raise(eDSAError
, NULL
);
79 dsa_generate(int size
)
82 unsigned char seed
[20];
83 int seed_len
= 20, counter
;
86 if (!RAND_bytes(seed
, seed_len
)) {
89 dsa
= DSA_generate_parameters(size
, seed
, seed_len
, &counter
, &h
,
90 rb_block_given_p() ? ossl_generate_cb
: NULL
,
94 if (!DSA_generate_key(dsa
)) {
103 ossl_dsa_s_generate(VALUE klass
, VALUE size
)
105 DSA
*dsa
= dsa_generate(FIX2INT(size
)); /* err handled by dsa_instance */
106 VALUE obj
= dsa_instance(klass
, dsa
);
110 ossl_raise(eDSAError
, NULL
);
117 ossl_dsa_initialize(int argc
, VALUE
*argv
, VALUE self
)
126 if(rb_scan_args(argc
, argv
, "02", &arg
, &pass
) == 0) {
129 else if (FIXNUM_P(arg
)) {
130 if (!(dsa
= dsa_generate(FIX2INT(arg
)))) {
131 ossl_raise(eDSAError
, NULL
);
135 if (!NIL_P(pass
)) passwd
= StringValuePtr(pass
);
136 arg
= ossl_to_der_if_possible(arg
);
137 in
= ossl_obj2bio(arg
);
138 dsa
= PEM_read_bio_DSAPrivateKey(in
, NULL
, ossl_pem_passwd_cb
, passwd
);
141 dsa
= PEM_read_bio_DSAPublicKey(in
, NULL
, NULL
, NULL
);
145 dsa
= PEM_read_bio_DSA_PUBKEY(in
, NULL
, NULL
, NULL
);
149 dsa
= d2i_DSAPrivateKey_bio(in
, NULL
);
153 dsa
= d2i_DSA_PUBKEY_bio(in
, NULL
);
156 if (!dsa
) ossl_raise(eDSAError
, "Neither PUB key nor PRIV key:");
158 if (!EVP_PKEY_assign_DSA(pkey
, dsa
)) {
160 ossl_raise(eDSAError
, NULL
);
167 ossl_dsa_is_public(VALUE self
)
171 GetPKeyDSA(self
, pkey
);
174 * Do we need to check dsap->dsa->public_pkey?
177 return (pkey
->pkey
.dsa
->pub_key
) ? Qtrue
: Qfalse
;
181 ossl_dsa_is_private(VALUE self
)
185 GetPKeyDSA(self
, pkey
);
187 return (DSA_PRIVATE(self
, pkey
->pkey
.dsa
)) ? Qtrue
: Qfalse
;
191 ossl_dsa_export(int argc
, VALUE
*argv
, VALUE self
)
195 const EVP_CIPHER
*ciph
= NULL
;
197 VALUE cipher
, pass
, str
;
199 GetPKeyDSA(self
, pkey
);
200 rb_scan_args(argc
, argv
, "02", &cipher
, &pass
);
201 if (!NIL_P(cipher
)) {
202 ciph
= GetCipherPtr(cipher
);
204 passwd
= StringValuePtr(pass
);
207 if (!(out
= BIO_new(BIO_s_mem()))) {
208 ossl_raise(eDSAError
, NULL
);
210 if (DSA_HAS_PRIVATE(pkey
->pkey
.dsa
)) {
211 if (!PEM_write_bio_DSAPrivateKey(out
, pkey
->pkey
.dsa
, ciph
,
212 NULL
, 0, ossl_pem_passwd_cb
, passwd
)){
214 ossl_raise(eDSAError
, NULL
);
217 if (!PEM_write_bio_DSAPublicKey(out
, pkey
->pkey
.dsa
)) {
219 ossl_raise(eDSAError
, NULL
);
222 str
= ossl_membio2str(out
);
228 ossl_dsa_to_der(VALUE self
)
231 int (*i2d_func
)_((DSA
*, unsigned char**));
236 GetPKeyDSA(self
, pkey
);
237 if(DSA_HAS_PRIVATE(pkey
->pkey
.dsa
))
238 i2d_func
= (int(*)_((DSA
*,unsigned char**)))i2d_DSAPrivateKey
;
240 i2d_func
= i2d_DSA_PUBKEY
;
241 if((len
= i2d_func(pkey
->pkey
.dsa
, NULL
)) <= 0)
242 ossl_raise(eDSAError
, NULL
);
243 str
= rb_str_new(0, len
);
244 p
= RSTRING(str
)->ptr
;
245 if(i2d_func(pkey
->pkey
.dsa
, &p
) < 0)
246 ossl_raise(eDSAError
, NULL
);
247 ossl_str_adjust(str
, p
);
253 * Stores all parameters of key to the hash
254 * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
255 * Don't use :-)) (I's up to you)
258 ossl_dsa_get_params(VALUE self
)
263 GetPKeyDSA(self
, pkey
);
265 hash
= rb_hash_new();
267 rb_hash_aset(hash
, rb_str_new2("p"), ossl_bn_new(pkey
->pkey
.dsa
->p
));
268 rb_hash_aset(hash
, rb_str_new2("q"), ossl_bn_new(pkey
->pkey
.dsa
->q
));
269 rb_hash_aset(hash
, rb_str_new2("g"), ossl_bn_new(pkey
->pkey
.dsa
->g
));
270 rb_hash_aset(hash
, rb_str_new2("pub_key"), ossl_bn_new(pkey
->pkey
.dsa
->pub_key
));
271 rb_hash_aset(hash
, rb_str_new2("priv_key"), ossl_bn_new(pkey
->pkey
.dsa
->priv_key
));
277 * Prints all parameters of key to buffer
278 * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
279 * Don't use :-)) (I's up to you)
282 ossl_dsa_to_text(VALUE self
)
288 GetPKeyDSA(self
, pkey
);
289 if (!(out
= BIO_new(BIO_s_mem()))) {
290 ossl_raise(eDSAError
, NULL
);
292 if (!DSA_print(out
, pkey
->pkey
.dsa
, 0)) { /* offset = 0 */
294 ossl_raise(eDSAError
, NULL
);
296 str
= ossl_membio2str(out
);
302 * Makes new instance DSA PUBLIC_KEY from PRIVATE_KEY
305 ossl_dsa_to_public_key(VALUE self
)
311 GetPKeyDSA(self
, pkey
);
312 /* err check performed by dsa_instance */
313 dsa
= DSAPublicKey_dup(pkey
->pkey
.dsa
);
314 obj
= dsa_instance(CLASS_OF(self
), dsa
);
317 ossl_raise(eDSAError
, NULL
);
322 #define ossl_dsa_buf_size(pkey) (DSA_size((pkey)->pkey.dsa)+16)
325 ossl_dsa_sign(VALUE self
, VALUE data
)
331 GetPKeyDSA(self
, pkey
);
333 if (!DSA_PRIVATE(self
, pkey
->pkey
.dsa
)) {
334 ossl_raise(eDSAError
, "Private DSA key needed!");
336 str
= rb_str_new(0, ossl_dsa_buf_size(pkey
));
337 if (!DSA_sign(0, RSTRING(data
)->ptr
, RSTRING(data
)->len
, RSTRING(str
)->ptr
,
338 &buf_len
, pkey
->pkey
.dsa
)) { /* type is ignored (0) */
339 ossl_raise(eDSAError
, NULL
);
341 RSTRING(str
)->len
= buf_len
;
342 RSTRING(str
)->ptr
[buf_len
] = 0;
348 ossl_dsa_verify(VALUE self
, VALUE digest
, VALUE sig
)
353 GetPKeyDSA(self
, pkey
);
356 /* type is ignored (0) */
357 ret
= DSA_verify(0, RSTRING(digest
)->ptr
, RSTRING(digest
)->len
,
358 RSTRING(sig
)->ptr
, RSTRING(sig
)->len
, pkey
->pkey
.dsa
);
360 ossl_raise(eDSAError
, NULL
);
369 OSSL_PKEY_BN(dsa
, p
);
370 OSSL_PKEY_BN(dsa
, q
);
371 OSSL_PKEY_BN(dsa
, g
);
372 OSSL_PKEY_BN(dsa
, pub_key
);
373 OSSL_PKEY_BN(dsa
, priv_key
);
381 #if 0 /* let rdoc know about mOSSL and mPKey */
382 mOSSL
= rb_define_module("OpenSSL");
383 mPKey
= rb_define_module_under(mOSSL
, "PKey");
386 eDSAError
= rb_define_class_under(mPKey
, "DSAError", ePKeyError
);
388 cDSA
= rb_define_class_under(mPKey
, "DSA", cPKey
);
390 rb_define_singleton_method(cDSA
, "generate", ossl_dsa_s_generate
, 1);
391 rb_define_method(cDSA
, "initialize", ossl_dsa_initialize
, -1);
393 rb_define_method(cDSA
, "public?", ossl_dsa_is_public
, 0);
394 rb_define_method(cDSA
, "private?", ossl_dsa_is_private
, 0);
395 rb_define_method(cDSA
, "to_text", ossl_dsa_to_text
, 0);
396 rb_define_method(cDSA
, "export", ossl_dsa_export
, -1);
397 rb_define_alias(cDSA
, "to_pem", "export");
398 rb_define_alias(cDSA
, "to_s", "export");
399 rb_define_method(cDSA
, "to_der", ossl_dsa_to_der
, 0);
400 rb_define_method(cDSA
, "public_key", ossl_dsa_to_public_key
, 0);
401 rb_define_method(cDSA
, "syssign", ossl_dsa_sign
, 1);
402 rb_define_method(cDSA
, "sysverify", ossl_dsa_verify
, 2);
404 DEF_OSSL_PKEY_BN(cDSA
, dsa
, p
);
405 DEF_OSSL_PKEY_BN(cDSA
, dsa
, q
);
406 DEF_OSSL_PKEY_BN(cDSA
, dsa
, g
);
407 DEF_OSSL_PKEY_BN(cDSA
, dsa
, pub_key
);
408 DEF_OSSL_PKEY_BN(cDSA
, dsa
, priv_key
);
410 rb_define_method(cDSA
, "params", ossl_dsa_get_params
, 0);
413 #else /* defined NO_DSA */
414 # warning >>> OpenSSL is compiled without DSA support <<<
419 rb_warning("OpenSSL is compiled without DSA support");