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 /*
13  * Classes
14  */
15 VALUE mPKey;
16 VALUE cPKey;
17 VALUE ePKeyError;
18 static ID id_private_q;
19 
20 /*
21  * callback for generating keys
22  */
23 static VALUE
call_check_ints0(VALUE arg)24 call_check_ints0(VALUE arg)
25 {
26     rb_thread_check_ints();
27     return Qnil;
28 }
29 
30 static void *
call_check_ints(void * arg)31 call_check_ints(void *arg)
32 {
33     int state;
34     rb_protect(call_check_ints0, Qnil, &state);
35     return (void *)(VALUE)state;
36 }
37 
38 int
ossl_generate_cb_2(int p,int n,BN_GENCB * cb)39 ossl_generate_cb_2(int p, int n, BN_GENCB *cb)
40 {
41     VALUE ary;
42     struct ossl_generate_cb_arg *arg;
43     int state;
44 
45     arg = (struct ossl_generate_cb_arg *)BN_GENCB_get_arg(cb);
46     if (arg->yield) {
47 	ary = rb_ary_new2(2);
48 	rb_ary_store(ary, 0, INT2NUM(p));
49 	rb_ary_store(ary, 1, INT2NUM(n));
50 
51 	/*
52 	* can be break by raising exception or 'break'
53 	*/
54 	rb_protect(rb_yield, ary, &state);
55 	if (state) {
56 	    arg->state = state;
57 	    return 0;
58 	}
59     }
60     if (arg->interrupted) {
61 	arg->interrupted = 0;
62 	state = (int)(VALUE)rb_thread_call_with_gvl(call_check_ints, NULL);
63 	if (state) {
64 	    arg->state = state;
65 	    return 0;
66 	}
67     }
68     return 1;
69 }
70 
71 void
ossl_generate_cb_stop(void * ptr)72 ossl_generate_cb_stop(void *ptr)
73 {
74     struct ossl_generate_cb_arg *arg = (struct ossl_generate_cb_arg *)ptr;
75     arg->interrupted = 1;
76 }
77 
78 static void
ossl_evp_pkey_free(void * ptr)79 ossl_evp_pkey_free(void *ptr)
80 {
81     EVP_PKEY_free(ptr);
82 }
83 
84 /*
85  * Public
86  */
87 const rb_data_type_t ossl_evp_pkey_type = {
88     "OpenSSL/EVP_PKEY",
89     {
90 	0, ossl_evp_pkey_free,
91     },
92     0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
93 };
94 
95 static VALUE
pkey_new0(EVP_PKEY * pkey)96 pkey_new0(EVP_PKEY *pkey)
97 {
98     VALUE obj;
99     int type;
100 
101     if (!pkey || (type = EVP_PKEY_base_id(pkey)) == EVP_PKEY_NONE)
102 	ossl_raise(rb_eRuntimeError, "pkey is empty");
103 
104     switch (type) {
105 #if !defined(OPENSSL_NO_RSA)
106     case EVP_PKEY_RSA:
107 	return ossl_rsa_new(pkey);
108 #endif
109 #if !defined(OPENSSL_NO_DSA)
110     case EVP_PKEY_DSA:
111 	return ossl_dsa_new(pkey);
112 #endif
113 #if !defined(OPENSSL_NO_DH)
114     case EVP_PKEY_DH:
115 	return ossl_dh_new(pkey);
116 #endif
117 #if !defined(OPENSSL_NO_EC)
118     case EVP_PKEY_EC:
119 	return ossl_ec_new(pkey);
120 #endif
121     default:
122 	obj = NewPKey(cPKey);
123 	SetPKey(obj, pkey);
124 	return obj;
125     }
126 }
127 
128 VALUE
ossl_pkey_new(EVP_PKEY * pkey)129 ossl_pkey_new(EVP_PKEY *pkey)
130 {
131     VALUE obj;
132     int status;
133 
134     obj = rb_protect((VALUE (*)(VALUE))pkey_new0, (VALUE)pkey, &status);
135     if (status) {
136 	EVP_PKEY_free(pkey);
137 	rb_jump_tag(status);
138     }
139 
140     return obj;
141 }
142 
143 /*
144  *  call-seq:
145  *     OpenSSL::PKey.read(string [, pwd ]) -> PKey
146  *     OpenSSL::PKey.read(io [, pwd ]) -> PKey
147  *
148  * Reads a DER or PEM encoded string from _string_ or _io_ and returns an
149  * instance of the appropriate PKey class.
150  *
151  * === Parameters
152  * * _string+ is a DER- or PEM-encoded string containing an arbitrary private
153  *   or public key.
154  * * _io_ is an instance of IO containing a DER- or PEM-encoded
155  *   arbitrary private or public key.
156  * * _pwd_ is an optional password in case _string_ or _io_ is an encrypted
157  *   PEM resource.
158  */
159 static VALUE
ossl_pkey_new_from_data(int argc,VALUE * argv,VALUE self)160 ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self)
161 {
162     EVP_PKEY *pkey;
163     BIO *bio;
164     VALUE data, pass;
165 
166     rb_scan_args(argc, argv, "11", &data, &pass);
167     pass = ossl_pem_passwd_value(pass);
168 
169     bio = ossl_obj2bio(&data);
170     if (!(pkey = d2i_PrivateKey_bio(bio, NULL))) {
171 	OSSL_BIO_reset(bio);
172 	if (!(pkey = PEM_read_bio_PrivateKey(bio, NULL, ossl_pem_passwd_cb, (void *)pass))) {
173 	    OSSL_BIO_reset(bio);
174 	    if (!(pkey = d2i_PUBKEY_bio(bio, NULL))) {
175 		OSSL_BIO_reset(bio);
176 		pkey = PEM_read_bio_PUBKEY(bio, NULL, ossl_pem_passwd_cb, (void *)pass);
177 	    }
178 	}
179     }
180 
181     BIO_free(bio);
182     if (!pkey)
183 	ossl_raise(ePKeyError, "Could not parse PKey");
184 
185     return ossl_pkey_new(pkey);
186 }
187 
188 void
ossl_pkey_check_public_key(const EVP_PKEY * pkey)189 ossl_pkey_check_public_key(const EVP_PKEY *pkey)
190 {
191     void *ptr;
192     const BIGNUM *n, *e, *pubkey;
193 
194     if (EVP_PKEY_missing_parameters(pkey))
195 	ossl_raise(ePKeyError, "parameters missing");
196 
197     /* OpenSSL < 1.1.0 takes non-const pointer */
198     ptr = EVP_PKEY_get0((EVP_PKEY *)pkey);
199     switch (EVP_PKEY_base_id(pkey)) {
200       case EVP_PKEY_RSA:
201 	RSA_get0_key(ptr, &n, &e, NULL);
202 	if (n && e)
203 	    return;
204 	break;
205       case EVP_PKEY_DSA:
206 	DSA_get0_key(ptr, &pubkey, NULL);
207 	if (pubkey)
208 	    return;
209 	break;
210       case EVP_PKEY_DH:
211 	DH_get0_key(ptr, &pubkey, NULL);
212 	if (pubkey)
213 	    return;
214 	break;
215 #if !defined(OPENSSL_NO_EC)
216       case EVP_PKEY_EC:
217 	if (EC_KEY_get0_public_key(ptr))
218 	    return;
219 	break;
220 #endif
221       default:
222 	/* unsupported type; assuming ok */
223 	return;
224     }
225     ossl_raise(ePKeyError, "public key missing");
226 }
227 
228 EVP_PKEY *
GetPKeyPtr(VALUE obj)229 GetPKeyPtr(VALUE obj)
230 {
231     EVP_PKEY *pkey;
232 
233     GetPKey(obj, pkey);
234 
235     return pkey;
236 }
237 
238 EVP_PKEY *
GetPrivPKeyPtr(VALUE obj)239 GetPrivPKeyPtr(VALUE obj)
240 {
241     EVP_PKEY *pkey;
242 
243     if (rb_funcallv(obj, id_private_q, 0, NULL) != Qtrue) {
244 	ossl_raise(rb_eArgError, "Private key is needed.");
245     }
246     GetPKey(obj, pkey);
247 
248     return pkey;
249 }
250 
251 EVP_PKEY *
DupPKeyPtr(VALUE obj)252 DupPKeyPtr(VALUE obj)
253 {
254     EVP_PKEY *pkey;
255 
256     GetPKey(obj, pkey);
257     EVP_PKEY_up_ref(pkey);
258 
259     return pkey;
260 }
261 
262 /*
263  * Private
264  */
265 static VALUE
ossl_pkey_alloc(VALUE klass)266 ossl_pkey_alloc(VALUE klass)
267 {
268     EVP_PKEY *pkey;
269     VALUE obj;
270 
271     obj = NewPKey(klass);
272     if (!(pkey = EVP_PKEY_new())) {
273 	ossl_raise(ePKeyError, NULL);
274     }
275     SetPKey(obj, pkey);
276 
277     return obj;
278 }
279 
280 /*
281  *  call-seq:
282  *      PKeyClass.new -> self
283  *
284  * Because PKey is an abstract class, actually calling this method explicitly
285  * will raise a NotImplementedError.
286  */
287 static VALUE
ossl_pkey_initialize(VALUE self)288 ossl_pkey_initialize(VALUE self)
289 {
290     if (rb_obj_is_instance_of(self, cPKey)) {
291 	ossl_raise(rb_eTypeError, "OpenSSL::PKey::PKey can't be instantiated directly");
292     }
293     return self;
294 }
295 
296 /*
297  *  call-seq:
298  *      pkey.sign(digest, data) -> String
299  *
300  * To sign the String _data_, _digest_, an instance of OpenSSL::Digest, must
301  * be provided. The return value is again a String containing the signature.
302  * A PKeyError is raised should errors occur.
303  * Any previous state of the Digest instance is irrelevant to the signature
304  * outcome, the digest instance is reset to its initial state during the
305  * operation.
306  *
307  * == Example
308  *   data = 'Sign me!'
309  *   digest = OpenSSL::Digest::SHA256.new
310  *   pkey = OpenSSL::PKey::RSA.new(2048)
311  *   signature = pkey.sign(digest, data)
312  */
313 static VALUE
ossl_pkey_sign(VALUE self,VALUE digest,VALUE data)314 ossl_pkey_sign(VALUE self, VALUE digest, VALUE data)
315 {
316     EVP_PKEY *pkey;
317     const EVP_MD *md;
318     EVP_MD_CTX *ctx;
319     unsigned int buf_len;
320     VALUE str;
321     int result;
322 
323     pkey = GetPrivPKeyPtr(self);
324     md = ossl_evp_get_digestbyname(digest);
325     StringValue(data);
326     str = rb_str_new(0, EVP_PKEY_size(pkey));
327 
328     ctx = EVP_MD_CTX_new();
329     if (!ctx)
330 	ossl_raise(ePKeyError, "EVP_MD_CTX_new");
331     if (!EVP_SignInit_ex(ctx, md, NULL)) {
332 	EVP_MD_CTX_free(ctx);
333 	ossl_raise(ePKeyError, "EVP_SignInit_ex");
334     }
335     if (!EVP_SignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data))) {
336 	EVP_MD_CTX_free(ctx);
337 	ossl_raise(ePKeyError, "EVP_SignUpdate");
338     }
339     result = EVP_SignFinal(ctx, (unsigned char *)RSTRING_PTR(str), &buf_len, pkey);
340     EVP_MD_CTX_free(ctx);
341     if (!result)
342 	ossl_raise(ePKeyError, "EVP_SignFinal");
343     rb_str_set_len(str, buf_len);
344 
345     return str;
346 }
347 
348 /*
349  *  call-seq:
350  *      pkey.verify(digest, signature, data) -> String
351  *
352  * To verify the String _signature_, _digest_, an instance of
353  * OpenSSL::Digest, must be provided to re-compute the message digest of the
354  * original _data_, also a String. The return value is +true+ if the
355  * signature is valid, +false+ otherwise. A PKeyError is raised should errors
356  * occur.
357  * Any previous state of the Digest instance is irrelevant to the validation
358  * outcome, the digest instance is reset to its initial state during the
359  * operation.
360  *
361  * == Example
362  *   data = 'Sign me!'
363  *   digest = OpenSSL::Digest::SHA256.new
364  *   pkey = OpenSSL::PKey::RSA.new(2048)
365  *   signature = pkey.sign(digest, data)
366  *   pub_key = pkey.public_key
367  *   puts pub_key.verify(digest, signature, data) # => true
368  */
369 static VALUE
ossl_pkey_verify(VALUE self,VALUE digest,VALUE sig,VALUE data)370 ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data)
371 {
372     EVP_PKEY *pkey;
373     const EVP_MD *md;
374     EVP_MD_CTX *ctx;
375     int siglen, result;
376 
377     GetPKey(self, pkey);
378     ossl_pkey_check_public_key(pkey);
379     md = ossl_evp_get_digestbyname(digest);
380     StringValue(sig);
381     siglen = RSTRING_LENINT(sig);
382     StringValue(data);
383 
384     ctx = EVP_MD_CTX_new();
385     if (!ctx)
386 	ossl_raise(ePKeyError, "EVP_MD_CTX_new");
387     if (!EVP_VerifyInit_ex(ctx, md, NULL)) {
388 	EVP_MD_CTX_free(ctx);
389 	ossl_raise(ePKeyError, "EVP_VerifyInit_ex");
390     }
391     if (!EVP_VerifyUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data))) {
392 	EVP_MD_CTX_free(ctx);
393 	ossl_raise(ePKeyError, "EVP_VerifyUpdate");
394     }
395     result = EVP_VerifyFinal(ctx, (unsigned char *)RSTRING_PTR(sig), siglen, pkey);
396     EVP_MD_CTX_free(ctx);
397     switch (result) {
398     case 0:
399 	ossl_clear_error();
400 	return Qfalse;
401     case 1:
402 	return Qtrue;
403     default:
404 	ossl_raise(ePKeyError, "EVP_VerifyFinal");
405     }
406 }
407 
408 /*
409  * INIT
410  */
411 void
Init_ossl_pkey(void)412 Init_ossl_pkey(void)
413 {
414 #undef rb_intern
415 #if 0
416     mOSSL = rb_define_module("OpenSSL");
417     eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
418 #endif
419 
420     /* Document-module: OpenSSL::PKey
421      *
422      * == Asymmetric Public Key Algorithms
423      *
424      * Asymmetric public key algorithms solve the problem of establishing and
425      * sharing secret keys to en-/decrypt messages. The key in such an
426      * algorithm consists of two parts: a public key that may be distributed
427      * to others and a private key that needs to remain secret.
428      *
429      * Messages encrypted with a public key can only be decrypted by
430      * recipients that are in possession of the associated private key.
431      * Since public key algorithms are considerably slower than symmetric
432      * key algorithms (cf. OpenSSL::Cipher) they are often used to establish
433      * a symmetric key shared between two parties that are in possession of
434      * each other's public key.
435      *
436      * Asymmetric algorithms offer a lot of nice features that are used in a
437      * lot of different areas. A very common application is the creation and
438      * validation of digital signatures. To sign a document, the signatory
439      * generally uses a message digest algorithm (cf. OpenSSL::Digest) to
440      * compute a digest of the document that is then encrypted (i.e. signed)
441      * using the private key. Anyone in possession of the public key may then
442      * verify the signature by computing the message digest of the original
443      * document on their own, decrypting the signature using the signatory's
444      * public key and comparing the result to the message digest they
445      * previously computed. The signature is valid if and only if the
446      * decrypted signature is equal to this message digest.
447      *
448      * The PKey module offers support for three popular public/private key
449      * algorithms:
450      * * RSA (OpenSSL::PKey::RSA)
451      * * DSA (OpenSSL::PKey::DSA)
452      * * Elliptic Curve Cryptography (OpenSSL::PKey::EC)
453      * Each of these implementations is in fact a sub-class of the abstract
454      * PKey class which offers the interface for supporting digital signatures
455      * in the form of PKey#sign and PKey#verify.
456      *
457      * == Diffie-Hellman Key Exchange
458      *
459      * Finally PKey also features OpenSSL::PKey::DH, an implementation of
460      * the Diffie-Hellman key exchange protocol based on discrete logarithms
461      * in finite fields, the same basis that DSA is built on.
462      * The Diffie-Hellman protocol can be used to exchange (symmetric) keys
463      * over insecure channels without needing any prior joint knowledge
464      * between the participating parties. As the security of DH demands
465      * relatively long "public keys" (i.e. the part that is overtly
466      * transmitted between participants) DH tends to be quite slow. If
467      * security or speed is your primary concern, OpenSSL::PKey::EC offers
468      * another implementation of the Diffie-Hellman protocol.
469      *
470      */
471     mPKey = rb_define_module_under(mOSSL, "PKey");
472 
473     /* Document-class: OpenSSL::PKey::PKeyError
474      *
475      *Raised when errors occur during PKey#sign or PKey#verify.
476      */
477     ePKeyError = rb_define_class_under(mPKey, "PKeyError", eOSSLError);
478 
479     /* Document-class: OpenSSL::PKey::PKey
480      *
481      * An abstract class that bundles signature creation (PKey#sign) and
482      * validation (PKey#verify) that is common to all implementations except
483      * OpenSSL::PKey::DH
484      * * OpenSSL::PKey::RSA
485      * * OpenSSL::PKey::DSA
486      * * OpenSSL::PKey::EC
487      */
488     cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject);
489 
490     rb_define_module_function(mPKey, "read", ossl_pkey_new_from_data, -1);
491 
492     rb_define_alloc_func(cPKey, ossl_pkey_alloc);
493     rb_define_method(cPKey, "initialize", ossl_pkey_initialize, 0);
494 
495     rb_define_method(cPKey, "sign", ossl_pkey_sign, 2);
496     rb_define_method(cPKey, "verify", ossl_pkey_verify, 3);
497 
498     id_private_q = rb_intern("private?");
499 
500     /*
501      * INIT rsa, dsa, dh, ec
502      */
503     Init_ossl_rsa();
504     Init_ossl_dsa();
505     Init_ossl_dh();
506     Init_ossl_ec();
507 }
508