Ruby  3.1.0dev(2021-09-10revisionb76ad15ed0da636161de0243c547ee1e6fc95681)
ossl_pkey_dsa.c
Go to the documentation of this file.
1 /*
2  * 'OpenSSL for Ruby' project
3  * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
4  * All rights reserved.
5  */
6 /*
7  * This program is licensed under the same licence as Ruby.
8  * (See the file 'LICENCE'.)
9  */
10 #include "ossl.h"
11 
12 #if !defined(OPENSSL_NO_DSA)
13 
14 #define GetPKeyDSA(obj, pkey) do { \
15  GetPKey((obj), (pkey)); \
16  if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DSA) { /* PARANOIA? */ \
17  ossl_raise(rb_eRuntimeError, "THIS IS NOT A DSA!"); \
18  } \
19 } while (0)
20 #define GetDSA(obj, dsa) do { \
21  EVP_PKEY *_pkey; \
22  GetPKeyDSA((obj), _pkey); \
23  (dsa) = EVP_PKEY_get0_DSA(_pkey); \
24 } while (0)
25 
26 static inline int
27 DSA_HAS_PRIVATE(DSA *dsa)
28 {
29  const BIGNUM *bn;
30  DSA_get0_key(dsa, NULL, &bn);
31  return !!bn;
32 }
33 
34 static inline int
35 DSA_PRIVATE(VALUE obj, DSA *dsa)
36 {
37  return DSA_HAS_PRIVATE(dsa) || OSSL_PKEY_IS_PRIVATE(obj);
38 }
39 
40 /*
41  * Classes
42  */
45 
46 /*
47  * Private
48  */
49 /*
50  * call-seq:
51  * DSA.new -> dsa
52  * DSA.new(string [, pass]) -> dsa
53  * DSA.new(size) -> dsa
54  *
55  * Creates a new DSA instance by reading an existing key from _string_.
56  *
57  * If called without arguments, creates a new instance with no key components
58  * set. They can be set individually by #set_pqg and #set_key.
59  *
60  * If called with a String, tries to parse as DER or PEM encoding of a \DSA key.
61  * See also OpenSSL::PKey.read which can parse keys of any kinds.
62  *
63  * If called with a number, generates random parameters and a key pair. This
64  * form works as an alias of DSA.generate.
65  *
66  * +string+::
67  * A String that contains a DER or PEM encoded key.
68  * +pass+::
69  * A String that contains an optional password.
70  * +size+::
71  * See DSA.generate.
72  *
73  * Examples:
74  * p OpenSSL::PKey::DSA.new(1024)
75  * #=> #<OpenSSL::PKey::DSA:0x000055a8d6025bf0 oid=DSA>
76  *
77  * p OpenSSL::PKey::DSA.new(File.read('dsa.pem'))
78  * #=> #<OpenSSL::PKey::DSA:0x000055555d6b8110 oid=DSA>
79  *
80  * p OpenSSL::PKey::DSA.new(File.read('dsa.pem'), 'mypassword')
81  * #=> #<OpenSSL::PKey::DSA:0x0000556f973c40b8 oid=DSA>
82  */
83 static VALUE
84 ossl_dsa_initialize(int argc, VALUE *argv, VALUE self)
85 {
86  EVP_PKEY *pkey, *tmp;
87  DSA *dsa = NULL;
88  BIO *in;
89  VALUE arg, pass;
90 
91  GetPKey(self, pkey);
92  /* The DSA.new(size, generator) form is handled by lib/openssl/pkey.rb */
93  rb_scan_args(argc, argv, "02", &arg, &pass);
94  if (argc == 0) {
95  dsa = DSA_new();
96  if (!dsa)
97  ossl_raise(eDSAError, "DSA_new");
98  }
99  else {
100  pass = ossl_pem_passwd_value(pass);
101  arg = ossl_to_der_if_possible(arg);
102  in = ossl_obj2bio(&arg);
103 
104  tmp = ossl_pkey_read_generic(in, pass);
105  if (tmp) {
106  if (EVP_PKEY_base_id(tmp) != EVP_PKEY_DSA)
107  rb_raise(eDSAError, "incorrect pkey type: %s",
108  OBJ_nid2sn(EVP_PKEY_base_id(tmp)));
109  dsa = EVP_PKEY_get1_DSA(tmp);
110  EVP_PKEY_free(tmp);
111  }
112  if (!dsa) {
113  OSSL_BIO_reset(in);
114 #define PEM_read_bio_DSAPublicKey(bp,x,cb,u) (DSA *)PEM_ASN1_read_bio( \
115  (d2i_of_void *)d2i_DSAPublicKey, PEM_STRING_DSA_PUBLIC, (bp), (void **)(x), (cb), (u))
117 #undef PEM_read_bio_DSAPublicKey
118  }
119  BIO_free(in);
120  if (!dsa) {
122  ossl_raise(eDSAError, "Neither PUB key nor PRIV key");
123  }
124  }
125  if (!EVP_PKEY_assign_DSA(pkey, dsa)) {
126  DSA_free(dsa);
128  }
129 
130  return self;
131 }
132 
133 static VALUE
134 ossl_dsa_initialize_copy(VALUE self, VALUE other)
135 {
136  EVP_PKEY *pkey;
137  DSA *dsa, *dsa_new;
138 
139  GetPKey(self, pkey);
140  if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE)
141  ossl_raise(eDSAError, "DSA already initialized");
142  GetDSA(other, dsa);
143 
144  dsa_new = ASN1_dup((i2d_of_void *)i2d_DSAPrivateKey, (d2i_of_void *)d2i_DSAPrivateKey, (char *)dsa);
145  if (!dsa_new)
146  ossl_raise(eDSAError, "ASN1_dup");
147 
148  EVP_PKEY_assign_DSA(pkey, dsa_new);
149 
150  return self;
151 }
152 
153 /*
154  * call-seq:
155  * dsa.public? -> true | false
156  *
157  * Indicates whether this DSA instance has a public key associated with it or
158  * not. The public key may be retrieved with DSA#public_key.
159  */
160 static VALUE
161 ossl_dsa_is_public(VALUE self)
162 {
163  DSA *dsa;
164  const BIGNUM *bn;
165 
166  GetDSA(self, dsa);
167  DSA_get0_key(dsa, &bn, NULL);
168 
169  return bn ? Qtrue : Qfalse;
170 }
171 
172 /*
173  * call-seq:
174  * dsa.private? -> true | false
175  *
176  * Indicates whether this DSA instance has a private key associated with it or
177  * not. The private key may be retrieved with DSA#private_key.
178  */
179 static VALUE
180 ossl_dsa_is_private(VALUE self)
181 {
182  DSA *dsa;
183 
184  GetDSA(self, dsa);
185 
186  return DSA_PRIVATE(self, dsa) ? Qtrue : Qfalse;
187 }
188 
189 /*
190  * call-seq:
191  * dsa.export([cipher, password]) -> aString
192  * dsa.to_pem([cipher, password]) -> aString
193  * dsa.to_s([cipher, password]) -> aString
194  *
195  * Encodes this DSA to its PEM encoding.
196  *
197  * === Parameters
198  * * _cipher_ is an OpenSSL::Cipher.
199  * * _password_ is a string containing your password.
200  *
201  * === Examples
202  * DSA.to_pem -> aString
203  * DSA.to_pem(cipher, 'mypassword') -> aString
204  *
205  */
206 static VALUE
207 ossl_dsa_export(int argc, VALUE *argv, VALUE self)
208 {
209  DSA *dsa;
210 
211  GetDSA(self, dsa);
212  if (DSA_HAS_PRIVATE(dsa))
213  return ossl_pkey_export_traditional(argc, argv, self, 0);
214  else
215  return ossl_pkey_export_spki(self, 0);
216 }
217 
218 /*
219  * call-seq:
220  * dsa.to_der -> aString
221  *
222  * Encodes this DSA to its DER encoding.
223  *
224  */
225 static VALUE
226 ossl_dsa_to_der(VALUE self)
227 {
228  DSA *dsa;
229 
230  GetDSA(self, dsa);
231  if (DSA_HAS_PRIVATE(dsa))
232  return ossl_pkey_export_traditional(0, NULL, self, 1);
233  else
234  return ossl_pkey_export_spki(self, 1);
235 }
236 
237 
238 /*
239  * call-seq:
240  * dsa.params -> hash
241  *
242  * Stores all parameters of key to the hash
243  * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
244  * Don't use :-)) (I's up to you)
245  */
246 static VALUE
247 ossl_dsa_get_params(VALUE self)
248 {
249  DSA *dsa;
250  VALUE hash;
251  const BIGNUM *p, *q, *g, *pub_key, *priv_key;
252 
253  GetDSA(self, dsa);
254  DSA_get0_pqg(dsa, &p, &q, &g);
255  DSA_get0_key(dsa, &pub_key, &priv_key);
256 
257  hash = rb_hash_new();
258  rb_hash_aset(hash, rb_str_new2("p"), ossl_bn_new(p));
259  rb_hash_aset(hash, rb_str_new2("q"), ossl_bn_new(q));
260  rb_hash_aset(hash, rb_str_new2("g"), ossl_bn_new(g));
261  rb_hash_aset(hash, rb_str_new2("pub_key"), ossl_bn_new(pub_key));
262  rb_hash_aset(hash, rb_str_new2("priv_key"), ossl_bn_new(priv_key));
263 
264  return hash;
265 }
266 
267 /*
268  * Document-method: OpenSSL::PKey::DSA#set_pqg
269  * call-seq:
270  * dsa.set_pqg(p, q, g) -> self
271  *
272  * Sets _p_, _q_, _g_ to the DSA instance.
273  */
274 OSSL_PKEY_BN_DEF3(dsa, DSA, pqg, p, q, g)
275 /*
276  * Document-method: OpenSSL::PKey::DSA#set_key
277  * call-seq:
278  * dsa.set_key(pub_key, priv_key) -> self
279  *
280  * Sets _pub_key_ and _priv_key_ for the DSA instance. _priv_key_ may be +nil+.
281  */
283 
284 /*
285  * INIT
286  */
287 void
289 {
290 #if 0
294 #endif
295 
296  /* Document-class: OpenSSL::PKey::DSAError
297  *
298  * Generic exception that is raised if an operation on a DSA PKey
299  * fails unexpectedly or in case an instantiation of an instance of DSA
300  * fails due to non-conformant input data.
301  */
303 
304  /* Document-class: OpenSSL::PKey::DSA
305  *
306  * DSA, the Digital Signature Algorithm, is specified in NIST's
307  * FIPS 186-3. It is an asymmetric public key algorithm that may be used
308  * similar to e.g. RSA.
309  */
311 
312  rb_define_method(cDSA, "initialize", ossl_dsa_initialize, -1);
313  rb_define_method(cDSA, "initialize_copy", ossl_dsa_initialize_copy, 1);
314 
315  rb_define_method(cDSA, "public?", ossl_dsa_is_public, 0);
316  rb_define_method(cDSA, "private?", ossl_dsa_is_private, 0);
317  rb_define_method(cDSA, "export", ossl_dsa_export, -1);
318  rb_define_alias(cDSA, "to_pem", "export");
319  rb_define_alias(cDSA, "to_s", "export");
320  rb_define_method(cDSA, "to_der", ossl_dsa_to_der, 0);
321 
322  DEF_OSSL_PKEY_BN(cDSA, dsa, p);
323  DEF_OSSL_PKEY_BN(cDSA, dsa, q);
324  DEF_OSSL_PKEY_BN(cDSA, dsa, g);
327  rb_define_method(cDSA, "set_pqg", ossl_dsa_set_pqg, 3);
328  rb_define_method(cDSA, "set_key", ossl_dsa_set_key, 2);
329 
330  rb_define_method(cDSA, "params", ossl_dsa_get_params, 0);
331 }
332 
333 #else /* defined NO_DSA */
334 void
335 Init_ossl_dsa(void)
336 {
337 }
338 #endif /* NO_DSA */
ossl_pkey_export_traditional
VALUE ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self, int to_der)
Definition: ossl_pkey.c:580
OSSL_PKEY_BN_DEF3
#define OSSL_PKEY_BN_DEF3(_keytype, _type, _group, a1, a2, a3)
Definition: ossl_pkey.h:176
priv_key
priv_key
Definition: openssl_missing.h:145
Init_ossl_dsa
void Init_ossl_dsa(void)
Definition: ossl_pkey_dsa.c:288
rb_hash_new
VALUE rb_hash_new(void)
Definition: hash.c:1526
rb_define_module_under
VALUE rb_define_module_under(VALUE outer, const char *name)
Definition: class.c:914
ossl_to_der_if_possible
VALUE ossl_to_der_if_possible(VALUE obj)
Definition: ossl.c:261
ossl_pkey_export_spki
VALUE ossl_pkey_export_spki(VALUE self, int to_der)
Definition: ossl_pkey.c:695
ePKeyError
VALUE ePKeyError
Definition: ossl_pkey.c:17
pub_key
pub_key
Definition: openssl_missing.h:145
ossl_obj2bio
BIO * ossl_obj2bio(volatile VALUE *pobj)
Definition: ossl_bio.c:13
OSSL_BIO_reset
#define OSSL_BIO_reset(bio)
Definition: ossl.h:115
eDSAError
VALUE eDSAError
Definition: ossl_pkey_dsa.c:44
ossl.h
argv
char ** argv
Definition: ruby.c:243
ossl_clear_error
void ossl_clear_error(void)
Definition: ossl.c:310
cPKey
VALUE cPKey
Definition: ossl_pkey.c:16
pkey_blocking_generate_arg::pkey
EVP_PKEY * pkey
Definition: ossl_pkey.c:180
OSSL_PKEY_BN_DEF2
#define OSSL_PKEY_BN_DEF2(_keytype, _type, _group, a1, a2)
Definition: ossl_pkey.h:180
rb_define_alias
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition: class.c:2050
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:3022
DEF_OSSL_PKEY_BN
#define DEF_OSSL_PKEY_BN(class, keytype, name)
Definition: ossl_pkey.h:184
mOSSL
VALUE mOSSL
Definition: ossl.c:237
rb_cObject
VALUE rb_cObject
Object class.
Definition: object.c:50
Qfalse
#define Qfalse
Definition: special_consts.h:50
ossl_pem_passwd_value
VALUE ossl_pem_passwd_value(VALUE pass)
Definition: ossl.c:157
GetPKey
#define GetPKey(obj, pkey)
Definition: ossl_pkey.h:31
ossl_bn_new
VALUE ossl_bn_new(const BIGNUM *bn)
Definition: ossl_bn.c:62
ossl_raise
void ossl_raise(VALUE exc, const char *fmt,...)
Definition: ossl.c:299
NULL
#define NULL
Definition: regenc.h:69
GetDSA
#define GetDSA(obj, dsa)
Definition: ossl_pkey_dsa.c:20
rb_scan_args
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:2347
key
key
Definition: openssl_missing.h:145
Qtrue
#define Qtrue
Definition: special_consts.h:52
OSSL_PKEY_IS_PRIVATE
#define OSSL_PKEY_IS_PRIVATE(obj)
Definition: ossl_pkey.h:20
VALUE
unsigned long VALUE
Definition: value.h:38
mPKey
VALUE mPKey
Definition: ossl_pkey.c:15
rb_hash_aset
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
Definition: hash.c:2892
argc
int argc
Definition: ruby.c:242
PEM_read_bio_DSAPublicKey
#define PEM_read_bio_DSAPublicKey(bp, x, cb, u)
cDSA
VALUE cDSA
Definition: ossl_pkey_dsa.c:43
rb_str_new2
#define rb_str_new2
Definition: string.h:276
eOSSLError
VALUE eOSSLError
Definition: ossl.c:242
rb_define_class_under
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:809
rb_define_method
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
Definition: cxxanyargs.hpp:655
ossl_pkey_read_generic
EVP_PKEY * ossl_pkey_read_generic(BIO *bio, VALUE pass)
Definition: ossl_pkey.c:82