Add the ability to set certificate type and SAN attributes in a CSR. Ticket #7527

TODO: They are not carried over after signing in the GUI
This commit is contained in:
jim-p 2017-07-05 16:41:38 -04:00
parent 5c985ed29b
commit 282b6c666a
3 changed files with 139 additions and 58 deletions

View File

@ -401,10 +401,32 @@ function cert_create(& $cert, $caref, $keylen, $lifetime, $dn, $type = "user", $
return true;
}
function csr_generate(& $cert, $keylen, $dn, $digest_alg = "sha256") {
function csr_generate(& $cert, $keylen, $dn, $type = "user", $digest_alg = "sha256") {
switch ($type) {
case "ca":
$cert_type = "v3_ca";
break;
case "server":
case "self-signed":
$cert_type = "server";
break;
default:
$cert_type = "usr_cert";
break;
}
// in case of using Subject Alternative Names use other sections (with postfix '_san')
// pass subjectAltName over environment variable 'SAN'
if ($dn['subjectAltName']) {
putenv("SAN={$dn['subjectAltName']}"); // subjectAltName can be set _only_ via configuration file
$cert_type .= '_san';
unset($dn['subjectAltName']);
}
$args = array(
"x509_extensions" => "v3_req",
"x509_extensions" => $cert_type,
"req_extensions" => "req_{$cert_type}",
"digest_alg" => $digest_alg,
"private_key_bits" => (int)$keylen,
"private_key_type" => OPENSSL_KEYTYPE_RSA,

View File

@ -168,68 +168,22 @@ unstructuredName = An optional company name
[ usr_cert ]
# These extensions are added when 'ca' signs a request.
# This goes against PKIX guidelines but some CAs do it and some software
# requires this to avoid interpreting an end user certificate as a CA.
basicConstraints=CA:FALSE
# Here are some examples of the usage of nsCertType. If it is omitted
# the certificate can be used for anything *except* object signing.
# This is OK for an SSL server.
# nsCertType = server
# For an object signing certificate this would be used.
# nsCertType = objsign
# For normal client use this is typical
# nsCertType = client, email
# and for everything including object signing:
# nsCertType = client, email, objsign
# This is typical in keyUsage for a client certificate.
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
# This will be displayed in Netscape's comment listbox.
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
nsComment = "OpenSSL Generated User Certificate"
# PKIX recommendations harmless if included in all certificates.
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer:always
extendedKeyUsage=clientAuth
# This stuff is for subjectAltName and issuerAltname.
# Import the email address.
# subjectAltName=email:copy
# An alternative to produce certificates that aren't
# deprecated according to PKIX.
# subjectAltName=email:move
# Copy subject details
# issuerAltName=issuer:copy
#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem
#nsBaseUrl
#nsRevocationUrl
#nsRenewalUrl
#nsCaPolicyUrl
#nsSslServerName
# This is required for TSA certificates.
# extendedKeyUsage = critical,timeStamping
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
extendedKeyUsage = clientAuth
[ usr_cert_san ]
# copy of [ usr_cert ] plus nonempty Subject Alternative Names
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
nsComment = "OpenSSL Generated User Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
extendedKeyUsage = clientAuth
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = $ENV::SAN
[ server ]
@ -237,22 +191,62 @@ subjectAltName = $ENV::SAN
# Make a cert with nsCertType=server
basicConstraints = CA:FALSE
nsCertType = server
keyUsage = digitalSignature, keyEncipherment
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
extendedKeyUsage = serverAuth,1.3.6.1.5.5.8.2.2
keyUsage = digitalSignature, keyEncipherment
[ server_san ]
# copy of [ server ] plus nonempty Subject Alternative Names
basicConstraints = CA:FALSE
nsCertType = server
keyUsage = digitalSignature, keyEncipherment
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
extendedKeyUsage = serverAuth,1.3.6.1.5.5.8.2.2
subjectAltName = $ENV::SAN
[ req_usr_cert ]
# Copy of [ usr_cert ] for CSR
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
nsComment = "OpenSSL Generated User Certificate"
subjectKeyIdentifier = hash
extendedKeyUsage = clientAuth
[ req_usr_cert_san ]
# Copy of [ usr_cert_san ] for CSR
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
nsComment = "OpenSSL Generated User Certificate"
subjectKeyIdentifier = hash
extendedKeyUsage = clientAuth
subjectAltName = $ENV::SAN
[ req_server ]
# Copy of [ server ] for CSR
basicConstraints = CA:FALSE
nsCertType = server
keyUsage = digitalSignature, keyEncipherment
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier = hash
extendedKeyUsage = serverAuth,1.3.6.1.5.5.8.2.2
[ req_server_san ]
# Copy of [ server_san ] for CSR
basicConstraints = CA:FALSE
nsCertType = server
keyUsage = digitalSignature, keyEncipherment
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier = hash
extendedKeyUsage = serverAuth,1.3.6.1.5.5.8.2.2
subjectAltName = $ENV::SAN
[ v3_req ]
@ -262,6 +256,7 @@ subjectAltName = $ENV::SAN
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
[ v3_ca ]
# Extensions for a typical CA

View File

@ -479,15 +479,21 @@ if ($_POST['save']) {
if (!empty($pconfig['csr_dn_organizationalunit'])) {
$dn['organizationalUnitName'] = cert_escape_x509_chars($pconfig['csr_dn_organizationalunit']);
}
$altnames_tmp = array(cert_add_altname_type($pconfig['csr_dn_commonname']));
if (count($altnames)) {
$altnames_tmp = "";
foreach ($altnames as $altname) {
$altnames_tmp[] = "{$altname['type']}:{$altname['value']}";
// The CN is added as a SAN automatically, do not add it again.
if ($altname['value'] != $pconfig['csr_dn_commonname']) {
$altnames_tmp[] = "{$altname['type']}:" . cert_escape_x509_chars($altname['value']);
}
}
}
if (!empty($altnames_tmp)) {
$dn['subjectAltName'] = implode(",", $altnames_tmp);
}
if (!csr_generate($cert, $pconfig['csr_keylen'], $dn, $pconfig['csr_digest_alg'])) {
if (!csr_generate($cert, $pconfig['csr_keylen'], $dn, $pconfig['type'], $pconfig['csr_digest_alg'])) {
$input_errors = array();
while ($ssl_err = openssl_error_string()) {
if (strpos($ssl_err, 'NCONF_get_string:no value') === false) {
@ -916,6 +922,14 @@ if ($act == "new" || (($_POST['save'] == gettext("Save")) && $input_errors)) {
))->setHelp('NOTE: It is recommended to use an algorithm stronger than '.
'SHA1 when possible');
$section->addInput(new Form_Select(
'type',
'*Certificate Type',
$pconfig['type'],
$cert_types
))->setHelp('Type of certificate to generate. Used for placing '.
'restrictions on the usage of the generated certificate.');
$section->addInput(new Form_Select(
'csr_dn_country',
'*Country Code',
@ -971,6 +985,56 @@ if ($act == "new" || (($_POST['save'] == gettext("Save")) && $input_errors)) {
['placeholder' => 'e.g. internal-ca']
));
if (empty($pconfig['altnames']['item'])) {
$pconfig['altnames']['item'] = array(
array('type' => null, 'value' => null)
);
}
$counter = 0;
$numrows = count($pconfig['altnames']['item']) - 1;
foreach ($pconfig['altnames']['item'] as $item) {
$group = new Form_Group($counter == 0 ? 'Alternative Names':'');
$group->add(new Form_Select(
'altname_type' . $counter,
'Type',
$item['type'],
$cert_altname_types
))->setHelp(($counter == $numrows) ? 'Type':null);
$group->add(new Form_Input(
'altname_value' . $counter,
null,
'text',
$item['value']
))->setHelp(($counter == $numrows) ? 'Value':null);
$group->add(new Form_Button(
'deleterow' . $counter,
'Delete',
null,
'fa-trash'
))->addClass('btn-warning');
$group->addClass('repeatable');
$group->setHelp('Enter additional identifiers for the certificate in this list. The Common Name field is automatically added to the certificate as an Alternative Name.');
$section->add($group);
$counter++;
}
$section->addInput(new Form_Button(
'addrow',
'Add',
null,
'fa-plus'
))->addClass('btn-success');
$form->add($section);
$section = new Form_Section('Choose an Existing Certificate');
$section->addClass('toggle-existing collapse');