1 /*
2 * 'OpenSSL for Ruby' project
3 * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
4 * All rights reserved.
5 */
6 /*
7 * This program is licensed under the same licence as Ruby.
8 * (See the file 'LICENCE'.)
9 */
10 #include "ossl.h"
11
12 #define NewX509Ext(klass) \
13 TypedData_Wrap_Struct((klass), &ossl_x509ext_type, 0)
14 #define SetX509Ext(obj, ext) do { \
15 if (!(ext)) { \
16 ossl_raise(rb_eRuntimeError, "EXT wasn't initialized!"); \
17 } \
18 RTYPEDDATA_DATA(obj) = (ext); \
19 } while (0)
20 #define GetX509Ext(obj, ext) do { \
21 TypedData_Get_Struct((obj), X509_EXTENSION, &ossl_x509ext_type, (ext)); \
22 if (!(ext)) { \
23 ossl_raise(rb_eRuntimeError, "EXT wasn't initialized!"); \
24 } \
25 } while (0)
26 #define MakeX509ExtFactory(klass, obj, ctx) do { \
27 (obj) = TypedData_Wrap_Struct((klass), &ossl_x509extfactory_type, 0); \
28 if (!((ctx) = OPENSSL_malloc(sizeof(X509V3_CTX)))) \
29 ossl_raise(rb_eRuntimeError, "CTX wasn't allocated!"); \
30 X509V3_set_ctx((ctx), NULL, NULL, NULL, NULL, 0); \
31 RTYPEDDATA_DATA(obj) = (ctx); \
32 } while (0)
33 #define GetX509ExtFactory(obj, ctx) do { \
34 TypedData_Get_Struct((obj), X509V3_CTX, &ossl_x509extfactory_type, (ctx)); \
35 if (!(ctx)) { \
36 ossl_raise(rb_eRuntimeError, "CTX wasn't initialized!"); \
37 } \
38 } while (0)
39
40 /*
41 * Classes
42 */
43 VALUE cX509Ext;
44 VALUE cX509ExtFactory;
45 VALUE eX509ExtError;
46
47 static void
ossl_x509ext_free(void * ptr)48 ossl_x509ext_free(void *ptr)
49 {
50 X509_EXTENSION_free(ptr);
51 }
52
53 static const rb_data_type_t ossl_x509ext_type = {
54 "OpenSSL/X509/EXTENSION",
55 {
56 0, ossl_x509ext_free,
57 },
58 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
59 };
60
61 /*
62 * Public
63 */
64 VALUE
ossl_x509ext_new(X509_EXTENSION * ext)65 ossl_x509ext_new(X509_EXTENSION *ext)
66 {
67 X509_EXTENSION *new;
68 VALUE obj;
69
70 obj = NewX509Ext(cX509Ext);
71 if (!ext) {
72 new = X509_EXTENSION_new();
73 } else {
74 new = X509_EXTENSION_dup(ext);
75 }
76 if (!new) {
77 ossl_raise(eX509ExtError, NULL);
78 }
79 SetX509Ext(obj, new);
80
81 return obj;
82 }
83
84 X509_EXTENSION *
GetX509ExtPtr(VALUE obj)85 GetX509ExtPtr(VALUE obj)
86 {
87 X509_EXTENSION *ext;
88
89 GetX509Ext(obj, ext);
90
91 return ext;
92 }
93
94 /*
95 * Private
96 */
97 /*
98 * Ext factory
99 */
100 static void
ossl_x509extfactory_free(void * ctx)101 ossl_x509extfactory_free(void *ctx)
102 {
103 OPENSSL_free(ctx);
104 }
105
106 static const rb_data_type_t ossl_x509extfactory_type = {
107 "OpenSSL/X509/EXTENSION/Factory",
108 {
109 0, ossl_x509extfactory_free,
110 },
111 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
112 };
113
114 static VALUE
ossl_x509extfactory_alloc(VALUE klass)115 ossl_x509extfactory_alloc(VALUE klass)
116 {
117 X509V3_CTX *ctx;
118 VALUE obj;
119
120 MakeX509ExtFactory(klass, obj, ctx);
121 rb_iv_set(obj, "@config", Qnil);
122
123 return obj;
124 }
125
126 static VALUE
ossl_x509extfactory_set_issuer_cert(VALUE self,VALUE cert)127 ossl_x509extfactory_set_issuer_cert(VALUE self, VALUE cert)
128 {
129 X509V3_CTX *ctx;
130
131 GetX509ExtFactory(self, ctx);
132 rb_iv_set(self, "@issuer_certificate", cert);
133 ctx->issuer_cert = GetX509CertPtr(cert); /* NO DUP NEEDED */
134
135 return cert;
136 }
137
138 static VALUE
ossl_x509extfactory_set_subject_cert(VALUE self,VALUE cert)139 ossl_x509extfactory_set_subject_cert(VALUE self, VALUE cert)
140 {
141 X509V3_CTX *ctx;
142
143 GetX509ExtFactory(self, ctx);
144 rb_iv_set(self, "@subject_certificate", cert);
145 ctx->subject_cert = GetX509CertPtr(cert); /* NO DUP NEEDED */
146
147 return cert;
148 }
149
150 static VALUE
ossl_x509extfactory_set_subject_req(VALUE self,VALUE req)151 ossl_x509extfactory_set_subject_req(VALUE self, VALUE req)
152 {
153 X509V3_CTX *ctx;
154
155 GetX509ExtFactory(self, ctx);
156 rb_iv_set(self, "@subject_request", req);
157 ctx->subject_req = GetX509ReqPtr(req); /* NO DUP NEEDED */
158
159 return req;
160 }
161
162 static VALUE
ossl_x509extfactory_set_crl(VALUE self,VALUE crl)163 ossl_x509extfactory_set_crl(VALUE self, VALUE crl)
164 {
165 X509V3_CTX *ctx;
166
167 GetX509ExtFactory(self, ctx);
168 rb_iv_set(self, "@crl", crl);
169 ctx->crl = GetX509CRLPtr(crl); /* NO DUP NEEDED */
170
171 return crl;
172 }
173
174 static VALUE
ossl_x509extfactory_initialize(int argc,VALUE * argv,VALUE self)175 ossl_x509extfactory_initialize(int argc, VALUE *argv, VALUE self)
176 {
177 /*X509V3_CTX *ctx;*/
178 VALUE issuer_cert, subject_cert, subject_req, crl;
179
180 /*GetX509ExtFactory(self, ctx);*/
181
182 rb_scan_args(argc, argv, "04",
183 &issuer_cert, &subject_cert, &subject_req, &crl);
184 if (!NIL_P(issuer_cert))
185 ossl_x509extfactory_set_issuer_cert(self, issuer_cert);
186 if (!NIL_P(subject_cert))
187 ossl_x509extfactory_set_subject_cert(self, subject_cert);
188 if (!NIL_P(subject_req))
189 ossl_x509extfactory_set_subject_req(self, subject_req);
190 if (!NIL_P(crl))
191 ossl_x509extfactory_set_crl(self, crl);
192
193 return self;
194 }
195
196 /*
197 * call-seq:
198 * ef.create_ext(ln_or_sn, "value", critical = false) -> X509::Extension
199 * ef.create_ext(ln_or_sn, "critical,value") -> X509::Extension
200 *
201 * Creates a new X509::Extension with passed values. See also x509v3_config(5).
202 */
203 static VALUE
ossl_x509extfactory_create_ext(int argc,VALUE * argv,VALUE self)204 ossl_x509extfactory_create_ext(int argc, VALUE *argv, VALUE self)
205 {
206 X509V3_CTX *ctx;
207 X509_EXTENSION *ext;
208 VALUE oid, value, critical, valstr, obj;
209 int nid;
210 VALUE rconf;
211 CONF *conf;
212
213 rb_scan_args(argc, argv, "21", &oid, &value, &critical);
214 StringValueCStr(oid);
215 StringValue(value);
216 if(NIL_P(critical)) critical = Qfalse;
217
218 nid = OBJ_ln2nid(RSTRING_PTR(oid));
219 if(!nid) nid = OBJ_sn2nid(RSTRING_PTR(oid));
220 if(!nid) ossl_raise(eX509ExtError, "unknown OID `%"PRIsVALUE"'", oid);
221
222 valstr = rb_str_new2(RTEST(critical) ? "critical," : "");
223 rb_str_append(valstr, value);
224 StringValueCStr(valstr);
225
226 GetX509ExtFactory(self, ctx);
227 obj = NewX509Ext(cX509Ext);
228 rconf = rb_iv_get(self, "@config");
229 conf = NIL_P(rconf) ? NULL : DupConfigPtr(rconf);
230 X509V3_set_nconf(ctx, conf);
231 ext = X509V3_EXT_nconf_nid(conf, ctx, nid, RSTRING_PTR(valstr));
232 X509V3_set_ctx_nodb(ctx);
233 NCONF_free(conf);
234 if (!ext){
235 ossl_raise(eX509ExtError, "%"PRIsVALUE" = %"PRIsVALUE, oid, valstr);
236 }
237 SetX509Ext(obj, ext);
238
239 return obj;
240 }
241
242 /*
243 * Ext
244 */
245 static VALUE
ossl_x509ext_alloc(VALUE klass)246 ossl_x509ext_alloc(VALUE klass)
247 {
248 X509_EXTENSION *ext;
249 VALUE obj;
250
251 obj = NewX509Ext(klass);
252 if(!(ext = X509_EXTENSION_new())){
253 ossl_raise(eX509ExtError, NULL);
254 }
255 SetX509Ext(obj, ext);
256
257 return obj;
258 }
259
260 /*
261 * call-seq:
262 * OpenSSL::X509::Extension.new(der)
263 * OpenSSL::X509::Extension.new(oid, value)
264 * OpenSSL::X509::Extension.new(oid, value, critical)
265 *
266 * Creates an X509 extension.
267 *
268 * The extension may be created from _der_ data or from an extension _oid_
269 * and _value_. The _oid_ may be either an OID or an extension name. If
270 * _critical_ is +true+ the extension is marked critical.
271 */
272 static VALUE
ossl_x509ext_initialize(int argc,VALUE * argv,VALUE self)273 ossl_x509ext_initialize(int argc, VALUE *argv, VALUE self)
274 {
275 VALUE oid, value, critical;
276 const unsigned char *p;
277 X509_EXTENSION *ext, *x;
278
279 GetX509Ext(self, ext);
280 if(rb_scan_args(argc, argv, "12", &oid, &value, &critical) == 1){
281 oid = ossl_to_der_if_possible(oid);
282 StringValue(oid);
283 p = (unsigned char *)RSTRING_PTR(oid);
284 x = d2i_X509_EXTENSION(&ext, &p, RSTRING_LEN(oid));
285 DATA_PTR(self) = ext;
286 if(!x)
287 ossl_raise(eX509ExtError, NULL);
288 return self;
289 }
290 rb_funcall(self, rb_intern("oid="), 1, oid);
291 rb_funcall(self, rb_intern("value="), 1, value);
292 if(argc > 2) rb_funcall(self, rb_intern("critical="), 1, critical);
293
294 return self;
295 }
296
297 static VALUE
ossl_x509ext_initialize_copy(VALUE self,VALUE other)298 ossl_x509ext_initialize_copy(VALUE self, VALUE other)
299 {
300 X509_EXTENSION *ext, *ext_other, *ext_new;
301
302 rb_check_frozen(self);
303 GetX509Ext(self, ext);
304 GetX509Ext(other, ext_other);
305
306 ext_new = X509_EXTENSION_dup(ext_other);
307 if (!ext_new)
308 ossl_raise(eX509ExtError, "X509_EXTENSION_dup");
309
310 SetX509Ext(self, ext_new);
311 X509_EXTENSION_free(ext);
312
313 return self;
314 }
315
316 static VALUE
ossl_x509ext_set_oid(VALUE self,VALUE oid)317 ossl_x509ext_set_oid(VALUE self, VALUE oid)
318 {
319 X509_EXTENSION *ext;
320 ASN1_OBJECT *obj;
321
322 GetX509Ext(self, ext);
323 obj = OBJ_txt2obj(StringValueCStr(oid), 0);
324 if (!obj)
325 ossl_raise(eX509ExtError, "OBJ_txt2obj");
326 if (!X509_EXTENSION_set_object(ext, obj)) {
327 ASN1_OBJECT_free(obj);
328 ossl_raise(eX509ExtError, "X509_EXTENSION_set_object");
329 }
330 ASN1_OBJECT_free(obj);
331
332 return oid;
333 }
334
335 static VALUE
ossl_x509ext_set_value(VALUE self,VALUE data)336 ossl_x509ext_set_value(VALUE self, VALUE data)
337 {
338 X509_EXTENSION *ext;
339 ASN1_OCTET_STRING *asn1s;
340
341 GetX509Ext(self, ext);
342 data = ossl_to_der_if_possible(data);
343 StringValue(data);
344 asn1s = X509_EXTENSION_get_data(ext);
345
346 if (!ASN1_OCTET_STRING_set(asn1s, (unsigned char *)RSTRING_PTR(data),
347 RSTRING_LENINT(data))) {
348 ossl_raise(eX509ExtError, "ASN1_OCTET_STRING_set");
349 }
350
351 return data;
352 }
353
354 static VALUE
ossl_x509ext_set_critical(VALUE self,VALUE flag)355 ossl_x509ext_set_critical(VALUE self, VALUE flag)
356 {
357 X509_EXTENSION *ext;
358
359 GetX509Ext(self, ext);
360 X509_EXTENSION_set_critical(ext, RTEST(flag) ? 1 : 0);
361
362 return flag;
363 }
364
365 static VALUE
ossl_x509ext_get_oid(VALUE obj)366 ossl_x509ext_get_oid(VALUE obj)
367 {
368 X509_EXTENSION *ext;
369 ASN1_OBJECT *extobj;
370 BIO *out;
371 VALUE ret;
372 int nid;
373
374 GetX509Ext(obj, ext);
375 extobj = X509_EXTENSION_get_object(ext);
376 if ((nid = OBJ_obj2nid(extobj)) != NID_undef)
377 ret = rb_str_new2(OBJ_nid2sn(nid));
378 else{
379 if (!(out = BIO_new(BIO_s_mem())))
380 ossl_raise(eX509ExtError, NULL);
381 i2a_ASN1_OBJECT(out, extobj);
382 ret = ossl_membio2str(out);
383 }
384
385 return ret;
386 }
387
388 static VALUE
ossl_x509ext_get_value(VALUE obj)389 ossl_x509ext_get_value(VALUE obj)
390 {
391 X509_EXTENSION *ext;
392 BIO *out;
393 VALUE ret;
394
395 GetX509Ext(obj, ext);
396 if (!(out = BIO_new(BIO_s_mem())))
397 ossl_raise(eX509ExtError, NULL);
398 if (!X509V3_EXT_print(out, ext, 0, 0))
399 ASN1_STRING_print(out, (ASN1_STRING *)X509_EXTENSION_get_data(ext));
400 ret = ossl_membio2str(out);
401
402 return ret;
403 }
404
405 static VALUE
ossl_x509ext_get_critical(VALUE obj)406 ossl_x509ext_get_critical(VALUE obj)
407 {
408 X509_EXTENSION *ext;
409
410 GetX509Ext(obj, ext);
411 return X509_EXTENSION_get_critical(ext) ? Qtrue : Qfalse;
412 }
413
414 static VALUE
ossl_x509ext_to_der(VALUE obj)415 ossl_x509ext_to_der(VALUE obj)
416 {
417 X509_EXTENSION *ext;
418 unsigned char *p;
419 long len;
420 VALUE str;
421
422 GetX509Ext(obj, ext);
423 if((len = i2d_X509_EXTENSION(ext, NULL)) <= 0)
424 ossl_raise(eX509ExtError, NULL);
425 str = rb_str_new(0, len);
426 p = (unsigned char *)RSTRING_PTR(str);
427 if(i2d_X509_EXTENSION(ext, &p) < 0)
428 ossl_raise(eX509ExtError, NULL);
429 ossl_str_adjust(str, p);
430
431 return str;
432 }
433
434 /*
435 * INIT
436 */
437 void
Init_ossl_x509ext(void)438 Init_ossl_x509ext(void)
439 {
440 #undef rb_intern
441 #if 0
442 mOSSL = rb_define_module("OpenSSL");
443 eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
444 mX509 = rb_define_module_under(mOSSL, "X509");
445 #endif
446
447 eX509ExtError = rb_define_class_under(mX509, "ExtensionError", eOSSLError);
448
449 cX509ExtFactory = rb_define_class_under(mX509, "ExtensionFactory", rb_cObject);
450
451 rb_define_alloc_func(cX509ExtFactory, ossl_x509extfactory_alloc);
452 rb_define_method(cX509ExtFactory, "initialize", ossl_x509extfactory_initialize, -1);
453
454 rb_attr(cX509ExtFactory, rb_intern("issuer_certificate"), 1, 0, Qfalse);
455 rb_attr(cX509ExtFactory, rb_intern("subject_certificate"), 1, 0, Qfalse);
456 rb_attr(cX509ExtFactory, rb_intern("subject_request"), 1, 0, Qfalse);
457 rb_attr(cX509ExtFactory, rb_intern("crl"), 1, 0, Qfalse);
458 rb_attr(cX509ExtFactory, rb_intern("config"), 1, 1, Qfalse);
459
460 rb_define_method(cX509ExtFactory, "issuer_certificate=", ossl_x509extfactory_set_issuer_cert, 1);
461 rb_define_method(cX509ExtFactory, "subject_certificate=", ossl_x509extfactory_set_subject_cert, 1);
462 rb_define_method(cX509ExtFactory, "subject_request=", ossl_x509extfactory_set_subject_req, 1);
463 rb_define_method(cX509ExtFactory, "crl=", ossl_x509extfactory_set_crl, 1);
464 rb_define_method(cX509ExtFactory, "create_ext", ossl_x509extfactory_create_ext, -1);
465
466 cX509Ext = rb_define_class_under(mX509, "Extension", rb_cObject);
467 rb_define_alloc_func(cX509Ext, ossl_x509ext_alloc);
468 rb_define_method(cX509Ext, "initialize", ossl_x509ext_initialize, -1);
469 rb_define_method(cX509Ext, "initialize_copy", ossl_x509ext_initialize_copy, 1);
470 rb_define_method(cX509Ext, "oid=", ossl_x509ext_set_oid, 1);
471 rb_define_method(cX509Ext, "value=", ossl_x509ext_set_value, 1);
472 rb_define_method(cX509Ext, "critical=", ossl_x509ext_set_critical, 1);
473 rb_define_method(cX509Ext, "oid", ossl_x509ext_get_oid, 0);
474 rb_define_method(cX509Ext, "value", ossl_x509ext_get_value, 0);
475 rb_define_method(cX509Ext, "critical?", ossl_x509ext_get_critical, 0);
476 rb_define_method(cX509Ext, "to_der", ossl_x509ext_to_der, 0);
477 }
478