Ruby 2.0.0p247(2013-06-27revision41674)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

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 */
16 VALUE mPKey;
17 VALUE cPKey;
18 VALUE ePKeyError;
19 ID id_private_q;
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
106 ossl_pkey_new_from_file(VALUE filename)
107 {
108 FILE *fp;
109 EVP_PKEY *pkey;
110
111 SafeStringValue(filename);
112 if (!(fp = fopen(RSTRING_PTR(filename), "r"))) {
113 ossl_raise(ePKeyError, "%s", strerror(errno));
114 }
115 rb_fd_fix_cloexec(fileno(fp));
116
117 pkey = PEM_read_PrivateKey(fp, NULL, ossl_pem_passwd_cb, NULL);
118 fclose(fp);
119 if (!pkey) {
120 ossl_raise(ePKeyError, NULL);
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
140 ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self)
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 *
174 GetPKeyPtr(VALUE obj)
175 {
176 EVP_PKEY *pkey;
177
178 SafeGetPKey(obj, pkey);
179
180 return pkey;
181 }
182
183 EVP_PKEY *
184 GetPrivPKeyPtr(VALUE obj)
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 *
197 DupPKeyPtr(VALUE obj)
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 *
208 DupPrivPKeyPtr(VALUE obj)
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
225 ossl_pkey_alloc(VALUE klass)
226 {
227 EVP_PKEY *pkey;
228 VALUE obj;
229
230 if (!(pkey = EVP_PKEY_new())) {
231 ossl_raise(ePKeyError, NULL);
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
246 ossl_pkey_initialize(VALUE self)
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))
288 ossl_raise(ePKeyError, NULL);
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:
333 ossl_raise(ePKeyError, NULL);
334 }
335 return Qnil; /* dummy */
336 }
337
338 /*
339 * INIT
340 */
341 void
342 Init_ossl_pkey()
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 */
399 mPKey = rb_define_module_under(mOSSL, "PKey");
400
401 /* Document-class: OpenSSL::PKey::PKeyError
402 *
403 *Raised when errors occur during PKey#sign or PKey#verify.
404 */
405 ePKeyError = rb_define_class_under(mPKey, "PKeyError", eOSSLError);
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 */
416 cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject);
417
418 rb_define_module_function(mPKey, "read", ossl_pkey_new_from_data, -1);
419
420 rb_define_alloc_func(cPKey, ossl_pkey_alloc);
421 rb_define_method(cPKey, "initialize", ossl_pkey_initialize, 0);
422
423 rb_define_method(cPKey, "sign", ossl_pkey_sign, 2);
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
437