Ruby
2.0.0p247(2013-06-27revision41674)
|
00001 /* 00002 * $Id: ossl_ns_spki.c 33497 2011-10-20 17:22:09Z 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 #define WrapSPKI(klass, obj, spki) do { \ 00014 if (!(spki)) { \ 00015 ossl_raise(rb_eRuntimeError, "SPKI wasn't initialized!"); \ 00016 } \ 00017 (obj) = Data_Wrap_Struct((klass), 0, NETSCAPE_SPKI_free, (spki)); \ 00018 } while (0) 00019 #define GetSPKI(obj, spki) do { \ 00020 Data_Get_Struct((obj), NETSCAPE_SPKI, (spki)); \ 00021 if (!(spki)) { \ 00022 ossl_raise(rb_eRuntimeError, "SPKI wasn't initialized!"); \ 00023 } \ 00024 } while (0) 00025 00026 /* 00027 * Classes 00028 */ 00029 VALUE mNetscape; 00030 VALUE cSPKI; 00031 VALUE eSPKIError; 00032 00033 /* 00034 * Public functions 00035 */ 00036 00037 /* 00038 * Private functions 00039 */ 00040 static VALUE 00041 ossl_spki_alloc(VALUE klass) 00042 { 00043 NETSCAPE_SPKI *spki; 00044 VALUE obj; 00045 00046 if (!(spki = NETSCAPE_SPKI_new())) { 00047 ossl_raise(eSPKIError, NULL); 00048 } 00049 WrapSPKI(klass, obj, spki); 00050 00051 return obj; 00052 } 00053 00054 /* 00055 * call-seq: 00056 * SPKI.new([request]) => spki 00057 * 00058 * === Parameters 00059 * * +request+ - optional raw request, either in PEM or DER format. 00060 */ 00061 static VALUE 00062 ossl_spki_initialize(int argc, VALUE *argv, VALUE self) 00063 { 00064 NETSCAPE_SPKI *spki; 00065 VALUE buffer; 00066 const unsigned char *p; 00067 00068 if (rb_scan_args(argc, argv, "01", &buffer) == 0) { 00069 return self; 00070 } 00071 StringValue(buffer); 00072 if (!(spki = NETSCAPE_SPKI_b64_decode(RSTRING_PTR(buffer), -1))) { 00073 p = (unsigned char *)RSTRING_PTR(buffer); 00074 if (!(spki = d2i_NETSCAPE_SPKI(NULL, &p, RSTRING_LEN(buffer)))) { 00075 ossl_raise(eSPKIError, NULL); 00076 } 00077 } 00078 NETSCAPE_SPKI_free(DATA_PTR(self)); 00079 DATA_PTR(self) = spki; 00080 ERR_clear_error(); 00081 00082 return self; 00083 } 00084 00085 /* 00086 * call-seq: 00087 * spki.to_der => DER-encoded string 00088 * 00089 * Returns the DER encoding of this SPKI. 00090 */ 00091 static VALUE 00092 ossl_spki_to_der(VALUE self) 00093 { 00094 NETSCAPE_SPKI *spki; 00095 VALUE str; 00096 long len; 00097 unsigned char *p; 00098 00099 GetSPKI(self, spki); 00100 if ((len = i2d_NETSCAPE_SPKI(spki, NULL)) <= 0) 00101 ossl_raise(eX509CertError, NULL); 00102 str = rb_str_new(0, len); 00103 p = (unsigned char *)RSTRING_PTR(str); 00104 if (i2d_NETSCAPE_SPKI(spki, &p) <= 0) 00105 ossl_raise(eX509CertError, NULL); 00106 ossl_str_adjust(str, p); 00107 00108 return str; 00109 } 00110 00111 /* 00112 * call-seq: 00113 * spki.to_pem => PEM-encoded string 00114 * 00115 * Returns the PEM encoding of this SPKI. 00116 */ 00117 static VALUE 00118 ossl_spki_to_pem(VALUE self) 00119 { 00120 NETSCAPE_SPKI *spki; 00121 char *data; 00122 VALUE str; 00123 00124 GetSPKI(self, spki); 00125 if (!(data = NETSCAPE_SPKI_b64_encode(spki))) { 00126 ossl_raise(eSPKIError, NULL); 00127 } 00128 str = ossl_buf2str(data, rb_long2int(strlen(data))); 00129 00130 return str; 00131 } 00132 00133 /* 00134 * call-seq: 00135 * spki.to_text => string 00136 * 00137 * Returns a textual representation of this SPKI, useful for debugging 00138 * purposes. 00139 */ 00140 static VALUE 00141 ossl_spki_print(VALUE self) 00142 { 00143 NETSCAPE_SPKI *spki; 00144 BIO *out; 00145 BUF_MEM *buf; 00146 VALUE str; 00147 00148 GetSPKI(self, spki); 00149 if (!(out = BIO_new(BIO_s_mem()))) { 00150 ossl_raise(eSPKIError, NULL); 00151 } 00152 if (!NETSCAPE_SPKI_print(out, spki)) { 00153 BIO_free(out); 00154 ossl_raise(eSPKIError, NULL); 00155 } 00156 BIO_get_mem_ptr(out, &buf); 00157 str = rb_str_new(buf->data, buf->length); 00158 BIO_free(out); 00159 00160 return str; 00161 } 00162 00163 /* 00164 * call-seq: 00165 * spki.public_key => pkey 00166 * 00167 * Returns the public key associated with the SPKI, an instance of 00168 * OpenSSL::PKey. 00169 */ 00170 static VALUE 00171 ossl_spki_get_public_key(VALUE self) 00172 { 00173 NETSCAPE_SPKI *spki; 00174 EVP_PKEY *pkey; 00175 00176 GetSPKI(self, spki); 00177 if (!(pkey = NETSCAPE_SPKI_get_pubkey(spki))) { /* adds an reference */ 00178 ossl_raise(eSPKIError, NULL); 00179 } 00180 00181 return ossl_pkey_new(pkey); /* NO DUP - OK */ 00182 } 00183 00184 /* 00185 * call-seq: 00186 * spki.public_key = pub => pkey 00187 * 00188 * === Parameters 00189 * * +pub+ - the public key to be set for this instance 00190 * 00191 * Sets the public key to be associated with the SPKI, an instance of 00192 * OpenSSL::PKey. This should be the public key corresponding to the 00193 * private key used for signing the SPKI. 00194 */ 00195 static VALUE 00196 ossl_spki_set_public_key(VALUE self, VALUE key) 00197 { 00198 NETSCAPE_SPKI *spki; 00199 00200 GetSPKI(self, spki); 00201 if (!NETSCAPE_SPKI_set_pubkey(spki, GetPKeyPtr(key))) { /* NO NEED TO DUP */ 00202 ossl_raise(eSPKIError, NULL); 00203 } 00204 00205 return key; 00206 } 00207 00208 /* 00209 * call-seq: 00210 * spki.challenge => string 00211 * 00212 * Returns the challenge string associated with this SPKI. 00213 */ 00214 static VALUE 00215 ossl_spki_get_challenge(VALUE self) 00216 { 00217 NETSCAPE_SPKI *spki; 00218 00219 GetSPKI(self, spki); 00220 if (spki->spkac->challenge->length <= 0) { 00221 OSSL_Debug("Challenge.length <= 0?"); 00222 return rb_str_new(0, 0); 00223 } 00224 00225 return rb_str_new((const char *)spki->spkac->challenge->data, 00226 spki->spkac->challenge->length); 00227 } 00228 00229 /* 00230 * call-seq: 00231 * spki.challenge = str => string 00232 * 00233 * === Parameters 00234 * * +str+ - the challenge string to be set for this instance 00235 * 00236 * Sets the challenge to be associated with the SPKI. May be used by the 00237 * server, e.g. to prevent replay. 00238 */ 00239 static VALUE 00240 ossl_spki_set_challenge(VALUE self, VALUE str) 00241 { 00242 NETSCAPE_SPKI *spki; 00243 00244 StringValue(str); 00245 GetSPKI(self, spki); 00246 if (!ASN1_STRING_set(spki->spkac->challenge, RSTRING_PTR(str), 00247 RSTRING_LENINT(str))) { 00248 ossl_raise(eSPKIError, NULL); 00249 } 00250 00251 return str; 00252 } 00253 00254 /* 00255 * call-seq: 00256 * spki.sign(key, digest) => spki 00257 * 00258 * === Parameters 00259 * * +key+ - the private key to be used for signing this instance 00260 * * +digest+ - the digest to be used for signing this instance 00261 * 00262 * To sign an SPKI, the private key corresponding to the public key set 00263 * for this instance should be used, in addition to a digest algorithm in 00264 * the form of an OpenSSL::Digest. The private key should be an instance of 00265 * OpenSSL::PKey. 00266 */ 00267 static VALUE 00268 ossl_spki_sign(VALUE self, VALUE key, VALUE digest) 00269 { 00270 NETSCAPE_SPKI *spki; 00271 EVP_PKEY *pkey; 00272 const EVP_MD *md; 00273 00274 pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */ 00275 md = GetDigestPtr(digest); 00276 GetSPKI(self, spki); 00277 if (!NETSCAPE_SPKI_sign(spki, pkey, md)) { 00278 ossl_raise(eSPKIError, NULL); 00279 } 00280 00281 return self; 00282 } 00283 00284 /* 00285 * call-seq: 00286 * spki.verify(key) => boolean 00287 * 00288 * === Parameters 00289 * * +key+ - the public key to be used for verifying the SPKI signature 00290 * 00291 * Returns +true+ if the signature is valid, +false+ otherwise. To verify an 00292 * SPKI, the public key contained within the SPKI should be used. 00293 */ 00294 static VALUE 00295 ossl_spki_verify(VALUE self, VALUE key) 00296 { 00297 NETSCAPE_SPKI *spki; 00298 00299 GetSPKI(self, spki); 00300 switch (NETSCAPE_SPKI_verify(spki, GetPKeyPtr(key))) { /* NO NEED TO DUP */ 00301 case 0: 00302 return Qfalse; 00303 case 1: 00304 return Qtrue; 00305 default: 00306 ossl_raise(eSPKIError, NULL); 00307 } 00308 return Qnil; /* dummy */ 00309 } 00310 00311 /* Document-class: OpenSSL::Netscape::SPKI 00312 * 00313 * A Simple Public Key Infrastructure implementation (pronounced "spookey"). 00314 * The structure is defined as 00315 * PublicKeyAndChallenge ::= SEQUENCE { 00316 * spki SubjectPublicKeyInfo, 00317 * challenge IA5STRING 00318 * } 00319 * 00320 * SignedPublicKeyAndChallenge ::= SEQUENCE { 00321 * publicKeyAndChallenge PublicKeyAndChallenge, 00322 * signatureAlgorithm AlgorithmIdentifier, 00323 * signature BIT STRING 00324 * } 00325 * where the definitions of SubjectPublicKeyInfo and AlgorithmIdentifier can 00326 * be found in RFC5280. SPKI is typically used in browsers for generating 00327 * a public/private key pair and a subsequent certificate request, using 00328 * the HTML <keygen> element. 00329 * 00330 * == Examples 00331 * 00332 * === Creating an SPKI 00333 * key = OpenSSL::PKey::RSA.new 2048 00334 * spki = OpenSSL::Netscape::SPKI.new 00335 * spki.challenge = "RandomChallenge" 00336 * spki.public_key = key.public_key 00337 * spki.sign(key, OpenSSL::Digest::SHA256.new) 00338 * #send a request containing this to a server generating a certificate 00339 * === Verifiying an SPKI request 00340 * request = #... 00341 * spki = OpenSSL::Netscape::SPKI.new request 00342 * unless spki.verify(spki.public_key) 00343 * # signature is invalid 00344 * end 00345 * #proceed 00346 */ 00347 00348 /* Document-module: OpenSSL::Netscape 00349 * 00350 * OpenSSL::Netscape is a namespace for SPKI (Simple Public Key 00351 * Infrastructure) which implements Signed Public Key and Challenge. 00352 * See {RFC 2692}[http://tools.ietf.org/html/rfc2692] and {RFC 00353 * 2693}[http://tools.ietf.org/html/rfc2692] for details. 00354 */ 00355 00356 /* Document-class: OpenSSL::Netscape::SPKIError 00357 * 00358 * Generic Exception class that is raised if an error occurs during an 00359 * operation on an instance of OpenSSL::Netscape::SPKI. 00360 */ 00361 00362 void 00363 Init_ossl_ns_spki() 00364 { 00365 #if 0 00366 mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */ 00367 #endif 00368 00369 mNetscape = rb_define_module_under(mOSSL, "Netscape"); 00370 00371 eSPKIError = rb_define_class_under(mNetscape, "SPKIError", eOSSLError); 00372 00373 cSPKI = rb_define_class_under(mNetscape, "SPKI", rb_cObject); 00374 00375 rb_define_alloc_func(cSPKI, ossl_spki_alloc); 00376 rb_define_method(cSPKI, "initialize", ossl_spki_initialize, -1); 00377 00378 rb_define_method(cSPKI, "to_der", ossl_spki_to_der, 0); 00379 rb_define_method(cSPKI, "to_pem", ossl_spki_to_pem, 0); 00380 rb_define_alias(cSPKI, "to_s", "to_pem"); 00381 rb_define_method(cSPKI, "to_text", ossl_spki_print, 0); 00382 rb_define_method(cSPKI, "public_key", ossl_spki_get_public_key, 0); 00383 rb_define_method(cSPKI, "public_key=", ossl_spki_set_public_key, 1); 00384 rb_define_method(cSPKI, "sign", ossl_spki_sign, 2); 00385 rb_define_method(cSPKI, "verify", ossl_spki_verify, 1); 00386 rb_define_method(cSPKI, "challenge", ossl_spki_get_challenge, 0); 00387 rb_define_method(cSPKI, "challenge=", ossl_spki_set_challenge, 1); 00388 } 00389 00390