1/*
2 * $Id: ossl_x509crl.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 WrapX509CRL(klass, obj, crl) do { \
14    if (!(crl)) { \
15	ossl_raise(rb_eRuntimeError, "CRL wasn't initialized!"); \
16    } \
17    (obj) = Data_Wrap_Struct((klass), 0, X509_CRL_free, (crl)); \
18} while (0)
19#define GetX509CRL(obj, crl) do { \
20    Data_Get_Struct((obj), X509_CRL, (crl)); \
21    if (!(crl)) { \
22	ossl_raise(rb_eRuntimeError, "CRL wasn't initialized!"); \
23    } \
24} while (0)
25#define SafeGetX509CRL(obj, crl) do { \
26    OSSL_Check_Kind((obj), cX509CRL); \
27    GetX509CRL((obj), (crl)); \
28} while (0)
29
30/*
31 * Classes
32 */
33VALUE cX509CRL;
34VALUE eX509CRLError;
35
36/*
37 * PUBLIC
38 */
39X509_CRL *
40GetX509CRLPtr(VALUE obj)
41{
42    X509_CRL *crl;
43
44    SafeGetX509CRL(obj, crl);
45
46    return crl;
47}
48
49X509_CRL *
50DupX509CRLPtr(VALUE obj)
51{
52    X509_CRL *crl;
53
54    SafeGetX509CRL(obj, crl);
55    CRYPTO_add(&crl->references, 1, CRYPTO_LOCK_X509_CRL);
56
57    return crl;
58}
59
60VALUE
61ossl_x509crl_new(X509_CRL *crl)
62{
63    X509_CRL *tmp;
64    VALUE obj;
65
66    tmp = crl ? X509_CRL_dup(crl) : X509_CRL_new();
67    if(!tmp) ossl_raise(eX509CRLError, NULL);
68    WrapX509CRL(cX509CRL, obj, tmp);
69
70    return obj;
71}
72
73/*
74 * PRIVATE
75 */
76static VALUE
77ossl_x509crl_alloc(VALUE klass)
78{
79    X509_CRL *crl;
80    VALUE obj;
81
82    if (!(crl = X509_CRL_new())) {
83	ossl_raise(eX509CRLError, NULL);
84    }
85    WrapX509CRL(klass, obj, crl);
86
87    return obj;
88}
89
90static VALUE
91ossl_x509crl_initialize(int argc, VALUE *argv, VALUE self)
92{
93    BIO *in;
94    X509_CRL *crl, *x = DATA_PTR(self);
95    VALUE arg;
96
97    if (rb_scan_args(argc, argv, "01", &arg) == 0) {
98	return self;
99    }
100    arg = ossl_to_der_if_possible(arg);
101    in = ossl_obj2bio(arg);
102    crl = PEM_read_bio_X509_CRL(in, &x, NULL, NULL);
103    DATA_PTR(self) = x;
104    if (!crl) {
105	OSSL_BIO_reset(in);
106	crl = d2i_X509_CRL_bio(in, &x);
107	DATA_PTR(self) = x;
108    }
109    BIO_free(in);
110    if (!crl) ossl_raise(eX509CRLError, NULL);
111
112    return self;
113}
114
115static VALUE
116ossl_x509crl_copy(VALUE self, VALUE other)
117{
118    X509_CRL *a, *b, *crl;
119
120    rb_check_frozen(self);
121    if (self == other) return self;
122    GetX509CRL(self, a);
123    SafeGetX509CRL(other, b);
124    if (!(crl = X509_CRL_dup(b))) {
125	ossl_raise(eX509CRLError, NULL);
126    }
127    X509_CRL_free(a);
128    DATA_PTR(self) = crl;
129
130    return self;
131}
132
133static VALUE
134ossl_x509crl_get_version(VALUE self)
135{
136    X509_CRL *crl;
137    long ver;
138
139    GetX509CRL(self, crl);
140    ver = X509_CRL_get_version(crl);
141
142    return LONG2NUM(ver);
143}
144
145static VALUE
146ossl_x509crl_set_version(VALUE self, VALUE version)
147{
148    X509_CRL *crl;
149    long ver;
150
151    if ((ver = NUM2LONG(version)) < 0) {
152	ossl_raise(eX509CRLError, "version must be >= 0!");
153    }
154    GetX509CRL(self, crl);
155    if (!X509_CRL_set_version(crl, ver)) {
156	ossl_raise(eX509CRLError, NULL);
157    }
158
159    return version;
160}
161
162static VALUE
163ossl_x509crl_get_signature_algorithm(VALUE self)
164{
165    X509_CRL *crl;
166    BIO *out;
167    BUF_MEM *buf;
168    VALUE str;
169
170    GetX509CRL(self, crl);
171    if (!(out = BIO_new(BIO_s_mem()))) {
172	ossl_raise(eX509CRLError, NULL);
173    }
174    if (!i2a_ASN1_OBJECT(out, crl->sig_alg->algorithm)) {
175	BIO_free(out);
176	ossl_raise(eX509CRLError, NULL);
177    }
178    BIO_get_mem_ptr(out, &buf);
179    str = rb_str_new(buf->data, buf->length);
180    BIO_free(out);
181    return str;
182}
183
184static VALUE
185ossl_x509crl_get_issuer(VALUE self)
186{
187    X509_CRL *crl;
188
189    GetX509CRL(self, crl);
190
191    return ossl_x509name_new(X509_CRL_get_issuer(crl)); /* NO DUP - don't free */
192}
193
194static VALUE
195ossl_x509crl_set_issuer(VALUE self, VALUE issuer)
196{
197    X509_CRL *crl;
198
199    GetX509CRL(self, crl);
200
201    if (!X509_CRL_set_issuer_name(crl, GetX509NamePtr(issuer))) { /* DUPs name */
202	ossl_raise(eX509CRLError, NULL);
203    }
204    return issuer;
205}
206
207static VALUE
208ossl_x509crl_get_last_update(VALUE self)
209{
210    X509_CRL *crl;
211
212    GetX509CRL(self, crl);
213
214    return asn1time_to_time(X509_CRL_get_lastUpdate(crl));
215}
216
217static VALUE
218ossl_x509crl_set_last_update(VALUE self, VALUE time)
219{
220    X509_CRL *crl;
221    time_t sec;
222
223    sec = time_to_time_t(time);
224    GetX509CRL(self, crl);
225    if (!X509_time_adj(crl->crl->lastUpdate, 0, &sec)) {
226	ossl_raise(eX509CRLError, NULL);
227    }
228
229    return time;
230}
231
232static VALUE
233ossl_x509crl_get_next_update(VALUE self)
234{
235    X509_CRL *crl;
236
237    GetX509CRL(self, crl);
238
239    return asn1time_to_time(X509_CRL_get_nextUpdate(crl));
240}
241
242static VALUE
243ossl_x509crl_set_next_update(VALUE self, VALUE time)
244{
245    X509_CRL *crl;
246    time_t sec;
247
248    sec = time_to_time_t(time);
249    GetX509CRL(self, crl);
250    /* This must be some thinko in OpenSSL */
251    if (!(crl->crl->nextUpdate = X509_time_adj(crl->crl->nextUpdate, 0, &sec))){
252	ossl_raise(eX509CRLError, NULL);
253    }
254
255    return time;
256}
257
258static VALUE
259ossl_x509crl_get_revoked(VALUE self)
260{
261    X509_CRL *crl;
262    int i, num;
263    X509_REVOKED *rev;
264    VALUE ary, revoked;
265
266    GetX509CRL(self, crl);
267    num = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl));
268    if (num < 0) {
269	OSSL_Debug("num < 0???");
270	return rb_ary_new();
271    }
272    ary = rb_ary_new2(num);
273    for(i=0; i<num; i++) {
274	/* NO DUP - don't free! */
275	rev = sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i);
276	revoked = ossl_x509revoked_new(rev);
277	rb_ary_push(ary, revoked);
278    }
279
280    return ary;
281}
282
283static VALUE
284ossl_x509crl_set_revoked(VALUE self, VALUE ary)
285{
286    X509_CRL *crl;
287    X509_REVOKED *rev;
288    int i;
289
290    Check_Type(ary, T_ARRAY);
291    /* All ary members should be X509 Revoked */
292    for (i=0; i<RARRAY_LEN(ary); i++) {
293	OSSL_Check_Kind(RARRAY_PTR(ary)[i], cX509Rev);
294    }
295    GetX509CRL(self, crl);
296    sk_X509_REVOKED_pop_free(crl->crl->revoked, X509_REVOKED_free);
297    crl->crl->revoked = NULL;
298    for (i=0; i<RARRAY_LEN(ary); i++) {
299	rev = DupX509RevokedPtr(RARRAY_PTR(ary)[i]);
300	if (!X509_CRL_add0_revoked(crl, rev)) { /* NO DUP - don't free! */
301	    ossl_raise(eX509CRLError, NULL);
302	}
303    }
304    X509_CRL_sort(crl);
305
306    return ary;
307}
308
309static VALUE
310ossl_x509crl_add_revoked(VALUE self, VALUE revoked)
311{
312    X509_CRL *crl;
313    X509_REVOKED *rev;
314
315    GetX509CRL(self, crl);
316    rev = DupX509RevokedPtr(revoked);
317    if (!X509_CRL_add0_revoked(crl, rev)) { /* NO DUP - don't free! */
318	ossl_raise(eX509CRLError, NULL);
319    }
320    X509_CRL_sort(crl);
321
322    return revoked;
323}
324
325static VALUE
326ossl_x509crl_sign(VALUE self, VALUE key, VALUE digest)
327{
328    X509_CRL *crl;
329    EVP_PKEY *pkey;
330    const EVP_MD *md;
331
332    GetX509CRL(self, crl);
333    pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
334    md = GetDigestPtr(digest);
335    if (!X509_CRL_sign(crl, pkey, md)) {
336	ossl_raise(eX509CRLError, NULL);
337    }
338
339    return self;
340}
341
342static VALUE
343ossl_x509crl_verify(VALUE self, VALUE key)
344{
345    X509_CRL *crl;
346    int ret;
347
348    GetX509CRL(self, crl);
349    if ((ret = X509_CRL_verify(crl, GetPKeyPtr(key))) < 0) {
350	ossl_raise(eX509CRLError, NULL);
351    }
352    if (ret == 1) {
353	return Qtrue;
354    }
355
356    return Qfalse;
357}
358
359static VALUE
360ossl_x509crl_to_der(VALUE self)
361{
362    X509_CRL *crl;
363    BIO *out;
364    BUF_MEM *buf;
365    VALUE str;
366
367    GetX509CRL(self, crl);
368    if (!(out = BIO_new(BIO_s_mem()))) {
369	ossl_raise(eX509CRLError, NULL);
370    }
371    if (!i2d_X509_CRL_bio(out, crl)) {
372	BIO_free(out);
373	ossl_raise(eX509CRLError, NULL);
374    }
375    BIO_get_mem_ptr(out, &buf);
376    str = rb_str_new(buf->data, buf->length);
377    BIO_free(out);
378
379    return str;
380}
381
382static VALUE
383ossl_x509crl_to_pem(VALUE self)
384{
385    X509_CRL *crl;
386    BIO *out;
387    BUF_MEM *buf;
388    VALUE str;
389
390    GetX509CRL(self, crl);
391    if (!(out = BIO_new(BIO_s_mem()))) {
392	ossl_raise(eX509CRLError, NULL);
393    }
394    if (!PEM_write_bio_X509_CRL(out, crl)) {
395	BIO_free(out);
396	ossl_raise(eX509CRLError, NULL);
397    }
398    BIO_get_mem_ptr(out, &buf);
399    str = rb_str_new(buf->data, buf->length);
400    BIO_free(out);
401
402    return str;
403}
404
405static VALUE
406ossl_x509crl_to_text(VALUE self)
407{
408    X509_CRL *crl;
409    BIO *out;
410    BUF_MEM *buf;
411    VALUE str;
412
413    GetX509CRL(self, crl);
414    if (!(out = BIO_new(BIO_s_mem()))) {
415	ossl_raise(eX509CRLError, NULL);
416    }
417    if (!X509_CRL_print(out, crl)) {
418	BIO_free(out);
419	ossl_raise(eX509CRLError, NULL);
420    }
421    BIO_get_mem_ptr(out, &buf);
422    str = rb_str_new(buf->data, buf->length);
423    BIO_free(out);
424
425    return str;
426}
427
428/*
429 * Gets X509v3 extensions as array of X509Ext objects
430 */
431static VALUE
432ossl_x509crl_get_extensions(VALUE self)
433{
434    X509_CRL *crl;
435    int count, i;
436    X509_EXTENSION *ext;
437    VALUE ary;
438
439    GetX509CRL(self, crl);
440    count = X509_CRL_get_ext_count(crl);
441    if (count < 0) {
442	OSSL_Debug("count < 0???");
443	return rb_ary_new();
444    }
445    ary = rb_ary_new2(count);
446    for (i=0; i<count; i++) {
447	ext = X509_CRL_get_ext(crl, i); /* NO DUP - don't free! */
448	rb_ary_push(ary, ossl_x509ext_new(ext));
449    }
450
451    return ary;
452}
453
454/*
455 * Sets X509_EXTENSIONs
456 */
457static VALUE
458ossl_x509crl_set_extensions(VALUE self, VALUE ary)
459{
460    X509_CRL *crl;
461    X509_EXTENSION *ext;
462    int i;
463
464    Check_Type(ary, T_ARRAY);
465    /* All ary members should be X509 Extensions */
466    for (i=0; i<RARRAY_LEN(ary); i++) {
467	OSSL_Check_Kind(RARRAY_PTR(ary)[i], cX509Ext);
468    }
469    GetX509CRL(self, crl);
470    sk_X509_EXTENSION_pop_free(crl->crl->extensions, X509_EXTENSION_free);
471    crl->crl->extensions = NULL;
472    for (i=0; i<RARRAY_LEN(ary); i++) {
473	ext = DupX509ExtPtr(RARRAY_PTR(ary)[i]);
474	if(!X509_CRL_add_ext(crl, ext, -1)) { /* DUPs ext - FREE it */
475	    X509_EXTENSION_free(ext);
476	    ossl_raise(eX509CRLError, NULL);
477	}
478	X509_EXTENSION_free(ext);
479    }
480
481    return ary;
482}
483
484static VALUE
485ossl_x509crl_add_extension(VALUE self, VALUE extension)
486{
487    X509_CRL *crl;
488    X509_EXTENSION *ext;
489
490    GetX509CRL(self, crl);
491    ext = DupX509ExtPtr(extension);
492    if (!X509_CRL_add_ext(crl, ext, -1)) { /* DUPs ext - FREE it */
493	X509_EXTENSION_free(ext);
494	ossl_raise(eX509CRLError, NULL);
495    }
496    X509_EXTENSION_free(ext);
497
498    return extension;
499}
500
501/*
502 * INIT
503 */
504void
505Init_ossl_x509crl()
506{
507    eX509CRLError = rb_define_class_under(mX509, "CRLError", eOSSLError);
508
509    cX509CRL = rb_define_class_under(mX509, "CRL", rb_cObject);
510
511    rb_define_alloc_func(cX509CRL, ossl_x509crl_alloc);
512    rb_define_method(cX509CRL, "initialize", ossl_x509crl_initialize, -1);
513    rb_define_copy_func(cX509CRL, ossl_x509crl_copy);
514
515    rb_define_method(cX509CRL, "version", ossl_x509crl_get_version, 0);
516    rb_define_method(cX509CRL, "version=", ossl_x509crl_set_version, 1);
517    rb_define_method(cX509CRL, "signature_algorithm", ossl_x509crl_get_signature_algorithm, 0);
518    rb_define_method(cX509CRL, "issuer", ossl_x509crl_get_issuer, 0);
519    rb_define_method(cX509CRL, "issuer=", ossl_x509crl_set_issuer, 1);
520    rb_define_method(cX509CRL, "last_update", ossl_x509crl_get_last_update, 0);
521    rb_define_method(cX509CRL, "last_update=", ossl_x509crl_set_last_update, 1);
522    rb_define_method(cX509CRL, "next_update", ossl_x509crl_get_next_update, 0);
523    rb_define_method(cX509CRL, "next_update=", ossl_x509crl_set_next_update, 1);
524    rb_define_method(cX509CRL, "revoked", ossl_x509crl_get_revoked, 0);
525    rb_define_method(cX509CRL, "revoked=", ossl_x509crl_set_revoked, 1);
526    rb_define_method(cX509CRL, "add_revoked", ossl_x509crl_add_revoked, 1);
527    rb_define_method(cX509CRL, "sign", ossl_x509crl_sign, 2);
528    rb_define_method(cX509CRL, "verify", ossl_x509crl_verify, 1);
529    rb_define_method(cX509CRL, "to_der", ossl_x509crl_to_der, 0);
530    rb_define_method(cX509CRL, "to_pem", ossl_x509crl_to_pem, 0);
531    rb_define_alias(cX509CRL, "to_s", "to_pem");
532    rb_define_method(cX509CRL, "to_text", ossl_x509crl_to_text, 0);
533    rb_define_method(cX509CRL, "extensions", ossl_x509crl_get_extensions, 0);
534    rb_define_method(cX509CRL, "extensions=", ossl_x509crl_set_extensions, 1);
535    rb_define_method(cX509CRL, "add_extension", ossl_x509crl_add_extension, 1);
536}
537
538