pki: Use X.509v3 EKU extension in CSR

This commit is contained in:
Andreas Steffen 2023-01-11 17:44:15 +01:00
parent 41b0dff92b
commit 8effb06d6c
5 changed files with 131 additions and 68 deletions

View File

@ -769,10 +769,9 @@ static const asn1Object_t extendedKeyUsageObjects[] = {
#define EXT_KEY_USAGE_PURPOSE_ID 1
/**
* Extracts extendedKeyUsage OIDs
* Extracts extendedKeyUsage OIDs (shared with x509_pkcs10.c)
*/
static bool parse_extendedKeyUsage(chunk_t blob, int level0,
private_x509_cert_t *this)
bool x509_parse_eku_extension(chunk_t blob, int level0, x509_flag_t *flags)
{
asn1_parser_t *parser;
chunk_t object;
@ -789,19 +788,19 @@ static bool parse_extendedKeyUsage(chunk_t blob, int level0,
switch (asn1_known_oid(object))
{
case OID_SERVER_AUTH:
this->flags |= X509_SERVER_AUTH;
*flags |= X509_SERVER_AUTH;
break;
case OID_CLIENT_AUTH:
this->flags |= X509_CLIENT_AUTH;
*flags |= X509_CLIENT_AUTH;
break;
case OID_IKE_INTERMEDIATE:
this->flags |= X509_IKE_INTERMEDIATE;
*flags |= X509_IKE_INTERMEDIATE;
break;
case OID_OCSP_SIGNING:
this->flags |= X509_OCSP_SIGNER;
*flags |= X509_OCSP_SIGNER;
break;
case OID_MS_SMARTCARD_LOGON:
this->flags |= X509_MS_SMARTCARD_LOGON;
*flags |= X509_MS_SMARTCARD_LOGON;
break;
default:
break;
@ -1516,7 +1515,7 @@ static bool parse_certificate(private_x509_cert_t *this)
parse_keyUsage(object, this);
break;
case OID_EXTENDED_KEY_USAGE:
if (!parse_extendedKeyUsage(object, level, this))
if (!x509_parse_eku_extension(object, level, &this->flags))
{
goto end;
}
@ -2207,6 +2206,50 @@ static chunk_t generate_ts(traffic_selector_t *ts)
return asn1_wrap(ASN1_SEQUENCE, "mm", from, to);
}
/**
* Generate an extendedKeyUsage X.509v3 extension (shared with x509_pkcs10.c)
*/
chunk_t x509_generate_eku_extension(x509_flag_t flags)
{
chunk_t extendedKeyUsage = chunk_empty, ocspSigning = chunk_empty;
chunk_t serverAuth = chunk_empty, clientAuth = chunk_empty;
chunk_t ikeIntermediate = chunk_empty, msSmartcardLogon = chunk_empty;
if (flags & X509_SERVER_AUTH)
{
serverAuth = asn1_build_known_oid(OID_SERVER_AUTH);
}
if (flags & X509_CLIENT_AUTH)
{
clientAuth = asn1_build_known_oid(OID_CLIENT_AUTH);
}
if (flags & X509_IKE_INTERMEDIATE)
{
ikeIntermediate = asn1_build_known_oid(OID_IKE_INTERMEDIATE);
}
if (flags & X509_OCSP_SIGNER)
{
ocspSigning = asn1_build_known_oid(OID_OCSP_SIGNING);
}
if (flags & X509_MS_SMARTCARD_LOGON)
{
msSmartcardLogon = asn1_build_known_oid(OID_MS_SMARTCARD_LOGON);
}
if (serverAuth.ptr || clientAuth.ptr || ikeIntermediate.ptr ||
ocspSigning.ptr || msSmartcardLogon.ptr)
{
extendedKeyUsage = asn1_wrap(ASN1_SEQUENCE, "mm",
asn1_build_known_oid(OID_EXTENDED_KEY_USAGE),
asn1_wrap(ASN1_OCTET_STRING, "m",
asn1_wrap(ASN1_SEQUENCE, "mmmmm",
serverAuth, clientAuth, ikeIntermediate,
ocspSigning, msSmartcardLogon)));
}
return extendedKeyUsage;
}
/**
* Generate and sign a new certificate
*/
@ -2215,18 +2258,15 @@ static bool generate(private_x509_cert_t *cert, certificate_t *sign_cert,
{
const chunk_t keyUsageCrlSign = chunk_from_chars(0x01, 0x02);
const chunk_t keyUsageCertSignCrlSign = chunk_from_chars(0x01, 0x06);
chunk_t extensions = chunk_empty, extendedKeyUsage = chunk_empty;
chunk_t serverAuth = chunk_empty, clientAuth = chunk_empty;
chunk_t ocspSigning = chunk_empty, certPolicies = chunk_empty;
chunk_t extensions = chunk_empty, certPolicies = chunk_empty;
chunk_t basicConstraints = chunk_empty, nameConstraints = chunk_empty;
chunk_t keyUsage = chunk_empty, keyUsageBits = chunk_empty;
chunk_t subjectAltNames = chunk_empty, policyMappings = chunk_empty;
chunk_t subjectKeyIdentifier = chunk_empty, authKeyIdentifier = chunk_empty;
chunk_t crlDistributionPoints = chunk_empty, authorityInfoAccess = chunk_empty;
chunk_t policyConstraints = chunk_empty, inhibitAnyPolicy = chunk_empty;
chunk_t ikeIntermediate = chunk_empty, msSmartcardLogon = chunk_empty;
chunk_t ipAddrBlocks = chunk_empty, sig_scheme = chunk_empty;
chunk_t criticalExtension = chunk_empty;
chunk_t criticalExtension = chunk_empty, extendedKeyUsage = chunk_empty;
identification_t *issuer, *subject;
chunk_t key_info;
hasher_t *hasher;
@ -2350,37 +2390,7 @@ static bool generate(private_x509_cert_t *cert, certificate_t *sign_cert,
}
/* add extendedKeyUsage flags */
if (cert->flags & X509_SERVER_AUTH)
{
serverAuth = asn1_build_known_oid(OID_SERVER_AUTH);
}
if (cert->flags & X509_CLIENT_AUTH)
{
clientAuth = asn1_build_known_oid(OID_CLIENT_AUTH);
}
if (cert->flags & X509_IKE_INTERMEDIATE)
{
ikeIntermediate = asn1_build_known_oid(OID_IKE_INTERMEDIATE);
}
if (cert->flags & X509_OCSP_SIGNER)
{
ocspSigning = asn1_build_known_oid(OID_OCSP_SIGNING);
}
if (cert->flags & X509_MS_SMARTCARD_LOGON)
{
msSmartcardLogon = asn1_build_known_oid(OID_MS_SMARTCARD_LOGON);
}
if (serverAuth.ptr || clientAuth.ptr || ikeIntermediate.ptr ||
ocspSigning.ptr || msSmartcardLogon.ptr)
{
extendedKeyUsage = asn1_wrap(ASN1_SEQUENCE, "mm",
asn1_build_known_oid(OID_EXTENDED_KEY_USAGE),
asn1_wrap(ASN1_OCTET_STRING, "m",
asn1_wrap(ASN1_SEQUENCE, "mmmmm",
serverAuth, clientAuth, ikeIntermediate,
ocspSigning, msSmartcardLogon)));
}
extendedKeyUsage = x509_generate_eku_extension(cert->flags);
/* add subjectKeyIdentifier to CA and OCSP signer certificates */
if (cert->flags & (X509_CA | X509_OCSP_SIGNER | X509_CRL_SIGN))

View File

@ -77,6 +77,11 @@ struct private_x509_pkcs10_t {
*/
chunk_t certTypeExt;
/**
* extendedKeyUsage flags
*/
x509_flag_t flags;
/**
* Signature scheme
*/
@ -110,6 +115,10 @@ extern bool x509_parse_generalNames(chunk_t blob, int level0, bool implicit,
linked_list_t *list);
extern chunk_t x509_build_subjectAltNames(linked_list_t *list);
extern bool x509_parse_eku_extension(chunk_t blob, int level0, x509_flag_t *flags);
extern chunk_t x509_generate_eku_extension(x509_flag_t flags);
METHOD(certificate_t, get_type, certificate_type_t,
private_x509_pkcs10_t *this)
{
@ -238,30 +247,31 @@ METHOD(pkcs10_t, get_challengePassword, chunk_t,
METHOD(pkcs10_t, get_flags, x509_flag_t,
private_x509_pkcs10_t *this)
{
x509_flag_t flags = X509_NONE;
char *profile;
if (this->certTypeExt.len > 0)
{
char *profile;
profile = strndup(this->certTypeExt.ptr, this->certTypeExt.len);
profile = strndup(this->certTypeExt.ptr, this->certTypeExt.len);
if (strcaseeq(profile, "server"))
{
flags |= X509_SERVER_AUTH;
if (strcaseeq(profile, "server"))
{
this->flags |= X509_SERVER_AUTH;
}
else if (strcaseeq(profile, "client"))
{
this->flags |= X509_CLIENT_AUTH;
}
else if (strcaseeq(profile, "dual"))
{
this->flags |= (X509_SERVER_AUTH | X509_CLIENT_AUTH);
}
else if (strcaseeq(profile, "ocsp"))
{
this->flags |= X509_OCSP_SIGNER;
}
free(profile);
}
else if (strcaseeq(profile, "client"))
{
flags |= X509_CLIENT_AUTH;
}
else if (strcaseeq(profile, "dual"))
{
flags |= (X509_SERVER_AUTH | X509_CLIENT_AUTH);
}
else if (strcaseeq(profile, "ocsp"))
{
flags |= X509_OCSP_SIGNER;
}
free(profile);
return flags;
return this->flags;
}
METHOD(pkcs10_t, create_subjectAltName_enumerator, enumerator_t*,
@ -279,6 +289,7 @@ static bool generate(private_x509_pkcs10_t *cert, private_key_t *sign_key,
chunk_t key_info, subjectAltNames, attributes;
chunk_t extensionRequest = chunk_empty, certTypeExt = chunk_empty;
chunk_t challengePassword = chunk_empty, sig_scheme = chunk_empty;
chunk_t extendedKeyUsage = chunk_empty;
identification_t *subject;
subject = cert->subject;
@ -322,13 +333,17 @@ static bool generate(private_x509_pkcs10_t *cert, private_key_t *sign_key,
));
}
/* encode extendedKeyUsage flags */
extendedKeyUsage = x509_generate_eku_extension(cert->flags);
/* encode extensionRequest attribute */
if (subjectAltNames.ptr || certTypeExt.ptr)
{
extensionRequest = asn1_wrap(ASN1_SEQUENCE, "mm",
asn1_build_known_oid(OID_EXTENSION_REQUEST),
asn1_wrap(ASN1_SET, "m",
asn1_wrap(ASN1_SEQUENCE, "mm", subjectAltNames, certTypeExt)
asn1_wrap(ASN1_SEQUENCE, "mmm",
subjectAltNames, certTypeExt, extendedKeyUsage)
));
}
@ -452,6 +467,12 @@ static bool parse_extension_request(private_x509_pkcs10_t *this, chunk_t blob, i
}
this->certTypeExt = object;
break;
case OID_EXTENDED_KEY_USAGE:
if (!x509_parse_eku_extension(object, level, &this->flags))
{
goto end;
}
break;
default:
break;
}
@ -769,6 +790,9 @@ x509_pkcs10_t *x509_pkcs10_gen(certificate_type_t type, va_list args)
case BUILD_CERT_TYPE_EXT:
cert->certTypeExt = chunk_clone(va_arg(args, chunk_t));
continue;
case BUILD_X509_FLAG:
cert->flags |= va_arg(args, x509_flag_t);
continue;
case BUILD_SIGNATURE_SCHEME:
cert->scheme = va_arg(args, signature_params_t*);
cert->scheme = signature_params_clone(cert->scheme);

View File

@ -43,6 +43,7 @@ static int req()
chunk_t encoding = chunk_empty;
chunk_t challenge_password = chunk_empty;
chunk_t cert_type_ext = chunk_empty;
x509_flag_t flags = 0;
char *arg;
bool pss = lib->settings->get_bool(lib->settings, "%s.rsa_pss", FALSE,
lib->ns);
@ -78,6 +79,24 @@ static int req()
goto usage;
}
continue;
case 'e':
if (streq(arg, "serverAuth"))
{
flags |= X509_SERVER_AUTH;
}
else if (streq(arg, "clientAuth"))
{
flags |= X509_CLIENT_AUTH;
}
else if (streq(arg, "ocspSigning"))
{
flags |= X509_OCSP_SIGNER;
}
else if (streq(arg, "msSmartcardLogon"))
{
flags |= X509_MS_SMARTCARD_LOGON;
}
continue;
case 'g': /* --digest */
if (!enum_from_name(hash_algorithm_short_names, arg, &digest))
{
@ -213,6 +232,7 @@ static int req()
BUILD_SUBJECT, id,
BUILD_SUBJECT_ALTNAMES, san,
BUILD_CHALLENGE_PWD, challenge_password,
BUILD_X509_FLAG, flags,
BUILD_CERT_TYPE_EXT, cert_type_ext,
BUILD_SIGNATURE_SCHEME, scheme,
BUILD_END);
@ -264,6 +284,7 @@ static void __attribute__ ((constructor))reg()
"create a PKCS#10 certificate request",
{"[--in file|--keyid hex] [--type rsa|ecdsa|bliss|priv]",
" --oldreq file|--dn distinguished-name [--san subjectAltName]+",
"[--flag serverAuth|clientAuth|ocspSigning|msSmartcardLogon]+",
"[--profile server|client|dual|ocsp] [--password challengePassword]",
"[--digest sha1|sha224|sha256|sha384|sha512|sha3_224|sha3_256|sha3_384|sha3_512]",
"[--rsa-padding pkcs1|pss] [--outform der|pem]"},
@ -275,6 +296,7 @@ static void __attribute__ ((constructor))reg()
{"oldreq", 'o', 1, "old certificate request to be used as a template"},
{"dn", 'd', 1, "subject distinguished name"},
{"san", 'a', 1, "subjectAltName to include in cert request"},
{"flag", 'e', 1, "include extendedKeyUsage flag"},
{"profile", 'P', 1, "certificate profile name to include in cert request"},
{"password", 'p', 1, "challengePassword to include in cert request"},
{"digest", 'g', 1, "digest for signature creation, default: key-specific"},

View File

@ -125,7 +125,8 @@ Serial number in hex. It is randomly allocated by default.
.TP
.BI "\-e, \-\-flag " flag
Add extendedKeyUsage flag. One of \fIserverAuth\fR, \fIclientAuth\fR,
\fIcrlSign\fR, or \fIocspSigning\fR. Can be used multiple times.
\fIcrlSign\fR, \fIocspSigning\fR or \fImsSmartcardLogon\fR. Can be used multiple
times.
.TP
.BI "\-g, \-\-digest " digest
Digest to use for signature creation. One of \fImd5\fR, \fIsha1\fR,

View File

@ -14,6 +14,7 @@ pki \-\-req \- Create a PKCS#10 certificate request
.BI \-\-dn\~ distinguished-name
.OP \-\-san subjectAltName
.OP \-\-profile profile
.OP \-\-flag flag
.OP \-\-password password
.OP \-\-digest digest
.OP \-\-rsa\-padding padding
@ -91,6 +92,11 @@ UTF8 string. Supported e.g. by
translated into corresponding Extended Key Usage (EKU) flags in the generated
X.509 certificate.
.TP
.BI "\-e, \-\-flag " flag
Add extendedKeyUsage flag. One of \fIserverAuth\fR, \fIclientAuth\fR,
\fIocspSigning\fR or \fImsSmartcardLogon\fR. Can be used multiple times. Adds an
X.509v3 EKU extension containing these flags to the certificate request.
.TP
.BI "\-p, \-\-password " password
The challengePassword to include in the certificate request.
.TP