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