File Coverage

PKCS12.xs
Criterion Covered Total %
statement 142 182 78.0
branch 69 118 58.4
condition n/a
subroutine n/a
pod n/a
total 211 300 70.3


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 2           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 2 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 2 50         CHECK_OPEN_SSL(stringBIO = BIO_new_file(keyString, "r"));
57             }
58              
59 2           pkey = p_loader(stringBIO, NULL, NULL, NULL);
60              
61 2           (void)BIO_set_close(stringBIO, BIO_CLOSE);
62 2           BIO_free_all(stringBIO);
63              
64 2 50         CHECK_OPEN_SSL(pkey);
65 2           return pkey;
66             }
67              
68 2           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 2           STACK_OF(X509_INFO) *xis = NULL;
71 2           X509_INFO *xi = NULL;
72             BIO* stringBIO;
73 2           STACK_OF(X509) *stack = sk_X509_new_null();
74              
75 2 50         if (!strncmp(keyString, "----", 4)) {
76 0 0         CHECK_OPEN_SSL(stringBIO = BIO_new_mem_buf(keyString, strlen(keyString)));
77             } else {
78 2 50         CHECK_OPEN_SSL(stringBIO = BIO_new_file(keyString, "r"));
79             }
80              
81 2           xis = p_loader(stringBIO, NULL, NULL, NULL);
82 4 100         for (i = 0; i < sk_X509_INFO_num(xis); i++) {
83 2           xi = sk_X509_INFO_value(xis, i);
84 2 50         if (xi->x509 != NULL && stack != NULL) {
    50          
85 2 50         CHECK_OPEN_SSL(xi->x509);
86 2 50         if (!sk_X509_push(stack, xi->x509))
87 0           goto end;
88 2           xi->x509 = NULL;
89             }
90             }
91              
92             end:
93 2           sk_X509_INFO_pop_free(xis, X509_INFO_free);
94 2           (void)BIO_set_close(stringBIO, BIO_CLOSE);
95 2           BIO_free_all(stringBIO);
96              
97 2           return stack;
98             }
99              
100             /* stolen from OpenSSL.xs */
101 92           long bio_write_cb(struct bio_st *bm, int m, const char *ptr, int l, long x, long y) {
102              
103 92 100         if (m == BIO_CB_WRITE) {
104 37           SV *sv = (SV *) BIO_get_callback_arg(bm);
105 37           sv_catpvn(sv, ptr, l);
106             }
107              
108 92 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 92           return l;
115             }
116              
117 9           static BIO* sv_bio_create(void) {
118              
119 9           SV *sv = newSVpvn("",0);
120              
121             /* create an in-memory BIO abstraction and callbacks */
122 9           BIO *bio = BIO_new(BIO_s_mem());
123              
124 9           BIO_set_callback(bio, bio_write_cb);
125 9           BIO_set_callback_arg(bio, (void *)sv);
126              
127 9           return bio;
128             }
129              
130 9           static SV* sv_bio_final(BIO *bio) {
131              
132             SV* sv;
133              
134 9           (void)BIO_flush(bio);
135 9           sv = (SV *)BIO_get_callback_arg(bio);
136 9           BIO_set_callback_arg(bio, (void *)NULL);
137 9           BIO_set_callback(bio, (void *)NULL);
138 9           BIO_free_all(bio);
139              
140 9 50         if (!sv) sv = &PL_sv_undef;
141              
142 9           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 3           static const char *ssl_error(void) {
154             BIO *bio;
155             SV *sv;
156             STRLEN l;
157              
158 3           bio = sv_bio_create();
159 3           ERR_print_errors(bio);
160 3           sv = sv_bio_final(bio);
161 3           ERR_clear_error();
162 3 50         return SvPV(sv, l);
163             }
164              
165             /* these are trimmed from their openssl/apps/pkcs12.c counterparts */
166 12           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 12           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 4 100         if (options & NOKEYS) return 1;
192              
193 2 50         if (!(p8 = PKCS12_decrypt_skey(bag, pass, passlen)))
194 0           return 0;
195              
196 2 50         if (!(pkey = EVP_PKCS82PKEY (p8))) {
197 0           PKCS8_PRIV_KEY_INFO_free(p8);
198 0           return 0;
199             }
200              
201 2           PKCS8_PRIV_KEY_INFO_free(p8);
202              
203 2           PEM_write_bio_PrivateKey (bio, pkey, enc, NULL, 0, NULL, pempass);
204              
205 2           EVP_PKEY_free(pkey);
206              
207 2           break;
208              
209             case NID_certBag:
210              
211 8 100         if (options & NOCERTS) return 1;
212              
213 4 100         if (PKCS12_SAFEBAG_get0_attr(bag, NID_localKeyID)) {
214              
215 2 50         if (options & CACERTS) return 1;
216              
217 2 50         } else if (options & CLCERTS) {
218              
219 2           return 1;
220             }
221              
222 2 50         if (M_PKCS12_cert_bag_type(bag) != NID_x509Certificate) return 1;
223              
224 2 50         if (!(x509 = PKCS12_certbag2x509(bag))) return 0;
225              
226 2           PEM_write_bio_X509 (bio, x509);
227              
228 2           X509_free(x509);
229              
230 2           break;
231             }
232              
233 4           return 1;
234             }
235              
236 8           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 20 100         for (i = 0; i < sk_PKCS12_SAFEBAG_num(bags); i++) {
241              
242 12 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 8           return 1;
248             }
249              
250 4           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 4 50         if ((asafes = PKCS12_unpack_authsafes(p12)) == NULL) {
259 0           croak("Unable to PKCS12_unpack_authsafes");
260             return 0;
261             }
262              
263 12 100         for (i = 0; i < sk_PKCS7_num(asafes); i++) {
264              
265 8           p7 = sk_PKCS7_value(asafes, i);
266              
267 8           bagnid = OBJ_obj2nid(p7->type);
268              
269 8 100         if (bagnid == NID_pkcs7_data) {
270              
271 4           bags = PKCS12_unpack_p7data(p7);
272              
273 4 50         } else if (bagnid == NID_pkcs7_encrypted) {
274              
275 4           bags = PKCS12_unpack_p7encdata(p7, pass, passlen);
276              
277             } else {
278 0           continue;
279             }
280              
281 8 50         if (!bags) return 0;
282              
283 8 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 8           sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
290             }
291              
292 4           sk_PKCS7_pop_free(asafes, PKCS7_free);
293              
294 4           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 3           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 3           OpenSSL_add_all_algorithms();
317              
318 3           stash = gv_stashpvn("Crypt::OpenSSL::PKCS12", 22, TRUE);
319              
320 18 100         for (i = 0; (name = Crypt__OpenSSL__PKCS12__const[i].n); i++) {
321 15           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 %" SVf "\n", SVfARG(class));
333             }
334              
335             OUTPUT:
336             RETVAL
337              
338             Crypt::OpenSSL::PKCS12
339             new_from_string(class, string)
340             SV *class
341             SV *string
342              
343             ALIAS:
344             new_from_file = 1
345              
346             PREINIT:
347             BIO *bio;
348             STRLEN str_len;
349             char *str_ptr;
350              
351             CODE:
352              
353 13 50         SvGETMAGIC(string);
    0          
354              
355 13 100         if (SvPOKp(string) || SvNOKp(string) || SvIOKp(string)) {
    100          
    100          
356 16 100         if (ix == 1) {
357             /* We are not looking up the SV's UTF8 bit because BIO_new_file() accepts
358             * filename like syscall fopen() which mainly may accept octet sequences
359             * for UTF-8 in C char*. That's what we get from using SvPV(). Also,
360             * using SvPV() is not a bug if ASCII input is only allowed. */
361 3 50         str_ptr = SvPV(string, str_len);
362             } else {
363             /* To avoid encoding mess, caller is not allowed to provide octets from
364             * UTF-8 encoded strings. BIO_new_mem_buf() needs octet input only. */
365 6 100         if (SvUTF8(string)) {
366 2           croak("PKCS12_new_from: Source string must not be UTF-8 encoded (please use octets)");
367             }
368 4 100         str_ptr = SvPV(string, str_len);
369             }
370             } else {
371 4           croak("PKCS12_new_from: Invalid Perl type for string or file was passed (0x%x).", (unsigned int)SvFLAGS(string));
372             }
373              
374 7 50         if (!str_ptr || !str_len) croak("PKCS12_new_from: No string or file was passed.");
    50          
375              
376 7 100         if (ix == 1) {
377 3           bio = BIO_new_file(str_ptr, "rb");
378             } else {
379 4           bio = BIO_new_mem_buf(str_ptr, str_len);
380             }
381              
382 7 50         if (!bio) croak("Failed to create BIO");
383              
384             /* this can come in any number of ways */
385 7 100         if ((RETVAL = d2i_PKCS12_bio(bio, 0)) == NULL) {
386 3           BIO_free_all(bio);
387 3           croak("%" SVf ": Couldn't create PKCS12 from d2i_PKCS12_BIO(): %s", SVfARG(class), ssl_error());
388             }
389              
390 4           BIO_free_all(bio);
391              
392             OUTPUT:
393             RETVAL
394              
395             # This is called at per-object destruction time.
396             void
397             DESTROY(pkcs12)
398             Crypt::OpenSSL::PKCS12 pkcs12;
399              
400             CODE:
401 4 50         if (pkcs12) {
402 4           PKCS12_free(pkcs12);
403             }
404              
405             # This is called via an END block in the Perl module to clean up initialization that happened in BOOT.
406             void
407             __PKCS12_cleanup(void)
408             CODE:
409              
410 3           CRYPTO_cleanup_all_ex_data();
411 3           ERR_free_strings();
412             #if OPENSSL_VERSION_NUMBER < 0x10100000L
413 3           ERR_remove_state(0);
414             #endif
415 3           EVP_cleanup();
416              
417             SV*
418             as_string(pkcs12)
419             Crypt::OpenSSL::PKCS12 pkcs12;
420              
421             PREINIT:
422             BIO *bio;
423              
424             CODE:
425              
426 2           bio = sv_bio_create();
427              
428 2 50         if (!(i2d_PKCS12_bio(bio, pkcs12))) {
429 0           sv_bio_error(bio);
430 0           croak("i2d_PKCS12_bio: %s", ssl_error());
431             }
432              
433 2           RETVAL = sv_bio_final(bio);
434              
435             OUTPUT:
436             RETVAL
437              
438             SV*
439             mac_ok(pkcs12, pwd = "")
440             Crypt::OpenSSL::PKCS12 pkcs12
441             char *pwd
442              
443             CODE:
444              
445 6 50         if (!(PKCS12_verify_mac(pkcs12, pwd, strlen(pwd)))) {
446 0           croak("PKCS12_verify_mac: \n%s", ssl_error());
447             }
448              
449 6 50         RETVAL = (PKCS12_verify_mac(pkcs12, pwd, strlen(pwd))) ? &PL_sv_yes : &PL_sv_no;
450              
451             OUTPUT:
452             RETVAL
453              
454             SV*
455             changepass(pkcs12, oldpwd = "", newpwd = "")
456             Crypt::OpenSSL::PKCS12 pkcs12
457             char *oldpwd
458             char *newpwd
459              
460             CODE:
461              
462 4 50         if (!(PKCS12_newpass(pkcs12, oldpwd, newpwd))) {
463 0           warn("PKCS12_newpass: %s %s\n%s", oldpwd, newpwd, ssl_error());
464 0           RETVAL = &PL_sv_no;
465             } else {
466 4           RETVAL = &PL_sv_yes;
467             }
468              
469             OUTPUT:
470             RETVAL
471              
472             SV*
473             create(pkcs12, cert_chain_pem = "", pk = "", pass = 0, file = 0, name = "PKCS12 Certificate")
474             char *cert_chain_pem
475             char *pk
476             char *pass
477             char *file
478             char *name
479              
480             PREINIT:
481             FILE *fp;
482             EVP_PKEY* pkey;
483             PKCS12 *p12;
484 2           STACK_OF(X509) *cert_chain = NULL;
485              
486             CODE:
487              
488 2           pkey = _load_pkey(pk, PEM_read_bio_PrivateKey);
489 2           cert_chain = _load_cert_chain(cert_chain_pem, PEM_X509_INFO_read_bio);
490 2           p12 = PKCS12_create(pass, name, pkey, sk_X509_shift(cert_chain), cert_chain, 0, 0, 0, 0, 0);
491              
492 2 50         if (!p12) {
493 0           ERR_print_errors_fp(stderr);
494 0           croak("Error creating PKCS#12 structure\n");
495             }
496              
497 2 50         if (!(fp = fopen(file, "wb"))) {
498 0           ERR_print_errors_fp(stderr);
499 0           croak("Error opening file %s\n", file);
500             }
501              
502 2           i2d_PKCS12_fp(fp, p12);
503 2           PKCS12_free(p12);
504 2           fclose(fp);
505              
506 2           RETVAL = &PL_sv_yes;
507              
508             OUTPUT:
509             RETVAL
510              
511             SV*
512             certificate(pkcs12, pwd = "")
513             Crypt::OpenSSL::PKCS12 pkcs12
514             char *pwd
515              
516             PREINIT:
517             BIO *bio;
518              
519             CODE:
520              
521 2           bio = sv_bio_create();
522              
523 2           PKCS12_unpack_authsafes(pkcs12);
524 2           dump_certs_keys_p12(bio, pkcs12, pwd, strlen(pwd), CLCERTS|NOKEYS, NULL);
525              
526 2           RETVAL = sv_bio_final(bio);
527              
528             OUTPUT:
529             RETVAL
530              
531             SV*
532             private_key(pkcs12, pwd = "")
533             Crypt::OpenSSL::PKCS12 pkcs12
534             char *pwd
535              
536             PREINIT:
537             BIO *bio;
538              
539             CODE:
540              
541 2           bio = sv_bio_create();
542              
543 2           PKCS12_unpack_authsafes(pkcs12);
544 2           dump_certs_keys_p12(bio, pkcs12, pwd, strlen(pwd), NOCERTS, NULL);
545              
546 2           RETVAL = sv_bio_final(bio);
547              
548             OUTPUT:
549             RETVAL