Change soft-fail to use the config, rather than env
[rbx.git] / stdlib / ext / openssl / ossl_pkey_rsa.c
blob0e73ae2d5b5873948d630915cb93b8ebf92159bd
1 /*
2 * $Id: ossl_pkey_rsa.c 12043 2007-03-12 04:12:32Z knu $
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'.)
11 #if !defined(OPENSSL_NO_RSA)
13 #include "ossl.h"
15 #define GetPKeyRSA(obj, pkey) do { \
16 GetPKey(obj, pkey); \
17 if (EVP_PKEY_type(pkey->type) != EVP_PKEY_RSA) { /* PARANOIA? */ \
18 ossl_raise(rb_eRuntimeError, "THIS IS NOT A RSA!") ; \
19 } \
20 } while (0)
22 #define RSA_HAS_PRIVATE(rsa) ((rsa)->p && (rsa)->q)
23 #define RSA_PRIVATE(obj,rsa) (RSA_HAS_PRIVATE(rsa)||OSSL_PKEY_IS_PRIVATE(obj))
26 * Classes
28 VALUE cRSA;
29 VALUE eRSAError;
32 * Public
34 static VALUE
35 rsa_instance(VALUE klass, RSA *rsa)
37 EVP_PKEY *pkey;
38 VALUE obj;
40 if (!rsa) {
41 return Qfalse;
43 if (!(pkey = EVP_PKEY_new())) {
44 return Qfalse;
46 if (!EVP_PKEY_assign_RSA(pkey, rsa)) {
47 EVP_PKEY_free(pkey);
48 return Qfalse;
50 WrapPKey(klass, obj, pkey);
52 return obj;
55 VALUE
56 ossl_rsa_new(EVP_PKEY *pkey)
58 VALUE obj;
60 if (!pkey) {
61 obj = rsa_instance(cRSA, RSA_new());
63 else {
64 if (EVP_PKEY_type(pkey->type) != EVP_PKEY_RSA) {
65 ossl_raise(rb_eTypeError, "Not a RSA key!");
67 WrapPKey(cRSA, obj, pkey);
69 if (obj == Qfalse) {
70 ossl_raise(eRSAError, NULL);
73 return obj;
77 * Private
79 static RSA *
80 rsa_generate(int size, int exp)
82 return RSA_generate_key(size, exp,
83 rb_block_given_p() ? ossl_generate_cb : NULL,
84 NULL);
87 static VALUE
88 ossl_rsa_s_generate(int argc, VALUE *argv, VALUE klass)
90 RSA *rsa;
91 VALUE size, exp;
92 VALUE obj;
94 rb_scan_args(argc, argv, "11", &size, &exp);
96 rsa = rsa_generate(NUM2INT(size), NIL_P(exp) ? RSA_F4 : NUM2INT(exp)); /* err handled by rsa_instance */
97 obj = rsa_instance(klass, rsa);
99 if (obj == Qfalse) {
100 RSA_free(rsa);
101 ossl_raise(eRSAError, NULL);
104 return obj;
107 static VALUE
108 ossl_rsa_initialize(int argc, VALUE *argv, VALUE self)
110 EVP_PKEY *pkey;
111 RSA *rsa;
112 BIO *in;
113 char *passwd = NULL;
114 VALUE arg, pass;
116 GetPKey(self, pkey);
117 if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) {
118 rsa = RSA_new();
120 else if (FIXNUM_P(arg)) {
121 rsa = rsa_generate(FIX2INT(arg), NIL_P(pass) ? RSA_F4 : NUM2INT(pass));
122 if (!rsa) ossl_raise(eRSAError, NULL);
124 else {
125 if (!NIL_P(pass)) passwd = StringValuePtr(pass);
126 arg = ossl_to_der_if_possible(arg);
127 in = ossl_obj2bio(arg);
128 rsa = PEM_read_bio_RSAPrivateKey(in, NULL, ossl_pem_passwd_cb, passwd);
129 if (!rsa) {
130 BIO_reset(in);
131 rsa = PEM_read_bio_RSAPublicKey(in, NULL, NULL, NULL);
133 if (!rsa) {
134 BIO_reset(in);
135 rsa = PEM_read_bio_RSA_PUBKEY(in, NULL, NULL, NULL);
137 if (!rsa) {
138 BIO_reset(in);
139 rsa = d2i_RSAPrivateKey_bio(in, NULL);
141 if (!rsa) {
142 BIO_reset(in);
143 rsa = d2i_RSAPublicKey_bio(in, NULL);
145 if (!rsa) {
146 BIO_reset(in);
147 rsa = d2i_RSA_PUBKEY_bio(in, NULL);
149 BIO_free(in);
150 if (!rsa) ossl_raise(eRSAError, "Neither PUB key nor PRIV key:");
152 if (!EVP_PKEY_assign_RSA(pkey, rsa)) {
153 RSA_free(rsa);
154 ossl_raise(eRSAError, NULL);
157 return self;
160 static VALUE
161 ossl_rsa_is_public(VALUE self)
163 EVP_PKEY *pkey;
165 GetPKeyRSA(self, pkey);
167 * SURPRISE! :-))
168 * Every key is public at the same time!
170 return Qtrue;
173 static VALUE
174 ossl_rsa_is_private(VALUE self)
176 EVP_PKEY *pkey;
178 GetPKeyRSA(self, pkey);
180 return (RSA_PRIVATE(self, pkey->pkey.rsa)) ? Qtrue : Qfalse;
183 static VALUE
184 ossl_rsa_export(int argc, VALUE *argv, VALUE self)
186 EVP_PKEY *pkey;
187 BIO *out;
188 const EVP_CIPHER *ciph = NULL;
189 char *passwd = NULL;
190 VALUE cipher, pass, str;
192 GetPKeyRSA(self, pkey);
194 rb_scan_args(argc, argv, "02", &cipher, &pass);
196 if (!NIL_P(cipher)) {
197 ciph = GetCipherPtr(cipher);
198 if (!NIL_P(pass)) {
199 passwd = StringValuePtr(pass);
202 if (!(out = BIO_new(BIO_s_mem()))) {
203 ossl_raise(eRSAError, NULL);
205 if (RSA_HAS_PRIVATE(pkey->pkey.rsa)) {
206 if (!PEM_write_bio_RSAPrivateKey(out, pkey->pkey.rsa, ciph,
207 NULL, 0, ossl_pem_passwd_cb, passwd)) {
208 BIO_free(out);
209 ossl_raise(eRSAError, NULL);
211 } else {
212 if (!PEM_write_bio_RSAPublicKey(out, pkey->pkey.rsa)) {
213 BIO_free(out);
214 ossl_raise(eRSAError, NULL);
217 str = ossl_membio2str(out);
219 return str;
222 static VALUE
223 ossl_rsa_to_der(VALUE self)
225 EVP_PKEY *pkey;
226 int (*i2d_func)_((const RSA*, unsigned char**));
227 unsigned char *p;
228 long len;
229 VALUE str;
231 GetPKeyRSA(self, pkey);
232 if(RSA_HAS_PRIVATE(pkey->pkey.rsa))
233 i2d_func = i2d_RSAPrivateKey;
234 else
235 i2d_func = i2d_RSAPublicKey;
236 if((len = i2d_func(pkey->pkey.rsa, NULL)) <= 0)
237 ossl_raise(eRSAError, NULL);
238 str = rb_str_new(0, len);
239 p = RSTRING(str)->ptr;
240 if(i2d_func(pkey->pkey.rsa, &p) < 0)
241 ossl_raise(eRSAError, NULL);
242 ossl_str_adjust(str, p);
244 return str;
247 #define ossl_rsa_buf_size(pkey) (RSA_size((pkey)->pkey.rsa)+16)
249 static VALUE
250 ossl_rsa_public_encrypt(int argc, VALUE *argv, VALUE self)
252 EVP_PKEY *pkey;
253 int buf_len, pad;
254 VALUE str, buffer, padding;
256 GetPKeyRSA(self, pkey);
257 rb_scan_args(argc, argv, "11", &buffer, &padding);
258 pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding);
259 StringValue(buffer);
260 str = rb_str_new(0, ossl_rsa_buf_size(pkey));
261 buf_len = RSA_public_encrypt(RSTRING(buffer)->len, RSTRING(buffer)->ptr,
262 RSTRING(str)->ptr, pkey->pkey.rsa,
263 pad);
264 if (buf_len < 0) ossl_raise(eRSAError, NULL);
265 RSTRING(str)->len = buf_len;
266 RSTRING(str)->ptr[buf_len] = 0;
268 return str;
271 static VALUE
272 ossl_rsa_public_decrypt(int argc, VALUE *argv, VALUE self)
274 EVP_PKEY *pkey;
275 int buf_len, pad;
276 VALUE str, buffer, padding;
278 GetPKeyRSA(self, pkey);
279 rb_scan_args(argc, argv, "11", &buffer, &padding);
280 pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding);
281 StringValue(buffer);
282 str = rb_str_new(0, ossl_rsa_buf_size(pkey));
283 buf_len = RSA_public_decrypt(RSTRING(buffer)->len, RSTRING(buffer)->ptr,
284 RSTRING(str)->ptr, pkey->pkey.rsa,
285 pad);
286 if (buf_len < 0) ossl_raise(eRSAError, NULL);
287 RSTRING(str)->len = buf_len;
288 RSTRING(str)->ptr[buf_len] = 0;
290 return str;
293 static VALUE
294 ossl_rsa_private_encrypt(int argc, VALUE *argv, VALUE self)
296 EVP_PKEY *pkey;
297 int buf_len, pad;
298 VALUE str, buffer, padding;
300 GetPKeyRSA(self, pkey);
301 if (!RSA_PRIVATE(self, pkey->pkey.rsa)) {
302 ossl_raise(eRSAError, "private key needed.");
304 rb_scan_args(argc, argv, "11", &buffer, &padding);
305 pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding);
306 StringValue(buffer);
307 str = rb_str_new(0, ossl_rsa_buf_size(pkey));
308 buf_len = RSA_private_encrypt(RSTRING(buffer)->len, RSTRING(buffer)->ptr,
309 RSTRING(str)->ptr, pkey->pkey.rsa,
310 pad);
311 if (buf_len < 0) ossl_raise(eRSAError, NULL);
312 RSTRING(str)->len = buf_len;
313 RSTRING(str)->ptr[buf_len] = 0;
315 return str;
318 static VALUE
319 ossl_rsa_private_decrypt(int argc, VALUE *argv, VALUE self)
321 EVP_PKEY *pkey;
322 int buf_len, pad;
323 VALUE str, buffer, padding;
325 GetPKeyRSA(self, pkey);
326 if (!RSA_PRIVATE(self, pkey->pkey.rsa)) {
327 ossl_raise(eRSAError, "private key needed.");
329 rb_scan_args(argc, argv, "11", &buffer, &padding);
330 pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding);
331 StringValue(buffer);
332 str = rb_str_new(0, ossl_rsa_buf_size(pkey));
333 buf_len = RSA_private_decrypt(RSTRING(buffer)->len, RSTRING(buffer)->ptr,
334 RSTRING(str)->ptr, pkey->pkey.rsa,
335 pad);
336 if (buf_len < 0) ossl_raise(eRSAError, NULL);
337 RSTRING(str)->len = buf_len;
338 RSTRING(str)->ptr[buf_len] = 0;
340 return str;
344 * Stores all parameters of key to the hash
345 * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
346 * Don't use :-)) (I's up to you)
348 static VALUE
349 ossl_rsa_get_params(VALUE self)
351 EVP_PKEY *pkey;
352 VALUE hash;
354 GetPKeyRSA(self, pkey);
356 hash = rb_hash_new();
358 rb_hash_aset(hash, rb_str_new2("n"), ossl_bn_new(pkey->pkey.rsa->n));
359 rb_hash_aset(hash, rb_str_new2("e"), ossl_bn_new(pkey->pkey.rsa->e));
360 rb_hash_aset(hash, rb_str_new2("d"), ossl_bn_new(pkey->pkey.rsa->d));
361 rb_hash_aset(hash, rb_str_new2("p"), ossl_bn_new(pkey->pkey.rsa->p));
362 rb_hash_aset(hash, rb_str_new2("q"), ossl_bn_new(pkey->pkey.rsa->q));
363 rb_hash_aset(hash, rb_str_new2("dmp1"), ossl_bn_new(pkey->pkey.rsa->dmp1));
364 rb_hash_aset(hash, rb_str_new2("dmq1"), ossl_bn_new(pkey->pkey.rsa->dmq1));
365 rb_hash_aset(hash, rb_str_new2("iqmp"), ossl_bn_new(pkey->pkey.rsa->iqmp));
367 return hash;
371 * Prints all parameters of key to buffer
372 * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
373 * Don't use :-)) (It's up to you)
375 static VALUE
376 ossl_rsa_to_text(VALUE self)
378 EVP_PKEY *pkey;
379 BIO *out;
380 VALUE str;
382 GetPKeyRSA(self, pkey);
383 if (!(out = BIO_new(BIO_s_mem()))) {
384 ossl_raise(eRSAError, NULL);
386 if (!RSA_print(out, pkey->pkey.rsa, 0)) { /* offset = 0 */
387 BIO_free(out);
388 ossl_raise(eRSAError, NULL);
390 str = ossl_membio2str(out);
392 return str;
396 * Makes new instance RSA PUBLIC_KEY from PRIVATE_KEY
398 static VALUE
399 ossl_rsa_to_public_key(VALUE self)
401 EVP_PKEY *pkey;
402 RSA *rsa;
403 VALUE obj;
405 GetPKeyRSA(self, pkey);
406 /* err check performed by rsa_instance */
407 rsa = RSAPublicKey_dup(pkey->pkey.rsa);
408 obj = rsa_instance(CLASS_OF(self), rsa);
409 if (obj == Qfalse) {
410 RSA_free(rsa);
411 ossl_raise(eRSAError, NULL);
413 return obj;
417 * TODO: Test me
418 extern BN_CTX *ossl_bn_ctx;
420 static VALUE
421 ossl_rsa_blinding_on(VALUE self)
423 EVP_PKEY *pkey;
425 GetPKeyRSA(self, pkey);
427 if (RSA_blinding_on(pkey->pkey.rsa, ossl_bn_ctx) != 1) {
428 ossl_raise(eRSAError, NULL);
430 return self;
433 static VALUE
434 ossl_rsa_blinding_off(VALUE self)
436 EVP_PKEY *pkey;
438 GetPKeyRSA(self, pkey);
439 RSA_blinding_off(pkey->pkey.rsa);
441 return self;
445 OSSL_PKEY_BN(rsa, n);
446 OSSL_PKEY_BN(rsa, e);
447 OSSL_PKEY_BN(rsa, d);
448 OSSL_PKEY_BN(rsa, p);
449 OSSL_PKEY_BN(rsa, q);
450 OSSL_PKEY_BN(rsa, dmp1);
451 OSSL_PKEY_BN(rsa, dmq1);
452 OSSL_PKEY_BN(rsa, iqmp);
455 * INIT
457 #define DefRSAConst(x) rb_define_const(cRSA, #x,INT2FIX(RSA_##x))
459 void
460 Init_ossl_rsa()
462 #if 0 /* let rdoc know about mOSSL and mPKey */
463 mOSSL = rb_define_module("OpenSSL");
464 mPKey = rb_define_module_under(mOSSL, "PKey");
465 #endif
467 eRSAError = rb_define_class_under(mPKey, "RSAError", ePKeyError);
469 cRSA = rb_define_class_under(mPKey, "RSA", cPKey);
471 rb_define_singleton_method(cRSA, "generate", ossl_rsa_s_generate, -1);
472 rb_define_method(cRSA, "initialize", ossl_rsa_initialize, -1);
474 rb_define_method(cRSA, "public?", ossl_rsa_is_public, 0);
475 rb_define_method(cRSA, "private?", ossl_rsa_is_private, 0);
476 rb_define_method(cRSA, "to_text", ossl_rsa_to_text, 0);
477 rb_define_method(cRSA, "export", ossl_rsa_export, -1);
478 rb_define_alias(cRSA, "to_pem", "export");
479 rb_define_alias(cRSA, "to_s", "export");
480 rb_define_method(cRSA, "to_der", ossl_rsa_to_der, 0);
481 rb_define_method(cRSA, "public_key", ossl_rsa_to_public_key, 0);
482 rb_define_method(cRSA, "public_encrypt", ossl_rsa_public_encrypt, -1);
483 rb_define_method(cRSA, "public_decrypt", ossl_rsa_public_decrypt, -1);
484 rb_define_method(cRSA, "private_encrypt", ossl_rsa_private_encrypt, -1);
485 rb_define_method(cRSA, "private_decrypt", ossl_rsa_private_decrypt, -1);
487 DEF_OSSL_PKEY_BN(cRSA, rsa, n);
488 DEF_OSSL_PKEY_BN(cRSA, rsa, e);
489 DEF_OSSL_PKEY_BN(cRSA, rsa, d);
490 DEF_OSSL_PKEY_BN(cRSA, rsa, p);
491 DEF_OSSL_PKEY_BN(cRSA, rsa, q);
492 DEF_OSSL_PKEY_BN(cRSA, rsa, dmp1);
493 DEF_OSSL_PKEY_BN(cRSA, rsa, dmq1);
494 DEF_OSSL_PKEY_BN(cRSA, rsa, iqmp);
496 rb_define_method(cRSA, "params", ossl_rsa_get_params, 0);
498 DefRSAConst(PKCS1_PADDING);
499 DefRSAConst(SSLV23_PADDING);
500 DefRSAConst(NO_PADDING);
501 DefRSAConst(PKCS1_OAEP_PADDING);
504 * TODO: Test it
505 rb_define_method(cRSA, "blinding_on!", ossl_rsa_blinding_on, 0);
506 rb_define_method(cRSA, "blinding_off!", ossl_rsa_blinding_off, 0);
510 #else /* defined NO_RSA */
511 # warning >>> OpenSSL is compiled without RSA support <<<
512 void
513 Init_ossl_rsa()
515 rb_warning("OpenSSL is compiled without RSA support");
517 #endif /* NO_RSA */