1/* 2 * $Id: ossl_x509req.c 32199 2011-06-22 08:41:08Z emboss $ 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#define WrapX509Req(klass, obj, req) do { \ 14 if (!(req)) { \ 15 ossl_raise(rb_eRuntimeError, "Req wasn't initialized!"); \ 16 } \ 17 (obj) = Data_Wrap_Struct((klass), 0, X509_REQ_free, (req)); \ 18} while (0) 19#define GetX509Req(obj, req) do { \ 20 Data_Get_Struct((obj), X509_REQ, (req)); \ 21 if (!(req)) { \ 22 ossl_raise(rb_eRuntimeError, "Req wasn't initialized!"); \ 23 } \ 24} while (0) 25#define SafeGetX509Req(obj, req) do { \ 26 OSSL_Check_Kind((obj), cX509Req); \ 27 GetX509Req((obj), (req)); \ 28} while (0) 29 30/* 31 * Classes 32 */ 33VALUE cX509Req; 34VALUE eX509ReqError; 35 36/* 37 * Public functions 38 */ 39VALUE 40ossl_x509req_new(X509_REQ *req) 41{ 42 X509_REQ *new; 43 VALUE obj; 44 45 if (!req) { 46 new = X509_REQ_new(); 47 } else { 48 new = X509_REQ_dup(req); 49 } 50 if (!new) { 51 ossl_raise(eX509ReqError, NULL); 52 } 53 WrapX509Req(cX509Req, obj, new); 54 55 return obj; 56} 57 58X509_REQ * 59GetX509ReqPtr(VALUE obj) 60{ 61 X509_REQ *req; 62 63 SafeGetX509Req(obj, req); 64 65 return req; 66} 67 68X509_REQ * 69DupX509ReqPtr(VALUE obj) 70{ 71 X509_REQ *req, *new; 72 73 SafeGetX509Req(obj, req); 74 if (!(new = X509_REQ_dup(req))) { 75 ossl_raise(eX509ReqError, NULL); 76 } 77 78 return new; 79} 80 81/* 82 * Private functions 83 */ 84static VALUE 85ossl_x509req_alloc(VALUE klass) 86{ 87 X509_REQ *req; 88 VALUE obj; 89 90 if (!(req = X509_REQ_new())) { 91 ossl_raise(eX509ReqError, NULL); 92 } 93 WrapX509Req(klass, obj, req); 94 95 return obj; 96} 97 98static VALUE 99ossl_x509req_initialize(int argc, VALUE *argv, VALUE self) 100{ 101 BIO *in; 102 X509_REQ *req, *x = DATA_PTR(self); 103 VALUE arg; 104 105 if (rb_scan_args(argc, argv, "01", &arg) == 0) { 106 return self; 107 } 108 arg = ossl_to_der_if_possible(arg); 109 in = ossl_obj2bio(arg); 110 req = PEM_read_bio_X509_REQ(in, &x, NULL, NULL); 111 DATA_PTR(self) = x; 112 if (!req) { 113 OSSL_BIO_reset(in); 114 req = d2i_X509_REQ_bio(in, &x); 115 DATA_PTR(self) = x; 116 } 117 BIO_free(in); 118 if (!req) ossl_raise(eX509ReqError, NULL); 119 120 return self; 121} 122 123static VALUE 124ossl_x509req_copy(VALUE self, VALUE other) 125{ 126 X509_REQ *a, *b, *req; 127 128 rb_check_frozen(self); 129 if (self == other) return self; 130 GetX509Req(self, a); 131 SafeGetX509Req(other, b); 132 if (!(req = X509_REQ_dup(b))) { 133 ossl_raise(eX509ReqError, NULL); 134 } 135 X509_REQ_free(a); 136 DATA_PTR(self) = req; 137 138 return self; 139} 140 141static VALUE 142ossl_x509req_to_pem(VALUE self) 143{ 144 X509_REQ *req; 145 BIO *out; 146 BUF_MEM *buf; 147 VALUE str; 148 149 GetX509Req(self, req); 150 if (!(out = BIO_new(BIO_s_mem()))) { 151 ossl_raise(eX509ReqError, NULL); 152 } 153 if (!PEM_write_bio_X509_REQ(out, req)) { 154 BIO_free(out); 155 ossl_raise(eX509ReqError, NULL); 156 } 157 BIO_get_mem_ptr(out, &buf); 158 str = rb_str_new(buf->data, buf->length); 159 BIO_free(out); 160 161 return str; 162} 163 164static VALUE 165ossl_x509req_to_der(VALUE self) 166{ 167 X509_REQ *req; 168 VALUE str; 169 long len; 170 unsigned char *p; 171 172 GetX509Req(self, req); 173 if ((len = i2d_X509_REQ(req, NULL)) <= 0) 174 ossl_raise(eX509ReqError, NULL); 175 str = rb_str_new(0, len); 176 p = (unsigned char *)RSTRING_PTR(str); 177 if (i2d_X509_REQ(req, &p) <= 0) 178 ossl_raise(eX509ReqError, NULL); 179 ossl_str_adjust(str, p); 180 181 return str; 182} 183 184static VALUE 185ossl_x509req_to_text(VALUE self) 186{ 187 X509_REQ *req; 188 BIO *out; 189 BUF_MEM *buf; 190 VALUE str; 191 192 GetX509Req(self, req); 193 if (!(out = BIO_new(BIO_s_mem()))) { 194 ossl_raise(eX509ReqError, NULL); 195 } 196 if (!X509_REQ_print(out, req)) { 197 BIO_free(out); 198 ossl_raise(eX509ReqError, NULL); 199 } 200 BIO_get_mem_ptr(out, &buf); 201 str = rb_str_new(buf->data, buf->length); 202 BIO_free(out); 203 204 return str; 205} 206 207#if 0 208/* 209 * Makes X509 from X509_REQuest 210 */ 211static VALUE 212ossl_x509req_to_x509(VALUE self, VALUE days, VALUE key) 213{ 214 X509_REQ *req; 215 X509 *x509; 216 217 GetX509Req(self, req); 218 ... 219 if (!(x509 = X509_REQ_to_X509(req, d, pkey))) { 220 ossl_raise(eX509ReqError, NULL); 221 } 222 223 return ossl_x509_new(x509); 224} 225#endif 226 227static VALUE 228ossl_x509req_get_version(VALUE self) 229{ 230 X509_REQ *req; 231 long version; 232 233 GetX509Req(self, req); 234 version = X509_REQ_get_version(req); 235 236 return LONG2FIX(version); 237} 238 239static VALUE 240ossl_x509req_set_version(VALUE self, VALUE version) 241{ 242 X509_REQ *req; 243 long ver; 244 245 if ((ver = FIX2LONG(version)) < 0) { 246 ossl_raise(eX509ReqError, "version must be >= 0!"); 247 } 248 GetX509Req(self, req); 249 if (!X509_REQ_set_version(req, ver)) { 250 ossl_raise(eX509ReqError, NULL); 251 } 252 253 return version; 254} 255 256static VALUE 257ossl_x509req_get_subject(VALUE self) 258{ 259 X509_REQ *req; 260 X509_NAME *name; 261 262 GetX509Req(self, req); 263 if (!(name = X509_REQ_get_subject_name(req))) { /* NO DUP - don't free */ 264 ossl_raise(eX509ReqError, NULL); 265 } 266 267 return ossl_x509name_new(name); 268} 269 270static VALUE 271ossl_x509req_set_subject(VALUE self, VALUE subject) 272{ 273 X509_REQ *req; 274 275 GetX509Req(self, req); 276 /* DUPs name */ 277 if (!X509_REQ_set_subject_name(req, GetX509NamePtr(subject))) { 278 ossl_raise(eX509ReqError, NULL); 279 } 280 281 return subject; 282} 283 284static VALUE 285ossl_x509req_get_signature_algorithm(VALUE self) 286{ 287 X509_REQ *req; 288 BIO *out; 289 BUF_MEM *buf; 290 VALUE str; 291 292 GetX509Req(self, req); 293 294 if (!(out = BIO_new(BIO_s_mem()))) { 295 ossl_raise(eX509ReqError, NULL); 296 } 297 if (!i2a_ASN1_OBJECT(out, req->sig_alg->algorithm)) { 298 BIO_free(out); 299 ossl_raise(eX509ReqError, NULL); 300 } 301 BIO_get_mem_ptr(out, &buf); 302 str = rb_str_new(buf->data, buf->length); 303 BIO_free(out); 304 return str; 305} 306 307static VALUE 308ossl_x509req_get_public_key(VALUE self) 309{ 310 X509_REQ *req; 311 EVP_PKEY *pkey; 312 313 GetX509Req(self, req); 314 if (!(pkey = X509_REQ_get_pubkey(req))) { /* adds reference */ 315 ossl_raise(eX509ReqError, NULL); 316 } 317 318 return ossl_pkey_new(pkey); /* NO DUP - OK */ 319} 320 321static VALUE 322ossl_x509req_set_public_key(VALUE self, VALUE key) 323{ 324 X509_REQ *req; 325 EVP_PKEY *pkey; 326 327 GetX509Req(self, req); 328 pkey = GetPKeyPtr(key); /* NO NEED TO DUP */ 329 if (!X509_REQ_set_pubkey(req, pkey)) { 330 ossl_raise(eX509ReqError, NULL); 331 } 332 333 return key; 334} 335 336static VALUE 337ossl_x509req_sign(VALUE self, VALUE key, VALUE digest) 338{ 339 X509_REQ *req; 340 EVP_PKEY *pkey; 341 const EVP_MD *md; 342 343 GetX509Req(self, req); 344 pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */ 345 md = GetDigestPtr(digest); 346 if (!X509_REQ_sign(req, pkey, md)) { 347 ossl_raise(eX509ReqError, NULL); 348 } 349 350 return self; 351} 352 353/* 354 * Checks that cert signature is made with PRIVversion of this PUBLIC 'key' 355 */ 356static VALUE 357ossl_x509req_verify(VALUE self, VALUE key) 358{ 359 X509_REQ *req; 360 EVP_PKEY *pkey; 361 int i; 362 363 GetX509Req(self, req); 364 pkey = GetPKeyPtr(key); /* NO NEED TO DUP */ 365 if ((i = X509_REQ_verify(req, pkey)) < 0) { 366 ossl_raise(eX509ReqError, NULL); 367 } 368 if (i > 0) { 369 return Qtrue; 370 } 371 372 return Qfalse; 373} 374 375static VALUE 376ossl_x509req_get_attributes(VALUE self) 377{ 378 X509_REQ *req; 379 int count, i; 380 X509_ATTRIBUTE *attr; 381 VALUE ary; 382 383 GetX509Req(self, req); 384 385 count = X509_REQ_get_attr_count(req); 386 if (count < 0) { 387 OSSL_Debug("count < 0???"); 388 return rb_ary_new(); 389 } 390 ary = rb_ary_new2(count); 391 for (i=0; i<count; i++) { 392 attr = X509_REQ_get_attr(req, i); 393 rb_ary_push(ary, ossl_x509attr_new(attr)); 394 } 395 396 return ary; 397} 398 399static VALUE 400ossl_x509req_set_attributes(VALUE self, VALUE ary) 401{ 402 X509_REQ *req; 403 X509_ATTRIBUTE *attr; 404 int i; 405 VALUE item; 406 407 Check_Type(ary, T_ARRAY); 408 for (i=0;i<RARRAY_LEN(ary); i++) { 409 OSSL_Check_Kind(RARRAY_PTR(ary)[i], cX509Attr); 410 } 411 GetX509Req(self, req); 412 sk_X509_ATTRIBUTE_pop_free(req->req_info->attributes, X509_ATTRIBUTE_free); 413 req->req_info->attributes = NULL; 414 for (i=0;i<RARRAY_LEN(ary); i++) { 415 item = RARRAY_PTR(ary)[i]; 416 attr = DupX509AttrPtr(item); 417 if (!X509_REQ_add1_attr(req, attr)) { 418 ossl_raise(eX509ReqError, NULL); 419 } 420 } 421 return ary; 422} 423 424static VALUE 425ossl_x509req_add_attribute(VALUE self, VALUE attr) 426{ 427 X509_REQ *req; 428 429 GetX509Req(self, req); 430 if (!X509_REQ_add1_attr(req, DupX509AttrPtr(attr))) { 431 ossl_raise(eX509ReqError, NULL); 432 } 433 434 return attr; 435} 436 437/* 438 * X509_REQUEST init 439 */ 440void 441Init_ossl_x509req() 442{ 443 eX509ReqError = rb_define_class_under(mX509, "RequestError", eOSSLError); 444 445 cX509Req = rb_define_class_under(mX509, "Request", rb_cObject); 446 447 rb_define_alloc_func(cX509Req, ossl_x509req_alloc); 448 rb_define_method(cX509Req, "initialize", ossl_x509req_initialize, -1); 449 rb_define_copy_func(cX509Req, ossl_x509req_copy); 450 451 rb_define_method(cX509Req, "to_pem", ossl_x509req_to_pem, 0); 452 rb_define_method(cX509Req, "to_der", ossl_x509req_to_der, 0); 453 rb_define_alias(cX509Req, "to_s", "to_pem"); 454 rb_define_method(cX509Req, "to_text", ossl_x509req_to_text, 0); 455 rb_define_method(cX509Req, "version", ossl_x509req_get_version, 0); 456 rb_define_method(cX509Req, "version=", ossl_x509req_set_version, 1); 457 rb_define_method(cX509Req, "subject", ossl_x509req_get_subject, 0); 458 rb_define_method(cX509Req, "subject=", ossl_x509req_set_subject, 1); 459 rb_define_method(cX509Req, "signature_algorithm", ossl_x509req_get_signature_algorithm, 0); 460 rb_define_method(cX509Req, "public_key", ossl_x509req_get_public_key, 0); 461 rb_define_method(cX509Req, "public_key=", ossl_x509req_set_public_key, 1); 462 rb_define_method(cX509Req, "sign", ossl_x509req_sign, 2); 463 rb_define_method(cX509Req, "verify", ossl_x509req_verify, 1); 464 rb_define_method(cX509Req, "attributes", ossl_x509req_get_attributes, 0); 465 rb_define_method(cX509Req, "attributes=", ossl_x509req_set_attributes, 1); 466 rb_define_method(cX509Req, "add_attribute", ossl_x509req_add_attribute, 1); 467} 468 469