1/* 2 * This program is licenced under the same licence as Ruby. 3 * (See the file 'LICENCE'.) 4 * $Id: ossl_pkcs12.c 32199 2011-06-22 08:41:08Z emboss $ 5 */ 6#include "ossl.h" 7 8#define WrapPKCS12(klass, obj, p12) do { \ 9 if(!(p12)) ossl_raise(rb_eRuntimeError, "PKCS12 wasn't initialized."); \ 10 (obj) = Data_Wrap_Struct((klass), 0, PKCS12_free, (p12)); \ 11} while (0) 12 13#define GetPKCS12(obj, p12) do { \ 14 Data_Get_Struct((obj), PKCS12, (p12)); \ 15 if(!(p12)) ossl_raise(rb_eRuntimeError, "PKCS12 wasn't initialized."); \ 16} while (0) 17 18#define SafeGetPKCS12(obj, p12) do { \ 19 OSSL_Check_Kind((obj), cPKCS12); \ 20 GetPKCS12((obj), (p12)); \ 21} while (0) 22 23#define ossl_pkcs12_set_key(o,v) rb_iv_set((o), "@key", (v)) 24#define ossl_pkcs12_set_cert(o,v) rb_iv_set((o), "@certificate", (v)) 25#define ossl_pkcs12_set_ca_certs(o,v) rb_iv_set((o), "@ca_certs", (v)) 26#define ossl_pkcs12_get_key(o) rb_iv_get((o), "@key") 27#define ossl_pkcs12_get_cert(o) rb_iv_get((o), "@certificate") 28#define ossl_pkcs12_get_ca_certs(o) rb_iv_get((o), "@ca_certs") 29 30/* 31 * Classes 32 */ 33VALUE cPKCS12; 34VALUE ePKCS12Error; 35 36/* 37 * Private 38 */ 39static VALUE 40ossl_pkcs12_s_allocate(VALUE klass) 41{ 42 PKCS12 *p12; 43 VALUE obj; 44 45 if(!(p12 = PKCS12_new())) ossl_raise(ePKCS12Error, NULL); 46 WrapPKCS12(klass, obj, p12); 47 48 return obj; 49} 50 51/* 52 * call-seq: 53 * PKCS12.create(pass, name, key, cert [, ca, [, key_pbe [, cert_pbe [, key_iter [, mac_iter [, keytype]]]]]]) 54 * 55 * === Parameters 56 * * +pass+ - string 57 * * +name+ - A string describing the key. 58 * * +key+ - Any PKey. 59 * * +cert+ - A X509::Certificate. 60 * * * The public_key portion of the certificate must contain a valid public key. 61 * * * The not_before and not_after fields must be filled in. 62 * * +ca+ - An optional array of X509::Certificate's. 63 * * +key_pbe+ - string 64 * * +cert_pbe+ - string 65 * * +key_iter+ - integer 66 * * +mac_iter+ - integer 67 * * +keytype+ - An integer representing an MSIE specific extension. 68 * 69 * Any optional arguments may be supplied as nil to preserve the OpenSSL defaults. 70 * 71 * See the OpenSSL documentation for PKCS12_create(). 72 */ 73static VALUE 74ossl_pkcs12_s_create(int argc, VALUE *argv, VALUE self) 75{ 76 VALUE pass, name, pkey, cert, ca, key_nid, cert_nid, key_iter, mac_iter, keytype; 77 VALUE obj; 78 char *passphrase, *friendlyname; 79 EVP_PKEY *key; 80 X509 *x509; 81 STACK_OF(X509) *x509s; 82 int nkey = 0, ncert = 0, kiter = 0, miter = 0, ktype = 0; 83 PKCS12 *p12; 84 85 rb_scan_args(argc, argv, "46", &pass, &name, &pkey, &cert, &ca, &key_nid, &cert_nid, &key_iter, &mac_iter, &keytype); 86 passphrase = NIL_P(pass) ? NULL : StringValuePtr(pass); 87 friendlyname = NIL_P(name) ? NULL : StringValuePtr(name); 88 key = GetPKeyPtr(pkey); 89 x509 = GetX509CertPtr(cert); 90 x509s = NIL_P(ca) ? NULL : ossl_x509_ary2sk(ca); 91/* TODO: make a VALUE to nid function */ 92 if (!NIL_P(key_nid)) { 93 if ((nkey = OBJ_txt2nid(StringValuePtr(key_nid))) == NID_undef) 94 ossl_raise(rb_eArgError, "Unknown PBE algorithm %s", StringValuePtr(key_nid)); 95 } 96 if (!NIL_P(cert_nid)) { 97 if ((ncert = OBJ_txt2nid(StringValuePtr(cert_nid))) == NID_undef) 98 ossl_raise(rb_eArgError, "Unknown PBE algorithm %s", StringValuePtr(cert_nid)); 99 } 100 if (!NIL_P(key_iter)) 101 kiter = NUM2INT(key_iter); 102 if (!NIL_P(mac_iter)) 103 miter = NUM2INT(mac_iter); 104 if (!NIL_P(keytype)) 105 ktype = NUM2INT(keytype); 106 107 p12 = PKCS12_create(passphrase, friendlyname, key, x509, x509s, 108 nkey, ncert, kiter, miter, ktype); 109 sk_X509_pop_free(x509s, X509_free); 110 if(!p12) ossl_raise(ePKCS12Error, NULL); 111 WrapPKCS12(cPKCS12, obj, p12); 112 113 ossl_pkcs12_set_key(obj, pkey); 114 ossl_pkcs12_set_cert(obj, cert); 115 ossl_pkcs12_set_ca_certs(obj, ca); 116 117 return obj; 118} 119 120/* 121 * call-seq: 122 * PKCS12.new -> pkcs12 123 * PKCS12.new(str) -> pkcs12 124 * PKCS12.new(str, pass) -> pkcs12 125 * 126 * === Parameters 127 * * +str+ - Must be a DER encoded PKCS12 string. 128 * * +pass+ - string 129 */ 130static VALUE 131ossl_pkcs12_initialize(int argc, VALUE *argv, VALUE self) 132{ 133 BIO *in; 134 VALUE arg, pass, pkey, cert, ca; 135 char *passphrase; 136 EVP_PKEY *key; 137 X509 *x509; 138 STACK_OF(X509) *x509s = NULL; 139 int st = 0; 140 PKCS12 *pkcs = DATA_PTR(self); 141 142 if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) return self; 143 passphrase = NIL_P(pass) ? NULL : StringValuePtr(pass); 144 in = ossl_obj2bio(arg); 145 d2i_PKCS12_bio(in, &pkcs); 146 DATA_PTR(self) = pkcs; 147 BIO_free(in); 148 149 pkey = cert = ca = Qnil; 150 if(!PKCS12_parse(pkcs, passphrase, &key, &x509, &x509s)) 151 ossl_raise(ePKCS12Error, "PKCS12_parse"); 152 pkey = rb_protect((VALUE(*)_((VALUE)))ossl_pkey_new, (VALUE)key, 153 &st); /* NO DUP */ 154 if(st) goto err; 155 cert = rb_protect((VALUE(*)_((VALUE)))ossl_x509_new, (VALUE)x509, &st); 156 if(st) goto err; 157 if(x509s){ 158 ca = 159 rb_protect((VALUE(*)_((VALUE)))ossl_x509_sk2ary, (VALUE)x509s, &st); 160 if(st) goto err; 161 } 162 163 err: 164 X509_free(x509); 165 sk_X509_pop_free(x509s, X509_free); 166 ossl_pkcs12_set_key(self, pkey); 167 ossl_pkcs12_set_cert(self, cert); 168 ossl_pkcs12_set_ca_certs(self, ca); 169 if(st) rb_jump_tag(st); 170 171 return self; 172} 173 174static VALUE 175ossl_pkcs12_to_der(VALUE self) 176{ 177 PKCS12 *p12; 178 VALUE str; 179 long len; 180 unsigned char *p; 181 182 GetPKCS12(self, p12); 183 if((len = i2d_PKCS12(p12, NULL)) <= 0) 184 ossl_raise(ePKCS12Error, NULL); 185 str = rb_str_new(0, len); 186 p = (unsigned char *)RSTRING_PTR(str); 187 if(i2d_PKCS12(p12, &p) <= 0) 188 ossl_raise(ePKCS12Error, NULL); 189 ossl_str_adjust(str, p); 190 191 return str; 192} 193 194void 195Init_ossl_pkcs12() 196{ 197 /* 198 * Defines a file format commonly used to store private keys with 199 * accompanying public key certificates, protected with a password-based 200 * symmetric key. 201 */ 202 cPKCS12 = rb_define_class_under(mOSSL, "PKCS12", rb_cObject); 203 ePKCS12Error = rb_define_class_under(cPKCS12, "PKCS12Error", eOSSLError); 204 rb_define_singleton_method(cPKCS12, "create", ossl_pkcs12_s_create, -1); 205 206 rb_define_alloc_func(cPKCS12, ossl_pkcs12_s_allocate); 207 rb_attr(cPKCS12, rb_intern("key"), 1, 0, Qfalse); 208 rb_attr(cPKCS12, rb_intern("certificate"), 1, 0, Qfalse); 209 rb_attr(cPKCS12, rb_intern("ca_certs"), 1, 0, Qfalse); 210 rb_define_method(cPKCS12, "initialize", ossl_pkcs12_initialize, -1); 211 rb_define_method(cPKCS12, "to_der", ossl_pkcs12_to_der, 0); 212} 213