Ruby  2.0.0p353(2013-11-22revision43784)
ossl_pkey.c
Go to the documentation of this file.
1 /*
2  * $Id: ossl_pkey.c 35322 2012-04-14 00:36:26Z drbrain $
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
272 ossl_pkey_sign(VALUE self, VALUE digest, VALUE data)
273 {
274  EVP_PKEY *pkey;
275  EVP_MD_CTX ctx;
276  unsigned int buf_len;
277  VALUE str;
278 
279  if (rb_funcall(self, id_private_q, 0, NULL) != Qtrue) {
280  ossl_raise(rb_eArgError, "Private key is needed.");
281  }
282  GetPKey(self, pkey);
283  EVP_SignInit(&ctx, GetDigestPtr(digest));
284  StringValue(data);
285  EVP_SignUpdate(&ctx, RSTRING_PTR(data), RSTRING_LEN(data));
286  str = rb_str_new(0, EVP_PKEY_size(pkey)+16);
287  if (!EVP_SignFinal(&ctx, (unsigned char *)RSTRING_PTR(str), &buf_len, pkey))
289  assert((long)buf_len <= RSTRING_LEN(str));
290  rb_str_set_len(str, buf_len);
291 
292  return str;
293 }
294 
295 /*
296  * call-seq:
297  * pkey.verify(digest, signature, data) -> String
298  *
299  * To verify the +String+ +signature+, +digest+, an instance of
300  * OpenSSL::Digest, must be provided to re-compute the message digest of the
301  * original +data+, also a +String+. The return value is +true+ if the
302  * signature is valid, +false+ otherwise. A PKeyError is raised should errors
303  * occur.
304  * Any previous state of the +Digest+ instance is irrelevant to the validation
305  * outcome, the digest instance is reset to its initial state during the
306  * operation.
307  *
308  * == Example
309  * data = 'Sign me!'
310  * digest = OpenSSL::Digest::SHA256.new
311  * pkey = OpenSSL::PKey::RSA.new(2048)
312  * signature = pkey.sign(digest, data)
313  * pub_key = pkey.public_key
314  * puts pub_key.verify(digest, signature, data) # => true
315  */
316 static VALUE
317 ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data)
318 {
319  EVP_PKEY *pkey;
320  EVP_MD_CTX ctx;
321 
322  GetPKey(self, pkey);
323  EVP_VerifyInit(&ctx, GetDigestPtr(digest));
324  StringValue(sig);
325  StringValue(data);
326  EVP_VerifyUpdate(&ctx, RSTRING_PTR(data), RSTRING_LEN(data));
327  switch (EVP_VerifyFinal(&ctx, (unsigned char *)RSTRING_PTR(sig), RSTRING_LENINT(sig), pkey)) {
328  case 0:
329  return Qfalse;
330  case 1:
331  return Qtrue;
332  default:
334  }
335  return Qnil; /* dummy */
336 }
337 
338 /*
339  * INIT
340  */
341 void
343 {
344 #if 0
345  mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */
346 #endif
347 
348  /* Document-module: OpenSSL::PKey
349  *
350  * == Asymmetric Public Key Algorithms
351  *
352  * Asymmetric public key algorithms solve the problem of establishing and
353  * sharing secret keys to en-/decrypt messages. The key in such an
354  * algorithm consists of two parts: a public key that may be distributed
355  * to others and a private key that needs to remain secret.
356  *
357  * Messages encrypted with a public key can only be encrypted by
358  * recipients that are in possession of the associated private key.
359  * Since public key algorithms are considerably slower than symmetric
360  * key algorithms (cf. OpenSSL::Cipher) they are often used to establish
361  * a symmetric key shared between two parties that are in possession of
362  * each other's public key.
363  *
364  * Asymmetric algorithms offer a lot of nice features that are used in a
365  * lot of different areas. A very common application is the creation and
366  * validation of digital signatures. To sign a document, the signatory
367  * generally uses a message digest algorithm (cf. OpenSSL::Digest) to
368  * compute a digest of the document that is then encrypted (i.e. signed)
369  * using the private key. Anyone in possession of the public key may then
370  * verify the signature by computing the message digest of the original
371  * document on their own, decrypting the signature using the signatory's
372  * public key and comparing the result to the message digest they
373  * previously computed. The signature is valid if and only if the
374  * decrypted signature is equal to this message digest.
375  *
376  * The PKey module offers support for three popular public/private key
377  * algorithms:
378  * * RSA (OpenSSL::PKey::RSA)
379  * * DSA (OpenSSL::PKey::DSA)
380  * * Elliptic Curve Cryptography (OpenSSL::PKey::EC)
381  * Each of these implementations is in fact a sub-class of the abstract
382  * PKey class which offers the interface for supporting digital signatures
383  * in the form of PKey#sign and PKey#verify.
384  *
385  * == Diffie-Hellman Key Exchange
386  *
387  * Finally PKey also features OpenSSL::PKey::DH, an implementation of
388  * the Diffie-Hellman key exchange protocol based on discrete logarithms
389  * in finite fields, the same basis that DSA is built on.
390  * The Diffie-Hellman protocol can be used to exchange (symmetric) keys
391  * over insecure channels without needing any prior joint knowledge
392  * between the participating parties. As the security of DH demands
393  * relatively long "public keys" (i.e. the part that is overtly
394  * transmitted between participants) DH tends to be quite slow. If
395  * security or speed is your primary concern, OpenSSL::PKey::EC offers
396  * another implementation of the Diffie-Hellman protocol.
397  *
398  */
400 
401  /* Document-class: OpenSSL::PKey::PKeyError
402  *
403  *Raised when errors occur during PKey#sign or PKey#verify.
404  */
406 
407  /* Document-class: OpenSSL::PKey::PKey
408  *
409  * An abstract class that bundles signature creation (PKey#sign) and
410  * validation (PKey#verify) that is common to all implementations except
411  * OpenSSL::PKey::DH
412  * * OpenSSL::PKey::RSA
413  * * OpenSSL::PKey::DSA
414  * * OpenSSL::PKey::EC
415  */
417 
419 
421  rb_define_method(cPKey, "initialize", ossl_pkey_initialize, 0);
422 
424  rb_define_method(cPKey, "verify", ossl_pkey_verify, 3);
425 
426  id_private_q = rb_intern("private?");
427 
428  /*
429  * INIT rsa, dsa, dh, ec
430  */
431  Init_ossl_rsa();
432  Init_ossl_dsa();
433  Init_ossl_dh();
434  Init_ossl_ec();
435 }
436 
VALUE mOSSL
Definition: ossl.c:259
ID id_private_q
Definition: ossl_pkey.c:19
#define INT2NUM(x)
Definition: ruby.h:1178
if(dispIdMember==DISPID_VALUE)
Definition: win32ole.c:791
VALUE mPKey
Definition: ossl_pkey.c:16
VALUE ePKeyError
Definition: ossl_pkey.c:18
#define Qtrue
Definition: ruby.h:434
EVP_PKEY * GetPrivPKeyPtr(VALUE obj)
Definition: ossl_pkey.c:184
void Init_ossl_dsa(void)
VALUE ossl_dsa_new(EVP_PKEY *)
Definition: ossl_pkey_dsa.c:56
#define UNREACHABLE
Definition: ruby.h:40
EVP_PKEY * DupPrivPKeyPtr(VALUE obj)
Definition: ossl_pkey.c:208
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
Definition: vm_eval.c:774
void rb_str_set_len(VALUE, long)
Definition: string.c:1837
VALUE rb_protect(VALUE(*proc)(VALUE), VALUE data, int *state)
Definition: eval.c:771
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:545
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
#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:342
VALUE ossl_pkey_new(EVP_PKEY *pkey)
Definition: ossl_pkey.c:76
Win32OLEIDispatch * p
Definition: win32ole.c:786
void ossl_generate_cb(int p, int n, void *arg)
Definition: ossl_pkey.c:25
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:1426
#define OSSL_BIO_reset(bio)
Definition: ossl.h:155
static VALUE ossl_pkey_initialize(VALUE self)
Definition: ossl_pkey.c:246
VALUE ossl_dh_new(EVP_PKEY *)
Definition: ossl_pkey_dh.c:62
#define NIL_P(v)
Definition: ruby.h:446
const EVP_MD * GetDigestPtr(VALUE obj)
Definition: ossl_digest.c:36
void rb_ary_store(VALUE ary, long idx, VALUE val)
Definition: array.c:719
#define SafeGetPKey(obj, pkey)
Definition: ossl_pkey.h:36
VALUE eOSSLError
Definition: ossl.c:264
int argc
Definition: ruby.c:130
#define Qfalse
Definition: ruby.h:433
static VALUE ossl_pkey_alloc(VALUE klass)
Definition: ossl_pkey.c:225
#define RSTRING_LEN(str)
Definition: ruby.h:862
void rb_define_module_function(VALUE module, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a module function for module.
Definition: class.c:1512
VALUE rb_yield(VALUE)
Definition: vm_eval.c:934
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
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:1570
void Init_ossl_ec(void)
unsigned long ID
Definition: ruby.h:105
VALUE ossl_pkey_new_from_file(VALUE filename)
Definition: ossl_pkey.c:106
#define Qnil
Definition: ruby.h:435
unsigned long VALUE
Definition: ruby.h:104
VALUE rb_define_module_under(VALUE outer, const char *name)
Definition: class.c:637
#define RSTRING_PTR(str)
Definition: ruby.h:866
VALUE rb_obj_is_instance_of(VALUE, VALUE)
Definition: object.c:545
void rb_fd_fix_cloexec(int fd)
Definition: io.c:202
RUBY_EXTERN char * strerror(int)
Definition: strerror.c:11
void ossl_raise(VALUE exc, const char *fmt,...)
Definition: ossl.c:328
EVP_PKEY * GetPKeyPtr(VALUE obj)
Definition: ossl_pkey.c:174
#define SafeStringValue(v)
Definition: ruby.h:552
VALUE rb_eNotImpError
Definition: error.c:521
EVP_PKEY * DupPKeyPtr(VALUE obj)
Definition: ossl_pkey.c:197
VALUE rb_ary_new2(long capa)
Definition: array.c:417
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:589
#define StringValuePtr(v)
Definition: ruby.h:547
int ossl_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd)
Definition: ossl.c:162
#define RSTRING_LENINT(str)
Definition: ruby.h:874
#define fileno(p)
Definition: vsnprintf.c:223
VALUE rb_define_module(const char *name)
Definition: class.c:617
VALUE cPKey
Definition: ossl_pkey.c:17
#define rb_intern(str)
#define NULL
Definition: _sdbm.c:103
static VALUE ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data)
Definition: ossl_pkey.c:317
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1344
VALUE ossl_ec_new(EVP_PKEY *)
VALUE rb_eArgError
Definition: error.c:512
char ** argv
Definition: ruby.c:131
#define StringValue(v)
Definition: ruby.h:546
VALUE rb_str_new(const char *, long)
Definition: string.c:425