Ruby: ext/openssl/ossl_x509ext.c Source File

Ruby 3.0.5p211 (2022-11-24 revision ba5cf0f7c52d4d35cc6a173c89eda98ceffa2dcf)

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 */
43 VALUE cX509Ext;
44 VALUE cX509ExtFactory;
45 VALUE eX509ExtError;
46
47static void
48ossl_x509ext_free(void *ptr)
49{
50 X509_EXTENSION_free(ptr);
51}
52
53static 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
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
84X509_EXTENSION *
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 */
100static void
101ossl_x509extfactory_free(void *ctx)
102{
103 OPENSSL_free(ctx);
104}
105
106static 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
114static VALUE
115ossl_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
126static VALUE
127ossl_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
138static VALUE
139ossl_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
150static VALUE
151ossl_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
162static VALUE
163ossl_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
174static VALUE
175ossl_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 */
203static VALUE
204ossl_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 */
245static VALUE
246ossl_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 */
272static VALUE
273ossl_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
297static VALUE
298ossl_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
316static VALUE
317ossl_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
335static VALUE
336ossl_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
354static VALUE
355ossl_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
365static VALUE
366ossl_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
388static VALUE
389ossl_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
405static VALUE
406ossl_x509ext_get_value_der(VALUE obj)
407{
408 X509_EXTENSION *ext;
409 ASN1_OCTET_STRING *value;
410
411 GetX509Ext(obj, ext);
412 if ((value = X509_EXTENSION_get_data(ext)) == NULL)
413 ossl_raise(eX509ExtError, NULL);
414
415 return rb_str_new((const char *)value->data, value->length);
416}
417
418static VALUE
419ossl_x509ext_get_critical(VALUE obj)
420{
421 X509_EXTENSION *ext;
422
423 GetX509Ext(obj, ext);
424 return X509_EXTENSION_get_critical(ext) ? Qtrue : Qfalse;
425}
426
427static VALUE
428ossl_x509ext_to_der(VALUE obj)
429{
430 X509_EXTENSION *ext;
431 unsigned char *p;
432 long len;
433 VALUE str;
434
435 GetX509Ext(obj, ext);
436 if((len = i2d_X509_EXTENSION(ext, NULL)) <= 0)
437 ossl_raise(eX509ExtError, NULL);
438 str = rb_str_new(0, len);
439 p = (unsigned char *)RSTRING_PTR(str);
440 if(i2d_X509_EXTENSION(ext, &p) < 0)
441 ossl_raise(eX509ExtError, NULL);
442 ossl_str_adjust(str, p);
443
444 return str;
445}
446
447/*
448 * INIT
449 */
450void
451 Init_ossl_x509ext(void)
452{
453#undef rb_intern
454#if 0
455 mOSSL = rb_define_module("OpenSSL");
456 eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
457 mX509 = rb_define_module_under(mOSSL, "X509");
458#endif
459
460 eX509ExtError = rb_define_class_under(mX509, "ExtensionError", eOSSLError);
461
462 cX509ExtFactory = rb_define_class_under(mX509, "ExtensionFactory", rb_cObject);
463
464 rb_define_alloc_func(cX509ExtFactory, ossl_x509extfactory_alloc);
465 rb_define_method(cX509ExtFactory, "initialize", ossl_x509extfactory_initialize, -1);
466
467 rb_attr(cX509ExtFactory, rb_intern("issuer_certificate"), 1, 0, Qfalse);
468 rb_attr(cX509ExtFactory, rb_intern("subject_certificate"), 1, 0, Qfalse);
469 rb_attr(cX509ExtFactory, rb_intern("subject_request"), 1, 0, Qfalse);
470 rb_attr(cX509ExtFactory, rb_intern("crl"), 1, 0, Qfalse);
471 rb_attr(cX509ExtFactory, rb_intern("config"), 1, 1, Qfalse);
472
473 rb_define_method(cX509ExtFactory, "issuer_certificate=", ossl_x509extfactory_set_issuer_cert, 1);
474 rb_define_method(cX509ExtFactory, "subject_certificate=", ossl_x509extfactory_set_subject_cert, 1);
475 rb_define_method(cX509ExtFactory, "subject_request=", ossl_x509extfactory_set_subject_req, 1);
476 rb_define_method(cX509ExtFactory, "crl=", ossl_x509extfactory_set_crl, 1);
477 rb_define_method(cX509ExtFactory, "create_ext", ossl_x509extfactory_create_ext, -1);
478
479 cX509Ext = rb_define_class_under(mX509, "Extension", rb_cObject);
480 rb_define_alloc_func(cX509Ext, ossl_x509ext_alloc);
481 rb_define_method(cX509Ext, "initialize", ossl_x509ext_initialize, -1);
482 rb_define_method(cX509Ext, "initialize_copy", ossl_x509ext_initialize_copy, 1);
483 rb_define_method(cX509Ext, "oid=", ossl_x509ext_set_oid, 1);
484 rb_define_method(cX509Ext, "value=", ossl_x509ext_set_value, 1);
485 rb_define_method(cX509Ext, "critical=", ossl_x509ext_set_critical, 1);
486 rb_define_method(cX509Ext, "oid", ossl_x509ext_get_oid, 0);
487 rb_define_method(cX509Ext, "value", ossl_x509ext_get_value, 0);
488 rb_define_method(cX509Ext, "value_der", ossl_x509ext_get_value_der, 0);
489 rb_define_method(cX509Ext, "critical?", ossl_x509ext_get_critical, 0);
490 rb_define_method(cX509Ext, "to_der", ossl_x509ext_to_der, 0);
491}
rb_define_method
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
Definition: cxxanyargs.hpp:653
ptr
struct RIMemo * ptr
Definition: debug.c:88
out
string_t out
Definition: enough.c:230
len
uint8_t len
Definition: escape.c:17
str
char str[HTML_ESCAPE_MAX_LEN+1]
Definition: escape.c:18
RSTRING_LEN
#define RSTRING_LEN(string)
Definition: fbuffer.h:22
RSTRING_PTR
#define RSTRING_PTR(string)
Definition: fbuffer.h:19
PRIsVALUE
#define PRIsVALUE
Definition: function.c:10
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:797
rb_define_module
VALUE rb_define_module(const char *name)
Definition: class.c:871
rb_define_module_under
VALUE rb_define_module_under(VALUE outer, const char *name)
Definition: class.c:895
rb_scan_args
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:2296
rb_eStandardError
VALUE rb_eStandardError
Definition: error.c:1054
rb_cObject
VALUE rb_cObject
Object class.
Definition: object.c:49
rb_funcall
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
Definition: vm_eval.c:1077
rb_check_frozen
#define rb_check_frozen
Definition: error.h:72
rb_str_new2
#define rb_str_new2
Definition: string.h:276
rb_str_new
#define rb_str_new(str, len)
Definition: string.h:213
rb_str_append
VALUE rb_str_append(VALUE, VALUE)
Definition: string.c:3118
rb_attr
void rb_attr(VALUE, ID, int, int, int)
Definition: vm_method.c:1508
rb_define_alloc_func
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
rb_intern
ID rb_intern(const char *)
Definition: symbol.c:785
rb_iv_set
VALUE rb_iv_set(VALUE, const char *, VALUE)
Definition: variable.c:3580
rb_iv_get
VALUE rb_iv_get(VALUE, const char *)
Definition: variable.c:3569
nid
int nid
Definition: openssl_missing.c:28
mOSSL
VALUE mOSSL
Definition: ossl.c:231
ossl_to_der_if_possible
VALUE ossl_to_der_if_possible(VALUE obj)
Definition: ossl.c:255
ossl_raise
void ossl_raise(VALUE exc, const char *fmt,...)
Definition: ossl.c:293
eOSSLError
VALUE eOSSLError
Definition: ossl.c:236
ossl.h
ossl_str_adjust
#define ossl_str_adjust(str, p)
Definition: ossl.h:89
ossl_membio2str
VALUE ossl_membio2str(BIO *bio)
Definition: ossl_bio.c:29
DupConfigPtr
CONF * DupConfigPtr(VALUE obj)
Definition: ossl_config.c:35
mX509
VALUE mX509
Definition: ossl_x509.c:12
GetX509ReqPtr
X509_REQ * GetX509ReqPtr(VALUE)
Definition: ossl_x509req.c:51
GetX509CertPtr
X509 * GetX509CertPtr(VALUE)
Definition: ossl_x509cert.c:71
GetX509CRLPtr
X509_CRL * GetX509CRLPtr(VALUE)
Definition: ossl_x509crl.c:51
GetX509ExtFactory
#define GetX509ExtFactory(obj, ctx)
Definition: ossl_x509ext.c:33
SetX509Ext
#define SetX509Ext(obj, ext)
Definition: ossl_x509ext.c:14
Init_ossl_x509ext
void Init_ossl_x509ext(void)
Definition: ossl_x509ext.c:451
eX509ExtError
VALUE eX509ExtError
Definition: ossl_x509ext.c:45
NewX509Ext
#define NewX509Ext(klass)
Definition: ossl_x509ext.c:12
MakeX509ExtFactory
#define MakeX509ExtFactory(klass, obj, ctx)
Definition: ossl_x509ext.c:26
cX509Ext
VALUE cX509Ext
Definition: ossl_x509ext.c:43
cX509ExtFactory
VALUE cX509ExtFactory
Definition: ossl_x509ext.c:44
GetX509Ext
#define GetX509Ext(obj, ext)
Definition: ossl_x509ext.c:20
ossl_x509ext_new
VALUE ossl_x509ext_new(X509_EXTENSION *ext)
Definition: ossl_x509ext.c:65
GetX509ExtPtr
X509_EXTENSION * GetX509ExtPtr(VALUE obj)
Definition: ossl_x509ext.c:85
DATA_PTR
#define DATA_PTR(obj)
Definition: rdata.h:56
NULL
#define NULL
Definition: regenc.h:69
StringValue
#define StringValue(v)
Definition: rstring.h:50
StringValueCStr
#define StringValueCStr(v)
Definition: rstring.h:52
RUBY_TYPED_FREE_IMMEDIATELY
@ RUBY_TYPED_FREE_IMMEDIATELY
Definition: rtypeddata.h:62
argc
int argc
Definition: ruby.c:240
argv
char ** argv
Definition: ruby.c:241
Qtrue
#define Qtrue
Definition: special_consts.h:52
RTEST
#define RTEST
Definition: special_consts.h:42
Qnil
#define Qnil
Definition: special_consts.h:51
Qfalse
#define Qfalse
Definition: special_consts.h:50
NIL_P
#define NIL_P
Definition: special_consts.h:46
rb_data_type_struct
Definition: rtypeddata.h:70
VALUE
unsigned long VALUE
Definition: value.h:38