Ruby 1.9.3p327(2012-11-10revision37606)
|
00001 /* 00002 * $Id: ossl_pkey.c 33317 2011-09-23 05:17:47Z emboss $ 00003 * 'OpenSSL for Ruby' project 00004 * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz> 00005 * All rights reserved. 00006 */ 00007 /* 00008 * This program is licenced under the same licence as Ruby. 00009 * (See the file 'LICENCE'.) 00010 */ 00011 #include "ossl.h" 00012 00013 /* 00014 * Classes 00015 */ 00016 VALUE mPKey; 00017 VALUE cPKey; 00018 VALUE ePKeyError; 00019 ID id_private_q; 00020 00021 /* 00022 * callback for generating keys 00023 */ 00024 void 00025 ossl_generate_cb(int p, int n, void *arg) 00026 { 00027 VALUE ary; 00028 00029 ary = rb_ary_new2(2); 00030 rb_ary_store(ary, 0, INT2NUM(p)); 00031 rb_ary_store(ary, 1, INT2NUM(n)); 00032 00033 rb_yield(ary); 00034 } 00035 00036 /* 00037 * Public 00038 */ 00039 VALUE 00040 ossl_pkey_new(EVP_PKEY *pkey) 00041 { 00042 if (!pkey) { 00043 ossl_raise(ePKeyError, "Cannot make new key from NULL."); 00044 } 00045 switch (EVP_PKEY_type(pkey->type)) { 00046 #if !defined(OPENSSL_NO_RSA) 00047 case EVP_PKEY_RSA: 00048 return ossl_rsa_new(pkey); 00049 #endif 00050 #if !defined(OPENSSL_NO_DSA) 00051 case EVP_PKEY_DSA: 00052 return ossl_dsa_new(pkey); 00053 #endif 00054 #if !defined(OPENSSL_NO_DH) 00055 case EVP_PKEY_DH: 00056 return ossl_dh_new(pkey); 00057 #endif 00058 #if !defined(OPENSSL_NO_EC) && (OPENSSL_VERSION_NUMBER >= 0x0090802fL) 00059 case EVP_PKEY_EC: 00060 return ossl_ec_new(pkey); 00061 #endif 00062 default: 00063 ossl_raise(ePKeyError, "unsupported key type"); 00064 } 00065 return Qnil; /* not reached */ 00066 } 00067 00068 VALUE 00069 ossl_pkey_new_from_file(VALUE filename) 00070 { 00071 FILE *fp; 00072 EVP_PKEY *pkey; 00073 00074 SafeStringValue(filename); 00075 if (!(fp = fopen(RSTRING_PTR(filename), "r"))) { 00076 ossl_raise(ePKeyError, "%s", strerror(errno)); 00077 } 00078 00079 pkey = PEM_read_PrivateKey(fp, NULL, ossl_pem_passwd_cb, NULL); 00080 fclose(fp); 00081 if (!pkey) { 00082 ossl_raise(ePKeyError, NULL); 00083 } 00084 00085 return ossl_pkey_new(pkey); 00086 } 00087 00088 /* 00089 * call-seq: 00090 * OpenSSL::PKey.read(string [, pwd ] ) -> PKey 00091 * OpenSSL::PKey.read(file [, pwd ]) -> PKey 00092 * 00093 * === Parameters 00094 * * +string+ is a DER- or PEM-encoded string containing an arbitrary private 00095 * or public key. 00096 * * +file+ is an instance of +File+ containing a DER- or PEM-encoded 00097 * arbitrary private or public key. 00098 * * +pwd+ is an optional password in case +string+ or +file+ is an encrypted 00099 * PEM resource. 00100 */ 00101 static VALUE 00102 ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self) 00103 { 00104 EVP_PKEY *pkey; 00105 BIO *bio; 00106 VALUE data, pass; 00107 char *passwd = NULL; 00108 00109 rb_scan_args(argc, argv, "11", &data, &pass); 00110 00111 bio = ossl_obj2bio(data); 00112 if (!(pkey = d2i_PrivateKey_bio(bio, NULL))) { 00113 OSSL_BIO_reset(bio); 00114 if (!NIL_P(pass)) { 00115 passwd = StringValuePtr(pass); 00116 } 00117 if (!(pkey = PEM_read_bio_PrivateKey(bio, NULL, ossl_pem_passwd_cb, passwd))) { 00118 OSSL_BIO_reset(bio); 00119 if (!(pkey = d2i_PUBKEY_bio(bio, NULL))) { 00120 OSSL_BIO_reset(bio); 00121 if (!NIL_P(pass)) { 00122 passwd = StringValuePtr(pass); 00123 } 00124 pkey = PEM_read_bio_PUBKEY(bio, NULL, ossl_pem_passwd_cb, passwd); 00125 } 00126 } 00127 } 00128 00129 BIO_free(bio); 00130 if (!pkey) 00131 ossl_raise(rb_eArgError, "Could not parse PKey"); 00132 return ossl_pkey_new(pkey); 00133 } 00134 00135 EVP_PKEY * 00136 GetPKeyPtr(VALUE obj) 00137 { 00138 EVP_PKEY *pkey; 00139 00140 SafeGetPKey(obj, pkey); 00141 00142 return pkey; 00143 } 00144 00145 EVP_PKEY * 00146 GetPrivPKeyPtr(VALUE obj) 00147 { 00148 EVP_PKEY *pkey; 00149 00150 if (rb_funcall(obj, id_private_q, 0, NULL) != Qtrue) { 00151 ossl_raise(rb_eArgError, "Private key is needed."); 00152 } 00153 SafeGetPKey(obj, pkey); 00154 00155 return pkey; 00156 } 00157 00158 EVP_PKEY * 00159 DupPKeyPtr(VALUE obj) 00160 { 00161 EVP_PKEY *pkey; 00162 00163 SafeGetPKey(obj, pkey); 00164 CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY); 00165 00166 return pkey; 00167 } 00168 00169 EVP_PKEY * 00170 DupPrivPKeyPtr(VALUE obj) 00171 { 00172 EVP_PKEY *pkey; 00173 00174 if (rb_funcall(obj, id_private_q, 0, NULL) != Qtrue) { 00175 ossl_raise(rb_eArgError, "Private key is needed."); 00176 } 00177 SafeGetPKey(obj, pkey); 00178 CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY); 00179 00180 return pkey; 00181 } 00182 00183 /* 00184 * Private 00185 */ 00186 static VALUE 00187 ossl_pkey_alloc(VALUE klass) 00188 { 00189 EVP_PKEY *pkey; 00190 VALUE obj; 00191 00192 if (!(pkey = EVP_PKEY_new())) { 00193 ossl_raise(ePKeyError, NULL); 00194 } 00195 WrapPKey(klass, obj, pkey); 00196 00197 return obj; 00198 } 00199 00200 /* 00201 * call-seq: 00202 * PKeyClass.new -> self 00203 * 00204 * Because PKey is an abstract class, actually calling this method explicitly 00205 * will raise a +NotImplementedError+. 00206 */ 00207 static VALUE 00208 ossl_pkey_initialize(VALUE self) 00209 { 00210 if (rb_obj_is_instance_of(self, cPKey)) { 00211 ossl_raise(rb_eNotImpError, "OpenSSL::PKey::PKey is an abstract class."); 00212 } 00213 return self; 00214 } 00215 00216 /* 00217 * call-seq: 00218 * pkey.sign(digest, data) -> String 00219 * 00220 * To sign the +String+ +data+, +digest+, an instance of OpenSSL::Digest, must 00221 * be provided. The return value is again a +String+ containing the signature. 00222 * A PKeyError is raised should errors occur. 00223 * Any previous state of the +Digest+ instance is irrelevant to the signature 00224 * outcome, the digest instance is reset to its initial state during the 00225 * operation. 00226 * 00227 * == Example 00228 * data = 'Sign me!' 00229 * digest = OpenSSL::Digest::SHA256.new 00230 * pkey = OpenSSL::PKey::RSA.new(2048) 00231 * signature = pkey.sign(digest, data) 00232 */ 00233 static VALUE 00234 ossl_pkey_sign(VALUE self, VALUE digest, VALUE data) 00235 { 00236 EVP_PKEY *pkey; 00237 EVP_MD_CTX ctx; 00238 unsigned int buf_len; 00239 VALUE str; 00240 00241 if (rb_funcall(self, id_private_q, 0, NULL) != Qtrue) { 00242 ossl_raise(rb_eArgError, "Private key is needed."); 00243 } 00244 GetPKey(self, pkey); 00245 EVP_SignInit(&ctx, GetDigestPtr(digest)); 00246 StringValue(data); 00247 EVP_SignUpdate(&ctx, RSTRING_PTR(data), RSTRING_LEN(data)); 00248 str = rb_str_new(0, EVP_PKEY_size(pkey)+16); 00249 if (!EVP_SignFinal(&ctx, (unsigned char *)RSTRING_PTR(str), &buf_len, pkey)) 00250 ossl_raise(ePKeyError, NULL); 00251 assert((long)buf_len <= RSTRING_LEN(str)); 00252 rb_str_set_len(str, buf_len); 00253 00254 return str; 00255 } 00256 00257 /* 00258 * call-seq: 00259 * pkey.verify(digest, signature, data) -> String 00260 * 00261 * To verify the +String+ +signature+, +digest+, an instance of 00262 * OpenSSL::Digest, must be provided to re-compute the message digest of the 00263 * original +data+, also a +String+. The return value is +true+ if the 00264 * signature is valid, +false+ otherwise. A PKeyError is raised should errors 00265 * occur. 00266 * Any previous state of the +Digest+ instance is irrelevant to the validation 00267 * outcome, the digest instance is reset to its initial state during the 00268 * operation. 00269 * 00270 * == Example 00271 * data = 'Sign me!' 00272 * digest = OpenSSL::Digest::SHA256.new 00273 * pkey = OpenSSL::PKey::RSA.new(2048) 00274 * signature = pkey.sign(digest, data) 00275 * pub_key = pkey.public_key 00276 * puts pub_key.verify(digest, signature, data) # => true 00277 */ 00278 static VALUE 00279 ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data) 00280 { 00281 EVP_PKEY *pkey; 00282 EVP_MD_CTX ctx; 00283 00284 GetPKey(self, pkey); 00285 EVP_VerifyInit(&ctx, GetDigestPtr(digest)); 00286 StringValue(sig); 00287 StringValue(data); 00288 EVP_VerifyUpdate(&ctx, RSTRING_PTR(data), RSTRING_LEN(data)); 00289 switch (EVP_VerifyFinal(&ctx, (unsigned char *)RSTRING_PTR(sig), RSTRING_LENINT(sig), pkey)) { 00290 case 0: 00291 return Qfalse; 00292 case 1: 00293 return Qtrue; 00294 default: 00295 ossl_raise(ePKeyError, NULL); 00296 } 00297 return Qnil; /* dummy */ 00298 } 00299 00300 /* 00301 * INIT 00302 */ 00303 void 00304 Init_ossl_pkey() 00305 { 00306 #if 0 00307 mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */ 00308 #endif 00309 00310 /* Document-module: OpenSSL::PKey 00311 * 00312 * == Asymmetric Public Key Algorithms 00313 * 00314 * Asymmetric public key algorithms solve the problem of establishing and 00315 * sharing secret keys to en-/decrypt messages. The key in such an 00316 * algorithm consists of two parts: a public key that may be distributed 00317 * to others and a private key that needs to remain secret. 00318 * 00319 * Messages encrypted with a public key can only be encrypted by 00320 * recipients that are in possession of the associated private key. 00321 * Since public key algorithms are considerably slower than symmetric 00322 * key algorithms (cf. OpenSSL::Cipher) they are often used to establish 00323 * a symmetric key shared between two parties that are in possession of 00324 * each other's public key. 00325 * 00326 * Asymmetric algorithms offer a lot of nice features that are used in a 00327 * lot of different areas. A very common application is the creation and 00328 * validation of digital signatures. To sign a document, the signatory 00329 * generally uses a message digest algorithm (cf. OpenSSL::Digest) to 00330 * compute a digest of the document that is then encrypted (i.e. signed) 00331 * using the private key. Anyone in possession of the public key may then 00332 * verify the signature by computing the message digest of the original 00333 * document on their own, decrypting the signature using the signatory's 00334 * public key and comparing the result to the message digest they 00335 * previously computed. The signature is valid if and only if the 00336 * decrypted signature is equal to this message digest. 00337 * 00338 * The PKey module offers support for three popular public/private key 00339 * algorithms: 00340 * * RSA (OpenSSL::PKey::RSA) 00341 * * DSA (OpenSSL::PKey::DSA) 00342 * * Elliptic Curve Cryptography (OpenSSL::PKey::EC) 00343 * Each of these implementations is in fact a sub-class of the abstract 00344 * PKey class which offers the interface for supporting digital signatures 00345 * in the form of PKey#sign and PKey#verify. 00346 * 00347 * == Diffie-Hellman Key Exchange 00348 * 00349 * Finally PKey also features OpenSSL::PKey::DH, an implementation of 00350 * the Diffie-Hellman key exchange protocol based on discrete logarithms 00351 * in finite fields, the same basis that DSA is built on. 00352 * The Diffie-Hellman protocol can be used to exchange (symmetric) keys 00353 * over insecure channels without needing any prior joint knowledge 00354 * between the participating parties. As the security of DH demands 00355 * relatively long "public keys" (i.e. the part that is overtly 00356 * transmitted between participants) DH tends to be quite slow. If 00357 * security or speed is your primary concern, OpenSSL::PKey::EC offers 00358 * another implementation of the Diffie-Hellman protocol. 00359 * 00360 */ 00361 mPKey = rb_define_module_under(mOSSL, "PKey"); 00362 00363 /* Document-class: OpenSSL::PKey::PKeyError 00364 * 00365 *Raised when errors occur during PKey#sign or PKey#verify. 00366 */ 00367 ePKeyError = rb_define_class_under(mPKey, "PKeyError", eOSSLError); 00368 00369 /* Document-class: OpenSSL::PKey::PKey 00370 * 00371 * An abstract class that bundles signature creation (PKey#sign) and 00372 * validation (PKey#verify) that is common to all implementations except 00373 * OpenSSL::PKey::DH 00374 * * OpenSSL::PKey::RSA 00375 * * OpenSSL::PKey::DSA 00376 * * OpenSSL::PKey::EC 00377 */ 00378 cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject); 00379 00380 rb_define_module_function(mPKey, "read", ossl_pkey_new_from_data, -1); 00381 00382 rb_define_alloc_func(cPKey, ossl_pkey_alloc); 00383 rb_define_method(cPKey, "initialize", ossl_pkey_initialize, 0); 00384 00385 rb_define_method(cPKey, "sign", ossl_pkey_sign, 2); 00386 rb_define_method(cPKey, "verify", ossl_pkey_verify, 3); 00387 00388 id_private_q = rb_intern("private?"); 00389 00390 /* 00391 * INIT rsa, dsa, dh, ec 00392 */ 00393 Init_ossl_rsa(); 00394 Init_ossl_dsa(); 00395 Init_ossl_dh(); 00396 Init_ossl_ec(); 00397 } 00398 00399