Ruby  2.1.10p492(2016-04-01revision54464)
ossl_pkey.c
Go to the documentation of this file.
1 /*
2  * $Id: ossl_pkey.c 52643 2015-11-18 11:39:53Z usa $
3  * 'OpenSSL for Ruby' project
4  * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
5  * All rights reserved.
6  */
7 /*
8  * This program is licenced under the same licence as Ruby.
9  * (See the file 'LICENCE'.)
10  */
11 #include "ossl.h"
12 
13 /*
14  * Classes
15  */
20 
21 /*
22  * callback for generating keys
23  */
24 void
25 ossl_generate_cb(int p, int n, void *arg)
26 {
27  VALUE ary;
28 
29  ary = rb_ary_new2(2);
30  rb_ary_store(ary, 0, INT2NUM(p));
31  rb_ary_store(ary, 1, INT2NUM(n));
32 
33  rb_yield(ary);
34 }
35 
36 #if HAVE_BN_GENCB
37 /* OpenSSL 2nd version of GN generation callback */
38 int
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 *)cb->arg;
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->stop = 1;
57  arg->state = state;
58  }
59  }
60  if (arg->stop) return 0;
61  return 1;
62 }
63 
64 void
65 ossl_generate_cb_stop(void *ptr)
66 {
67  struct ossl_generate_cb_arg *arg = (struct ossl_generate_cb_arg *)ptr;
68  arg->stop = 1;
69 }
70 #endif
71 
72 /*
73  * Public
74  */
75 VALUE
76 ossl_pkey_new(EVP_PKEY *pkey)
77 {
78  if (!pkey) {
79  ossl_raise(ePKeyError, "Cannot make new key from NULL.");
80  }
81  switch (EVP_PKEY_type(pkey->type)) {
82 #if !defined(OPENSSL_NO_RSA)
83  case EVP_PKEY_RSA:
84  return ossl_rsa_new(pkey);
85 #endif
86 #if !defined(OPENSSL_NO_DSA)
87  case EVP_PKEY_DSA:
88  return ossl_dsa_new(pkey);
89 #endif
90 #if !defined(OPENSSL_NO_DH)
91  case EVP_PKEY_DH:
92  return ossl_dh_new(pkey);
93 #endif
94 #if !defined(OPENSSL_NO_EC) && (OPENSSL_VERSION_NUMBER >= 0x0090802fL)
95  case EVP_PKEY_EC:
96  return ossl_ec_new(pkey);
97 #endif
98  default:
99  ossl_raise(ePKeyError, "unsupported key type");
100  }
101 
102  UNREACHABLE;
103 }
104 
105 VALUE
107 {
108  FILE *fp;
109  EVP_PKEY *pkey;
110 
111  SafeStringValue(filename);
112  if (!(fp = fopen(RSTRING_PTR(filename), "r"))) {
114  }
116 
117  pkey = PEM_read_PrivateKey(fp, NULL, ossl_pem_passwd_cb, NULL);
118  fclose(fp);
119  if (!pkey) {
121  }
122 
123  return ossl_pkey_new(pkey);
124 }
125 
126 /*
127  * call-seq:
128  * OpenSSL::PKey.read(string [, pwd ] ) -> PKey
129  * OpenSSL::PKey.read(file [, pwd ]) -> PKey
130  *
131  * === Parameters
132  * * +string+ is a DER- or PEM-encoded string containing an arbitrary private
133  * or public key.
134  * * +file+ is an instance of +File+ containing a DER- or PEM-encoded
135  * arbitrary private or public key.
136  * * +pwd+ is an optional password in case +string+ or +file+ is an encrypted
137  * PEM resource.
138  */
139 static VALUE
141 {
142  EVP_PKEY *pkey;
143  BIO *bio;
144  VALUE data, pass;
145  char *passwd = NULL;
146 
147  rb_scan_args(argc, argv, "11", &data, &pass);
148 
149  bio = ossl_obj2bio(data);
150  if (!(pkey = d2i_PrivateKey_bio(bio, NULL))) {
151  OSSL_BIO_reset(bio);
152  if (!NIL_P(pass)) {
153  passwd = StringValuePtr(pass);
154  }
155  if (!(pkey = PEM_read_bio_PrivateKey(bio, NULL, ossl_pem_passwd_cb, passwd))) {
156  OSSL_BIO_reset(bio);
157  if (!(pkey = d2i_PUBKEY_bio(bio, NULL))) {
158  OSSL_BIO_reset(bio);
159  if (!NIL_P(pass)) {
160  passwd = StringValuePtr(pass);
161  }
162  pkey = PEM_read_bio_PUBKEY(bio, NULL, ossl_pem_passwd_cb, passwd);
163  }
164  }
165  }
166 
167  BIO_free(bio);
168  if (!pkey)
169  ossl_raise(rb_eArgError, "Could not parse PKey");
170  return ossl_pkey_new(pkey);
171 }
172 
173 EVP_PKEY *
175 {
176  EVP_PKEY *pkey;
177 
178  SafeGetPKey(obj, pkey);
179 
180  return pkey;
181 }
182 
183 EVP_PKEY *
185 {
186  EVP_PKEY *pkey;
187 
188  if (rb_funcall(obj, id_private_q, 0, NULL) != Qtrue) {
189  ossl_raise(rb_eArgError, "Private key is needed.");
190  }
191  SafeGetPKey(obj, pkey);
192 
193  return pkey;
194 }
195 
196 EVP_PKEY *
198 {
199  EVP_PKEY *pkey;
200 
201  SafeGetPKey(obj, pkey);
202  CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY);
203 
204  return pkey;
205 }
206 
207 EVP_PKEY *
209 {
210  EVP_PKEY *pkey;
211 
212  if (rb_funcall(obj, id_private_q, 0, NULL) != Qtrue) {
213  ossl_raise(rb_eArgError, "Private key is needed.");
214  }
215  SafeGetPKey(obj, pkey);
216  CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY);
217 
218  return pkey;
219 }
220 
221 /*
222  * Private
223  */
224 static VALUE
226 {
227  EVP_PKEY *pkey;
228  VALUE obj;
229 
230  if (!(pkey = EVP_PKEY_new())) {
232  }
233  WrapPKey(klass, obj, pkey);
234 
235  return obj;
236 }
237 
238 /*
239  * call-seq:
240  * PKeyClass.new -> self
241  *
242  * Because PKey is an abstract class, actually calling this method explicitly
243  * will raise a +NotImplementedError+.
244  */
245 static VALUE
247 {
248  if (rb_obj_is_instance_of(self, cPKey)) {
249  ossl_raise(rb_eNotImpError, "OpenSSL::PKey::PKey is an abstract class.");
250  }
251  return self;
252 }
253 
254 /*
255  * call-seq:
256  * pkey.sign(digest, data) -> String
257  *
258  * To sign the +String+ +data+, +digest+, an instance of OpenSSL::Digest, must
259  * be provided. The return value is again a +String+ containing the signature.
260  * A PKeyError is raised should errors occur.
261  * Any previous state of the +Digest+ instance is irrelevant to the signature
262  * outcome, the digest instance is reset to its initial state during the
263  * operation.
264  *
265  * == Example
266  * data = 'Sign me!'
267  * digest = OpenSSL::Digest::SHA256.new
268  * pkey = OpenSSL::PKey::RSA.new(2048)
269  * signature = pkey.sign(digest, data)
270  */
271 static VALUE
273 {
274  EVP_PKEY *pkey;
275  EVP_MD_CTX ctx;
276  unsigned int buf_len;
277  VALUE str;
278  int result;
279 
280  if (rb_funcall(self, id_private_q, 0, NULL) != Qtrue) {
281  ossl_raise(rb_eArgError, "Private key is needed.");
282  }
283  GetPKey(self, pkey);
284  EVP_SignInit(&ctx, GetDigestPtr(digest));
285  StringValue(data);
286  EVP_SignUpdate(&ctx, RSTRING_PTR(data), RSTRING_LEN(data));
287  str = rb_str_new(0, EVP_PKEY_size(pkey)+16);
288  result = EVP_SignFinal(&ctx, (unsigned char *)RSTRING_PTR(str), &buf_len, pkey);
289  EVP_MD_CTX_cleanup(&ctx);
290  if (!result)
292  assert((long)buf_len <= RSTRING_LEN(str));
293  rb_str_set_len(str, buf_len);
294 
295  return str;
296 }
297 
298 /*
299  * call-seq:
300  * pkey.verify(digest, signature, data) -> String
301  *
302  * To verify the +String+ +signature+, +digest+, an instance of
303  * OpenSSL::Digest, must be provided to re-compute the message digest of the
304  * original +data+, also a +String+. The return value is +true+ if the
305  * signature is valid, +false+ otherwise. A PKeyError is raised should errors
306  * occur.
307  * Any previous state of the +Digest+ instance is irrelevant to the validation
308  * outcome, the digest instance is reset to its initial state during the
309  * operation.
310  *
311  * == Example
312  * data = 'Sign me!'
313  * digest = OpenSSL::Digest::SHA256.new
314  * pkey = OpenSSL::PKey::RSA.new(2048)
315  * signature = pkey.sign(digest, data)
316  * pub_key = pkey.public_key
317  * puts pub_key.verify(digest, signature, data) # => true
318  */
319 static VALUE
321 {
322  EVP_PKEY *pkey;
323  EVP_MD_CTX ctx;
324  int result;
325 
326  GetPKey(self, pkey);
327  StringValue(sig);
328  StringValue(data);
329  EVP_VerifyInit(&ctx, GetDigestPtr(digest));
330  EVP_VerifyUpdate(&ctx, RSTRING_PTR(data), RSTRING_LEN(data));
331  result = EVP_VerifyFinal(&ctx, (unsigned char *)RSTRING_PTR(sig), RSTRING_LENINT(sig), pkey);
332  EVP_MD_CTX_cleanup(&ctx);
333  switch (result) {
334  case 0:
335  return Qfalse;
336  case 1:
337  return Qtrue;
338  default:
340  }
341  return Qnil; /* dummy */
342 }
343 
344 /*
345  * INIT
346  */
347 void
349 {
350 #if 0
351  mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */
352 #endif
353 
354  /* Document-module: OpenSSL::PKey
355  *
356  * == Asymmetric Public Key Algorithms
357  *
358  * Asymmetric public key algorithms solve the problem of establishing and
359  * sharing secret keys to en-/decrypt messages. The key in such an
360  * algorithm consists of two parts: a public key that may be distributed
361  * to others and a private key that needs to remain secret.
362  *
363  * Messages encrypted with a public key can only be encrypted by
364  * recipients that are in possession of the associated private key.
365  * Since public key algorithms are considerably slower than symmetric
366  * key algorithms (cf. OpenSSL::Cipher) they are often used to establish
367  * a symmetric key shared between two parties that are in possession of
368  * each other's public key.
369  *
370  * Asymmetric algorithms offer a lot of nice features that are used in a
371  * lot of different areas. A very common application is the creation and
372  * validation of digital signatures. To sign a document, the signatory
373  * generally uses a message digest algorithm (cf. OpenSSL::Digest) to
374  * compute a digest of the document that is then encrypted (i.e. signed)
375  * using the private key. Anyone in possession of the public key may then
376  * verify the signature by computing the message digest of the original
377  * document on their own, decrypting the signature using the signatory's
378  * public key and comparing the result to the message digest they
379  * previously computed. The signature is valid if and only if the
380  * decrypted signature is equal to this message digest.
381  *
382  * The PKey module offers support for three popular public/private key
383  * algorithms:
384  * * RSA (OpenSSL::PKey::RSA)
385  * * DSA (OpenSSL::PKey::DSA)
386  * * Elliptic Curve Cryptography (OpenSSL::PKey::EC)
387  * Each of these implementations is in fact a sub-class of the abstract
388  * PKey class which offers the interface for supporting digital signatures
389  * in the form of PKey#sign and PKey#verify.
390  *
391  * == Diffie-Hellman Key Exchange
392  *
393  * Finally PKey also features OpenSSL::PKey::DH, an implementation of
394  * the Diffie-Hellman key exchange protocol based on discrete logarithms
395  * in finite fields, the same basis that DSA is built on.
396  * The Diffie-Hellman protocol can be used to exchange (symmetric) keys
397  * over insecure channels without needing any prior joint knowledge
398  * between the participating parties. As the security of DH demands
399  * relatively long "public keys" (i.e. the part that is overtly
400  * transmitted between participants) DH tends to be quite slow. If
401  * security or speed is your primary concern, OpenSSL::PKey::EC offers
402  * another implementation of the Diffie-Hellman protocol.
403  *
404  */
406 
407  /* Document-class: OpenSSL::PKey::PKeyError
408  *
409  *Raised when errors occur during PKey#sign or PKey#verify.
410  */
412 
413  /* Document-class: OpenSSL::PKey::PKey
414  *
415  * An abstract class that bundles signature creation (PKey#sign) and
416  * validation (PKey#verify) that is common to all implementations except
417  * OpenSSL::PKey::DH
418  * * OpenSSL::PKey::RSA
419  * * OpenSSL::PKey::DSA
420  * * OpenSSL::PKey::EC
421  */
423 
425 
427  rb_define_method(cPKey, "initialize", ossl_pkey_initialize, 0);
428 
430  rb_define_method(cPKey, "verify", ossl_pkey_verify, 3);
431 
432  id_private_q = rb_intern("private?");
433 
434  /*
435  * INIT rsa, dsa, dh, ec
436  */
437  Init_ossl_rsa();
438  Init_ossl_dsa();
439  Init_ossl_dh();
440  Init_ossl_ec();
441 }
442 
VALUE data
Definition: tcltklib.c:3360
VALUE mOSSL
Definition: ossl.c:259
ID id_private_q
Definition: ossl_pkey.c:19
VALUE mPKey
Definition: ossl_pkey.c:16
VALUE ePKeyError
Definition: ossl_pkey.c:18
rb_funcall(memo->yielder, id_lshift, 1, rb_assoc_new(memo->prev_value, memo->prev_elts))
EVP_PKEY * GetPrivPKeyPtr(VALUE obj)
Definition: ossl_pkey.c:184
rb_yield(i)
void Init_ossl_dsa(void)
VALUE ossl_dsa_new(EVP_PKEY *)
Definition: ossl_pkey_dsa.c:56
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
#define UNREACHABLE
Definition: ruby.h:42
EVP_PKEY * DupPrivPKeyPtr(VALUE obj)
Definition: ossl_pkey.c:208
#define RSTRING_PTR(str)
NIL_P(eventloop_thread)
Definition: tcltklib.c:4056
VALUE rb_protect(VALUE(*proc)(VALUE), VALUE data, int *state)
Definition: eval.c:807
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:657
return Qtrue
Definition: tcltklib.c:9618
#define SafeStringValue(v)
#define GetPKey(obj, pkey)
Definition: ossl_pkey.h:30
VALUE ossl_rsa_new(EVP_PKEY *)
Definition: ossl_pkey_rsa.c:56
void Init_ossl_pkey()
Definition: ossl_pkey.c:348
VALUE ossl_pkey_new(EVP_PKEY *pkey)
Definition: ossl_pkey.c:76
if(args--[1]==0)
Definition: array.c:3187
memo state
Definition: enum.c:2432
#define rb_ary_new2
void rb_fd_fix_cloexec(int fd)
Definition: io.c:221
VALUE ary
Definition: enum.c:674
void ossl_generate_cb(int p, int n, void *arg)
Definition: ossl_pkey.c:25
VALUE rb_obj_is_instance_of(VALUE, VALUE)
Definition: object.c:609
return Qfalse
Definition: tcltklib.c:6790
#define Qnil
Definition: enum.c:67
#define StringValuePtr(v)
static VALUE char * str
Definition: tcltklib.c:3539
#define OSSL_BIO_reset(bio)
Definition: ossl.h:155
unsigned long ID
Definition: ripper.y:89
static VALUE ossl_pkey_initialize(VALUE self)
Definition: ossl_pkey.c:246
VALUE ossl_dh_new(EVP_PKEY *)
Definition: ossl_pkey_dh.c:62
const EVP_MD * GetDigestPtr(VALUE obj)
Definition: ossl_digest.c:36
static VALUE VALUE obj
Definition: tcltklib.c:3150
#define RSTRING_LEN(str)
void rb_ary_store(VALUE ary, long idx, VALUE val)
Definition: array.c:794
#define SafeGetPKey(obj, pkey)
Definition: ossl_pkey.h:36
VALUE eOSSLError
Definition: ossl.c:264
VALUE arg
Definition: enum.c:2427
static VALUE ossl_pkey_alloc(VALUE klass)
Definition: ossl_pkey.c:225
VALUE * argv
Definition: tcltklib.c:1969
void rb_define_module_function(VALUE module, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a module function for module.
Definition: class.c:1661
static VALUE ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self)
Definition: ossl_pkey.c:140
int errno
#define WrapPKey(klass, obj, pkey)
Definition: ossl_pkey.h:23
#define StringValue(v)
BIO * ossl_obj2bio(VALUE obj)
Definition: ossl_bio.c:17
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1719
void Init_ossl_ec(void)
VALUE ossl_pkey_new_from_file(VALUE filename)
Definition: ossl_pkey.c:106
int argc
Definition: tcltklib.c:1968
return ptr
Definition: tcltklib.c:789
VALUE rb_define_module_under(VALUE outer, const char *name)
Definition: class.c:747
RUBY_EXTERN char * strerror(int)
Definition: strerror.c:11
SSL_CTX * ctx
Definition: ossl_ssl.c:486
RUBY_EXTERN VALUE rb_cObject
Definition: ripper.y:1561
klass
Definition: tcltklib.c:3496
#define INT2NUM(x)
int EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx)
void ossl_raise(VALUE exc, const char *fmt,...)
Definition: ossl.c:333
EVP_PKEY * GetPKeyPtr(VALUE obj)
Definition: ossl_pkey.c:174
#define RSTRING_LENINT(str)
register C_block * p
Definition: crypt.c:309
VALUE rb_eNotImpError
Definition: error.c:558
EVP_PKEY * DupPKeyPtr(VALUE obj)
Definition: ossl_pkey.c:197
VALUE rb_str_new(const char *, long)
Definition: string.c:534
data n
Definition: enum.c:860
void Init_ossl_rsa(void)
static VALUE ossl_pkey_sign(VALUE self, VALUE digest, VALUE data)
Definition: ossl_pkey.c:272
#define assert(condition)
Definition: ossl.h:45
void Init_ossl_dh(void)
Definition: ossl_pkey_dh.c:591
unsigned long VALUE
Definition: ripper.y:88
int ossl_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd)
Definition: ossl.c:162
#define fileno(p)
Definition: vsnprintf.c:223
VALUE rb_define_module(const char *name)
Definition: class.c:727
VALUE cPKey
Definition: ossl_pkey.c:17
#define rb_intern(str)
#define NULL
Definition: _sdbm.c:102
static VALUE ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data)
Definition: ossl_pkey.c:320
volatile VALUE result
Definition: enum.c:1989
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1479
VALUE ossl_ec_new(EVP_PKEY *)
VALUE rb_eArgError
Definition: error.c:549
void rb_str_set_len(VALUE, long)
Definition: string.c:2007