File Coverage

PKCS12.xs
Criterion Covered Total %
statement 125 174 71.8
branch 51 98 52.0
condition n/a
subroutine n/a
pod n/a
total 176 272 64.7


line stmt bran cond sub pod time code
1             #include "EXTERN.h"
2             #include "perl.h"
3             #include "XSUB.h"
4              
5             #include
6             #include
7             #include
8             #include
9             #include
10             #include
11              
12             #define NOKEYS 0x1
13             #define NOCERTS 0x2
14             #define INFO 0x4
15             #define CLCERTS 0x8
16             #define CACERTS 0x10
17              
18             #if OPENSSL_VERSION_NUMBER < 0x10100000L
19             #define PKCS12_SAFEBAG_get0_p8inf(o) ((o)->value.keybag)
20             #define PKCS12_SAFEBAG_get0_attr PKCS12_get_attr
21             #define CONST_PKCS8_PRIV_KEY_INFO PKCS8_PRIV_KEY_INFO
22             #else
23             #define CONST_PKCS8_PRIV_KEY_INFO const PKCS8_PRIV_KEY_INFO
24             #endif
25              
26             const EVP_CIPHER *enc;
27              
28             /* fake our package name */
29             typedef PKCS12* Crypt__OpenSSL__PKCS12;
30              
31 0           void croakSSL(char* p_file, int p_line) {
32              
33             const char* errorReason;
34              
35             /* Just return the top error on the stack */
36 0           errorReason = ERR_reason_error_string(ERR_get_error());
37              
38 0           ERR_clear_error();
39              
40 0           croak("%s:%d: OpenSSL error: %s", p_file, p_line, errorReason);
41             }
42              
43             #define CHECK_OPEN_SSL(p_result) if (!(p_result)) croakSSL(__FILE__, __LINE__);
44              
45 1           EVP_PKEY* _load_pkey(char* keyString, EVP_PKEY*(*p_loader)(BIO*, EVP_PKEY**, pem_password_cb*, void*)) {
46              
47             EVP_PKEY* pkey;
48             BIO* stringBIO;
49              
50 1 50         if (!strncmp(keyString, "----", 4)) {
51              
52 0 0         CHECK_OPEN_SSL(stringBIO = BIO_new_mem_buf(keyString, strlen(keyString)));
53              
54             } else {
55              
56 1 50         CHECK_OPEN_SSL(stringBIO = BIO_new_file(keyString, "r"));
57             }
58              
59 1           pkey = p_loader(stringBIO, NULL, NULL, NULL);
60              
61 1           (void)BIO_set_close(stringBIO, BIO_CLOSE);
62 1           BIO_free_all(stringBIO);
63              
64 1 50         CHECK_OPEN_SSL(pkey);
65 1           return pkey;
66             }
67              
68 1           STACK_OF(X509)* _load_cert_chain(char* keyString, STACK_OF(X509_INFO)*(*p_loader)(BIO*, STACK_OF(X509_INFO)*, pem_password_cb*, void*)) {
69             int i;
70 1           STACK_OF(X509_INFO) *xis = NULL;
71 1           X509_INFO *xi = NULL;
72             BIO* stringBIO;
73 1           STACK_OF(X509) *stack = sk_X509_new_null();
74              
75 1 50         if (!strncmp(keyString, "----", 4)) {
76 0 0         CHECK_OPEN_SSL(stringBIO = BIO_new_mem_buf(keyString, strlen(keyString)));
77             } else {
78 1 50         CHECK_OPEN_SSL(stringBIO = BIO_new_file(keyString, "r"));
79             }
80              
81 1           xis = p_loader(stringBIO, NULL, NULL, NULL);
82 2 100         for (i = 0; i < sk_X509_INFO_num(xis); i++) {
83 1           xi = sk_X509_INFO_value(xis, i);
84 1 50         if (xi->x509 != NULL && stack != NULL) {
    50          
85 1 50         CHECK_OPEN_SSL(xi->x509);
86 1 50         if (!sk_X509_push(stack, xi->x509))
87 0           goto end;
88 1           xi->x509 = NULL;
89             }
90             }
91              
92             end:
93 1           sk_X509_INFO_pop_free(xis, X509_INFO_free);
94 1           (void)BIO_set_close(stringBIO, BIO_CLOSE);
95 1           BIO_free_all(stringBIO);
96              
97 1           return stack;
98             }
99              
100             /* stolen from OpenSSL.xs */
101 40           long bio_write_cb(struct bio_st *bm, int m, const char *ptr, int l, long x, long y) {
102              
103 40 100         if (m == BIO_CB_WRITE) {
104 17           SV *sv = (SV *) BIO_get_callback_arg(bm);
105 17           sv_catpvn(sv, ptr, l);
106             }
107              
108 40 50         if (m == BIO_CB_PUTS) {
109 0           SV *sv = (SV *) BIO_get_callback_arg(bm);
110 0           l = strlen(ptr);
111 0           sv_catpvn(sv, ptr, l);
112             }
113              
114 40           return l;
115             }
116              
117 3           static BIO* sv_bio_create(void) {
118              
119 3           SV *sv = newSVpvn("",0);
120              
121             /* create an in-memory BIO abstraction and callbacks */
122 3           BIO *bio = BIO_new(BIO_s_mem());
123              
124 3           BIO_set_callback(bio, bio_write_cb);
125 3           BIO_set_callback_arg(bio, (void *)sv);
126              
127 3           return bio;
128             }
129              
130 3           static SV* sv_bio_final(BIO *bio) {
131              
132             SV* sv;
133              
134 3           (void)BIO_flush(bio);
135 3           sv = (SV *)BIO_get_callback_arg(bio);
136 3           BIO_set_callback_arg(bio, (void *)NULL);
137 3           BIO_set_callback(bio, (void *)NULL);
138 3           BIO_free_all(bio);
139              
140 3 50         if (!sv) sv = &PL_sv_undef;
141              
142 3           return sv;
143             }
144              
145 0           static void sv_bio_error(BIO *bio) {
146              
147 0           SV* sv = (SV *)BIO_get_callback_arg(bio);
148 0 0         if (sv) sv_free(sv);
149              
150 0           BIO_free_all (bio);
151 0           }
152              
153 0           static const char *ssl_error(void) {
154             BIO *bio;
155             SV *sv;
156             STRLEN l;
157              
158 0           bio = sv_bio_create();
159 0           ERR_print_errors(bio);
160 0           sv = sv_bio_final(bio);
161 0           ERR_clear_error();
162 0 0         return SvPV(sv, l);
163             }
164              
165             /* these are trimmed from their openssl/apps/pkcs12.c counterparts */
166 6           int dump_certs_pkeys_bag (BIO *bio, PKCS12_SAFEBAG *bag, char *pass, int passlen, int options, char *pempass) {
167              
168             EVP_PKEY *pkey;
169             X509 *x509;
170             PKCS8_PRIV_KEY_INFO *p8;
171             CONST_PKCS8_PRIV_KEY_INFO *p8c;
172              
173 6           switch (M_PKCS12_bag_type(bag)) {
174              
175             case NID_keyBag: ;
176              
177 0 0         if (options & NOKEYS) return 1;
178              
179 0           p8c = PKCS12_SAFEBAG_get0_p8inf(bag);
180              
181 0 0         if (!(pkey = EVP_PKCS82PKEY (p8c))) return 0;
182              
183 0           PEM_write_bio_PrivateKey (bio, pkey, enc, NULL, 0, NULL, pempass);
184              
185 0           EVP_PKEY_free(pkey);
186              
187 0           break;
188              
189             case NID_pkcs8ShroudedKeyBag: ;
190              
191 2 100         if (options & NOKEYS) return 1;
192              
193 1 50         if (!(p8 = PKCS12_decrypt_skey(bag, pass, passlen)))
194 0           return 0;
195              
196 1 50         if (!(pkey = EVP_PKCS82PKEY (p8))) {
197 0           PKCS8_PRIV_KEY_INFO_free(p8);
198 0           return 0;
199             }
200              
201 1           PKCS8_PRIV_KEY_INFO_free(p8);
202              
203 1           PEM_write_bio_PrivateKey (bio, pkey, enc, NULL, 0, NULL, pempass);
204              
205 1           EVP_PKEY_free(pkey);
206              
207 1           break;
208              
209             case NID_certBag:
210              
211 4 100         if (options & NOCERTS) return 1;
212              
213 2 100         if (PKCS12_SAFEBAG_get0_attr(bag, NID_localKeyID)) {
214              
215 1 50         if (options & CACERTS) return 1;
216              
217 1 50         } else if (options & CLCERTS) {
218              
219 1           return 1;
220             }
221              
222 1 50         if (M_PKCS12_cert_bag_type(bag) != NID_x509Certificate) return 1;
223              
224 1 50         if (!(x509 = PKCS12_certbag2x509(bag))) return 0;
225              
226 1           PEM_write_bio_X509 (bio, x509);
227              
228 1           X509_free(x509);
229              
230 1           break;
231             }
232              
233 2           return 1;
234             }
235              
236 4           int dump_certs_pkeys_bags(BIO *bio, STACK_OF(PKCS12_SAFEBAG) *bags, char *pass, int passlen, int options, char *pempass) {
237              
238             int i;
239              
240 10 100         for (i = 0; i < sk_PKCS12_SAFEBAG_num(bags); i++) {
241              
242 6 50         if (!dump_certs_pkeys_bag (bio, sk_PKCS12_SAFEBAG_value (bags, i), pass, passlen, options, pempass)) {
243 0           return 0;
244             }
245             }
246              
247 4           return 1;
248             }
249              
250 2           int dump_certs_keys_p12(BIO *bio, PKCS12 *p12, char *pass, int passlen, int options, char *pempass) {
251              
252             STACK_OF(PKCS7) *asafes;
253             STACK_OF(PKCS12_SAFEBAG) *bags;
254              
255             int i, bagnid;
256             PKCS7 *p7;
257              
258 2 50         if ((asafes = PKCS12_unpack_authsafes(p12)) == NULL) {
259 0           croak("Unable to PKCS12_unpack_authsafes");
260             return 0;
261             }
262              
263 6 100         for (i = 0; i < sk_PKCS7_num(asafes); i++) {
264              
265 4           p7 = sk_PKCS7_value(asafes, i);
266              
267 4           bagnid = OBJ_obj2nid(p7->type);
268              
269 4 100         if (bagnid == NID_pkcs7_data) {
270              
271 2           bags = PKCS12_unpack_p7data(p7);
272              
273 2 50         } else if (bagnid == NID_pkcs7_encrypted) {
274              
275 2           bags = PKCS12_unpack_p7encdata(p7, pass, passlen);
276              
277             } else {
278 0           continue;
279             }
280              
281 4 50         if (!bags) return 0;
282              
283 4 50         if (!dump_certs_pkeys_bags(bio, bags, pass, passlen, options, pempass)) {
284              
285 0           sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
286 0           return 0;
287             }
288              
289 4           sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
290             }
291              
292 2           sk_PKCS7_pop_free(asafes, PKCS7_free);
293              
294 2           return 1;
295             }
296              
297             MODULE = Crypt::OpenSSL::PKCS12 PACKAGE = Crypt::OpenSSL::PKCS12
298              
299             PROTOTYPES: DISABLE
300              
301             BOOT:
302             {
303             HV *stash;
304             char *name;
305             int i;
306              
307 2           struct { char *n; I32 v; } Crypt__OpenSSL__PKCS12__const[] = {
308             {"NOKEYS", NOKEYS},
309             {"NOCERTS", NOCERTS},
310             {"INFO", INFO},
311             {"CLCERTS", CLCERTS},
312             {"CACERTS", CACERTS},
313             {Nullch,0}
314             };
315              
316 2           OpenSSL_add_all_algorithms();
317              
318 2           stash = gv_stashpvn("Crypt::OpenSSL::PKCS12", 22, TRUE);
319              
320 12 100         for (i = 0; (name = Crypt__OpenSSL__PKCS12__const[i].n); i++) {
321 10           newCONSTSUB(stash, name, newSViv(Crypt__OpenSSL__PKCS12__const[i].v));
322             }
323             }
324              
325             Crypt::OpenSSL::PKCS12
326             new(class)
327             SV *class
328              
329             CODE:
330              
331 0 0         if ((RETVAL = PKCS12_new()) == NULL) {
332 0           croak("Couldn't create PKCS12_new() for class %s", (char*)class);
333             }
334              
335             OUTPUT:
336             RETVAL
337              
338             Crypt::OpenSSL::PKCS12
339             new_from_string(class, string)
340             SV *class
341             char *string
342              
343             ALIAS:
344             new_from_file = 1
345              
346             PREINIT:
347             BIO *bio;
348              
349             CODE:
350              
351 2 50         if (!string) croak("PKCS12_new_from: No string or file was passed.");
352              
353 2 50         if (ix == 1) {
354 2           bio = BIO_new_file(string, "r");
355             } else {
356 0           bio = BIO_new_mem_buf(string, strlen(string));
357             }
358              
359 2 50         if (!bio) croak("Failed to create BIO");
360              
361             /* this can come in any number of ways */
362 2 50         if ((RETVAL = d2i_PKCS12_bio(bio, 0)) == NULL) {
363 0           BIO_free_all(bio);
364 0           croak("%s: Couldn't create PKCS12 from d2i_PKCS12_BIO(): %s", (char*)class, ssl_error());
365             }
366              
367 2           BIO_free_all(bio);
368              
369             OUTPUT:
370             RETVAL
371              
372             # This is called at per-object destruction time.
373             void
374             DESTROY(pkcs12)
375             Crypt::OpenSSL::PKCS12 pkcs12;
376              
377             CODE:
378 2 50         if (pkcs12) {
379 2           PKCS12_free(pkcs12);
380             }
381              
382             # This is called via an END block in the Perl module to clean up initialization that happened in BOOT.
383             void
384             __PKCS12_cleanup(void)
385             CODE:
386              
387 2           CRYPTO_cleanup_all_ex_data();
388 2           ERR_free_strings();
389             #if OPENSSL_VERSION_NUMBER < 0x10100000L
390 2           ERR_remove_state(0);
391             #endif
392 2           EVP_cleanup();
393              
394             SV*
395             as_string(pkcs12)
396             Crypt::OpenSSL::PKCS12 pkcs12;
397              
398             PREINIT:
399             BIO *bio;
400              
401             CODE:
402              
403 1           bio = sv_bio_create();
404              
405 1 50         if (!(i2d_PKCS12_bio(bio, pkcs12))) {
406 0           sv_bio_error(bio);
407 0           croak("i2d_PKCS12_bio: %s", ssl_error());
408             }
409              
410 1           RETVAL = sv_bio_final(bio);
411              
412             OUTPUT:
413             RETVAL
414              
415             SV*
416             mac_ok(pkcs12, pwd = "")
417             Crypt::OpenSSL::PKCS12 pkcs12
418             char *pwd
419              
420             CODE:
421              
422 3 50         if (!(PKCS12_verify_mac(pkcs12, pwd, strlen(pwd)))) {
423 0           croak("PKCS12_verify_mac: \n%s", ssl_error());
424             }
425              
426 3 50         RETVAL = (PKCS12_verify_mac(pkcs12, pwd, strlen(pwd))) ? &PL_sv_yes : &PL_sv_no;
427              
428             OUTPUT:
429             RETVAL
430              
431             SV*
432             changepass(pkcs12, oldpwd = "", newpwd = "")
433             Crypt::OpenSSL::PKCS12 pkcs12
434             char *oldpwd
435             char *newpwd
436              
437             CODE:
438              
439 2 50         if (!(PKCS12_newpass(pkcs12, oldpwd, newpwd))) {
440 0           warn("PKCS12_newpass: %s %s\n%s", oldpwd, newpwd, ssl_error());
441 0           RETVAL = &PL_sv_no;
442             } else {
443 2           RETVAL = &PL_sv_yes;
444             }
445              
446             OUTPUT:
447             RETVAL
448              
449             SV*
450             create(pkcs12, cert_chain_pem = "", pk = "", pass = 0, file = 0, name = "PKCS12 Certificate")
451             char *cert_chain_pem
452             char *pk
453             char *pass
454             char *file
455             char *name
456              
457             PREINIT:
458             FILE *fp;
459             EVP_PKEY* pkey;
460             PKCS12 *p12;
461 1           STACK_OF(X509) *cert_chain = NULL;
462              
463             CODE:
464              
465 1           pkey = _load_pkey(pk, PEM_read_bio_PrivateKey);
466 1           cert_chain = _load_cert_chain(cert_chain_pem, PEM_X509_INFO_read_bio);
467 1           p12 = PKCS12_create(pass, name, pkey, sk_X509_shift(cert_chain), cert_chain, 0, 0, 0, 0, 0);
468              
469 1 50         if (!p12) {
470 0           ERR_print_errors_fp(stderr);
471 0           croak("Error creating PKCS#12 structure\n");
472             }
473              
474 1 50         if (!(fp = fopen(file, "wb"))) {
475 0           ERR_print_errors_fp(stderr);
476 0           croak("Error opening file %s\n", file);
477             }
478              
479 1           i2d_PKCS12_fp(fp, p12);
480 1           PKCS12_free(p12);
481 1           fclose(fp);
482              
483 1           RETVAL = &PL_sv_yes;
484              
485             OUTPUT:
486             RETVAL
487              
488             SV*
489             certificate(pkcs12, pwd = "")
490             Crypt::OpenSSL::PKCS12 pkcs12
491             char *pwd
492              
493             PREINIT:
494             BIO *bio;
495              
496             CODE:
497              
498 1           bio = sv_bio_create();
499              
500 1           PKCS12_unpack_authsafes(pkcs12);
501 1           dump_certs_keys_p12(bio, pkcs12, pwd, strlen(pwd), CLCERTS|NOKEYS, NULL);
502              
503 1           RETVAL = sv_bio_final(bio);
504              
505             OUTPUT:
506             RETVAL
507              
508             SV*
509             private_key(pkcs12, pwd = "")
510             Crypt::OpenSSL::PKCS12 pkcs12
511             char *pwd
512              
513             PREINIT:
514             BIO *bio;
515              
516             CODE:
517              
518 1           bio = sv_bio_create();
519              
520 1           PKCS12_unpack_authsafes(pkcs12);
521 1           dump_certs_keys_p12(bio, pkcs12, pwd, strlen(pwd), NOCERTS, NULL);
522              
523 1           RETVAL = sv_bio_final(bio);
524              
525             OUTPUT:
526             RETVAL