// JWSmythe SSL Certificate Generator
// v2.4 - 12-22-2015. Added Modulus MD5 check.
// Added ability to check user provided key, csr, and/or cert.
// any can be provided. The key is only required if the user
// wants the checksum to validate.
// v2.3 - 12-07-2015. Changed layout to horizontal, to show more element details
// Added L ST and C defaults. OU was already done.
//
// v2.2 - 09-21-2015. Changed flag in genrsa to really switch from SHA1 to SHA256.
// Increased key size from 2048 to 4096.
// v2.1 - 11-18-2014. Changed key to AES256. Changed signing hash SHA1 to SHA256.
// This is demonstration of how to generate your SSL certificate.
// You should not use anything generated on *my* server. You are trusting
// a 3rd party with confidential data.
//
// Reference the openssl commands below for the whole generation process.
//
// Notice that I do not do housekeeping for the temp files. This is so *you*
// can use this code to learn from, and examine the files used after the process is complete.
//
// If you should choose to use this code, use it on your own machine.
// Ideally, an air-gapped machine.
// Your own security decisions are your own problem.
//
// You may use this code with attribution.
// Unattributed use will be pointed out and taunted.
?>
// This turns on debugging output. It will just show at the top of the page.
// you can add more logic here, or in the function show_debug().
$GLOBALS[debug] = "off";
// Generate as much as we can here.
// Auto-generate as much as we can here, to help guide the user through.
// We'll populate all the details below.
// Use $pid for the timestamp. It's grown from the initial version,
// and I don't want to change the variable.
// The $randkey section is from http://jwsmythe.com/password/passgen.php .
$chars = "abcdefghijklmnopqrstuvwxyz1234567890";
$numchar = rand(32,63);
$charlist = preg_split("//u", $chars, -1, PREG_SPLIT_NO_EMPTY);
$disp_size = count($charlist);
$list_size = $disp_size - 1;
// print "
" . print_r($charlist, TRUE) . "
";
$randkey = '';
for ($i=0; $i<$numchar; $i++) {
$thischar = intval(rand(0,$list_size));
$randkey .= $charlist[$thischar];
};
$pid = "sslgen_" . $randkey;
show_debug("Generated PID: $pid");
// print "$disp_size char pool, $numchar char string ";
// print "PID: $pid";
// If the user didn't provide anything, fill in these defaults.
if (($_POST[OU]) == ''){
$_POST[OU] = "Security Services";
show_debug("Setting DEFAULT OU as $_POST[OU]");
};
if (($_POST[L]) == ''){
$_POST[L] = "New York";
show_debug("Setting DEFAULT L as $_POST[L]");
};
if (($_POST[ST]) == ''){
$_POST[ST] = "NY";
show_debug("Setting DEFAULT ST as $_POST[ST]");
};
if (($_POST[C]) == ''){
$_POST[C] = "US";
show_debug("Setting DEFAULT C as $_POST[C]");
};
if (($_POST[private_key]) == ''){
// No private key was received. Generate one. A password is required. We'll clear it below.
show_debug("No private key was received. Generate one.");
$c = "/usr/bin/openssl genrsa -aes256 -passout pass:secret -out /tmp/$pid.key 4096";
#$c = "/usr/bin/openssl genrsa -passout pass:secret -out /tmp/$pid.key 4096";
system ($c);
// Remove password, so the web server can restart without user interaction.
$c = "/usr/bin/openssl rsa -passin pass:secret -in /tmp/$pid.key -out /tmp/$pid.key.insecure";
system($c);
$_POST[private_key] = file_get_contents("/tmp/$pid.key.insecure");
// Cleanup. We aren't sure if we're continuing or not yet.
unlink("/tmp/$pid.key.insecure");
unlink("/tmp/$pid.key");
$debug_showkey = substr($_POST['private_key'], 0, 48) . "...";
show_debug("Setting generated Private_Key as $debug_showkey");
};
if (
(($_POST[private_key]) != '') &&
(($_POST[C]) != '') &&
(($_POST[ST]) != '') &&
(($_POST[L]) != '') &&
(($_POST[O]) != '') &&
(($_POST[OU]) != '') &&
(($_POST[CN]) != '')
){
show_debug("Completed form provided. Generate CSR and self-cert.");
$conf_data = "
[ req ]
default_bits = 4096
default_days = 3650
default_keyfile = /tmp/$pid.key
distinguished_name = req_distinguished_name
prompt = no
[ req_distinguished_name ]
C = $_POST[C]
ST = $_POST[ST]
L = $_POST[L]
O = $_POST[O]
OU = $_POST[OU]
CN = $_POST[CN]
";
file_put_contents("/tmp/$pid.key", $_POST[private_key]);
file_put_contents("/tmp/$pid.conf", $conf_data);
#$c = "/usr/bin/openssl req -new -key /tmp/$pid.key -out /tmp/$pid.csr -config /tmp/$pid.conf";
$c = "/usr/bin/openssl req -sha256 -new -key /tmp/$pid.key -out /tmp/$pid.csr -config /tmp/$pid.conf";
#print "$c";
system($c);
$_POST[csr] = file_get_contents("/tmp/$pid.csr");
$c = "/usr/bin/openssl x509 -sha256 -req -days 3650 -in /tmp/$pid.csr -signkey /tmp/$pid.key -out /tmp/$pid.selfcert";
#print "$c ";
system($c);
$_POST[selfcert] = file_get_contents("/tmp/$pid.selfcert");
};
// The following tests are for if someone was validating data through the form.
// We support putting the key, csr, or cert in the file row,
// and seeing the result in the validation row.
if (
(($_POST[private_key]) != '') &&
(!file_exists("/tmp/$pid.key"))
){
show_debug("Writing PK file");
// We have a key sent, but no key file present. Probably a validation. Save the file.
file_put_contents("/tmp/$pid.key", $_POST[private_key]);
};
if (
(($_POST[csr]) != '' ) &&
(!file_exists("/tmp/$pid.csr"))
){
show_debug("Writing CSR file");
// We have a csr sent, but no csr file present. Probably a validation. Save the file.
file_put_contents("/tmp/$pid.csr", $_POST[csr]);
};
// Note: Throughout we reference the cert as "selfcert". It is assumed
// that this script is generating the temporary (self-signed) certificate.
// If the user is submitting a real certificate for validation, it will
// still process fine. It uses the same OpenSSL command.
// We may sign with our own CA later.
if (
(($_POST[selfcert]) != '') &&
(!file_exists("/tmp/$pid.selfcert"))
){
show_debug("Writing self-cert file");
// We have a csr sent, but no csr file present. Probably a validation. Save the file.
file_put_contents("/tmp/$pid.selfcert", $_POST[selfcert]);
};
if (file_exists("/tmp/$pid.key")){
$_POST[check_key] = `/usr/bin/openssl rsa -check -noout -text -in /tmp/$pid.key`;
$_POST[mod_key] = `/usr/bin/openssl rsa -modulus -noout -in /tmp/$pid.key`;
$_POST[mod_key] = md5($_POST[mod_key]);
};
if (file_exists("/tmp/$pid.csr")){
$_POST[check_csr] = `/usr/bin/openssl req -verify -noout -text -in /tmp/$pid.csr`;
$_POST[mod_csr] = `/usr/bin/openssl req -modulus -noout -in /tmp/$pid.csr`;
$_POST[mod_csr] = md5($_POST[mod_csr]);
};
if (file_exists("/tmp/$pid.selfcert")){
$_POST[check_selfcert] = `/usr/bin/openssl x509 -noout -text -in /tmp/$pid.selfcert`;
$_POST[mod_selfcert] = `/usr/bin/openssl x509 -modulus -noout -in /tmp/$pid.selfcert`;
$_POST[mod_selfcert] = md5($_POST[mod_selfcert]);
show_debug("mod_selfcert check " . $_POST[mod_selfcert]);
};
// Determine if the modulus md5 matches.
if ($_POST[mod_key] != ''){
show_debug("mod key found good");
$mod_class_key='modulus_good';
}else{
show_debug("mod key found bad");
$mod_class_key='modulus_bad';
};
if ($_POST[mod_key] == $_POST[mod_csr]){
show_debug("mod csr found good");
$mod_class_csr='modulus_good';
}else{
show_debug("mod csr found bad");
$mod_class_csr='modulus_bad';
};
if ($_POST[mod_key] == $_POST[mod_selfcert]){
show_debug("mod cert found good");
$mod_class_cert='modulus_good';
}else{
show_debug("mod cert found bad");
$mod_class_cert='modulus_bad';
};
// IMPORTANT!!! The cleanup section is disabled on the testing site.
// Make sure it's enabled on the production site, or we'll have a ton of junk files.
/*
// Clean up all temp files. We don't want to retain anything for liability reasons.
if(file_exists("/tmp/$pid.key")){ unlink("/tmp/$pid.key"); };
if(file_exists("/tmp/$pid.conf")){ unlink("/tmp/$pid.conf"); };
if(file_exists("/tmp/$pid.csr")){ unlink("/tmp/$pid.csr"); };
if(file_exists("/tmp/$pid.selfcert")){ unlink("/tmp/$pid.selfcert"); };
*/
function show_debug($in){
$debug = $GLOBALS[debug];
if ($debug == 'on'){
if(is_array($in)){
$out = "