Updated MSpec source to 1c3ee1c8.
[rbx.git] / stdlib / ext / openssl / ossl_pkey.c
blobc797275786eef5ff7fdc0d625d98c8e91ecf5eea
1 /*
2 * $Id: ossl_pkey.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 #include "ossl.h"
14 * Classes
16 VALUE mPKey;
17 VALUE cPKey;
18 VALUE ePKeyError;
19 ID id_private_q;
22 * callback for generating keys
24 void
25 ossl_generate_cb(int p, int n, void *arg)
27 VALUE ary;
29 ary = rb_ary_new2(2);
30 rb_ary_store(ary, 0, INT2NUM(p));
31 rb_ary_store(ary, 1, INT2NUM(n));
33 rb_yield(ary);
37 * Public
39 VALUE
40 ossl_pkey_new(EVP_PKEY *pkey)
42 if (!pkey) {
43 ossl_raise(ePKeyError, "Cannot make new key from NULL.");
45 switch (EVP_PKEY_type(pkey->type)) {
46 #if !defined(OPENSSL_NO_RSA)
47 case EVP_PKEY_RSA:
48 return ossl_rsa_new(pkey);
49 #endif
50 #if !defined(OPENSSL_NO_DSA)
51 case EVP_PKEY_DSA:
52 return ossl_dsa_new(pkey);
53 #endif
54 #if !defined(OPENSSL_NO_DH)
55 case EVP_PKEY_DH:
56 return ossl_dh_new(pkey);
57 #endif
58 default:
59 ossl_raise(ePKeyError, "unsupported key type");
61 return Qnil; /* not reached */
64 VALUE
65 ossl_pkey_new_from_file(VALUE filename)
67 FILE *fp;
68 EVP_PKEY *pkey;
70 SafeStringValue(filename);
71 if (!(fp = fopen(RSTRING(filename)->ptr, "r"))) {
72 ossl_raise(ePKeyError, "%s", strerror(errno));
75 pkey = PEM_read_PrivateKey(fp, NULL, ossl_pem_passwd_cb, NULL);
76 fclose(fp);
77 if (!pkey) {
78 ossl_raise(ePKeyError, NULL);
81 return ossl_pkey_new(pkey);
84 EVP_PKEY *
85 GetPKeyPtr(VALUE obj)
87 EVP_PKEY *pkey;
89 SafeGetPKey(obj, pkey);
91 return pkey;
94 EVP_PKEY *
95 GetPrivPKeyPtr(VALUE obj)
97 EVP_PKEY *pkey;
99 if (rb_funcall(obj, id_private_q, 0, NULL) != Qtrue) {
100 ossl_raise(rb_eArgError, "Private key is needed.");
102 SafeGetPKey(obj, pkey);
104 return pkey;
107 EVP_PKEY *
108 DupPKeyPtr(VALUE obj)
110 EVP_PKEY *pkey;
112 SafeGetPKey(obj, pkey);
113 CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY);
115 return pkey;
118 EVP_PKEY *
119 DupPrivPKeyPtr(VALUE obj)
121 EVP_PKEY *pkey;
123 if (rb_funcall(obj, id_private_q, 0, NULL) != Qtrue) {
124 ossl_raise(rb_eArgError, "Private key is needed.");
126 SafeGetPKey(obj, pkey);
127 CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY);
129 return pkey;
133 * Private
135 static VALUE
136 ossl_pkey_alloc(VALUE klass)
138 EVP_PKEY *pkey;
139 VALUE obj;
141 if (!(pkey = EVP_PKEY_new())) {
142 ossl_raise(ePKeyError, NULL);
144 WrapPKey(klass, obj, pkey);
146 return obj;
149 static VALUE
150 ossl_pkey_initialize(VALUE self)
152 if (rb_obj_is_instance_of(self, cPKey)) {
153 ossl_raise(rb_eNotImpError, "OpenSSL::PKey::PKey is an abstract class.");
155 return self;
158 static VALUE
159 ossl_pkey_sign(VALUE self, VALUE digest, VALUE data)
161 EVP_PKEY *pkey;
162 EVP_MD_CTX ctx;
163 int buf_len;
164 VALUE str;
166 if (rb_funcall(self, id_private_q, 0, NULL) != Qtrue) {
167 ossl_raise(rb_eArgError, "Private key is needed.");
169 GetPKey(self, pkey);
170 EVP_SignInit(&ctx, GetDigestPtr(digest));
171 StringValue(data);
172 EVP_SignUpdate(&ctx, RSTRING(data)->ptr, RSTRING(data)->len);
173 str = rb_str_new(0, EVP_PKEY_size(pkey)+16);
174 if (!EVP_SignFinal(&ctx, RSTRING(str)->ptr, &buf_len, pkey))
175 ossl_raise(ePKeyError, NULL);
176 assert(buf_len <= RSTRING(str)->len);
177 RSTRING(str)->len = buf_len;
178 RSTRING(str)->ptr[buf_len] = 0;
180 return str;
183 static VALUE
184 ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data)
186 EVP_PKEY *pkey;
187 EVP_MD_CTX ctx;
189 GetPKey(self, pkey);
190 EVP_VerifyInit(&ctx, GetDigestPtr(digest));
191 StringValue(sig);
192 StringValue(data);
193 EVP_VerifyUpdate(&ctx, RSTRING(data)->ptr, RSTRING(data)->len);
194 switch (EVP_VerifyFinal(&ctx, RSTRING(sig)->ptr, RSTRING(sig)->len, pkey)) {
195 case 0:
196 return Qfalse;
197 case 1:
198 return Qtrue;
199 default:
200 ossl_raise(ePKeyError, NULL);
202 return Qnil; /* dummy */
206 * INIT
208 void
209 Init_ossl_pkey()
211 #if 0 /* let rdoc know about mOSSL */
212 mOSSL = rb_define_module("OpenSSL");
213 #endif
215 mPKey = rb_define_module_under(mOSSL, "PKey");
217 ePKeyError = rb_define_class_under(mPKey, "PKeyError", eOSSLError);
219 cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject);
221 rb_define_alloc_func(cPKey, ossl_pkey_alloc);
222 rb_define_method(cPKey, "initialize", ossl_pkey_initialize, 0);
224 rb_define_method(cPKey, "sign", ossl_pkey_sign, 2);
225 rb_define_method(cPKey, "verify", ossl_pkey_verify, 3);
227 id_private_q = rb_intern("private?");
230 * INIT rsa, dsa
232 Init_ossl_rsa();
233 Init_ossl_dsa();
234 Init_ossl_dh();