1/*
2 * $Id: ossl_pkcs7.c 35167 2012-03-29 01:27:17Z 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 WrapPKCS7(klass, obj, pkcs7) do { \
14    if (!(pkcs7)) { \
15	ossl_raise(rb_eRuntimeError, "PKCS7 wasn't initialized."); \
16    } \
17    (obj) = Data_Wrap_Struct((klass), 0, PKCS7_free, (pkcs7)); \
18} while (0)
19#define GetPKCS7(obj, pkcs7) do { \
20    Data_Get_Struct((obj), PKCS7, (pkcs7)); \
21    if (!(pkcs7)) { \
22	ossl_raise(rb_eRuntimeError, "PKCS7 wasn't initialized."); \
23    } \
24} while (0)
25#define SafeGetPKCS7(obj, pkcs7) do { \
26    OSSL_Check_Kind((obj), cPKCS7); \
27    GetPKCS7((obj), (pkcs7)); \
28} while (0)
29
30#define WrapPKCS7si(klass, obj, p7si) do { \
31    if (!(p7si)) { \
32	ossl_raise(rb_eRuntimeError, "PKCS7si wasn't initialized."); \
33    } \
34    (obj) = Data_Wrap_Struct((klass), 0, PKCS7_SIGNER_INFO_free, (p7si)); \
35} while (0)
36#define GetPKCS7si(obj, p7si) do { \
37    Data_Get_Struct((obj), PKCS7_SIGNER_INFO, (p7si)); \
38    if (!(p7si)) { \
39	ossl_raise(rb_eRuntimeError, "PKCS7si wasn't initialized."); \
40    } \
41} while (0)
42#define SafeGetPKCS7si(obj, p7si) do { \
43    OSSL_Check_Kind((obj), cPKCS7Signer); \
44    GetPKCS7si((obj), (p7si)); \
45} while (0)
46
47#define WrapPKCS7ri(klass, obj, p7ri) do { \
48    if (!(p7ri)) { \
49	ossl_raise(rb_eRuntimeError, "PKCS7ri wasn't initialized."); \
50    } \
51    (obj) = Data_Wrap_Struct((klass), 0, PKCS7_RECIP_INFO_free, (p7ri)); \
52} while (0)
53#define GetPKCS7ri(obj, p7ri) do { \
54    Data_Get_Struct((obj), PKCS7_RECIP_INFO, (p7ri)); \
55    if (!(p7ri)) { \
56	ossl_raise(rb_eRuntimeError, "PKCS7ri wasn't initialized."); \
57    } \
58} while (0)
59#define SafeGetPKCS7ri(obj, p7ri) do { \
60    OSSL_Check_Kind((obj), cPKCS7Recipient); \
61    GetPKCS7ri((obj), (p7ri)); \
62} while (0)
63
64#define numberof(ary) (int)(sizeof(ary)/sizeof((ary)[0]))
65
66#define ossl_pkcs7_set_data(o,v)       rb_iv_set((o), "@data", (v))
67#define ossl_pkcs7_get_data(o)         rb_iv_get((o), "@data")
68#define ossl_pkcs7_set_err_string(o,v) rb_iv_set((o), "@error_string", (v))
69#define ossl_pkcs7_get_err_string(o)   rb_iv_get((o), "@error_string")
70
71/*
72 * Classes
73 */
74VALUE cPKCS7;
75VALUE cPKCS7Signer;
76VALUE cPKCS7Recipient;
77VALUE ePKCS7Error;
78
79/*
80 * Public
81 * (MADE PRIVATE UNTIL SOMEBODY WILL NEED THEM)
82 */
83static VALUE
84ossl_pkcs7si_new(PKCS7_SIGNER_INFO *p7si)
85{
86    PKCS7_SIGNER_INFO *pkcs7;
87    VALUE obj;
88
89    pkcs7 = p7si ? PKCS7_SIGNER_INFO_dup(p7si) : PKCS7_SIGNER_INFO_new();
90    if (!pkcs7) ossl_raise(ePKCS7Error, NULL);
91    WrapPKCS7si(cPKCS7Signer, obj, pkcs7);
92
93    return obj;
94}
95
96static PKCS7_SIGNER_INFO *
97DupPKCS7SignerPtr(VALUE obj)
98{
99    PKCS7_SIGNER_INFO *p7si, *pkcs7;
100
101    SafeGetPKCS7si(obj, p7si);
102    if (!(pkcs7 = PKCS7_SIGNER_INFO_dup(p7si))) {
103	ossl_raise(ePKCS7Error, NULL);
104    }
105
106    return pkcs7;
107}
108
109static VALUE
110ossl_pkcs7ri_new(PKCS7_RECIP_INFO *p7ri)
111{
112    PKCS7_RECIP_INFO *pkcs7;
113    VALUE obj;
114
115    pkcs7 = p7ri ? PKCS7_RECIP_INFO_dup(p7ri) : PKCS7_RECIP_INFO_new();
116    if (!pkcs7) ossl_raise(ePKCS7Error, NULL);
117    WrapPKCS7ri(cPKCS7Recipient, obj, pkcs7);
118
119    return obj;
120}
121
122static PKCS7_RECIP_INFO *
123DupPKCS7RecipientPtr(VALUE obj)
124{
125    PKCS7_RECIP_INFO *p7ri, *pkcs7;
126
127    SafeGetPKCS7ri(obj, p7ri);
128    if (!(pkcs7 = PKCS7_RECIP_INFO_dup(p7ri))) {
129	ossl_raise(ePKCS7Error, NULL);
130    }
131
132    return pkcs7;
133}
134
135/*
136 * call-seq:
137 *    PKCS7.read_smime(string) => pkcs7
138 */
139static VALUE
140ossl_pkcs7_s_read_smime(VALUE klass, VALUE arg)
141{
142    BIO *in, *out;
143    PKCS7 *pkcs7;
144    VALUE ret, data;
145
146    in = ossl_obj2bio(arg);
147    out = NULL;
148    pkcs7 = SMIME_read_PKCS7(in, &out);
149    BIO_free(in);
150    if(!pkcs7) ossl_raise(ePKCS7Error, NULL);
151    data = out ? ossl_membio2str(out) : Qnil;
152    WrapPKCS7(cPKCS7, ret, pkcs7);
153    ossl_pkcs7_set_data(ret, data);
154    ossl_pkcs7_set_err_string(ret, Qnil);
155
156    return ret;
157}
158
159/*
160 * call-seq:
161 *    PKCS7.write_smime(pkcs7 [, data [, flags]]) => string
162 */
163static VALUE
164ossl_pkcs7_s_write_smime(int argc, VALUE *argv, VALUE klass)
165{
166    VALUE pkcs7, data, flags;
167    BIO *out, *in;
168    PKCS7 *p7;
169    VALUE str;
170    int flg;
171
172    rb_scan_args(argc, argv, "12", &pkcs7, &data, &flags);
173    flg = NIL_P(flags) ? 0 : NUM2INT(flags);
174    if(NIL_P(data)) data = ossl_pkcs7_get_data(pkcs7);
175    SafeGetPKCS7(pkcs7, p7);
176    if(!NIL_P(data) && PKCS7_is_detached(p7))
177	flg |= PKCS7_DETACHED;
178    in = NIL_P(data) ? NULL : ossl_obj2bio(data);
179    if(!(out = BIO_new(BIO_s_mem()))){
180        BIO_free(in);
181        ossl_raise(ePKCS7Error, NULL);
182    }
183    if(!SMIME_write_PKCS7(out, p7, in, flg)){
184        BIO_free(out);
185        BIO_free(in);
186        ossl_raise(ePKCS7Error, NULL);
187    }
188    BIO_free(in);
189    str = ossl_membio2str(out);
190
191    return str;
192}
193
194/*
195 * call-seq:
196 *    PKCS7.sign(cert, key, data, [, certs [, flags]]) => pkcs7
197 */
198static VALUE
199ossl_pkcs7_s_sign(int argc, VALUE *argv, VALUE klass)
200{
201    VALUE cert, key, data, certs, flags;
202    X509 *x509;
203    EVP_PKEY *pkey;
204    BIO *in;
205    STACK_OF(X509) *x509s;
206    int flg, status = 0;
207    PKCS7 *pkcs7;
208    VALUE ret;
209
210    rb_scan_args(argc, argv, "32", &cert, &key, &data, &certs, &flags);
211    x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */
212    pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
213    flg = NIL_P(flags) ? 0 : NUM2INT(flags);
214    in = ossl_obj2bio(data);
215    if(NIL_P(certs)) x509s = NULL;
216    else{
217	x509s = ossl_protect_x509_ary2sk(certs, &status);
218	if(status){
219	    BIO_free(in);
220	    rb_jump_tag(status);
221	}
222    }
223    if(!(pkcs7 = PKCS7_sign(x509, pkey, x509s, in, flg))){
224	BIO_free(in);
225	sk_X509_pop_free(x509s, X509_free);
226	ossl_raise(ePKCS7Error, NULL);
227    }
228    WrapPKCS7(cPKCS7, ret, pkcs7);
229    ossl_pkcs7_set_data(ret, data);
230    ossl_pkcs7_set_err_string(ret, Qnil);
231    BIO_free(in);
232    sk_X509_pop_free(x509s, X509_free);
233
234    return ret;
235}
236
237/*
238 * call-seq:
239 *    PKCS7.encrypt(certs, data, [, cipher [, flags]]) => pkcs7
240 */
241static VALUE
242ossl_pkcs7_s_encrypt(int argc, VALUE *argv, VALUE klass)
243{
244    VALUE certs, data, cipher, flags;
245    STACK_OF(X509) *x509s;
246    BIO *in;
247    const EVP_CIPHER *ciph;
248    int flg, status = 0;
249    VALUE ret;
250    PKCS7 *p7;
251
252    rb_scan_args(argc, argv, "22", &certs, &data, &cipher, &flags);
253    if(NIL_P(cipher)){
254#if !defined(OPENSSL_NO_RC2)
255	ciph = EVP_rc2_40_cbc();
256#elif !defined(OPENSSL_NO_DES)
257	ciph = EVP_des_ede3_cbc();
258#elif !defined(OPENSSL_NO_RC2)
259	ciph = EVP_rc2_40_cbc();
260#elif !defined(OPENSSL_NO_AES)
261	ciph = EVP_EVP_aes_128_cbc();
262#else
263	ossl_raise(ePKCS7Error, "Must specify cipher");
264#endif
265
266    }
267    else ciph = GetCipherPtr(cipher); /* NO NEED TO DUP */
268    flg = NIL_P(flags) ? 0 : NUM2INT(flags);
269    in = ossl_obj2bio(data);
270    x509s = ossl_protect_x509_ary2sk(certs, &status);
271    if(status){
272	BIO_free(in);
273	rb_jump_tag(status);
274    }
275    if(!(p7 = PKCS7_encrypt(x509s, in, (EVP_CIPHER*)ciph, flg))){
276	BIO_free(in);
277	sk_X509_pop_free(x509s, X509_free);
278	ossl_raise(ePKCS7Error, NULL);
279    }
280    BIO_free(in);
281    WrapPKCS7(cPKCS7, ret, p7);
282    ossl_pkcs7_set_data(ret, data);
283    sk_X509_pop_free(x509s, X509_free);
284
285    return ret;
286}
287
288static VALUE
289ossl_pkcs7_alloc(VALUE klass)
290{
291    PKCS7 *pkcs7;
292    VALUE obj;
293
294    if (!(pkcs7 = PKCS7_new())) {
295	ossl_raise(ePKCS7Error, NULL);
296    }
297    WrapPKCS7(klass, obj, pkcs7);
298
299    return obj;
300}
301
302/*
303 * call-seq:
304 *    PKCS7.new => pkcs7
305 *    PKCS7.new(string) => pkcs7
306 *
307 * Many methods in this class aren't documented.
308 */
309static VALUE
310ossl_pkcs7_initialize(int argc, VALUE *argv, VALUE self)
311{
312    PKCS7 *p7, *pkcs = DATA_PTR(self);
313    BIO *in;
314    VALUE arg;
315
316    if(rb_scan_args(argc, argv, "01", &arg) == 0)
317	return self;
318    arg = ossl_to_der_if_possible(arg);
319    in = ossl_obj2bio(arg);
320    p7 = PEM_read_bio_PKCS7(in, &pkcs, NULL, NULL);
321    if (!p7) {
322	OSSL_BIO_reset(in);
323        p7 = d2i_PKCS7_bio(in, &pkcs);
324	if (!p7) {
325	    BIO_free(in);
326	    PKCS7_free(pkcs);
327	    DATA_PTR(self) = NULL;
328	    ossl_raise(rb_eArgError, "Could not parse the PKCS7");
329	}
330    }
331    DATA_PTR(self) = pkcs;
332    BIO_free(in);
333    ossl_pkcs7_set_data(self, Qnil);
334    ossl_pkcs7_set_err_string(self, Qnil);
335
336    return self;
337}
338
339static VALUE
340ossl_pkcs7_copy(VALUE self, VALUE other)
341{
342    PKCS7 *a, *b, *pkcs7;
343
344    rb_check_frozen(self);
345    if (self == other) return self;
346
347    GetPKCS7(self, a);
348    SafeGetPKCS7(other, b);
349
350    pkcs7 = PKCS7_dup(b);
351    if (!pkcs7) {
352	ossl_raise(ePKCS7Error, NULL);
353    }
354    DATA_PTR(self) = pkcs7;
355    PKCS7_free(a);
356
357    return self;
358}
359
360static int
361ossl_pkcs7_sym2typeid(VALUE sym)
362{
363    int i, ret = Qnil;
364    const char *s;
365
366    static struct {
367        const char *name;
368        int nid;
369    } p7_type_tab[] = {
370        { "signed",             NID_pkcs7_signed },
371        { "data",               NID_pkcs7_data },
372        { "signedAndEnveloped", NID_pkcs7_signedAndEnveloped },
373        { "enveloped",          NID_pkcs7_enveloped },
374        { "encrypted",          NID_pkcs7_encrypted },
375        { "digest",             NID_pkcs7_digest },
376        { NULL,                 0 },
377    };
378
379    if(TYPE(sym) == T_SYMBOL) s = rb_id2name(SYM2ID(sym));
380    else s = StringValuePtr(sym);
381    for(i = 0; i < numberof(p7_type_tab); i++){
382	if(p7_type_tab[i].name == NULL)
383	    ossl_raise(ePKCS7Error, "unknown type \"%s\"", s);
384	if(strcmp(p7_type_tab[i].name, s) == 0){
385	    ret = p7_type_tab[i].nid;
386	    break;
387	}
388    }
389
390    return ret;
391}
392
393/*
394 * call-seq:
395 *    pkcs7.type = type => type
396 */
397static VALUE
398ossl_pkcs7_set_type(VALUE self, VALUE type)
399{
400    PKCS7 *p7;
401
402    GetPKCS7(self, p7);
403    if(!PKCS7_set_type(p7, ossl_pkcs7_sym2typeid(type)))
404	ossl_raise(ePKCS7Error, NULL);
405
406    return type;
407}
408
409/*
410 * call-seq:
411 *    pkcs7.type => string or nil
412 */
413static VALUE
414ossl_pkcs7_get_type(VALUE self)
415{
416    PKCS7 *p7;
417
418    GetPKCS7(self, p7);
419    if(PKCS7_type_is_signed(p7))
420	return ID2SYM(rb_intern("signed"));
421    if(PKCS7_type_is_encrypted(p7))
422	return ID2SYM(rb_intern("encrypted"));
423    if(PKCS7_type_is_enveloped(p7))
424	return ID2SYM(rb_intern("enveloped"));
425    if(PKCS7_type_is_signedAndEnveloped(p7))
426	return ID2SYM(rb_intern("signedAndEnveloped"));
427    if(PKCS7_type_is_data(p7))
428	return ID2SYM(rb_intern("data"));
429    return Qnil;
430}
431
432static VALUE
433ossl_pkcs7_set_detached(VALUE self, VALUE flag)
434{
435    PKCS7 *p7;
436
437    GetPKCS7(self, p7);
438    if(flag != Qtrue && flag != Qfalse)
439	ossl_raise(ePKCS7Error, "must specify a boolean");
440    if(!PKCS7_set_detached(p7, flag == Qtrue ? 1 : 0))
441	ossl_raise(ePKCS7Error, NULL);
442
443    return flag;
444}
445
446static VALUE
447ossl_pkcs7_get_detached(VALUE self)
448{
449    PKCS7 *p7;
450    GetPKCS7(self, p7);
451    return PKCS7_get_detached(p7) ? Qtrue : Qfalse;
452}
453
454static VALUE
455ossl_pkcs7_detached_p(VALUE self)
456{
457    PKCS7 *p7;
458    GetPKCS7(self, p7);
459    return PKCS7_is_detached(p7) ? Qtrue : Qfalse;
460}
461
462static VALUE
463ossl_pkcs7_set_cipher(VALUE self, VALUE cipher)
464{
465    PKCS7 *pkcs7;
466
467    GetPKCS7(self, pkcs7);
468    if (!PKCS7_set_cipher(pkcs7, GetCipherPtr(cipher))) {
469	ossl_raise(ePKCS7Error, NULL);
470    }
471
472    return cipher;
473}
474
475static VALUE
476ossl_pkcs7_add_signer(VALUE self, VALUE signer)
477{
478    PKCS7 *pkcs7;
479    PKCS7_SIGNER_INFO *p7si;
480
481    p7si = DupPKCS7SignerPtr(signer); /* NEED TO DUP */
482    GetPKCS7(self, pkcs7);
483    if (!PKCS7_add_signer(pkcs7, p7si)) {
484	PKCS7_SIGNER_INFO_free(p7si);
485	ossl_raise(ePKCS7Error, "Could not add signer.");
486    }
487    if (PKCS7_type_is_signed(pkcs7)){
488	PKCS7_add_signed_attribute(p7si, NID_pkcs9_contentType,
489				   V_ASN1_OBJECT, OBJ_nid2obj(NID_pkcs7_data));
490    }
491
492    return self;
493}
494
495static VALUE
496ossl_pkcs7_get_signer(VALUE self)
497{
498    PKCS7 *pkcs7;
499    STACK_OF(PKCS7_SIGNER_INFO) *sk;
500    PKCS7_SIGNER_INFO *si;
501    int num, i;
502    VALUE ary;
503
504    GetPKCS7(self, pkcs7);
505    if (!(sk = PKCS7_get_signer_info(pkcs7))) {
506	OSSL_Debug("OpenSSL::PKCS7#get_signer_info == NULL!");
507	return rb_ary_new();
508    }
509    if ((num = sk_PKCS7_SIGNER_INFO_num(sk)) < 0) {
510	ossl_raise(ePKCS7Error, "Negative number of signers!");
511    }
512    ary = rb_ary_new2(num);
513    for (i=0; i<num; i++) {
514	si = sk_PKCS7_SIGNER_INFO_value(sk, i);
515	rb_ary_push(ary, ossl_pkcs7si_new(si));
516    }
517
518    return ary;
519}
520
521static VALUE
522ossl_pkcs7_add_recipient(VALUE self, VALUE recip)
523{
524    PKCS7 *pkcs7;
525    PKCS7_RECIP_INFO *ri;
526
527    ri = DupPKCS7RecipientPtr(recip); /* NEED TO DUP */
528    GetPKCS7(self, pkcs7);
529    if (!PKCS7_add_recipient_info(pkcs7, ri)) {
530	PKCS7_RECIP_INFO_free(ri);
531	ossl_raise(ePKCS7Error, "Could not add recipient.");
532    }
533
534    return self;
535}
536
537static VALUE
538ossl_pkcs7_get_recipient(VALUE self)
539{
540    PKCS7 *pkcs7;
541    STACK_OF(PKCS7_RECIP_INFO) *sk;
542    PKCS7_RECIP_INFO *si;
543    int num, i;
544    VALUE ary;
545
546    GetPKCS7(self, pkcs7);
547    if (PKCS7_type_is_enveloped(pkcs7))
548	sk = pkcs7->d.enveloped->recipientinfo;
549    else if (PKCS7_type_is_signedAndEnveloped(pkcs7))
550	sk = pkcs7->d.signed_and_enveloped->recipientinfo;
551    else sk = NULL;
552    if (!sk) return rb_ary_new();
553    if ((num = sk_PKCS7_RECIP_INFO_num(sk)) < 0) {
554	ossl_raise(ePKCS7Error, "Negative number of recipient!");
555    }
556    ary = rb_ary_new2(num);
557    for (i=0; i<num; i++) {
558	si = sk_PKCS7_RECIP_INFO_value(sk, i);
559	rb_ary_push(ary, ossl_pkcs7ri_new(si));
560    }
561
562    return ary;
563}
564
565static VALUE
566ossl_pkcs7_add_certificate(VALUE self, VALUE cert)
567{
568    PKCS7 *pkcs7;
569    X509 *x509;
570
571    GetPKCS7(self, pkcs7);
572    x509 = GetX509CertPtr(cert);  /* NO NEED TO DUP */
573    if (!PKCS7_add_certificate(pkcs7, x509)){
574	ossl_raise(ePKCS7Error, NULL);
575    }
576
577    return self;
578}
579
580static STACK_OF(X509) *
581pkcs7_get_certs(VALUE self)
582{
583    PKCS7 *pkcs7;
584    STACK_OF(X509) *certs;
585    int i;
586
587    GetPKCS7(self, pkcs7);
588    i = OBJ_obj2nid(pkcs7->type);
589    switch(i){
590    case NID_pkcs7_signed:
591        certs = pkcs7->d.sign->cert;
592        break;
593    case NID_pkcs7_signedAndEnveloped:
594        certs = pkcs7->d.signed_and_enveloped->cert;
595        break;
596    default:
597        certs = NULL;
598    }
599
600    return certs;
601}
602
603static STACK_OF(X509_CRL) *
604pkcs7_get_crls(VALUE self)
605{
606    PKCS7 *pkcs7;
607    STACK_OF(X509_CRL) *crls;
608    int i;
609
610    GetPKCS7(self, pkcs7);
611    i = OBJ_obj2nid(pkcs7->type);
612    switch(i){
613    case NID_pkcs7_signed:
614        crls = pkcs7->d.sign->crl;
615        break;
616    case NID_pkcs7_signedAndEnveloped:
617        crls = pkcs7->d.signed_and_enveloped->crl;
618        break;
619    default:
620        crls = NULL;
621    }
622
623    return crls;
624}
625
626static VALUE
627ossl_pkcs7_set_certs_i(VALUE i, VALUE arg)
628{
629    return ossl_pkcs7_add_certificate(arg, i);
630}
631
632static VALUE
633ossl_pkcs7_set_certificates(VALUE self, VALUE ary)
634{
635    STACK_OF(X509) *certs;
636    X509 *cert;
637
638    certs = pkcs7_get_certs(self);
639    while((cert = sk_X509_pop(certs))) X509_free(cert);
640    rb_block_call(ary, rb_intern("each"), 0, 0, ossl_pkcs7_set_certs_i, self);
641
642    return ary;
643}
644
645static VALUE
646ossl_pkcs7_get_certificates(VALUE self)
647{
648    return ossl_x509_sk2ary(pkcs7_get_certs(self));
649}
650
651static VALUE
652ossl_pkcs7_add_crl(VALUE self, VALUE crl)
653{
654    PKCS7 *pkcs7;
655    X509_CRL *x509crl;
656
657    GetPKCS7(self, pkcs7); /* NO DUP needed! */
658    x509crl = GetX509CRLPtr(crl);
659    if (!PKCS7_add_crl(pkcs7, x509crl)) {
660	ossl_raise(ePKCS7Error, NULL);
661    }
662
663    return self;
664}
665
666static VALUE
667ossl_pkcs7_set_crls_i(VALUE i, VALUE arg)
668{
669    return ossl_pkcs7_add_crl(arg, i);
670}
671
672static VALUE
673ossl_pkcs7_set_crls(VALUE self, VALUE ary)
674{
675    STACK_OF(X509_CRL) *crls;
676    X509_CRL *crl;
677
678    crls = pkcs7_get_crls(self);
679    while((crl = sk_X509_CRL_pop(crls))) X509_CRL_free(crl);
680    rb_block_call(ary, rb_intern("each"), 0, 0, ossl_pkcs7_set_crls_i, self);
681
682    return ary;
683}
684
685static VALUE
686ossl_pkcs7_get_crls(VALUE self)
687{
688    return ossl_x509crl_sk2ary(pkcs7_get_crls(self));
689}
690
691static VALUE
692ossl_pkcs7_verify(int argc, VALUE *argv, VALUE self)
693{
694    VALUE certs, store, indata, flags;
695    STACK_OF(X509) *x509s;
696    X509_STORE *x509st;
697    int flg, ok, status = 0;
698    BIO *in, *out;
699    PKCS7 *p7;
700    VALUE data;
701    const char *msg;
702
703    rb_scan_args(argc, argv, "22", &certs, &store, &indata, &flags);
704    flg = NIL_P(flags) ? 0 : NUM2INT(flags);
705    if(NIL_P(indata)) indata = ossl_pkcs7_get_data(self);
706    in = NIL_P(indata) ? NULL : ossl_obj2bio(indata);
707    if(NIL_P(certs)) x509s = NULL;
708    else{
709	x509s = ossl_protect_x509_ary2sk(certs, &status);
710	if(status){
711	    BIO_free(in);
712	    rb_jump_tag(status);
713	}
714    }
715    x509st = GetX509StorePtr(store);
716    GetPKCS7(self, p7);
717    if(!(out = BIO_new(BIO_s_mem()))){
718	BIO_free(in);
719	sk_X509_pop_free(x509s, X509_free);
720	ossl_raise(ePKCS7Error, NULL);
721    }
722    ok = PKCS7_verify(p7, x509s, x509st, in, out, flg);
723    BIO_free(in);
724    if (ok < 0) ossl_raise(ePKCS7Error, NULL);
725    msg = ERR_reason_error_string(ERR_get_error());
726    ossl_pkcs7_set_err_string(self, msg ? rb_str_new2(msg) : Qnil);
727    ERR_clear_error();
728    data = ossl_membio2str(out);
729    ossl_pkcs7_set_data(self, data);
730    sk_X509_pop_free(x509s, X509_free);
731
732    return (ok == 1) ? Qtrue : Qfalse;
733}
734
735static VALUE
736ossl_pkcs7_decrypt(int argc, VALUE *argv, VALUE self)
737{
738    VALUE pkey, cert, flags;
739    EVP_PKEY *key;
740    X509 *x509;
741    int flg;
742    PKCS7 *p7;
743    BIO *out;
744    VALUE str;
745
746    rb_scan_args(argc, argv, "21", &pkey, &cert, &flags);
747    key = GetPrivPKeyPtr(pkey); /* NO NEED TO DUP */
748    x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */
749    flg = NIL_P(flags) ? 0 : NUM2INT(flags);
750    GetPKCS7(self, p7);
751    if(!(out = BIO_new(BIO_s_mem())))
752	ossl_raise(ePKCS7Error, NULL);
753    if(!PKCS7_decrypt(p7, key, x509, out, flg)){
754	BIO_free(out);
755	ossl_raise(ePKCS7Error, NULL);
756    }
757    str = ossl_membio2str(out); /* out will be free */
758
759    return str;
760}
761
762static VALUE
763ossl_pkcs7_add_data(VALUE self, VALUE data)
764{
765    PKCS7 *pkcs7;
766    BIO *out, *in;
767    char buf[4096];
768    int len;
769
770    in = ossl_obj2bio(data);
771    GetPKCS7(self, pkcs7);
772    if(PKCS7_type_is_signed(pkcs7)){
773	if(!PKCS7_content_new(pkcs7, NID_pkcs7_data))
774	    ossl_raise(ePKCS7Error, NULL);
775    }
776    if(!(out = PKCS7_dataInit(pkcs7, NULL))) goto err;
777    for(;;){
778	if((len = BIO_read(in, buf, sizeof(buf))) <= 0)
779	    break;
780	if(BIO_write(out, buf, len) != len)
781	    goto err;
782    }
783    if(!PKCS7_dataFinal(pkcs7, out)) goto err;
784    ossl_pkcs7_set_data(self, Qnil);
785
786 err:
787    BIO_free(out);
788    BIO_free(in);
789    if(ERR_peek_error()){
790	ossl_raise(ePKCS7Error, NULL);
791    }
792
793    return data;
794}
795
796static VALUE
797ossl_pkcs7_to_der(VALUE self)
798{
799    PKCS7 *pkcs7;
800    VALUE str;
801    long len;
802    unsigned char *p;
803
804    GetPKCS7(self, pkcs7);
805    if((len = i2d_PKCS7(pkcs7, NULL)) <= 0)
806	ossl_raise(ePKCS7Error, NULL);
807    str = rb_str_new(0, len);
808    p = (unsigned char *)RSTRING_PTR(str);
809    if(i2d_PKCS7(pkcs7, &p) <= 0)
810	ossl_raise(ePKCS7Error, NULL);
811    ossl_str_adjust(str, p);
812
813    return str;
814}
815
816static VALUE
817ossl_pkcs7_to_pem(VALUE self)
818{
819    PKCS7 *pkcs7;
820    BIO *out;
821    VALUE str;
822
823    GetPKCS7(self, pkcs7);
824    if (!(out = BIO_new(BIO_s_mem()))) {
825	ossl_raise(ePKCS7Error, NULL);
826    }
827    if (!PEM_write_bio_PKCS7(out, pkcs7)) {
828	BIO_free(out);
829	ossl_raise(ePKCS7Error, NULL);
830    }
831    str = ossl_membio2str(out);
832
833    return str;
834}
835
836/*
837 * SIGNER INFO
838 */
839static VALUE
840ossl_pkcs7si_alloc(VALUE klass)
841{
842    PKCS7_SIGNER_INFO *p7si;
843    VALUE obj;
844
845    if (!(p7si = PKCS7_SIGNER_INFO_new())) {
846	ossl_raise(ePKCS7Error, NULL);
847    }
848    WrapPKCS7si(klass, obj, p7si);
849
850    return obj;
851}
852
853static VALUE
854ossl_pkcs7si_initialize(VALUE self, VALUE cert, VALUE key, VALUE digest)
855{
856    PKCS7_SIGNER_INFO *p7si;
857    EVP_PKEY *pkey;
858    X509 *x509;
859    const EVP_MD *md;
860
861    pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
862    x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */
863    md = GetDigestPtr(digest);
864    GetPKCS7si(self, p7si);
865    if (!(PKCS7_SIGNER_INFO_set(p7si, x509, pkey, (EVP_MD*)md))) {
866	ossl_raise(ePKCS7Error, NULL);
867    }
868
869    return self;
870}
871
872static VALUE
873ossl_pkcs7si_get_issuer(VALUE self)
874{
875    PKCS7_SIGNER_INFO *p7si;
876
877    GetPKCS7si(self, p7si);
878
879    return ossl_x509name_new(p7si->issuer_and_serial->issuer);
880}
881
882static VALUE
883ossl_pkcs7si_get_serial(VALUE self)
884{
885    PKCS7_SIGNER_INFO *p7si;
886
887    GetPKCS7si(self, p7si);
888
889    return asn1integer_to_num(p7si->issuer_and_serial->serial);
890}
891
892static VALUE
893ossl_pkcs7si_get_signed_time(VALUE self)
894{
895    PKCS7_SIGNER_INFO *p7si;
896    ASN1_TYPE *asn1obj;
897
898    GetPKCS7si(self, p7si);
899
900    if (!(asn1obj = PKCS7_get_signed_attribute(p7si, NID_pkcs9_signingTime))) {
901	ossl_raise(ePKCS7Error, NULL);
902    }
903    if (asn1obj->type == V_ASN1_UTCTIME) {
904	return asn1time_to_time(asn1obj->value.utctime);
905    }
906    /*
907     * OR
908     * ossl_raise(ePKCS7Error, "...");
909     * ?
910     */
911
912    return Qnil;
913}
914
915/*
916 * RECIPIENT INFO
917 */
918static VALUE
919ossl_pkcs7ri_alloc(VALUE klass)
920{
921    PKCS7_RECIP_INFO *p7ri;
922    VALUE obj;
923
924    if (!(p7ri = PKCS7_RECIP_INFO_new())) {
925	ossl_raise(ePKCS7Error, NULL);
926    }
927    WrapPKCS7ri(klass, obj, p7ri);
928
929    return obj;
930}
931
932static VALUE
933ossl_pkcs7ri_initialize(VALUE self, VALUE cert)
934{
935    PKCS7_RECIP_INFO *p7ri;
936    X509 *x509;
937
938    x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */
939    GetPKCS7ri(self, p7ri);
940    if (!PKCS7_RECIP_INFO_set(p7ri, x509)) {
941	ossl_raise(ePKCS7Error, NULL);
942    }
943
944    return self;
945}
946
947static VALUE
948ossl_pkcs7ri_get_issuer(VALUE self)
949{
950    PKCS7_RECIP_INFO *p7ri;
951
952    GetPKCS7ri(self, p7ri);
953
954    return ossl_x509name_new(p7ri->issuer_and_serial->issuer);
955}
956
957static VALUE
958ossl_pkcs7ri_get_serial(VALUE self)
959{
960    PKCS7_RECIP_INFO *p7ri;
961
962    GetPKCS7ri(self, p7ri);
963
964    return asn1integer_to_num(p7ri->issuer_and_serial->serial);
965}
966
967static VALUE
968ossl_pkcs7ri_get_enc_key(VALUE self)
969{
970    PKCS7_RECIP_INFO *p7ri;
971
972    GetPKCS7ri(self, p7ri);
973
974    return asn1str_to_str(p7ri->enc_key);
975}
976
977/*
978 * INIT
979 */
980void
981Init_ossl_pkcs7()
982{
983    cPKCS7 = rb_define_class_under(mOSSL, "PKCS7", rb_cObject);
984    ePKCS7Error = rb_define_class_under(cPKCS7, "PKCS7Error", eOSSLError);
985    rb_define_singleton_method(cPKCS7, "read_smime", ossl_pkcs7_s_read_smime, 1);
986    rb_define_singleton_method(cPKCS7, "write_smime", ossl_pkcs7_s_write_smime, -1);
987    rb_define_singleton_method(cPKCS7, "sign",  ossl_pkcs7_s_sign, -1);
988    rb_define_singleton_method(cPKCS7, "encrypt", ossl_pkcs7_s_encrypt, -1);
989    rb_attr(cPKCS7, rb_intern("data"), 1, 0, Qfalse);
990    rb_attr(cPKCS7, rb_intern("error_string"), 1, 1, Qfalse);
991    rb_define_alloc_func(cPKCS7, ossl_pkcs7_alloc);
992    rb_define_copy_func(cPKCS7, ossl_pkcs7_copy);
993    rb_define_method(cPKCS7, "initialize", ossl_pkcs7_initialize, -1);
994    rb_define_method(cPKCS7, "type=", ossl_pkcs7_set_type, 1);
995    rb_define_method(cPKCS7, "type", ossl_pkcs7_get_type, 0);
996    rb_define_method(cPKCS7, "detached=", ossl_pkcs7_set_detached, 1);
997    rb_define_method(cPKCS7, "detached", ossl_pkcs7_get_detached, 0);
998    rb_define_method(cPKCS7, "detached?", ossl_pkcs7_detached_p, 0);
999    rb_define_method(cPKCS7, "cipher=", ossl_pkcs7_set_cipher, 1);
1000    rb_define_method(cPKCS7, "add_signer", ossl_pkcs7_add_signer, 1);
1001    rb_define_method(cPKCS7, "signers", ossl_pkcs7_get_signer, 0);
1002    rb_define_method(cPKCS7, "add_recipient", ossl_pkcs7_add_recipient, 1);
1003    rb_define_method(cPKCS7, "recipients", ossl_pkcs7_get_recipient, 0);
1004    rb_define_method(cPKCS7, "add_certificate", ossl_pkcs7_add_certificate, 1);
1005    rb_define_method(cPKCS7, "certificates=", ossl_pkcs7_set_certificates, 1);
1006    rb_define_method(cPKCS7, "certificates", ossl_pkcs7_get_certificates, 0);
1007    rb_define_method(cPKCS7, "add_crl", ossl_pkcs7_add_crl, 1);
1008    rb_define_method(cPKCS7, "crls=", ossl_pkcs7_set_crls, 1);
1009    rb_define_method(cPKCS7, "crls", ossl_pkcs7_get_crls, 0);
1010    rb_define_method(cPKCS7, "add_data", ossl_pkcs7_add_data, 1);
1011    rb_define_alias(cPKCS7,  "data=", "add_data");
1012    rb_define_method(cPKCS7, "verify", ossl_pkcs7_verify, -1);
1013    rb_define_method(cPKCS7, "decrypt", ossl_pkcs7_decrypt, -1);
1014    rb_define_method(cPKCS7, "to_pem", ossl_pkcs7_to_pem, 0);
1015    rb_define_alias(cPKCS7,  "to_s", "to_pem");
1016    rb_define_method(cPKCS7, "to_der", ossl_pkcs7_to_der, 0);
1017
1018    cPKCS7Signer = rb_define_class_under(cPKCS7, "SignerInfo", rb_cObject);
1019    rb_define_const(cPKCS7, "Signer", cPKCS7Signer);
1020    rb_define_alloc_func(cPKCS7Signer, ossl_pkcs7si_alloc);
1021    rb_define_method(cPKCS7Signer, "initialize", ossl_pkcs7si_initialize,3);
1022    rb_define_method(cPKCS7Signer, "issuer", ossl_pkcs7si_get_issuer, 0);
1023    rb_define_alias(cPKCS7Signer, "name", "issuer");
1024    rb_define_method(cPKCS7Signer, "serial", ossl_pkcs7si_get_serial,0);
1025    rb_define_method(cPKCS7Signer,"signed_time",ossl_pkcs7si_get_signed_time,0);
1026
1027    cPKCS7Recipient = rb_define_class_under(cPKCS7,"RecipientInfo",rb_cObject);
1028    rb_define_alloc_func(cPKCS7Recipient, ossl_pkcs7ri_alloc);
1029    rb_define_method(cPKCS7Recipient, "initialize", ossl_pkcs7ri_initialize,1);
1030    rb_define_method(cPKCS7Recipient, "issuer", ossl_pkcs7ri_get_issuer,0);
1031    rb_define_method(cPKCS7Recipient, "serial", ossl_pkcs7ri_get_serial,0);
1032    rb_define_method(cPKCS7Recipient, "enc_key", ossl_pkcs7ri_get_enc_key,0);
1033
1034#define DefPKCS7Const(x) rb_define_const(cPKCS7, #x, INT2NUM(PKCS7_##x))
1035
1036    DefPKCS7Const(TEXT);
1037    DefPKCS7Const(NOCERTS);
1038    DefPKCS7Const(NOSIGS);
1039    DefPKCS7Const(NOCHAIN);
1040    DefPKCS7Const(NOINTERN);
1041    DefPKCS7Const(NOVERIFY);
1042    DefPKCS7Const(DETACHED);
1043    DefPKCS7Const(BINARY);
1044    DefPKCS7Const(NOATTR);
1045    DefPKCS7Const(NOSMIMECAP);
1046}
1047