Ruby  2.0.0p247(2013-06-27revision41674)
ext/openssl/ossl_pkcs7.c
Go to the documentation of this file.
00001 /*
00002  * $Id: ossl_pkcs7.c 35167 2012-03-29 01:27:17Z emboss $
00003  * 'OpenSSL for Ruby' project
00004  * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
00005  * All rights reserved.
00006  */
00007 /*
00008  * This program is licenced under the same licence as Ruby.
00009  * (See the file 'LICENCE'.)
00010  */
00011 #include "ossl.h"
00012 
00013 #define WrapPKCS7(klass, obj, pkcs7) do { \
00014     if (!(pkcs7)) { \
00015         ossl_raise(rb_eRuntimeError, "PKCS7 wasn't initialized."); \
00016     } \
00017     (obj) = Data_Wrap_Struct((klass), 0, PKCS7_free, (pkcs7)); \
00018 } while (0)
00019 #define GetPKCS7(obj, pkcs7) do { \
00020     Data_Get_Struct((obj), PKCS7, (pkcs7)); \
00021     if (!(pkcs7)) { \
00022         ossl_raise(rb_eRuntimeError, "PKCS7 wasn't initialized."); \
00023     } \
00024 } while (0)
00025 #define SafeGetPKCS7(obj, pkcs7) do { \
00026     OSSL_Check_Kind((obj), cPKCS7); \
00027     GetPKCS7((obj), (pkcs7)); \
00028 } while (0)
00029 
00030 #define WrapPKCS7si(klass, obj, p7si) do { \
00031     if (!(p7si)) { \
00032         ossl_raise(rb_eRuntimeError, "PKCS7si wasn't initialized."); \
00033     } \
00034     (obj) = Data_Wrap_Struct((klass), 0, PKCS7_SIGNER_INFO_free, (p7si)); \
00035 } while (0)
00036 #define GetPKCS7si(obj, p7si) do { \
00037     Data_Get_Struct((obj), PKCS7_SIGNER_INFO, (p7si)); \
00038     if (!(p7si)) { \
00039         ossl_raise(rb_eRuntimeError, "PKCS7si wasn't initialized."); \
00040     } \
00041 } while (0)
00042 #define SafeGetPKCS7si(obj, p7si) do { \
00043     OSSL_Check_Kind((obj), cPKCS7Signer); \
00044     GetPKCS7si((obj), (p7si)); \
00045 } while (0)
00046 
00047 #define WrapPKCS7ri(klass, obj, p7ri) do { \
00048     if (!(p7ri)) { \
00049         ossl_raise(rb_eRuntimeError, "PKCS7ri wasn't initialized."); \
00050     } \
00051     (obj) = Data_Wrap_Struct((klass), 0, PKCS7_RECIP_INFO_free, (p7ri)); \
00052 } while (0)
00053 #define GetPKCS7ri(obj, p7ri) do { \
00054     Data_Get_Struct((obj), PKCS7_RECIP_INFO, (p7ri)); \
00055     if (!(p7ri)) { \
00056         ossl_raise(rb_eRuntimeError, "PKCS7ri wasn't initialized."); \
00057     } \
00058 } while (0)
00059 #define SafeGetPKCS7ri(obj, p7ri) do { \
00060     OSSL_Check_Kind((obj), cPKCS7Recipient); \
00061     GetPKCS7ri((obj), (p7ri)); \
00062 } while (0)
00063 
00064 #define numberof(ary) (int)(sizeof(ary)/sizeof((ary)[0]))
00065 
00066 #define ossl_pkcs7_set_data(o,v)       rb_iv_set((o), "@data", (v))
00067 #define ossl_pkcs7_get_data(o)         rb_iv_get((o), "@data")
00068 #define ossl_pkcs7_set_err_string(o,v) rb_iv_set((o), "@error_string", (v))
00069 #define ossl_pkcs7_get_err_string(o)   rb_iv_get((o), "@error_string")
00070 
00071 /*
00072  * Classes
00073  */
00074 VALUE cPKCS7;
00075 VALUE cPKCS7Signer;
00076 VALUE cPKCS7Recipient;
00077 VALUE ePKCS7Error;
00078 
00079 /*
00080  * Public
00081  * (MADE PRIVATE UNTIL SOMEBODY WILL NEED THEM)
00082  */
00083 static VALUE
00084 ossl_pkcs7si_new(PKCS7_SIGNER_INFO *p7si)
00085 {
00086     PKCS7_SIGNER_INFO *pkcs7;
00087     VALUE obj;
00088 
00089     pkcs7 = p7si ? PKCS7_SIGNER_INFO_dup(p7si) : PKCS7_SIGNER_INFO_new();
00090     if (!pkcs7) ossl_raise(ePKCS7Error, NULL);
00091     WrapPKCS7si(cPKCS7Signer, obj, pkcs7);
00092 
00093     return obj;
00094 }
00095 
00096 static PKCS7_SIGNER_INFO *
00097 DupPKCS7SignerPtr(VALUE obj)
00098 {
00099     PKCS7_SIGNER_INFO *p7si, *pkcs7;
00100 
00101     SafeGetPKCS7si(obj, p7si);
00102     if (!(pkcs7 = PKCS7_SIGNER_INFO_dup(p7si))) {
00103         ossl_raise(ePKCS7Error, NULL);
00104     }
00105 
00106     return pkcs7;
00107 }
00108 
00109 static VALUE
00110 ossl_pkcs7ri_new(PKCS7_RECIP_INFO *p7ri)
00111 {
00112     PKCS7_RECIP_INFO *pkcs7;
00113     VALUE obj;
00114 
00115     pkcs7 = p7ri ? PKCS7_RECIP_INFO_dup(p7ri) : PKCS7_RECIP_INFO_new();
00116     if (!pkcs7) ossl_raise(ePKCS7Error, NULL);
00117     WrapPKCS7ri(cPKCS7Recipient, obj, pkcs7);
00118 
00119     return obj;
00120 }
00121 
00122 static PKCS7_RECIP_INFO *
00123 DupPKCS7RecipientPtr(VALUE obj)
00124 {
00125     PKCS7_RECIP_INFO *p7ri, *pkcs7;
00126 
00127     SafeGetPKCS7ri(obj, p7ri);
00128     if (!(pkcs7 = PKCS7_RECIP_INFO_dup(p7ri))) {
00129         ossl_raise(ePKCS7Error, NULL);
00130     }
00131 
00132     return pkcs7;
00133 }
00134 
00135 /*
00136  * call-seq:
00137  *    PKCS7.read_smime(string) => pkcs7
00138  */
00139 static VALUE
00140 ossl_pkcs7_s_read_smime(VALUE klass, VALUE arg)
00141 {
00142     BIO *in, *out;
00143     PKCS7 *pkcs7;
00144     VALUE ret, data;
00145 
00146     in = ossl_obj2bio(arg);
00147     out = NULL;
00148     pkcs7 = SMIME_read_PKCS7(in, &out);
00149     BIO_free(in);
00150     if(!pkcs7) ossl_raise(ePKCS7Error, NULL);
00151     data = out ? ossl_membio2str(out) : Qnil;
00152     WrapPKCS7(cPKCS7, ret, pkcs7);
00153     ossl_pkcs7_set_data(ret, data);
00154     ossl_pkcs7_set_err_string(ret, Qnil);
00155 
00156     return ret;
00157 }
00158 
00159 /*
00160  * call-seq:
00161  *    PKCS7.write_smime(pkcs7 [, data [, flags]]) => string
00162  */
00163 static VALUE
00164 ossl_pkcs7_s_write_smime(int argc, VALUE *argv, VALUE klass)
00165 {
00166     VALUE pkcs7, data, flags;
00167     BIO *out, *in;
00168     PKCS7 *p7;
00169     VALUE str;
00170     int flg;
00171 
00172     rb_scan_args(argc, argv, "12", &pkcs7, &data, &flags);
00173     flg = NIL_P(flags) ? 0 : NUM2INT(flags);
00174     if(NIL_P(data)) data = ossl_pkcs7_get_data(pkcs7);
00175     SafeGetPKCS7(pkcs7, p7);
00176     if(!NIL_P(data) && PKCS7_is_detached(p7))
00177         flg |= PKCS7_DETACHED;
00178     in = NIL_P(data) ? NULL : ossl_obj2bio(data);
00179     if(!(out = BIO_new(BIO_s_mem()))){
00180         BIO_free(in);
00181         ossl_raise(ePKCS7Error, NULL);
00182     }
00183     if(!SMIME_write_PKCS7(out, p7, in, flg)){
00184         BIO_free(out);
00185         BIO_free(in);
00186         ossl_raise(ePKCS7Error, NULL);
00187     }
00188     BIO_free(in);
00189     str = ossl_membio2str(out);
00190 
00191     return str;
00192 }
00193 
00194 /*
00195  * call-seq:
00196  *    PKCS7.sign(cert, key, data, [, certs [, flags]]) => pkcs7
00197  */
00198 static VALUE
00199 ossl_pkcs7_s_sign(int argc, VALUE *argv, VALUE klass)
00200 {
00201     VALUE cert, key, data, certs, flags;
00202     X509 *x509;
00203     EVP_PKEY *pkey;
00204     BIO *in;
00205     STACK_OF(X509) *x509s;
00206     int flg, status = 0;
00207     PKCS7 *pkcs7;
00208     VALUE ret;
00209 
00210     rb_scan_args(argc, argv, "32", &cert, &key, &data, &certs, &flags);
00211     x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */
00212     pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
00213     flg = NIL_P(flags) ? 0 : NUM2INT(flags);
00214     in = ossl_obj2bio(data);
00215     if(NIL_P(certs)) x509s = NULL;
00216     else{
00217         x509s = ossl_protect_x509_ary2sk(certs, &status);
00218         if(status){
00219             BIO_free(in);
00220             rb_jump_tag(status);
00221         }
00222     }
00223     if(!(pkcs7 = PKCS7_sign(x509, pkey, x509s, in, flg))){
00224         BIO_free(in);
00225         sk_X509_pop_free(x509s, X509_free);
00226         ossl_raise(ePKCS7Error, NULL);
00227     }
00228     WrapPKCS7(cPKCS7, ret, pkcs7);
00229     ossl_pkcs7_set_data(ret, data);
00230     ossl_pkcs7_set_err_string(ret, Qnil);
00231     BIO_free(in);
00232     sk_X509_pop_free(x509s, X509_free);
00233 
00234     return ret;
00235 }
00236 
00237 /*
00238  * call-seq:
00239  *    PKCS7.encrypt(certs, data, [, cipher [, flags]]) => pkcs7
00240  */
00241 static VALUE
00242 ossl_pkcs7_s_encrypt(int argc, VALUE *argv, VALUE klass)
00243 {
00244     VALUE certs, data, cipher, flags;
00245     STACK_OF(X509) *x509s;
00246     BIO *in;
00247     const EVP_CIPHER *ciph;
00248     int flg, status = 0;
00249     VALUE ret;
00250     PKCS7 *p7;
00251 
00252     rb_scan_args(argc, argv, "22", &certs, &data, &cipher, &flags);
00253     if(NIL_P(cipher)){
00254 #if !defined(OPENSSL_NO_RC2)
00255         ciph = EVP_rc2_40_cbc();
00256 #elif !defined(OPENSSL_NO_DES)
00257         ciph = EVP_des_ede3_cbc();
00258 #elif !defined(OPENSSL_NO_RC2)
00259         ciph = EVP_rc2_40_cbc();
00260 #elif !defined(OPENSSL_NO_AES)
00261         ciph = EVP_EVP_aes_128_cbc();
00262 #else
00263         ossl_raise(ePKCS7Error, "Must specify cipher");
00264 #endif
00265 
00266     }
00267     else ciph = GetCipherPtr(cipher); /* NO NEED TO DUP */
00268     flg = NIL_P(flags) ? 0 : NUM2INT(flags);
00269     in = ossl_obj2bio(data);
00270     x509s = ossl_protect_x509_ary2sk(certs, &status);
00271     if(status){
00272         BIO_free(in);
00273         rb_jump_tag(status);
00274     }
00275     if(!(p7 = PKCS7_encrypt(x509s, in, (EVP_CIPHER*)ciph, flg))){
00276         BIO_free(in);
00277         sk_X509_pop_free(x509s, X509_free);
00278         ossl_raise(ePKCS7Error, NULL);
00279     }
00280     BIO_free(in);
00281     WrapPKCS7(cPKCS7, ret, p7);
00282     ossl_pkcs7_set_data(ret, data);
00283     sk_X509_pop_free(x509s, X509_free);
00284 
00285     return ret;
00286 }
00287 
00288 static VALUE
00289 ossl_pkcs7_alloc(VALUE klass)
00290 {
00291     PKCS7 *pkcs7;
00292     VALUE obj;
00293 
00294     if (!(pkcs7 = PKCS7_new())) {
00295         ossl_raise(ePKCS7Error, NULL);
00296     }
00297     WrapPKCS7(klass, obj, pkcs7);
00298 
00299     return obj;
00300 }
00301 
00302 /*
00303  * call-seq:
00304  *    PKCS7.new => pkcs7
00305  *    PKCS7.new(string) => pkcs7
00306  *
00307  * Many methods in this class aren't documented.
00308  */
00309 static VALUE
00310 ossl_pkcs7_initialize(int argc, VALUE *argv, VALUE self)
00311 {
00312     PKCS7 *p7, *pkcs = DATA_PTR(self);
00313     BIO *in;
00314     VALUE arg;
00315 
00316     if(rb_scan_args(argc, argv, "01", &arg) == 0)
00317         return self;
00318     arg = ossl_to_der_if_possible(arg);
00319     in = ossl_obj2bio(arg);
00320     p7 = PEM_read_bio_PKCS7(in, &pkcs, NULL, NULL);
00321     if (!p7) {
00322         OSSL_BIO_reset(in);
00323         p7 = d2i_PKCS7_bio(in, &pkcs);
00324         if (!p7) {
00325             BIO_free(in);
00326             PKCS7_free(pkcs);
00327             DATA_PTR(self) = NULL;
00328             ossl_raise(rb_eArgError, "Could not parse the PKCS7");
00329         }
00330     }
00331     DATA_PTR(self) = pkcs;
00332     BIO_free(in);
00333     ossl_pkcs7_set_data(self, Qnil);
00334     ossl_pkcs7_set_err_string(self, Qnil);
00335 
00336     return self;
00337 }
00338 
00339 static VALUE
00340 ossl_pkcs7_copy(VALUE self, VALUE other)
00341 {
00342     PKCS7 *a, *b, *pkcs7;
00343 
00344     rb_check_frozen(self);
00345     if (self == other) return self;
00346 
00347     GetPKCS7(self, a);
00348     SafeGetPKCS7(other, b);
00349 
00350     pkcs7 = PKCS7_dup(b);
00351     if (!pkcs7) {
00352         ossl_raise(ePKCS7Error, NULL);
00353     }
00354     DATA_PTR(self) = pkcs7;
00355     PKCS7_free(a);
00356 
00357     return self;
00358 }
00359 
00360 static int
00361 ossl_pkcs7_sym2typeid(VALUE sym)
00362 {
00363     int i, ret = Qnil;
00364     const char *s;
00365 
00366     static struct {
00367         const char *name;
00368         int nid;
00369     } p7_type_tab[] = {
00370         { "signed",             NID_pkcs7_signed },
00371         { "data",               NID_pkcs7_data },
00372         { "signedAndEnveloped", NID_pkcs7_signedAndEnveloped },
00373         { "enveloped",          NID_pkcs7_enveloped },
00374         { "encrypted",          NID_pkcs7_encrypted },
00375         { "digest",             NID_pkcs7_digest },
00376         { NULL,                 0 },
00377     };
00378 
00379     if(TYPE(sym) == T_SYMBOL) s = rb_id2name(SYM2ID(sym));
00380     else s = StringValuePtr(sym);
00381     for(i = 0; i < numberof(p7_type_tab); i++){
00382         if(p7_type_tab[i].name == NULL)
00383             ossl_raise(ePKCS7Error, "unknown type \"%s\"", s);
00384         if(strcmp(p7_type_tab[i].name, s) == 0){
00385             ret = p7_type_tab[i].nid;
00386             break;
00387         }
00388     }
00389 
00390     return ret;
00391 }
00392 
00393 /*
00394  * call-seq:
00395  *    pkcs7.type = type => type
00396  */
00397 static VALUE
00398 ossl_pkcs7_set_type(VALUE self, VALUE type)
00399 {
00400     PKCS7 *p7;
00401 
00402     GetPKCS7(self, p7);
00403     if(!PKCS7_set_type(p7, ossl_pkcs7_sym2typeid(type)))
00404         ossl_raise(ePKCS7Error, NULL);
00405 
00406     return type;
00407 }
00408 
00409 /*
00410  * call-seq:
00411  *    pkcs7.type => string or nil
00412  */
00413 static VALUE
00414 ossl_pkcs7_get_type(VALUE self)
00415 {
00416     PKCS7 *p7;
00417 
00418     GetPKCS7(self, p7);
00419     if(PKCS7_type_is_signed(p7))
00420         return ID2SYM(rb_intern("signed"));
00421     if(PKCS7_type_is_encrypted(p7))
00422         return ID2SYM(rb_intern("encrypted"));
00423     if(PKCS7_type_is_enveloped(p7))
00424         return ID2SYM(rb_intern("enveloped"));
00425     if(PKCS7_type_is_signedAndEnveloped(p7))
00426         return ID2SYM(rb_intern("signedAndEnveloped"));
00427     if(PKCS7_type_is_data(p7))
00428         return ID2SYM(rb_intern("data"));
00429     return Qnil;
00430 }
00431 
00432 static VALUE
00433 ossl_pkcs7_set_detached(VALUE self, VALUE flag)
00434 {
00435     PKCS7 *p7;
00436 
00437     GetPKCS7(self, p7);
00438     if(flag != Qtrue && flag != Qfalse)
00439         ossl_raise(ePKCS7Error, "must specify a boolean");
00440     if(!PKCS7_set_detached(p7, flag == Qtrue ? 1 : 0))
00441         ossl_raise(ePKCS7Error, NULL);
00442 
00443     return flag;
00444 }
00445 
00446 static VALUE
00447 ossl_pkcs7_get_detached(VALUE self)
00448 {
00449     PKCS7 *p7;
00450     GetPKCS7(self, p7);
00451     return PKCS7_get_detached(p7) ? Qtrue : Qfalse;
00452 }
00453 
00454 static VALUE
00455 ossl_pkcs7_detached_p(VALUE self)
00456 {
00457     PKCS7 *p7;
00458     GetPKCS7(self, p7);
00459     return PKCS7_is_detached(p7) ? Qtrue : Qfalse;
00460 }
00461 
00462 static VALUE
00463 ossl_pkcs7_set_cipher(VALUE self, VALUE cipher)
00464 {
00465     PKCS7 *pkcs7;
00466 
00467     GetPKCS7(self, pkcs7);
00468     if (!PKCS7_set_cipher(pkcs7, GetCipherPtr(cipher))) {
00469         ossl_raise(ePKCS7Error, NULL);
00470     }
00471 
00472     return cipher;
00473 }
00474 
00475 static VALUE
00476 ossl_pkcs7_add_signer(VALUE self, VALUE signer)
00477 {
00478     PKCS7 *pkcs7;
00479     PKCS7_SIGNER_INFO *p7si;
00480 
00481     p7si = DupPKCS7SignerPtr(signer); /* NEED TO DUP */
00482     GetPKCS7(self, pkcs7);
00483     if (!PKCS7_add_signer(pkcs7, p7si)) {
00484         PKCS7_SIGNER_INFO_free(p7si);
00485         ossl_raise(ePKCS7Error, "Could not add signer.");
00486     }
00487     if (PKCS7_type_is_signed(pkcs7)){
00488         PKCS7_add_signed_attribute(p7si, NID_pkcs9_contentType,
00489                                    V_ASN1_OBJECT, OBJ_nid2obj(NID_pkcs7_data));
00490     }
00491 
00492     return self;
00493 }
00494 
00495 static VALUE
00496 ossl_pkcs7_get_signer(VALUE self)
00497 {
00498     PKCS7 *pkcs7;
00499     STACK_OF(PKCS7_SIGNER_INFO) *sk;
00500     PKCS7_SIGNER_INFO *si;
00501     int num, i;
00502     VALUE ary;
00503 
00504     GetPKCS7(self, pkcs7);
00505     if (!(sk = PKCS7_get_signer_info(pkcs7))) {
00506         OSSL_Debug("OpenSSL::PKCS7#get_signer_info == NULL!");
00507         return rb_ary_new();
00508     }
00509     if ((num = sk_PKCS7_SIGNER_INFO_num(sk)) < 0) {
00510         ossl_raise(ePKCS7Error, "Negative number of signers!");
00511     }
00512     ary = rb_ary_new2(num);
00513     for (i=0; i<num; i++) {
00514         si = sk_PKCS7_SIGNER_INFO_value(sk, i);
00515         rb_ary_push(ary, ossl_pkcs7si_new(si));
00516     }
00517 
00518     return ary;
00519 }
00520 
00521 static VALUE
00522 ossl_pkcs7_add_recipient(VALUE self, VALUE recip)
00523 {
00524     PKCS7 *pkcs7;
00525     PKCS7_RECIP_INFO *ri;
00526 
00527     ri = DupPKCS7RecipientPtr(recip); /* NEED TO DUP */
00528     GetPKCS7(self, pkcs7);
00529     if (!PKCS7_add_recipient_info(pkcs7, ri)) {
00530         PKCS7_RECIP_INFO_free(ri);
00531         ossl_raise(ePKCS7Error, "Could not add recipient.");
00532     }
00533 
00534     return self;
00535 }
00536 
00537 static VALUE
00538 ossl_pkcs7_get_recipient(VALUE self)
00539 {
00540     PKCS7 *pkcs7;
00541     STACK_OF(PKCS7_RECIP_INFO) *sk;
00542     PKCS7_RECIP_INFO *si;
00543     int num, i;
00544     VALUE ary;
00545 
00546     GetPKCS7(self, pkcs7);
00547     if (PKCS7_type_is_enveloped(pkcs7))
00548         sk = pkcs7->d.enveloped->recipientinfo;
00549     else if (PKCS7_type_is_signedAndEnveloped(pkcs7))
00550         sk = pkcs7->d.signed_and_enveloped->recipientinfo;
00551     else sk = NULL;
00552     if (!sk) return rb_ary_new();
00553     if ((num = sk_PKCS7_RECIP_INFO_num(sk)) < 0) {
00554         ossl_raise(ePKCS7Error, "Negative number of recipient!");
00555     }
00556     ary = rb_ary_new2(num);
00557     for (i=0; i<num; i++) {
00558         si = sk_PKCS7_RECIP_INFO_value(sk, i);
00559         rb_ary_push(ary, ossl_pkcs7ri_new(si));
00560     }
00561 
00562     return ary;
00563 }
00564 
00565 static VALUE
00566 ossl_pkcs7_add_certificate(VALUE self, VALUE cert)
00567 {
00568     PKCS7 *pkcs7;
00569     X509 *x509;
00570 
00571     GetPKCS7(self, pkcs7);
00572     x509 = GetX509CertPtr(cert);  /* NO NEED TO DUP */
00573     if (!PKCS7_add_certificate(pkcs7, x509)){
00574         ossl_raise(ePKCS7Error, NULL);
00575     }
00576 
00577     return self;
00578 }
00579 
00580 static STACK_OF(X509) *
00581 pkcs7_get_certs(VALUE self)
00582 {
00583     PKCS7 *pkcs7;
00584     STACK_OF(X509) *certs;
00585     int i;
00586 
00587     GetPKCS7(self, pkcs7);
00588     i = OBJ_obj2nid(pkcs7->type);
00589     switch(i){
00590     case NID_pkcs7_signed:
00591         certs = pkcs7->d.sign->cert;
00592         break;
00593     case NID_pkcs7_signedAndEnveloped:
00594         certs = pkcs7->d.signed_and_enveloped->cert;
00595         break;
00596     default:
00597         certs = NULL;
00598     }
00599 
00600     return certs;
00601 }
00602 
00603 static STACK_OF(X509_CRL) *
00604 pkcs7_get_crls(VALUE self)
00605 {
00606     PKCS7 *pkcs7;
00607     STACK_OF(X509_CRL) *crls;
00608     int i;
00609 
00610     GetPKCS7(self, pkcs7);
00611     i = OBJ_obj2nid(pkcs7->type);
00612     switch(i){
00613     case NID_pkcs7_signed:
00614         crls = pkcs7->d.sign->crl;
00615         break;
00616     case NID_pkcs7_signedAndEnveloped:
00617         crls = pkcs7->d.signed_and_enveloped->crl;
00618         break;
00619     default:
00620         crls = NULL;
00621     }
00622 
00623     return crls;
00624 }
00625 
00626 static VALUE
00627 ossl_pkcs7_set_certs_i(VALUE i, VALUE arg)
00628 {
00629     return ossl_pkcs7_add_certificate(arg, i);
00630 }
00631 
00632 static VALUE
00633 ossl_pkcs7_set_certificates(VALUE self, VALUE ary)
00634 {
00635     STACK_OF(X509) *certs;
00636     X509 *cert;
00637 
00638     certs = pkcs7_get_certs(self);
00639     while((cert = sk_X509_pop(certs))) X509_free(cert);
00640     rb_block_call(ary, rb_intern("each"), 0, 0, ossl_pkcs7_set_certs_i, self);
00641 
00642     return ary;
00643 }
00644 
00645 static VALUE
00646 ossl_pkcs7_get_certificates(VALUE self)
00647 {
00648     return ossl_x509_sk2ary(pkcs7_get_certs(self));
00649 }
00650 
00651 static VALUE
00652 ossl_pkcs7_add_crl(VALUE self, VALUE crl)
00653 {
00654     PKCS7 *pkcs7;
00655     X509_CRL *x509crl;
00656 
00657     GetPKCS7(self, pkcs7); /* NO DUP needed! */
00658     x509crl = GetX509CRLPtr(crl);
00659     if (!PKCS7_add_crl(pkcs7, x509crl)) {
00660         ossl_raise(ePKCS7Error, NULL);
00661     }
00662 
00663     return self;
00664 }
00665 
00666 static VALUE
00667 ossl_pkcs7_set_crls_i(VALUE i, VALUE arg)
00668 {
00669     return ossl_pkcs7_add_crl(arg, i);
00670 }
00671 
00672 static VALUE
00673 ossl_pkcs7_set_crls(VALUE self, VALUE ary)
00674 {
00675     STACK_OF(X509_CRL) *crls;
00676     X509_CRL *crl;
00677 
00678     crls = pkcs7_get_crls(self);
00679     while((crl = sk_X509_CRL_pop(crls))) X509_CRL_free(crl);
00680     rb_block_call(ary, rb_intern("each"), 0, 0, ossl_pkcs7_set_crls_i, self);
00681 
00682     return ary;
00683 }
00684 
00685 static VALUE
00686 ossl_pkcs7_get_crls(VALUE self)
00687 {
00688     return ossl_x509crl_sk2ary(pkcs7_get_crls(self));
00689 }
00690 
00691 static VALUE
00692 ossl_pkcs7_verify(int argc, VALUE *argv, VALUE self)
00693 {
00694     VALUE certs, store, indata, flags;
00695     STACK_OF(X509) *x509s;
00696     X509_STORE *x509st;
00697     int flg, ok, status = 0;
00698     BIO *in, *out;
00699     PKCS7 *p7;
00700     VALUE data;
00701     const char *msg;
00702 
00703     rb_scan_args(argc, argv, "22", &certs, &store, &indata, &flags);
00704     flg = NIL_P(flags) ? 0 : NUM2INT(flags);
00705     if(NIL_P(indata)) indata = ossl_pkcs7_get_data(self);
00706     in = NIL_P(indata) ? NULL : ossl_obj2bio(indata);
00707     if(NIL_P(certs)) x509s = NULL;
00708     else{
00709         x509s = ossl_protect_x509_ary2sk(certs, &status);
00710         if(status){
00711             BIO_free(in);
00712             rb_jump_tag(status);
00713         }
00714     }
00715     x509st = GetX509StorePtr(store);
00716     GetPKCS7(self, p7);
00717     if(!(out = BIO_new(BIO_s_mem()))){
00718         BIO_free(in);
00719         sk_X509_pop_free(x509s, X509_free);
00720         ossl_raise(ePKCS7Error, NULL);
00721     }
00722     ok = PKCS7_verify(p7, x509s, x509st, in, out, flg);
00723     BIO_free(in);
00724     if (ok < 0) ossl_raise(ePKCS7Error, NULL);
00725     msg = ERR_reason_error_string(ERR_get_error());
00726     ossl_pkcs7_set_err_string(self, msg ? rb_str_new2(msg) : Qnil);
00727     ERR_clear_error();
00728     data = ossl_membio2str(out);
00729     ossl_pkcs7_set_data(self, data);
00730     sk_X509_pop_free(x509s, X509_free);
00731 
00732     return (ok == 1) ? Qtrue : Qfalse;
00733 }
00734 
00735 static VALUE
00736 ossl_pkcs7_decrypt(int argc, VALUE *argv, VALUE self)
00737 {
00738     VALUE pkey, cert, flags;
00739     EVP_PKEY *key;
00740     X509 *x509;
00741     int flg;
00742     PKCS7 *p7;
00743     BIO *out;
00744     VALUE str;
00745 
00746     rb_scan_args(argc, argv, "21", &pkey, &cert, &flags);
00747     key = GetPrivPKeyPtr(pkey); /* NO NEED TO DUP */
00748     x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */
00749     flg = NIL_P(flags) ? 0 : NUM2INT(flags);
00750     GetPKCS7(self, p7);
00751     if(!(out = BIO_new(BIO_s_mem())))
00752         ossl_raise(ePKCS7Error, NULL);
00753     if(!PKCS7_decrypt(p7, key, x509, out, flg)){
00754         BIO_free(out);
00755         ossl_raise(ePKCS7Error, NULL);
00756     }
00757     str = ossl_membio2str(out); /* out will be free */
00758 
00759     return str;
00760 }
00761 
00762 static VALUE
00763 ossl_pkcs7_add_data(VALUE self, VALUE data)
00764 {
00765     PKCS7 *pkcs7;
00766     BIO *out, *in;
00767     char buf[4096];
00768     int len;
00769 
00770     in = ossl_obj2bio(data);
00771     GetPKCS7(self, pkcs7);
00772     if(PKCS7_type_is_signed(pkcs7)){
00773         if(!PKCS7_content_new(pkcs7, NID_pkcs7_data))
00774             ossl_raise(ePKCS7Error, NULL);
00775     }
00776     if(!(out = PKCS7_dataInit(pkcs7, NULL))) goto err;
00777     for(;;){
00778         if((len = BIO_read(in, buf, sizeof(buf))) <= 0)
00779             break;
00780         if(BIO_write(out, buf, len) != len)
00781             goto err;
00782     }
00783     if(!PKCS7_dataFinal(pkcs7, out)) goto err;
00784     ossl_pkcs7_set_data(self, Qnil);
00785 
00786  err:
00787     BIO_free(out);
00788     BIO_free(in);
00789     if(ERR_peek_error()){
00790         ossl_raise(ePKCS7Error, NULL);
00791     }
00792 
00793     return data;
00794 }
00795 
00796 static VALUE
00797 ossl_pkcs7_to_der(VALUE self)
00798 {
00799     PKCS7 *pkcs7;
00800     VALUE str;
00801     long len;
00802     unsigned char *p;
00803 
00804     GetPKCS7(self, pkcs7);
00805     if((len = i2d_PKCS7(pkcs7, NULL)) <= 0)
00806         ossl_raise(ePKCS7Error, NULL);
00807     str = rb_str_new(0, len);
00808     p = (unsigned char *)RSTRING_PTR(str);
00809     if(i2d_PKCS7(pkcs7, &p) <= 0)
00810         ossl_raise(ePKCS7Error, NULL);
00811     ossl_str_adjust(str, p);
00812 
00813     return str;
00814 }
00815 
00816 static VALUE
00817 ossl_pkcs7_to_pem(VALUE self)
00818 {
00819     PKCS7 *pkcs7;
00820     BIO *out;
00821     VALUE str;
00822 
00823     GetPKCS7(self, pkcs7);
00824     if (!(out = BIO_new(BIO_s_mem()))) {
00825         ossl_raise(ePKCS7Error, NULL);
00826     }
00827     if (!PEM_write_bio_PKCS7(out, pkcs7)) {
00828         BIO_free(out);
00829         ossl_raise(ePKCS7Error, NULL);
00830     }
00831     str = ossl_membio2str(out);
00832 
00833     return str;
00834 }
00835 
00836 /*
00837  * SIGNER INFO
00838  */
00839 static VALUE
00840 ossl_pkcs7si_alloc(VALUE klass)
00841 {
00842     PKCS7_SIGNER_INFO *p7si;
00843     VALUE obj;
00844 
00845     if (!(p7si = PKCS7_SIGNER_INFO_new())) {
00846         ossl_raise(ePKCS7Error, NULL);
00847     }
00848     WrapPKCS7si(klass, obj, p7si);
00849 
00850     return obj;
00851 }
00852 
00853 static VALUE
00854 ossl_pkcs7si_initialize(VALUE self, VALUE cert, VALUE key, VALUE digest)
00855 {
00856     PKCS7_SIGNER_INFO *p7si;
00857     EVP_PKEY *pkey;
00858     X509 *x509;
00859     const EVP_MD *md;
00860 
00861     pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
00862     x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */
00863     md = GetDigestPtr(digest);
00864     GetPKCS7si(self, p7si);
00865     if (!(PKCS7_SIGNER_INFO_set(p7si, x509, pkey, (EVP_MD*)md))) {
00866         ossl_raise(ePKCS7Error, NULL);
00867     }
00868 
00869     return self;
00870 }
00871 
00872 static VALUE
00873 ossl_pkcs7si_get_issuer(VALUE self)
00874 {
00875     PKCS7_SIGNER_INFO *p7si;
00876 
00877     GetPKCS7si(self, p7si);
00878 
00879     return ossl_x509name_new(p7si->issuer_and_serial->issuer);
00880 }
00881 
00882 static VALUE
00883 ossl_pkcs7si_get_serial(VALUE self)
00884 {
00885     PKCS7_SIGNER_INFO *p7si;
00886 
00887     GetPKCS7si(self, p7si);
00888 
00889     return asn1integer_to_num(p7si->issuer_and_serial->serial);
00890 }
00891 
00892 static VALUE
00893 ossl_pkcs7si_get_signed_time(VALUE self)
00894 {
00895     PKCS7_SIGNER_INFO *p7si;
00896     ASN1_TYPE *asn1obj;
00897 
00898     GetPKCS7si(self, p7si);
00899 
00900     if (!(asn1obj = PKCS7_get_signed_attribute(p7si, NID_pkcs9_signingTime))) {
00901         ossl_raise(ePKCS7Error, NULL);
00902     }
00903     if (asn1obj->type == V_ASN1_UTCTIME) {
00904         return asn1time_to_time(asn1obj->value.utctime);
00905     }
00906     /*
00907      * OR
00908      * ossl_raise(ePKCS7Error, "...");
00909      * ?
00910      */
00911 
00912     return Qnil;
00913 }
00914 
00915 /*
00916  * RECIPIENT INFO
00917  */
00918 static VALUE
00919 ossl_pkcs7ri_alloc(VALUE klass)
00920 {
00921     PKCS7_RECIP_INFO *p7ri;
00922     VALUE obj;
00923 
00924     if (!(p7ri = PKCS7_RECIP_INFO_new())) {
00925         ossl_raise(ePKCS7Error, NULL);
00926     }
00927     WrapPKCS7ri(klass, obj, p7ri);
00928 
00929     return obj;
00930 }
00931 
00932 static VALUE
00933 ossl_pkcs7ri_initialize(VALUE self, VALUE cert)
00934 {
00935     PKCS7_RECIP_INFO *p7ri;
00936     X509 *x509;
00937 
00938     x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */
00939     GetPKCS7ri(self, p7ri);
00940     if (!PKCS7_RECIP_INFO_set(p7ri, x509)) {
00941         ossl_raise(ePKCS7Error, NULL);
00942     }
00943 
00944     return self;
00945 }
00946 
00947 static VALUE
00948 ossl_pkcs7ri_get_issuer(VALUE self)
00949 {
00950     PKCS7_RECIP_INFO *p7ri;
00951 
00952     GetPKCS7ri(self, p7ri);
00953 
00954     return ossl_x509name_new(p7ri->issuer_and_serial->issuer);
00955 }
00956 
00957 static VALUE
00958 ossl_pkcs7ri_get_serial(VALUE self)
00959 {
00960     PKCS7_RECIP_INFO *p7ri;
00961 
00962     GetPKCS7ri(self, p7ri);
00963 
00964     return asn1integer_to_num(p7ri->issuer_and_serial->serial);
00965 }
00966 
00967 static VALUE
00968 ossl_pkcs7ri_get_enc_key(VALUE self)
00969 {
00970     PKCS7_RECIP_INFO *p7ri;
00971 
00972     GetPKCS7ri(self, p7ri);
00973 
00974     return asn1str_to_str(p7ri->enc_key);
00975 }
00976 
00977 /*
00978  * INIT
00979  */
00980 void
00981 Init_ossl_pkcs7()
00982 {
00983     cPKCS7 = rb_define_class_under(mOSSL, "PKCS7", rb_cObject);
00984     ePKCS7Error = rb_define_class_under(cPKCS7, "PKCS7Error", eOSSLError);
00985     rb_define_singleton_method(cPKCS7, "read_smime", ossl_pkcs7_s_read_smime, 1);
00986     rb_define_singleton_method(cPKCS7, "write_smime", ossl_pkcs7_s_write_smime, -1);
00987     rb_define_singleton_method(cPKCS7, "sign",  ossl_pkcs7_s_sign, -1);
00988     rb_define_singleton_method(cPKCS7, "encrypt", ossl_pkcs7_s_encrypt, -1);
00989     rb_attr(cPKCS7, rb_intern("data"), 1, 0, Qfalse);
00990     rb_attr(cPKCS7, rb_intern("error_string"), 1, 1, Qfalse);
00991     rb_define_alloc_func(cPKCS7, ossl_pkcs7_alloc);
00992     rb_define_copy_func(cPKCS7, ossl_pkcs7_copy);
00993     rb_define_method(cPKCS7, "initialize", ossl_pkcs7_initialize, -1);
00994     rb_define_method(cPKCS7, "type=", ossl_pkcs7_set_type, 1);
00995     rb_define_method(cPKCS7, "type", ossl_pkcs7_get_type, 0);
00996     rb_define_method(cPKCS7, "detached=", ossl_pkcs7_set_detached, 1);
00997     rb_define_method(cPKCS7, "detached", ossl_pkcs7_get_detached, 0);
00998     rb_define_method(cPKCS7, "detached?", ossl_pkcs7_detached_p, 0);
00999     rb_define_method(cPKCS7, "cipher=", ossl_pkcs7_set_cipher, 1);
01000     rb_define_method(cPKCS7, "add_signer", ossl_pkcs7_add_signer, 1);
01001     rb_define_method(cPKCS7, "signers", ossl_pkcs7_get_signer, 0);
01002     rb_define_method(cPKCS7, "add_recipient", ossl_pkcs7_add_recipient, 1);
01003     rb_define_method(cPKCS7, "recipients", ossl_pkcs7_get_recipient, 0);
01004     rb_define_method(cPKCS7, "add_certificate", ossl_pkcs7_add_certificate, 1);
01005     rb_define_method(cPKCS7, "certificates=", ossl_pkcs7_set_certificates, 1);
01006     rb_define_method(cPKCS7, "certificates", ossl_pkcs7_get_certificates, 0);
01007     rb_define_method(cPKCS7, "add_crl", ossl_pkcs7_add_crl, 1);
01008     rb_define_method(cPKCS7, "crls=", ossl_pkcs7_set_crls, 1);
01009     rb_define_method(cPKCS7, "crls", ossl_pkcs7_get_crls, 0);
01010     rb_define_method(cPKCS7, "add_data", ossl_pkcs7_add_data, 1);
01011     rb_define_alias(cPKCS7,  "data=", "add_data");
01012     rb_define_method(cPKCS7, "verify", ossl_pkcs7_verify, -1);
01013     rb_define_method(cPKCS7, "decrypt", ossl_pkcs7_decrypt, -1);
01014     rb_define_method(cPKCS7, "to_pem", ossl_pkcs7_to_pem, 0);
01015     rb_define_alias(cPKCS7,  "to_s", "to_pem");
01016     rb_define_method(cPKCS7, "to_der", ossl_pkcs7_to_der, 0);
01017 
01018     cPKCS7Signer = rb_define_class_under(cPKCS7, "SignerInfo", rb_cObject);
01019     rb_define_const(cPKCS7, "Signer", cPKCS7Signer);
01020     rb_define_alloc_func(cPKCS7Signer, ossl_pkcs7si_alloc);
01021     rb_define_method(cPKCS7Signer, "initialize", ossl_pkcs7si_initialize,3);
01022     rb_define_method(cPKCS7Signer, "issuer", ossl_pkcs7si_get_issuer, 0);
01023     rb_define_alias(cPKCS7Signer, "name", "issuer");
01024     rb_define_method(cPKCS7Signer, "serial", ossl_pkcs7si_get_serial,0);
01025     rb_define_method(cPKCS7Signer,"signed_time",ossl_pkcs7si_get_signed_time,0);
01026 
01027     cPKCS7Recipient = rb_define_class_under(cPKCS7,"RecipientInfo",rb_cObject);
01028     rb_define_alloc_func(cPKCS7Recipient, ossl_pkcs7ri_alloc);
01029     rb_define_method(cPKCS7Recipient, "initialize", ossl_pkcs7ri_initialize,1);
01030     rb_define_method(cPKCS7Recipient, "issuer", ossl_pkcs7ri_get_issuer,0);
01031     rb_define_method(cPKCS7Recipient, "serial", ossl_pkcs7ri_get_serial,0);
01032     rb_define_method(cPKCS7Recipient, "enc_key", ossl_pkcs7ri_get_enc_key,0);
01033 
01034 #define DefPKCS7Const(x) rb_define_const(cPKCS7, #x, INT2NUM(PKCS7_##x))
01035 
01036     DefPKCS7Const(TEXT);
01037     DefPKCS7Const(NOCERTS);
01038     DefPKCS7Const(NOSIGS);
01039     DefPKCS7Const(NOCHAIN);
01040     DefPKCS7Const(NOINTERN);
01041     DefPKCS7Const(NOVERIFY);
01042     DefPKCS7Const(DETACHED);
01043     DefPKCS7Const(BINARY);
01044     DefPKCS7Const(NOATTR);
01045     DefPKCS7Const(NOSMIMECAP);
01046 }
01047