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