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