diff --git a/root/admin/index.php b/root/admin/index.php index f3727e6..486e2e3 100644 --- a/root/admin/index.php +++ b/root/admin/index.php @@ -28,7 +28,7 @@ case 'list_users': case 'add_user_form'; printHeader('admin'); ?> -
+
'.ta_key_text().'
'.dhparam_text().'
'.root_pem_text().'
Debug Info: =$errtxt?> @@ -312,14 +308,13 @@ default: printHeader('ca'); ?> - + CERTIFICATE MANAGEMENT CONTROL PANEL " method=get name=filter> Search: -       >Valid +       >Valid   >Revoked   >Expired       @@ -364,12 +359,7 @@ default: $x = "^[$show_valid$show_revoked$show_expired]"; - if (in_array($PHPki_user, $PHPki_admins)) { - $x = "$x.*$search"; - } - else { - $x = "$x.*$search.*$PHPki_user|$x.*$PHPki_user.*$search"; - } + $x = "$x.*$search"; $db = csort(CAdb_to_array($x), $sortfield, ($ascdec=='A'?SORT_ASC:SORT_DESC)); diff --git a/root/ca/request_cert.php b/root/ca/request_cert.php index 16c816f..31582e7 100644 --- a/root/ca/request_cert.php +++ b/root/ca/request_cert.php @@ -141,7 +141,7 @@ case 'confirm': = $hidden_fields ?> - + @@ -165,7 +165,7 @@ case 'confirm': break; case 'final': - if ($submit == "Yes! Create and Download") { + if ($submit == "Yes") { if (! $serial = CAdb_in($email,$common_name)) { list($ret,$errtxt) = CA_create_cert($cert_type,$country, $province, $locality, $organization, $unit, $common_name, $email, $expiry, $passwd, $keysize); @@ -194,22 +194,9 @@ case 'final': $serial = $errtxt; } } + # CLear common_name fiels + $common_name = ''; - switch($cert_type) { - case 'server': - upload(array("$config[private_dir]/$serial-key.pem","$config[new_certs_dir]/$serial.pem",$config['cacert_pem']), "$common_name ($email).pem",'application/pkix-cert'); - break; - case 'email': - case 'email_signing': - case 'time_stamping': - case 'vpn_client_server': - case 'vpn_client': - case 'vpn_server': - upload("$config[pfx_dir]/$serial.pfx", "$common_name ($email).p12", 'application/x-pkcs12'); - break; - } - - break; } default: # @@ -229,7 +216,7 @@ default: printHeader(); ?> - + Certificate Request Form @@ -276,8 +263,10 @@ default: + print "3 Months\n" ; + print "6 Months\n" ; print "1 Year\n" ; - for ( $i = 2 ; $i < 6 ; $i++ ) { + for ( $i = 2 ; $i <= 5 ; $i++ ) { print "$i Years\n" ; } @@ -290,7 +279,7 @@ default: Key Size - for ( $i = 512 ; $i < 4096 ; $i+= 512 ) { + for ( $i = 512 ; $i <= 4096 ; $i+= 512 ) { print "$i bits\n" ; } diff --git a/root/gen_crl.php b/root/gen_crl.php new file mode 100644 index 0000000..dfab63a --- /dev/null +++ b/root/gen_crl.php @@ -0,0 +1,12 @@ + + diff --git a/root/include/common.php b/root/include/common.php index 2ccecc1..1f652bc 100644 --- a/root/include/common.php +++ b/root/include/common.php @@ -2,13 +2,12 @@ umask(0007); -if ($HTTP_SERVER_VARS['PHP_AUTH_USER']) - $PHPki_user = md5($HTTP_SERVER_VARS['PHP_AUTH_USER']); +if ($HTTP_SERVER_VARS['REMOTE_USER']) + $PHPki_user = md5($HTTP_SERVER_VARS['REMOTE_USER']); else $PHPki_user = md5('default'); -$PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF']; - +$PHP_SELF = htmlspecialchars($HTTP_SERVER_VARS['PHP_SELF'], ENT_QUOTES, "utf-8"); function printHeader($withmenu="default") { global $config; diff --git a/root/include/my_functions.php b/root/include/my_functions.php index a316476..1dc2e59 100644 --- a/root/include/my_functions.php +++ b/root/include/my_functions.php @@ -1,6 +1,6 @@ = 4.3.0 diff --git a/root/include/openssl_functions.php b/root/include/openssl_functions.php index 9f3cbb3..331b0d0 100644 --- a/root/include/openssl_functions.php +++ b/root/include/openssl_functions.php @@ -13,7 +13,7 @@ function CA_create_cnf($country='',$province='',$locality='',$organization='',$u $cnf_contents = " HOME = $config[home_dir] RANDFILE = $config[random] -dir = $config[ca_dir] +dir = $config[ca_dir] certs = $config[cert_dir] crl_dir = $config[crl_dir] database = $config[index] @@ -27,7 +27,7 @@ crl_extentions = crl_ext default_days = 365 default_crl_days = 30 preserve = no -default_md = md5 +default_md = sha1 [ req ] default_bits = $keysize @@ -59,8 +59,8 @@ x509_extensions = email_ext default_days = 365 policy = policy_supplied -[ email_codesigning_cert ] -x509_extensions = email_codesigning_ext +[ email_signing_cert ] +x509_extensions = email_signing_ext default_days = 365 policy = policy_supplied @@ -122,7 +122,7 @@ nsBaseUrl = $config[base_url] nsRevocationUrl = ns_revoke_query.php? nsCaPolicyUrl = $config[base_url]policy.html -[ email_codesigning_ext ] +[ email_signing_ext ] basicConstraints = critical, CA:false keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment extendedKeyUsage = critical, emailProtection, clientAuth, codeSigning @@ -194,7 +194,7 @@ subjectAltName = DNS:$common_name,email:copy "; # Write out the config file. - $cnf_file = tempnam('./tmp','cnf-'); + $cnf_file = tempnam('../../tmp','cnf-'); $handle = fopen($cnf_file,"w"); fwrite($handle, $cnf_contents); fclose($handle); @@ -212,18 +212,22 @@ function CAdb_to_array($search = '.*') { global $config; # Prepend a default status to search string if missing. - if (! ereg('^\^\[.*\]', $search)) $search = '^[VRE].*'.$search; - + #if (! ereg('^\^\[.*\]', $search)) $search = '^[VRE].*'.$search; + if (! preg_match("/^\^\[.*\]/", $search)) $search = '^[VRE].*'.$search; # Include valid certs? - if (ereg('^\^\[.*V.*\]',$search)) $inclval = true; + #if (ereg('^\^\[.*V.*\]',$search)) $inclval = true; + if (preg_match('/^\^\[.*V.*\]/',$search)) $inclval = true; # Include revoked certs? - if (ereg('^\^\[.*R.*\]',$search)) $inclrev = true; + #if (ereg('^\^\[.*R.*\]',$search)) $inclrev = true; + if (preg_match('/^\^\[.*R.*\]/',$search)) $inclrev = true; # Include expired certs? - if (ereg('^\^\[.*E.*\]',$search)) $inclexp = true; + #if (ereg('^\^\[.*E.*\]',$search)) $inclexp = true; + if (preg_match('/^\^\[.*E.*\]/',$search)) $inclexp = true; # There isn't really a status of 'E' in the openssl index. # Change (E)xpired to (V)alid within the search string. - $search = ereg_replace('^(\^\[.*)E(.*\])','\\1V\\2',$search); + #$search = ereg_replace('^(\^\[.*)E(.*\])','\\1V\\2',$search); + $search = preg_replace('/^(\^\[.*)E(.*\])/','${1}V${2}',$search); $db = array(); exec('egrep -i '.escshellarg($search).' '.$config['index'], $x); @@ -315,24 +319,59 @@ function CAdb_explode_entry($dbentry) { break; } - sscanf(CA_cert_startdate($a[3]),"%s %s %s %s", $mm,$dd,$tt,$yy); - $db['issued'] = strftime("%y-%b-%d", strtotime("$dd $mm $yy")); + // CA_cert_start/enddate + // A date will be returned in this format + // Feb 27 16:00:09 2020 GMT + // Add a 'digital' sort key for digital date sorting later + sscanf(CA_cert_startdate($a[3]),"%s%s%s%s", $mm,$dd,$tt,$yy); + $db['issued'] = strftime("%Y-%b-%d", strtotime("$yy-$mm-$dd")); + $db['issuedSort'] = strftime("%Y-%m-%d", strtotime("$yy-$mm-$dd")); - sscanf($a[1], "%2s%2s%2s",$yy,$mm,$dd); - $db['expires'] = strftime("%y-%b-%d", strtotime("$mm/$dd/$yy")); + sscanf(CA_cert_enddate($a[3]), "%s%s%s%s",$mm,$dd,$tt,$yy); + $db['expires'] = strftime("%Y-%b-%d", strtotime("$yy-$mm-$dd")); + $db['expiresSort'] = strftime("%Y-%m-%d", strtotime("$yy-$mm-$dd")); - if (time() > strtotime("$mm/$dd/$yy")) - $db['status'] = "Expired"; + if (time() > strtotime("$yy-$mm-$dd")) { + $db['status'] = "Expired"; + } - $db['serial'] = $a[3]; - $db['country'] = $b[1]; - $db['province'] = $b[2]; - $db['locality'] = $b[3]; - $db['organization'] = $b[4]; - $db['issuer'] = $b[5]; - $db['unit'] = $b[6]; - $db['common_name'] = $b[7]; - $db['email'] = $b[8]; + + // Compatibility with migrated certs from openvpn-bridge + if(count($b) == 7){ + $db['serial'] = $a[3]; + $db['country'] = $b[1]; + $db['province'] = $b[2]; + $db['locality'] = ''; + $db['organization'] = $b[3]; + $db['issuer'] = ''; + $db['unit'] = $b[4]; + $db['common_name'] = $b[5]; + $db['email'] = $b[6]; + } + // Compatibility with renewed certs from openvpn-bridge + elseif(count($b) == 8){ + $db['serial'] = $a[3]; + $db['country'] = $b[1]; + $db['province'] = $b[2]; + $db['locality'] = $b[3]; + $db['organization'] = $b[4]; + $db['issuer'] = ''; + $db['unit'] = $b[5]; + $db['common_name'] = $b[6]; + $db['email'] = $b[7]; + } + // Else, it's a certificate created with phpki + else{ + $db['serial'] = $a[3]; + $db['country'] = $b[1]; + $db['province'] = $b[2]; + $db['locality'] = $b[3]; + $db['organization'] = $b[4]; + $db['issuer'] = $b[5]; + $db['unit'] = $b[6]; + $db['common_name'] = $b[7]; + $db['email'] = $b[8]; + } return $db; } @@ -349,7 +388,7 @@ function CAdb_is_revoked($serial) { if ($x) { list($j,$j,$revoke_date,$j,$j,$j) = explode("\t", $x); sscanf($revoke_date, "%2s%2s%2s",$yy,$mm,$dd); - return strftime("%b %d, %Y", strtotime("$mm/$dd/$yy")); + return strftime("%b %d, %Y", strtotime("$yy-$mm-$dd")); } else return false; @@ -388,6 +427,24 @@ function CA_crl_text() { return(shell_exec(CRL.' -in '.escshellarg($crlfile).' -text 2>&1')); } +// Returns the static takey.pem file +function ta_key_text() { + global $config; + return(shell_exec('cat '.escshellarg($config['private_dir']).'/takey.pem 2>&1')); +} + +// Returns the dhparam file +function dhparam_text() { + global $config; + return(shell_exec('cat '.escshellarg($config['private_dir']).'/dhparam1024.pem 2>&1')); +} + +// Returns the root CA certificate file (PEM Encoded) +function root_pem_text() { + global $config; + return(shell_exec('cat '.escshellarg($config['cacert_pem']).' 2>&1')); +} + // // Returns the subject of a certificate. // @@ -403,7 +460,9 @@ function CA_cert_subject($serial) { // function CA_cert_cname($serial) { global $config; - return(ereg_replace('^.*/CN=(.*)/.*','\\1',CA_cert_subject($serial))); + #return(ereg_replace('^.*/CN=(.*)/.*','\\1',CA_cert_subject($serial))); + return(preg_replace('/^.*\/CN=(.*)\/.*/','${1}',CA_cert_subject($serial))); + } // @@ -497,7 +556,7 @@ function CA_create_cert($cert_type='email',$country,$province,$locality,$organiz unset($cmd_output); $cmd_output[] = 'Creating certifcate request.'; - if ($passwd) { + if (($passwd) && ($passwd != "''")) { exec(REQ." -new -newkey rsa:$keysize -keyout '$userkey' -out '$userreq' -config '$cnf_file' -days '$expiry_days' -passout pass:$passwd 2>&1", $cmd_output, $ret); } else { @@ -665,6 +724,14 @@ function CA_renew_cert($old_serial,$expiry,$passwd) { #Unlock the CA database fclose($fd); + # https://github.com/radicand/phpki/issues/14 + if (preg_match('E-mail Protection', $certtext) && preg_match('Code Signing', $certtest)) { + $cert_type = 'email_signing'; + } + if (preg_match('E-mail Protection', $certtext)) { + $cert_type = 'email'; + } + #Remove temporary openssl config file. if (file_exists($cnf_file)) unlink($cnf_file); @@ -748,25 +815,32 @@ function CA_cert_type($serial) { $certtext = CA_cert_text($serial); - if (ereg('OpenSSL.* (E.?mail|Personal) .*Certificate', $certtext) && ereg('Code Signing', $certtest)) { + #if (ereg('OpenSSL.* (E.?mail|Personal) .*Certificate', $certtext) && ereg('Code Signing', $certtest)) { + if (preg_match('~OpenSSL.* (E.?mail|Personal) .*Certificate~', $certtext) && preg_match('~Code Signing~', $certtest)) { $cert_type = 'email_codesigning'; } - if (ereg('OpenSSL.* (E.?mail|Personal) .*Certificate', $certtext)) { + #if (ereg('OpenSSL.* (E.?mail|Personal) .*Certificate', $certtext)) { + if (preg_match('~OpenSSL.* (E.?mail|Personal) .*Certificate~', $certtext)) { $cert_type = 'email'; } - elseif (ereg('OpenSSL.* Server .*Certificate', $certtext)) { + #elseif (ereg('OpenSSL.* Server .*Certificate', $certtext)) { + elseif (preg_match('~OpenSSL.* Server .*Certificate~', $certtext)) { $cert_type = 'server'; } - elseif (ereg('timeStamping|Time Stamping', $certtext)) { + #elseif (ereg('timeStamping|Time Stamping', $certtext)) { + elseif (preg_match('~timeStamping|Time Stamping~', $certtext)) { $cert_type = 'time_stamping'; } - elseif (ereg('TLS Web Client Authentication', $certtext) && ereg('TLS Web Server Authentication', $certtext)) { + #elseif (ereg('TLS Web Client Authentication', $certtext) && ereg('TLS Web Server Authentication', $certtext)) { + elseif (preg_match('~TLS Web Client Authentication~', $certtext) && preg_match('~TLS Web Server Authentication~', $certtext)) { $cert_type = 'vpn_client_server'; } - elseif (ereg('TLS Web Client Authentication', $certtext)) { + #elseif (ereg('TLS Web Client Authentication', $certtext)) { + elseif (preg_match('~TLS Web Client Authentication~', $certtext)) { $cert_type = 'vpn_client'; } - elseif (ereg('TLS Web Server Authentication', $certtext)) { + #elseif (ereg('TLS Web Server Authentication', $certtext)) { + elseif (preg_match('~TLS Web Server Authentication~', $certtext)) { $cert_type = 'vpn_server'; } else { diff --git a/root/main.php b/root/main.php index 483191c..5b0dc76 100644 --- a/root/main.php +++ b/root/main.php @@ -17,6 +17,10 @@ case 'dl_crl': upload("$config[cacrl_der]", "$config[ca_prefix]cacrl.crl", 'application/pkix-crl'); break; +case 'dl_crl_pem': + upload("$config[cacrl_pem]", "$config[ca_prefix]cacrl.crl", 'application/octet-stream'); + break; + default: printHeader('public'); @@ -39,7 +43,8 @@ default: ?stage=dl_crl>Download Our Certificate Revocation List The official list of certificates revoked by this site. Installation and use of - this list is optional. Some e-mail programs will reference this list automagically. + this list is optional. Some e-mail programs will reference this list automagically. + (Some will need it in PEM format.) diff --git a/root/openssl.cnf b/root/openssl.cnf index 8cbf59e..a1283f6 100644 --- a/root/openssl.cnf +++ b/root/openssl.cnf @@ -14,7 +14,7 @@ crl_extensions = crl_ext default_days = 365 default_crl_days = 30 preserve = no -default_md = md5 +default_md = sha1 [ ca ] default_ca = email_cert @@ -29,8 +29,8 @@ x509_extensions = email_ext default_days = 365 policy = policy_supplied -[ email_codesigning_cert ] -x509_extensions = email_codesigning_ext +[ email_signing_cert ] +x509_extensions = email_signing_ext default_days = 365 policy = policy_supplied @@ -82,7 +82,7 @@ nsRevocationUrl = ns_revoke_query.php? nsCaPolicyUrl = http://www.somewhere.com/phpki/policy.html #nsSslServerName = -[ email_codesigning_ext ] +[ email_signing_ext ] basicConstraints = critical, CA:false keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment extendedKeyUsage = critical, emailProtection, clientAuth, codeSigning diff --git a/root/search.php b/root/search.php index f779353..f628bde 100644 --- a/root/search.php +++ b/root/search.php @@ -36,7 +36,12 @@ case display: case 'download': $rec = CAdb_get_entry($serial); - upload("$config[cert_dir]/$serial.der", "$rec[common_name] ($rec[email]).cer", 'application/pkix-cert'); + upload("$config[cert_dir]/$serial.der", "$rec[common_name].cer", 'application/pkix-cert'); + break; + +case 'download_pem': + $rec = CAdb_get_entry($serial); + upload("$config[new_certs_dir]/$serial.pem", "$rec[common_name].pem", 'application/pkix-cert'); break; case search: @@ -44,7 +49,7 @@ case search: $db = CAdb_to_array("^[${show_valid}${show_revoked}${show_expired}].*$search"); - print ''; + print ''; if (sizeof($db) == 0) { ?> @@ -97,6 +102,7 @@ case search: if ($rec['status'] != 'Revoked') { ?> ?stage=download&serial==htvar($rec['serial'])?>> + ?stage=download_pem&serial==htvar($rec['serial'])?>> } print ''; @@ -121,7 +127,7 @@ default: printHeader('public'); ?> - + Certificate Search method=post name=search> diff --git a/root/setup.php-presetup b/root/setup.php-presetup index b0118f7..69ee414 100644 --- a/root/setup.php-presetup +++ b/root/setup.php-presetup @@ -102,6 +102,11 @@ case 'validate': if (! $passwd_file) $er .= 'Missing User Password File Location'; if (! $store_dir) $er .= 'Missing Storage Directory'; + $countrycode = strtoupper($country); + + if (! preg_match("/\b[A-Z][A-Z]\b/", $countrycode, $match) ) { + $er .= 'Country Code must be ISO 3166 two letters '; + } if ( $passwd && strlen($passwd) < 8 ) $er .= 'Certificate password is too short.'; @@ -248,7 +253,7 @@ case 'write': # Default OpenSSL Config File. \$config['openssl_cnf'] = \$config['home_dir'] . '/config/openssl.cnf'; -\$PHPki_admins = Array(md5('pkiadmin')); +\$PHPki_admins = Array(md5('admin')); define('OPENSSL',\$config['openssl_bin'].' '); define('X509', OPENSSL . ' x509 '); @@ -314,7 +319,7 @@ crl_extensions = crl_ext default_days = 365 default_crl_days = 30 preserve = no -default_md = md5 +default_md = sha1 [ ca ] default_ca = email_cert @@ -604,6 +609,17 @@ EOS; flush(); flush_exec($cmd,100); + # + # Create a TLS auth key for OpenVPN. + # + + print 'Creating a TLS authentication key used by OpenVPN.'; + print "Saving to $store_dir/takey.pem."; + $cmd = "openvpn --genkey --secret '$config[private_dir]/takey.pem'"; + print $cmd.''; + flush(); + flush_exec($cmd); + #print 'Creating 2048 bit Diffie-Hellman parameters used by OpenVPN.'; #print "Saving to $store_dir/dhparam2048.pem."; @@ -624,7 +640,6 @@ EOS; ?> Setup is complete. Your CA root certificate as been created. - SECURITY WARNING! Be sure to run the secure.sh shell script as the root user. @@ -752,9 +767,8 @@ E-mail: someone@somewhere.com &nbs - for ( $i = 5 ; $i < 20 ; $i+=5 ) { - print "$i Years\n" ; + for ( $i = 5 ; $i <= 20 ; $i+=5 ) { + print "$i Years\n" ; } ?> @@ -770,8 +784,7 @@ E-mail: someone@somewhere.com &nbs for ( $i = 512 ; $i <= 4096 ; $i+=512 ) { - print "$i bits\n" ; + print "$i bits\n" ; } ?>
=$errtxt?>
Creating a TLS authentication key used by OpenVPN.'; + print "Saving to $store_dir/takey.pem."; + $cmd = "openvpn --genkey --secret '$config[private_dir]/takey.pem'"; + print $cmd.''; + flush(); + flush_exec($cmd); + #print '
Creating 2048 bit Diffie-Hellman parameters used by OpenVPN.'; #print "Saving to $store_dir/dhparam2048.pem."; @@ -624,7 +640,6 @@ EOS; ?>