2606 |
2606 |
return $list;
|
2607 |
2607 |
}
|
2608 |
2608 |
|
|
2609 |
/****f* certs/cert_pkcs12_export
|
|
2610 |
* NAME
|
|
2611 |
* cert_pkcs12_export - Export a PKCS#12 archive file for a given certificate
|
|
2612 |
* and optional CA and passphrase.
|
|
2613 |
* INPUTS
|
|
2614 |
* $cert : Certificate entry array.
|
|
2615 |
* $passphrase: Optional passphrase used to encrypt the archive contents and
|
|
2616 |
* private key.
|
|
2617 |
* $add_ca : Boolean flag which determines whether or not the certificate
|
|
2618 |
* CA is included in the archive (if available)
|
|
2619 |
* $delivery : Delivery method for the result: "file", "download", or "data".
|
|
2620 |
* See RESULT section for details.
|
|
2621 |
* RESULT
|
|
2622 |
* Returns false on failure, otherwise result depends upon the value passed in
|
|
2623 |
* $delivery:
|
|
2624 |
* "file" : Returns the path to the output archive file.
|
|
2625 |
* NOTE: Does not clean up path, caller must clean up the
|
|
2626 |
* entire directory containing the output file.
|
|
2627 |
* "download": Sends the archive data to the current GUI browser session.
|
|
2628 |
* Must be called before any output is sent to the user
|
|
2629 |
* session.
|
|
2630 |
* "data" : Returns the contents of the PKCS#12 archive as a string.
|
|
2631 |
* NOTES
|
|
2632 |
* If the certificate entry does not contain a private key, the archive will
|
|
2633 |
* also not contain a key.
|
|
2634 |
******/
|
|
2635 |
|
|
2636 |
function cert_pkcs12_export($cert, $passphrase = '', $add_ca = true, $delivery = 'download') {
|
|
2637 |
global $g;
|
|
2638 |
|
|
2639 |
/* Unusable certificate entry, bail early. */
|
|
2640 |
if (!is_array($cert) || empty($cert)) {
|
|
2641 |
return false;
|
|
2642 |
}
|
|
2643 |
|
|
2644 |
/* Encryption and Digest */
|
|
2645 |
$algo = '-aes256 -certpbe AES-256-CBC -keypbe AES-256-CBC';
|
|
2646 |
$hash = '-macalg sha256';
|
|
2647 |
|
|
2648 |
/* Make a secure temporary directory */
|
|
2649 |
$workdir = tempnam("{$g['tmp_path']}/", "p12export");
|
|
2650 |
@unlink_if_exists($workdir);
|
|
2651 |
mkdir($workdir, 0600);
|
|
2652 |
|
|
2653 |
/* Set the friendly name to the certificate description, if available */
|
|
2654 |
$descr = "";
|
|
2655 |
if (!empty($cert['descr'])) {
|
|
2656 |
$edescr = escapeshellarg($cert['descr']);
|
|
2657 |
$descr = "-name {$edescr} -CSP {$edescr}";
|
|
2658 |
$fileprefix = basename($cert['descr']);
|
|
2659 |
}
|
|
2660 |
|
|
2661 |
/* If there isn't a usable portion of the description, use the refid */
|
|
2662 |
if (empty($fileprefix)) {
|
|
2663 |
$fileprefix = $cert['refid'];
|
|
2664 |
}
|
|
2665 |
|
|
2666 |
/* Exported output archive filename */
|
|
2667 |
$outpath = "{$workdir}/{$fileprefix}.p12";
|
|
2668 |
$eoutpath = escapeshellarg($outpath);
|
|
2669 |
|
|
2670 |
/* Passphrase handling */
|
|
2671 |
if (!empty($passphrase)) {
|
|
2672 |
/* Use passphrase text file so the passphrase is not visible in
|
|
2673 |
* process list. */
|
|
2674 |
$passfile = "{$workdir}/passphrase.txt";
|
|
2675 |
file_put_contents($passfile, $passphrase . "\n");
|
|
2676 |
$pass = '-passout file:' . escapeshellarg($passfile);
|
|
2677 |
} else {
|
|
2678 |
/* Null password + disable encryption of the keys */
|
|
2679 |
$pass = '-passout pass: -nodes';
|
|
2680 |
}
|
|
2681 |
|
|
2682 |
/* Certificate file */
|
|
2683 |
$crtpath = "{$workdir}/cert.pem";
|
|
2684 |
$ecrtpath = escapeshellarg($crtpath);
|
|
2685 |
file_put_contents($crtpath, base64_decode($cert['crt']));
|
|
2686 |
|
|
2687 |
/* Private key (if present) */
|
|
2688 |
if (!empty($cert['prv'])) {
|
|
2689 |
$keypath = "{$workdir}/key.pem";
|
|
2690 |
/* Write key to a secure temporary name */
|
|
2691 |
file_put_contents($keypath, base64_decode($cert['prv']));
|
|
2692 |
$key = '-inkey ' . escapeshellarg($keypath);
|
|
2693 |
} else {
|
|
2694 |
$key = '-nokeys';
|
|
2695 |
}
|
|
2696 |
|
|
2697 |
/* Add CA if one is defined and requested */
|
|
2698 |
$eca = '';
|
|
2699 |
if ($add_ca && !empty($cert['caref'])) {
|
|
2700 |
$ca = lookup_ca($cert['caref']);
|
|
2701 |
if ($ca) {
|
|
2702 |
$capath = "{$workdir}/ca.pem";
|
|
2703 |
file_put_contents($capath, base64_decode($ca['crt']));
|
|
2704 |
$eca = '-certfile ' . escapeshellarg($capath);
|
|
2705 |
}
|
|
2706 |
}
|
|
2707 |
|
|
2708 |
/* Export a PKCS#12 archive using these components and settings */
|
|
2709 |
exec("/usr/bin/openssl pkcs12 -export -in {$ecrtpath} {$eca} {$key} -out {$eoutpath} {$pass} {$descr} {$algo} {$hash}");
|
|
2710 |
|
|
2711 |
/* Bail if the output is invalid */
|
|
2712 |
if (!file_exists($outpath) ||
|
|
2713 |
(filesize($outpath) == 0)) {
|
|
2714 |
return false;
|
|
2715 |
}
|
|
2716 |
|
|
2717 |
/* Tailor output as requested by the caller */
|
|
2718 |
switch ($delivery) {
|
|
2719 |
case 'file':
|
|
2720 |
/* Return path to export file, do not clean up, caller must clean up. */
|
|
2721 |
return $outpath;
|
|
2722 |
break;
|
|
2723 |
case 'download':
|
|
2724 |
/* Send file to user and cleanup */
|
|
2725 |
$p12_data = file_get_contents($outpath);
|
|
2726 |
rmdir_recursive($workdir);
|
|
2727 |
send_user_download('data', $p12_data, "{$cert['descr']}.p12");
|
|
2728 |
return true;
|
|
2729 |
break;
|
|
2730 |
case 'data':
|
|
2731 |
default:
|
|
2732 |
/* Return PKCS#12 archive data and cleanup */
|
|
2733 |
$p12_data = file_get_contents($outpath);
|
|
2734 |
rmdir_recursive($workdir);
|
|
2735 |
return $p12_data;
|
|
2736 |
break;
|
|
2737 |
}
|
|
2738 |
|
|
2739 |
return null;
|
|
2740 |
}
|
2609 |
2741 |
?>
|
Convert P12 export to OpenSSL. Fixes #13257
PHP native method of creating PKCS#12 archives does not support using specific algorithms for encryption, so use the openssl binary instead.
Use AES-256 and SHA256 when encrypting the PKCS#12 data and private key.