Ruby  3.1.0dev(2021-09-10revisionb76ad15ed0da636161de0243c547ee1e6fc95681)
ossl_x509ext.c
Go to the documentation of this file.
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  */
46 
47 static void
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  },
59 };
60 
61 /*
62  * Public
63  */
64 VALUE
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) {
78  }
79  SetX509Ext(obj, new);
80 
81  return obj;
82 }
83 
84 X509_EXTENSION *
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
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  },
112 };
113 
114 static VALUE
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
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
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
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
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
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
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 : GetConfig(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  if (!ext){
234  ossl_raise(eX509ExtError, "%"PRIsVALUE" = %"PRIsVALUE, oid, valstr);
235  }
236  SetX509Ext(obj, ext);
237 
238  return obj;
239 }
240 
241 /*
242  * Ext
243  */
244 static VALUE
245 ossl_x509ext_alloc(VALUE klass)
246 {
247  X509_EXTENSION *ext;
248  VALUE obj;
249 
250  obj = NewX509Ext(klass);
251  if(!(ext = X509_EXTENSION_new())){
253  }
254  SetX509Ext(obj, ext);
255 
256  return obj;
257 }
258 
259 /*
260  * call-seq:
261  * OpenSSL::X509::Extension.new(der)
262  * OpenSSL::X509::Extension.new(oid, value)
263  * OpenSSL::X509::Extension.new(oid, value, critical)
264  *
265  * Creates an X509 extension.
266  *
267  * The extension may be created from _der_ data or from an extension _oid_
268  * and _value_. The _oid_ may be either an OID or an extension name. If
269  * _critical_ is +true+ the extension is marked critical.
270  */
271 static VALUE
272 ossl_x509ext_initialize(int argc, VALUE *argv, VALUE self)
273 {
274  VALUE oid, value, critical;
275  const unsigned char *p;
276  X509_EXTENSION *ext, *x;
277 
278  GetX509Ext(self, ext);
279  if(rb_scan_args(argc, argv, "12", &oid, &value, &critical) == 1){
280  oid = ossl_to_der_if_possible(oid);
281  StringValue(oid);
282  p = (unsigned char *)RSTRING_PTR(oid);
283  x = d2i_X509_EXTENSION(&ext, &p, RSTRING_LEN(oid));
284  DATA_PTR(self) = ext;
285  if(!x)
287  return self;
288  }
289  rb_funcall(self, rb_intern("oid="), 1, oid);
290  rb_funcall(self, rb_intern("value="), 1, value);
291  if(argc > 2) rb_funcall(self, rb_intern("critical="), 1, critical);
292 
293  return self;
294 }
295 
296 static VALUE
297 ossl_x509ext_initialize_copy(VALUE self, VALUE other)
298 {
299  X509_EXTENSION *ext, *ext_other, *ext_new;
300 
301  rb_check_frozen(self);
302  GetX509Ext(self, ext);
303  GetX509Ext(other, ext_other);
304 
305  ext_new = X509_EXTENSION_dup(ext_other);
306  if (!ext_new)
307  ossl_raise(eX509ExtError, "X509_EXTENSION_dup");
308 
309  SetX509Ext(self, ext_new);
310  X509_EXTENSION_free(ext);
311 
312  return self;
313 }
314 
315 static VALUE
316 ossl_x509ext_set_oid(VALUE self, VALUE oid)
317 {
318  X509_EXTENSION *ext;
319  ASN1_OBJECT *obj;
320 
321  GetX509Ext(self, ext);
322  obj = OBJ_txt2obj(StringValueCStr(oid), 0);
323  if (!obj)
324  ossl_raise(eX509ExtError, "OBJ_txt2obj");
325  if (!X509_EXTENSION_set_object(ext, obj)) {
326  ASN1_OBJECT_free(obj);
327  ossl_raise(eX509ExtError, "X509_EXTENSION_set_object");
328  }
329  ASN1_OBJECT_free(obj);
330 
331  return oid;
332 }
333 
334 static VALUE
335 ossl_x509ext_set_value(VALUE self, VALUE data)
336 {
337  X509_EXTENSION *ext;
338  ASN1_OCTET_STRING *asn1s;
339 
340  GetX509Ext(self, ext);
341  data = ossl_to_der_if_possible(data);
342  StringValue(data);
343  asn1s = X509_EXTENSION_get_data(ext);
344 
345  if (!ASN1_OCTET_STRING_set(asn1s, (unsigned char *)RSTRING_PTR(data),
346  RSTRING_LENINT(data))) {
347  ossl_raise(eX509ExtError, "ASN1_OCTET_STRING_set");
348  }
349 
350  return data;
351 }
352 
353 static VALUE
354 ossl_x509ext_set_critical(VALUE self, VALUE flag)
355 {
356  X509_EXTENSION *ext;
357 
358  GetX509Ext(self, ext);
359  X509_EXTENSION_set_critical(ext, RTEST(flag) ? 1 : 0);
360 
361  return flag;
362 }
363 
364 static VALUE
365 ossl_x509ext_get_oid(VALUE obj)
366 {
367  X509_EXTENSION *ext;
368  ASN1_OBJECT *extobj;
369  BIO *out;
370  VALUE ret;
371  int nid;
372 
373  GetX509Ext(obj, ext);
374  extobj = X509_EXTENSION_get_object(ext);
375  if ((nid = OBJ_obj2nid(extobj)) != NID_undef)
376  ret = rb_str_new2(OBJ_nid2sn(nid));
377  else{
378  if (!(out = BIO_new(BIO_s_mem())))
380  i2a_ASN1_OBJECT(out, extobj);
381  ret = ossl_membio2str(out);
382  }
383 
384  return ret;
385 }
386 
387 static VALUE
388 ossl_x509ext_get_value(VALUE obj)
389 {
390  X509_EXTENSION *ext;
391  BIO *out;
392  VALUE ret;
393 
394  GetX509Ext(obj, ext);
395  if (!(out = BIO_new(BIO_s_mem())))
397  if (!X509V3_EXT_print(out, ext, 0, 0))
398  ASN1_STRING_print(out, (ASN1_STRING *)X509_EXTENSION_get_data(ext));
399  ret = ossl_membio2str(out);
400 
401  return ret;
402 }
403 
404 static VALUE
405 ossl_x509ext_get_value_der(VALUE obj)
406 {
407  X509_EXTENSION *ext;
408  ASN1_OCTET_STRING *value;
409 
410  GetX509Ext(obj, ext);
411  if ((value = X509_EXTENSION_get_data(ext)) == NULL)
413 
414  return rb_str_new((const char *)value->data, value->length);
415 }
416 
417 static VALUE
418 ossl_x509ext_get_critical(VALUE obj)
419 {
420  X509_EXTENSION *ext;
421 
422  GetX509Ext(obj, ext);
423  return X509_EXTENSION_get_critical(ext) ? Qtrue : Qfalse;
424 }
425 
426 static VALUE
427 ossl_x509ext_to_der(VALUE obj)
428 {
429  X509_EXTENSION *ext;
430  unsigned char *p;
431  long len;
432  VALUE str;
433 
434  GetX509Ext(obj, ext);
435  if((len = i2d_X509_EXTENSION(ext, NULL)) <= 0)
437  str = rb_str_new(0, len);
438  p = (unsigned char *)RSTRING_PTR(str);
439  if(i2d_X509_EXTENSION(ext, &p) < 0)
441  ossl_str_adjust(str, p);
442 
443  return str;
444 }
445 
446 /*
447  * INIT
448  */
449 void
451 {
452 #undef rb_intern
453 #if 0
454  mOSSL = rb_define_module("OpenSSL");
457 #endif
458 
459  eX509ExtError = rb_define_class_under(mX509, "ExtensionError", eOSSLError);
460 
461  cX509ExtFactory = rb_define_class_under(mX509, "ExtensionFactory", rb_cObject);
462 
463  rb_define_alloc_func(cX509ExtFactory, ossl_x509extfactory_alloc);
464  rb_define_method(cX509ExtFactory, "initialize", ossl_x509extfactory_initialize, -1);
465 
466  rb_attr(cX509ExtFactory, rb_intern("issuer_certificate"), 1, 0, Qfalse);
467  rb_attr(cX509ExtFactory, rb_intern("subject_certificate"), 1, 0, Qfalse);
468  rb_attr(cX509ExtFactory, rb_intern("subject_request"), 1, 0, Qfalse);
469  rb_attr(cX509ExtFactory, rb_intern("crl"), 1, 0, Qfalse);
470  rb_attr(cX509ExtFactory, rb_intern("config"), 1, 1, Qfalse);
471 
472  rb_define_method(cX509ExtFactory, "issuer_certificate=", ossl_x509extfactory_set_issuer_cert, 1);
473  rb_define_method(cX509ExtFactory, "subject_certificate=", ossl_x509extfactory_set_subject_cert, 1);
474  rb_define_method(cX509ExtFactory, "subject_request=", ossl_x509extfactory_set_subject_req, 1);
475  rb_define_method(cX509ExtFactory, "crl=", ossl_x509extfactory_set_crl, 1);
476  rb_define_method(cX509ExtFactory, "create_ext", ossl_x509extfactory_create_ext, -1);
477 
479  rb_define_alloc_func(cX509Ext, ossl_x509ext_alloc);
480  rb_define_method(cX509Ext, "initialize", ossl_x509ext_initialize, -1);
481  rb_define_method(cX509Ext, "initialize_copy", ossl_x509ext_initialize_copy, 1);
482  rb_define_method(cX509Ext, "oid=", ossl_x509ext_set_oid, 1);
483  rb_define_method(cX509Ext, "value=", ossl_x509ext_set_value, 1);
484  rb_define_method(cX509Ext, "critical=", ossl_x509ext_set_critical, 1);
485  rb_define_method(cX509Ext, "oid", ossl_x509ext_get_oid, 0);
486  rb_define_method(cX509Ext, "value", ossl_x509ext_get_value, 0);
487  rb_define_method(cX509Ext, "value_der", ossl_x509ext_get_value_der, 0);
488  rb_define_method(cX509Ext, "critical?", ossl_x509ext_get_critical, 0);
489  rb_define_method(cX509Ext, "to_der", ossl_x509ext_to_der, 0);
490 }
GetConfig
CONF * GetConfig(VALUE obj)
Definition: ossl_config.c:29
StringValue
#define StringValue(v)
Definition: rstring.h:50
rb_define_module_under
VALUE rb_define_module_under(VALUE outer, const char *name)
Definition: class.c:914
rb_attr
void rb_attr(VALUE, ID, int, int, int)
Definition: vm_method.c:1519
rb_intern
ID rb_intern(const char *)
Definition: symbol.c:784
ossl_to_der_if_possible
VALUE ossl_to_der_if_possible(VALUE obj)
Definition: ossl.c:261
PRIsVALUE
#define PRIsVALUE
Definition: inttypes.h:77
ossl_membio2str
VALUE ossl_membio2str(BIO *bio)
Definition: ossl_bio.c:29
rb_define_module
VALUE rb_define_module(const char *name)
Definition: class.c:887
mX509
VALUE mX509
Definition: ossl_x509.c:12
ossl.h
cX509Ext
VALUE cX509Ext
Definition: ossl_x509ext.c:43
argv
char ** argv
Definition: ruby.c:243
GetX509ExtFactory
#define GetX509ExtFactory(obj, ctx)
Definition: ossl_x509ext.c:33
ptr
struct RIMemo * ptr
Definition: debug.c:87
ossl_str_adjust
#define ossl_str_adjust(str, p)
Definition: ossl.h:88
RSTRING_LEN
#define RSTRING_LEN(string)
Definition: fbuffer.h:22
rb_str_append
VALUE rb_str_append(VALUE, VALUE)
Definition: string.c:3109
cX509ExtFactory
VALUE cX509ExtFactory
Definition: ossl_x509ext.c:44
rb_str_new
#define rb_str_new(str, len)
Definition: string.h:213
rb_iv_get
VALUE rb_iv_get(VALUE, const char *)
Definition: variable.c:3659
GetX509ExtPtr
X509_EXTENSION * GetX509ExtPtr(VALUE obj)
Definition: ossl_x509ext.c:85
RUBY_TYPED_FREE_IMMEDIATELY
@ RUBY_TYPED_FREE_IMMEDIATELY
Definition: rtypeddata.h:62
NIL_P
#define NIL_P
Definition: special_consts.h:46
rb_iv_set
VALUE rb_iv_set(VALUE, const char *, VALUE)
Definition: variable.c:3670
Init_ossl_x509ext
void Init_ossl_x509ext(void)
Definition: ossl_x509ext.c:450
mOSSL
VALUE mOSSL
Definition: ossl.c:237
rb_define_alloc_func
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
GetX509CRLPtr
X509_CRL * GetX509CRLPtr(VALUE)
Definition: ossl_x509crl.c:51
GetX509CertPtr
X509 * GetX509CertPtr(VALUE)
Definition: ossl_x509cert.c:71
rb_cObject
VALUE rb_cObject
Object class.
Definition: object.c:50
NewX509Ext
#define NewX509Ext(klass)
Definition: ossl_x509ext.c:12
Qfalse
#define Qfalse
Definition: special_consts.h:50
len
uint8_t len
Definition: escape.c:17
Qnil
#define Qnil
Definition: special_consts.h:51
ossl_raise
void ossl_raise(VALUE exc, const char *fmt,...)
Definition: ossl.c:299
NULL
#define NULL
Definition: regenc.h:69
ossl_x509ext_new
VALUE ossl_x509ext_new(X509_EXTENSION *ext)
Definition: ossl_x509ext.c:65
rb_scan_args
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:2347
RTEST
#define RTEST
Definition: special_consts.h:42
Qtrue
#define Qtrue
Definition: special_consts.h:52
SetX509Ext
#define SetX509Ext(obj, ext)
Definition: ossl_x509ext.c:14
VALUE
unsigned long VALUE
Definition: value.h:38
MakeX509ExtFactory
#define MakeX509ExtFactory(klass, obj, ctx)
Definition: ossl_x509ext.c:26
rb_funcall
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
Definition: vm_eval.c:1113
eX509ExtError
VALUE eX509ExtError
Definition: ossl_x509ext.c:45
RSTRING_PTR
#define RSTRING_PTR(string)
Definition: fbuffer.h:19
str
char str[HTML_ESCAPE_MAX_LEN+1]
Definition: escape.c:18
ret
return ret
Definition: memory.h:232
rb_check_frozen
#define rb_check_frozen
Definition: error.h:72
argc
int argc
Definition: ruby.c:242
rb_str_new2
#define rb_str_new2
Definition: string.h:276
rb_data_type_struct
Definition: rtypeddata.h:70
GetX509Ext
#define GetX509Ext(obj, ext)
Definition: ossl_x509ext.c:20
GetX509ReqPtr
X509_REQ * GetX509ReqPtr(VALUE)
Definition: ossl_x509req.c:51
eOSSLError
VALUE eOSSLError
Definition: ossl.c:242
rb_define_class_under
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:809
DATA_PTR
#define DATA_PTR(obj)
Definition: rdata.h:55
StringValueCStr
#define StringValueCStr(v)
Definition: rstring.h:52
rb_define_method
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
Definition: cxxanyargs.hpp:655
rb_eStandardError
VALUE rb_eStandardError
Definition: error.c:1090