1 /*
2  * 'OpenSSL for Ruby' project
3  * Copyright (C) 2001 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 NewX509Attr(klass) \
13     TypedData_Wrap_Struct((klass), &ossl_x509attr_type, 0)
14 #define SetX509Attr(obj, attr) do { \
15     if (!(attr)) { \
16 	ossl_raise(rb_eRuntimeError, "ATTR wasn't initialized!"); \
17     } \
18     RTYPEDDATA_DATA(obj) = (attr); \
19 } while (0)
20 #define GetX509Attr(obj, attr) do { \
21     TypedData_Get_Struct((obj), X509_ATTRIBUTE, &ossl_x509attr_type, (attr)); \
22     if (!(attr)) { \
23 	ossl_raise(rb_eRuntimeError, "ATTR wasn't initialized!"); \
24     } \
25 } while (0)
26 
27 /*
28  * Classes
29  */
30 VALUE cX509Attr;
31 VALUE eX509AttrError;
32 
33 static void
ossl_x509attr_free(void * ptr)34 ossl_x509attr_free(void *ptr)
35 {
36     X509_ATTRIBUTE_free(ptr);
37 }
38 
39 static const rb_data_type_t ossl_x509attr_type = {
40     "OpenSSL/X509/ATTRIBUTE",
41     {
42 	0, ossl_x509attr_free,
43     },
44     0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
45 };
46 
47 /*
48  * Public
49  */
50 VALUE
ossl_x509attr_new(X509_ATTRIBUTE * attr)51 ossl_x509attr_new(X509_ATTRIBUTE *attr)
52 {
53     X509_ATTRIBUTE *new;
54     VALUE obj;
55 
56     obj = NewX509Attr(cX509Attr);
57     if (!attr) {
58 	new = X509_ATTRIBUTE_new();
59     } else {
60 	new = X509_ATTRIBUTE_dup(attr);
61     }
62     if (!new) {
63 	ossl_raise(eX509AttrError, NULL);
64     }
65     SetX509Attr(obj, new);
66 
67     return obj;
68 }
69 
70 X509_ATTRIBUTE *
GetX509AttrPtr(VALUE obj)71 GetX509AttrPtr(VALUE obj)
72 {
73     X509_ATTRIBUTE *attr;
74 
75     GetX509Attr(obj, attr);
76 
77     return attr;
78 }
79 
80 /*
81  * Private
82  */
83 static VALUE
ossl_x509attr_alloc(VALUE klass)84 ossl_x509attr_alloc(VALUE klass)
85 {
86     X509_ATTRIBUTE *attr;
87     VALUE obj;
88 
89     obj = NewX509Attr(klass);
90     if (!(attr = X509_ATTRIBUTE_new()))
91 	ossl_raise(eX509AttrError, NULL);
92     SetX509Attr(obj, attr);
93 
94     return obj;
95 }
96 
97 /*
98  * call-seq:
99  *    Attribute.new(oid [, value]) => attr
100  */
101 static VALUE
ossl_x509attr_initialize(int argc,VALUE * argv,VALUE self)102 ossl_x509attr_initialize(int argc, VALUE *argv, VALUE self)
103 {
104     VALUE oid, value;
105     X509_ATTRIBUTE *attr, *x;
106     const unsigned char *p;
107 
108     GetX509Attr(self, attr);
109     if(rb_scan_args(argc, argv, "11", &oid, &value) == 1){
110 	oid = ossl_to_der_if_possible(oid);
111 	StringValue(oid);
112 	p = (unsigned char *)RSTRING_PTR(oid);
113 	x = d2i_X509_ATTRIBUTE(&attr, &p, RSTRING_LEN(oid));
114 	DATA_PTR(self) = attr;
115 	if(!x){
116 	    ossl_raise(eX509AttrError, NULL);
117 	}
118 	return self;
119     }
120     rb_funcall(self, rb_intern("oid="), 1, oid);
121     rb_funcall(self, rb_intern("value="), 1, value);
122 
123     return self;
124 }
125 
126 static VALUE
ossl_x509attr_initialize_copy(VALUE self,VALUE other)127 ossl_x509attr_initialize_copy(VALUE self, VALUE other)
128 {
129     X509_ATTRIBUTE *attr, *attr_other, *attr_new;
130 
131     rb_check_frozen(self);
132     GetX509Attr(self, attr);
133     GetX509Attr(other, attr_other);
134 
135     attr_new = X509_ATTRIBUTE_dup(attr_other);
136     if (!attr_new)
137 	ossl_raise(eX509AttrError, "X509_ATTRIBUTE_dup");
138 
139     SetX509Attr(self, attr_new);
140     X509_ATTRIBUTE_free(attr);
141 
142     return self;
143 }
144 
145 /*
146  * call-seq:
147  *    attr.oid = string => string
148  */
149 static VALUE
ossl_x509attr_set_oid(VALUE self,VALUE oid)150 ossl_x509attr_set_oid(VALUE self, VALUE oid)
151 {
152     X509_ATTRIBUTE *attr;
153     ASN1_OBJECT *obj;
154     char *s;
155 
156     GetX509Attr(self, attr);
157     s = StringValueCStr(oid);
158     obj = OBJ_txt2obj(s, 0);
159     if(!obj) ossl_raise(eX509AttrError, NULL);
160     if (!X509_ATTRIBUTE_set1_object(attr, obj)) {
161 	ASN1_OBJECT_free(obj);
162 	ossl_raise(eX509AttrError, "X509_ATTRIBUTE_set1_object");
163     }
164     ASN1_OBJECT_free(obj);
165 
166     return oid;
167 }
168 
169 /*
170  * call-seq:
171  *    attr.oid => string
172  */
173 static VALUE
ossl_x509attr_get_oid(VALUE self)174 ossl_x509attr_get_oid(VALUE self)
175 {
176     X509_ATTRIBUTE *attr;
177     ASN1_OBJECT *oid;
178     BIO *out;
179     VALUE ret;
180     int nid;
181 
182     GetX509Attr(self, attr);
183     oid = X509_ATTRIBUTE_get0_object(attr);
184     if ((nid = OBJ_obj2nid(oid)) != NID_undef)
185 	ret = rb_str_new2(OBJ_nid2sn(nid));
186     else{
187 	if (!(out = BIO_new(BIO_s_mem())))
188 	    ossl_raise(eX509AttrError, NULL);
189 	i2a_ASN1_OBJECT(out, oid);
190 	ret = ossl_membio2str(out);
191     }
192 
193     return ret;
194 }
195 
196 /*
197  * call-seq:
198  *    attr.value = asn1 => asn1
199  */
200 static VALUE
ossl_x509attr_set_value(VALUE self,VALUE value)201 ossl_x509attr_set_value(VALUE self, VALUE value)
202 {
203     X509_ATTRIBUTE *attr;
204     VALUE asn1_value;
205     int i, asn1_tag;
206 
207     OSSL_Check_Kind(value, cASN1Data);
208     asn1_tag = NUM2INT(rb_attr_get(value, rb_intern("@tag")));
209     asn1_value = rb_attr_get(value, rb_intern("@value"));
210     if (asn1_tag != V_ASN1_SET)
211 	ossl_raise(eASN1Error, "argument must be ASN1::Set");
212     if (!RB_TYPE_P(asn1_value, T_ARRAY))
213 	ossl_raise(eASN1Error, "ASN1::Set has non-array value");
214 
215     GetX509Attr(self, attr);
216     if (X509_ATTRIBUTE_count(attr)) { /* populated, reset first */
217 	ASN1_OBJECT *obj = X509_ATTRIBUTE_get0_object(attr);
218 	X509_ATTRIBUTE *new_attr = X509_ATTRIBUTE_create_by_OBJ(NULL, obj, 0, NULL, -1);
219 	if (!new_attr)
220 	    ossl_raise(eX509AttrError, NULL);
221 	SetX509Attr(self, new_attr);
222 	X509_ATTRIBUTE_free(attr);
223 	attr = new_attr;
224     }
225 
226     for (i = 0; i < RARRAY_LEN(asn1_value); i++) {
227 	ASN1_TYPE *a1type = ossl_asn1_get_asn1type(RARRAY_AREF(asn1_value, i));
228 	if (!X509_ATTRIBUTE_set1_data(attr, ASN1_TYPE_get(a1type),
229 				      a1type->value.ptr, -1)) {
230 	    ASN1_TYPE_free(a1type);
231 	    ossl_raise(eX509AttrError, NULL);
232 	}
233 	ASN1_TYPE_free(a1type);
234     }
235 
236     return value;
237 }
238 
239 /*
240  * call-seq:
241  *    attr.value => asn1
242  */
243 static VALUE
ossl_x509attr_get_value(VALUE self)244 ossl_x509attr_get_value(VALUE self)
245 {
246     X509_ATTRIBUTE *attr;
247     STACK_OF(ASN1_TYPE) *sk;
248     VALUE str;
249     int i, count, len;
250     unsigned char *p;
251 
252     GetX509Attr(self, attr);
253     /* there is no X509_ATTRIBUTE_get0_set() :( */
254     if (!(sk = sk_ASN1_TYPE_new_null()))
255 	ossl_raise(eX509AttrError, "sk_new");
256 
257     count = X509_ATTRIBUTE_count(attr);
258     for (i = 0; i < count; i++)
259 	sk_ASN1_TYPE_push(sk, X509_ATTRIBUTE_get0_type(attr, i));
260 
261     if ((len = i2d_ASN1_SET_ANY(sk, NULL)) <= 0) {
262 	sk_ASN1_TYPE_free(sk);
263 	ossl_raise(eX509AttrError, NULL);
264     }
265     str = rb_str_new(0, len);
266     p = (unsigned char *)RSTRING_PTR(str);
267     if (i2d_ASN1_SET_ANY(sk, &p) <= 0) {
268 	sk_ASN1_TYPE_free(sk);
269 	ossl_raise(eX509AttrError, NULL);
270     }
271     ossl_str_adjust(str, p);
272     sk_ASN1_TYPE_free(sk);
273 
274     return rb_funcall(mASN1, rb_intern("decode"), 1, str);
275 }
276 
277 /*
278  * call-seq:
279  *    attr.to_der => string
280  */
281 static VALUE
ossl_x509attr_to_der(VALUE self)282 ossl_x509attr_to_der(VALUE self)
283 {
284     X509_ATTRIBUTE *attr;
285     VALUE str;
286     int len;
287     unsigned char *p;
288 
289     GetX509Attr(self, attr);
290     if((len = i2d_X509_ATTRIBUTE(attr, NULL)) <= 0)
291 	ossl_raise(eX509AttrError, NULL);
292     str = rb_str_new(0, len);
293     p = (unsigned char *)RSTRING_PTR(str);
294     if(i2d_X509_ATTRIBUTE(attr, &p) <= 0)
295 	ossl_raise(eX509AttrError, NULL);
296     ossl_str_adjust(str, p);
297 
298     return str;
299 }
300 
301 /*
302  * X509_ATTRIBUTE init
303  */
304 void
Init_ossl_x509attr(void)305 Init_ossl_x509attr(void)
306 {
307 #if 0
308     mOSSL = rb_define_module("OpenSSL");
309     eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
310     mX509 = rb_define_module_under(mOSSL, "X509");
311 #endif
312 
313     eX509AttrError = rb_define_class_under(mX509, "AttributeError", eOSSLError);
314 
315     cX509Attr = rb_define_class_under(mX509, "Attribute", rb_cObject);
316     rb_define_alloc_func(cX509Attr, ossl_x509attr_alloc);
317     rb_define_method(cX509Attr, "initialize", ossl_x509attr_initialize, -1);
318     rb_define_method(cX509Attr, "initialize_copy", ossl_x509attr_initialize_copy, 1);
319     rb_define_method(cX509Attr, "oid=", ossl_x509attr_set_oid, 1);
320     rb_define_method(cX509Attr, "oid", ossl_x509attr_get_oid, 0);
321     rb_define_method(cX509Attr, "value=", ossl_x509attr_set_value, 1);
322     rb_define_method(cX509Attr, "value", ossl_x509attr_get_value, 0);
323     rb_define_method(cX509Attr, "to_der", ossl_x509attr_to_der, 0);
324 }
325