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