diff --git a/src/etc/inc/certs.inc b/src/etc/inc/certs.inc index 4f5bebeed..7c2a67ab9 100644 --- a/src/etc/inc/certs.inc +++ b/src/etc/inc/certs.inc @@ -144,16 +144,21 @@ function ca_chain(&$cert) return str_replace("\n\n", "\n", str_replace("\r", "", $ca)); } -function ca_create(&$ca, $keylen, $lifetime, $dn, $digest_alg = 'sha256') +function ca_create(&$ca, $keylen_curve, $lifetime, $dn, $digest_alg) { $args = array( 'config' => '/usr/local/etc/ssl/opnsense.cnf', - 'private_key_type' => OPENSSL_KEYTYPE_RSA, - 'private_key_bits' => (int)$keylen, 'x509_extensions' => 'v3_ca', 'digest_alg' => $digest_alg, 'encrypt_key' => false ); + if (is_numeric($keylen_curve)) { + $args['private_key_type'] = OPENSSL_KEYTYPE_RSA; + $args['private_key_bits'] = (int)$keylen_curve; + } else { + $args['private_key_type'] = OPENSSL_KEYTYPE_EC; + $args['curve_name'] = $keylen_curve; + } // generate a new key pair $res_key = openssl_pkey_new($args); @@ -205,7 +210,7 @@ function cert_import(& $cert, $crt_str, $key_str) return true; } -function cert_create(&$cert, $caref, $keylen, $lifetime, $dn, $digest_alg = 'sha256', $x509_extensions = 'usr_cert') +function cert_create(&$cert, $caref, $keylen_curve, $lifetime, $dn, $digest_alg, $x509_extensions = 'usr_cert') { $ca = &lookup_ca($caref); if (!$ca) { @@ -226,12 +231,17 @@ function cert_create(&$cert, $caref, $keylen, $lifetime, $dn, $digest_alg = 'sha $args = array( 'config' => $config_filename, - 'private_key_type' => OPENSSL_KEYTYPE_RSA, - 'private_key_bits' => (int)$keylen, 'x509_extensions' => $x509_extensions, 'digest_alg' => $digest_alg, 'encrypt_key' => false ); + if (is_numeric($keylen_curve)) { + $args['private_key_type'] = OPENSSL_KEYTYPE_RSA; + $args['private_key_bits'] = (int)$keylen_curve; + } else { + $args['private_key_type'] = OPENSSL_KEYTYPE_EC; + $args['curve_name'] = $keylen_curve; + } // generate a new key pair $res_key = openssl_pkey_new($args); diff --git a/src/www/system_camanager.php b/src/www/system_camanager.php index ad98087ae..364dcadc2 100644 --- a/src/www/system_camanager.php +++ b/src/www/system_camanager.php @@ -27,10 +27,11 @@ * POSSIBILITY OF SUCH DAMAGE. */ -require_once('guiconfig.inc'); +require_once("guiconfig.inc"); require_once("system.inc"); -function ca_import(& $ca, $str, $key="", $serial=0) { +function ca_import(& $ca, $str, $key="", $serial=0) +{ global $config; $ca['crt'] = base64_encode($str); @@ -71,7 +72,7 @@ function ca_import(& $ca, $str, $key="", $serial=0) { return true; } -function ca_inter_create(&$ca, $keylen, $lifetime, $dn, $caref, $digest_alg = 'sha256') +function ca_inter_create(&$ca, $keylen_curve, $lifetime, $dn, $caref, $digest_alg = 'sha256') { // Create Intermediate Certificate Authority $signing_ca = &lookup_ca($caref); @@ -88,12 +89,17 @@ function ca_inter_create(&$ca, $keylen, $lifetime, $dn, $caref, $digest_alg = 's $args = array( 'config' => '/usr/local/etc/ssl/opnsense.cnf', - 'private_key_type' => OPENSSL_KEYTYPE_RSA, - 'private_key_bits' => (int)$keylen, 'x509_extensions' => 'v3_ca', 'digest_alg' => $digest_alg, 'encrypt_key' => false ); + if (is_numeric($keylen_curve)) { + $args['private_key_type'] = OPENSSL_KEYTYPE_RSA; + $args['private_key_bits'] = (int)$keylen_curve; + } else { + $args['private_key_type'] = OPENSSL_KEYTYPE_EC; + $args['curve_name'] = $keylen_curve; + } // generate a new key pair $res_key = openssl_pkey_new($args); @@ -128,8 +134,8 @@ function ca_inter_create(&$ca, $keylen, $lifetime, $dn, $caref, $digest_alg = 's return true; } - $ca_keylens = array( "512", "1024", "2048", "3072", "4096", "8192"); +$ca_curves = array( "prime256v1", "secp384r1", "secp521r1"); $openssl_digest_algs = array("sha1", "sha224", "sha256", "sha384", "sha512"); $a_ca = &config_read_array('ca'); $a_cert = &config_read_array('cert'); @@ -176,6 +182,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') { $pconfig['camethod'] = $_GET['method']; } $pconfig['refid'] = null; + $pconfig['keytype'] = "RSA"; $pconfig['keylen'] = "2048"; $pconfig['digest_alg'] = "sha256"; $pconfig['lifetime'] = "365"; @@ -264,12 +271,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') { } elseif ($pconfig['camethod'] == "internal") { $reqdfields = explode( " ", - "descr keylen lifetime dn_country dn_state dn_city ". + "descr keytype keylen curve digest_alg lifetime dn_country dn_state dn_city ". "dn_organization dn_email dn_commonname" ); $reqdfieldsn = array( gettext("Descriptive name"), + gettext("Key type"), gettext("Key length"), + gettext("Curve"), + gettext("Digest algorithm"), gettext("Lifetime"), gettext("Distinguished name Country Code"), gettext("Distinguished name State or Province"), @@ -280,13 +290,16 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') { } elseif ($pconfig['camethod'] == "intermediate") { $reqdfields = explode( " ", - "descr caref keylen lifetime dn_country dn_state dn_city ". + "descr caref keytype keylen curve digest_alg lifetime dn_country dn_state dn_city ". "dn_organization dn_email dn_commonname" ); $reqdfieldsn = array( gettext("Descriptive name"), gettext("Signing Certificate Authority"), + gettext("Key type"), gettext("Key length"), + gettext("Curve"), + gettext("Digest algorithm"), gettext("Lifetime"), gettext("Distinguished name Country Code"), gettext("Distinguished name State or Province"), @@ -312,9 +325,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') { $input_errors[] = sprintf(gettext("The field '%s' contains invalid characters."), $reqdfieldsn[$i]); } } - if (!in_array($pconfig["keylen"], $ca_keylens)) { + if (!in_array($pconfig["keytype"], array("RSA", "Elliptic Curve"))) { + $input_errors[] = gettext("Please select a valid Key Type."); + } + if (!in_array($pconfig['keylen'], $ca_keylens) && $pconfig["keytype"] == "RSA") { $input_errors[] = gettext("Please select a valid Key Length."); } + if (!in_array($pconfig['curve'], $ca_curves) && $pconfig["keytype"] == "Elliptic Curve") { + $input_errors[] = gettext("Please select a valid Curve."); + } if (!in_array($pconfig["digest_alg"], $openssl_digest_algs)) { $input_errors[] = gettext("Please select a valid Digest Algorithm."); } @@ -353,6 +372,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') { } } else { $old_err_level = error_reporting(0); /* otherwise openssl_ functions throw warnings directly to a page screwing menu tab */ + if ($pconfig['keytype'] == "Elliptic Curve") { + $pconfig['keylen_curve'] = $pconfig['curve']; + } else { + $pconfig['keylen_curve'] = $pconfig['keylen']; + } if ($pconfig['camethod'] == "existing") { ca_import($ca, $pconfig['cert'], $pconfig['key'], $pconfig['serial']); } elseif ($pconfig['camethod'] == "internal") { @@ -363,7 +387,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') { 'organizationName' => $pconfig['dn_organization'], 'emailAddress' => $pconfig['dn_email'], 'commonName' => $pconfig['dn_commonname']); - if (!ca_create($ca, $pconfig['keylen'], $pconfig['lifetime'], $dn, $pconfig['digest_alg'])) { + if (!ca_create($ca, $pconfig['keylen_curve'], $pconfig['lifetime'], $dn, $pconfig['digest_alg'])) { $input_errors = array(); while ($ssl_err = openssl_error_string()) { $input_errors[] = gettext("openssl library returns:") . " " . $ssl_err; @@ -377,7 +401,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') { 'organizationName' => $pconfig['dn_organization'], 'emailAddress' => $pconfig['dn_email'], 'commonName' => $pconfig['dn_commonname']); - if (!ca_inter_create($ca, $pconfig['keylen'], $pconfig['lifetime'], $dn, $pconfig['caref'], $pconfig['digest_alg'])) { + if (!ca_inter_create($ca, $pconfig['keylen_curve'], $pconfig['lifetime'], $dn, $pconfig['caref'], $pconfig['digest_alg'])) { $input_errors = array(); while ($ssl_err = openssl_error_string()) { $input_errors[] = gettext("openssl library returns:") . " " . $ssl_err; @@ -453,6 +477,19 @@ $main_buttons = array( }); $("#camethod").change(); + + $("#keytype").change(function(){ + $("#EC").addClass("hidden"); + $("#RSA").addClass("hidden"); + $("#blank").addClass("hidden"); + if ($(this).val() == "Elliptic Curve") { + $("#EC").removeClass("hidden"); + } else { + $("#RSA").removeClass("hidden"); + } + }); + + $("#keytype").change(); }); @@ -573,12 +610,38 @@ $main_buttons = array( + + + + + + () + + + + + + + diff --git a/src/www/system_certmanager.php b/src/www/system_certmanager.php index 333b70869..aaec3373c 100644 --- a/src/www/system_certmanager.php +++ b/src/www/system_certmanager.php @@ -36,18 +36,24 @@ require_once('phpseclib/File/ASN1/Element.php'); require_once('phpseclib/Crypt/RSA.php'); require_once('phpseclib/Crypt/Hash.php'); -function csr_generate(&$cert, $keylen, $dn, $digest_alg = 'sha256') +function csr_generate(&$cert, $keylen_curve, $dn, $digest_alg) { $configFilename = create_temp_openssl_config($dn); + $args = array( 'config' => $configFilename, - 'private_key_type' => OPENSSL_KEYTYPE_RSA, - 'private_key_bits' => (int)$keylen, 'req_extensions' => 'v3_req', 'digest_alg' => $digest_alg, 'encrypt_key' => false ); + if (is_numeric($keylen_curve)) { + $args['private_key_type'] = OPENSSL_KEYTYPE_RSA; + $args['private_key_bits'] = (int)$keylen_curve; + } else { + $args['private_key_type'] = OPENSSL_KEYTYPE_EC; + $args['curve_name'] = $keylen_curve; + } // generate a new key pair $res_key = openssl_pkey_new($args); @@ -214,6 +220,7 @@ $cert_methods = array( "sign_cert_csr" => gettext("Sign a Certificate Signing Request"), ); $cert_keylens = array( "512", "1024", "2048", "3072", "4096", "8192"); +$cert_curves = array( "prime256v1", "secp384r1", "secp521r1"); $openssl_digest_algs = array("sha1", "sha224", "sha256", "sha384", "sha512"); $cert_types = array('usr_cert', 'server_cert', 'combined_server_client', 'v3_ca'); $key_usages = array( @@ -266,9 +273,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') { } else { $pconfig['certmethod'] = null; } + $pconfig['keytype'] = "RSA"; $pconfig['keylen'] = "2048"; $pconfig['digest_alg'] = "sha256"; $pconfig['digest_alg_sign_csr'] = "sha256"; + $pconfig['csr_keytype'] = "RSA"; $pconfig['csr_keylen'] = "2048"; $pconfig['csr_digest_alg'] = "sha256"; $pconfig['lifetime'] = "365"; @@ -495,13 +504,16 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') { $input_errors[] = gettext("This certificate does not appear to be valid."); } } elseif ($pconfig['certmethod'] == "internal") { - $reqdfields = explode(" ", "descr caref keylen lifetime dn_country dn_state dn_city ". + $reqdfields = explode(" ", "descr caref keytype keylen curve digest_alg lifetime dn_country dn_state dn_city ". "dn_organization dn_email dn_commonname" ); $reqdfieldsn = array( gettext("Descriptive name"), gettext("Certificate authority"), + gettext("Key type"), gettext("Key length"), + gettext("Curve"), + gettext("Digest algorithm"), gettext("Lifetime"), gettext("Distinguished name Country Code"), gettext("Distinguished name State or Province"), @@ -510,12 +522,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') { gettext("Distinguished name Email Address"), gettext("Distinguished name Common Name")); } elseif ($pconfig['certmethod'] == "external") { - $reqdfields = explode(" ", "descr csr_keylen csr_dn_country csr_dn_state csr_dn_city ". + $reqdfields = explode(" ", "descr csr_keytype csr_keylen csr_curve csr_digest_alg csr_dn_country csr_dn_state csr_dn_city ". "csr_dn_organization csr_dn_email csr_dn_commonname" ); $reqdfieldsn = array( gettext("Descriptive name"), + gettext("Key type"), gettext("Key length"), + gettext("Curve"), + gettext("Digest algorithm"), gettext("Distinguished name Country Code"), gettext("Distinguished name State or Province"), gettext("Distinguished name City"), @@ -564,20 +579,30 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') { } } + if ($pconfig['certmethod'] != "external" && !in_array($pconfig["keytype"], array("RSA", "Elliptic Curve"))) { + $input_errors[] = gettext("Please select a valid Key Type."); + } if ($pconfig['certmethod'] == "internal" && !in_array($pconfig["cert_type"], $cert_types)) { $input_errors[] = gettext("Please select a valid Type."); } - - if ($pconfig['certmethod'] != "external" && isset($pconfig["keylen"]) && !in_array($pconfig["keylen"], $cert_keylens)) { + if ($pconfig['certmethod'] != "external" && isset($pconfig["keylen"]) && $pconfig["keytype"] == "RSA" && !in_array($pconfig["keylen"], $cert_keylens)) { $input_errors[] = gettext("Please select a valid Key Length."); } + if ($pconfig['certmethod'] != "external" && isset($pconfig["curve"]) && $pconfig["keytype"] == "Elliptic Curve" && !in_array($pconfig["curve"], $cert_curves)) { + $input_errors[] = gettext("Please select a valid Curve."); + } if ($pconfig['certmethod'] != "external" && !in_array($pconfig["digest_alg"], $openssl_digest_algs)) { $input_errors[] = gettext("Please select a valid Digest Algorithm."); } - - if ($pconfig['certmethod'] == "external" && isset($pconfig["csr_keylen"]) && !in_array($pconfig["csr_keylen"], $cert_keylens)) { + if ($pconfig['certmethod'] == "external" && !in_array($pconfig["keytype"], array("RSA", "Elliptic Curve"))) { + $input_errors[] = gettext("Please select a valid Key Type."); + } + if ($pconfig['certmethod'] == "external" && isset($pconfig["csr_keylen"]) && $pconfig["keytype"] == "RSA" && !in_array($pconfig["csr_keylen"], $cert_keylens)) { $input_errors[] = gettext("Please select a valid Key Length."); } + if ($pconfig['certmethod'] == "external" && isset($pconfig["csr_curve"]) && $pconfig["keytype"] == "Elliptic Curve" && !in_array($pconfig["csr_curve"], $cert_curves)) { + $input_errors[] = gettext("Please select a valid Curve."); + } if ($pconfig['certmethod'] == "external" && !in_array($pconfig["csr_digest_alg"], $openssl_digest_algs)) { $input_errors[] = gettext("Please select a valid Digest Algorithm."); } @@ -667,7 +692,16 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') { $cert['descr'] = $pconfig['descr']; $old_err_level = error_reporting(0); /* otherwise openssl_ functions throw warings directly to a page screwing menu tab */ - + if ($pconfig['keytype'] == "Elliptic Curve") { + $pconfig['keylen_curve'] = $pconfig['curve']; + } else { + $pconfig['keylen_curve'] = $pconfig['keylen']; + } + if ($pconfig['csr_keytype'] == "Elliptic Curve") { + $pconfig['csr_keylen_curve'] = $pconfig['csr_curve']; + } else { + $pconfig['csr_keylen_curve'] = $pconfig['csr_keylen']; + } if ($pconfig['certmethod'] == "import") { cert_import($cert, $pconfig['cert'], $pconfig['key']); } elseif ($pconfig['certmethod'] == "internal") { @@ -689,7 +723,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') { if (!cert_create( $cert, $pconfig['caref'], - $pconfig['keylen'], + $pconfig['keylen_curve'], $pconfig['lifetime'], $dn, $pconfig['digest_alg'], @@ -732,7 +766,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') { } $dn['subjectAltName'] = implode(",", $altnames_tmp); } - if (!csr_generate($cert, $pconfig['csr_keylen'], $dn, $pconfig['csr_digest_alg'])) { + if (!csr_generate($cert, $pconfig['csr_keylen_curve'], $dn, $pconfig['csr_digest_alg'])) { $input_errors = array(); while ($ssl_err = openssl_error_string()) { $input_errors[] = gettext("openssl library returns:") . " " . $ssl_err; @@ -1117,6 +1151,31 @@ if (empty($act)) { $(".text_download_btn").remove(); } +$("#keytype").change(function(){ + $("#EC").addClass("hidden"); + $("#RSA").addClass("hidden"); + $("#blank").addClass("hidden"); + if ($(this).val() == "Elliptic Curve") { + $("#EC").removeClass("hidden"); + } else { + $("#RSA").removeClass("hidden"); + } +}); + +$("#keytype").change(); + +$("#csr_keytype").change(function(){ + $("#csr_EC").addClass("hidden"); + $("#csr_RSA").addClass("hidden"); + $("#csr_blank").addClass("hidden"); + if ($(this).val() == "Elliptic Curve") { + $("#csr_EC").removeClass("hidden"); + } else { + $("#csr_RSA").removeClass("hidden"); + } +}); + +$("#csr_keytype").change(); }); @@ -1474,17 +1533,43 @@ $( document ).ready(function() { + + + + + + () + + + + + + + @@ -1670,18 +1755,43 @@ $( document ).ready(function() { + + + + + + () - + + + + + + +