From 218bf7bbb87a3e5347cc3db3b0b1a3c6be0c2399 Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Thu, 31 May 2018 14:00:36 -0500 Subject: [PATCH 1/4] Fixes #4500. Custom exteded key usage for PKI. - Adds ability to have roles that sign certificates with custom EKU OIDs. --- builtin/logical/pki/cert_util.go | 14 ++++++++++++++ builtin/logical/pki/path_roles.go | 9 +++++++++ ui/app/models/role-pki.js | 6 +++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/builtin/logical/pki/cert_util.go b/builtin/logical/pki/cert_util.go index 55fc52b90014..bfdc32aff05d 100644 --- a/builtin/logical/pki/cert_util.go +++ b/builtin/logical/pki/cert_util.go @@ -62,6 +62,7 @@ type creationParameters struct { NotAfter time.Time KeyUsage x509.KeyUsage ExtKeyUsage certExtKeyUsage + ExtKeyUsageOIDs []string PolicyIdentifiers []string BasicConstraintsValidForNonCA bool @@ -918,6 +919,7 @@ func generateCreationBundle(b *backend, data *dataBundle) error { NotAfter: notAfter, KeyUsage: x509.KeyUsage(parseKeyUsages(data.role.KeyUsage)), ExtKeyUsage: extUsage, + ExtKeyUsageOIDs: data.role.ExtKeyUsageOIDs, PolicyIdentifiers: data.role.PolicyIdentifiers, BasicConstraintsValidForNonCA: data.role.BasicConstraintsValidForNonCA, } @@ -989,6 +991,16 @@ func addPolicyIdentifiers(data *dataBundle, certTemplate *x509.Certificate) { } } +// addExtKeyUsageOids adds custom extended key usage OIDs to certificate +func addExtKeyUsageOids(data *dataBundle, certTemplate *x509.Certificate) { + for _, oidstr := range data.params.ExtKeyUsageOIDs { + oid, err := stringToOid(oidstr) + if err == nil { + certTemplate.UnknownExtKeyUsage = append(certTemplate.UnknownExtKeyUsage, oid) + } + } +} + // Performs the heavy lifting of creating a certificate. Returns // a fully-filled-in ParsedCertBundle. func createCertificate(data *dataBundle) (*certutil.ParsedCertBundle, error) { @@ -1045,6 +1057,8 @@ func createCertificate(data *dataBundle) (*certutil.ParsedCertBundle, error) { addKeyUsages(data, certTemplate) + addExtKeyUsageOids(data, certTemplate) + certTemplate.IssuingCertificateURL = data.params.URLs.IssuingCertificates certTemplate.CRLDistributionPoints = data.params.URLs.CRLDistributionPoints certTemplate.OCSPServer = data.params.URLs.OCSPServers diff --git a/builtin/logical/pki/path_roles.go b/builtin/logical/pki/path_roles.go index c2b706598ffc..518da5bb8351 100644 --- a/builtin/logical/pki/path_roles.go +++ b/builtin/logical/pki/path_roles.go @@ -166,6 +166,12 @@ To remove all key usages from being set, set this value to an empty list.`, }, + "ext_key_usage_oids": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Default: []string{}, + Description: `A comma-separated string or list of extended key usage oids.`, + }, + "use_csr_common_name": &framework.FieldSchema{ Type: framework.TypeBool, Default: true, @@ -451,6 +457,7 @@ func (b *backend) pathRoleCreate(ctx context.Context, req *logical.Request, data UseCSRCommonName: data.Get("use_csr_common_name").(bool), UseCSRSANs: data.Get("use_csr_sans").(bool), KeyUsage: data.Get("key_usage").([]string), + ExtKeyUsageOIDs: data.Get("ext_key_usage_oids").([]string), OU: data.Get("ou").([]string), Organization: data.Get("organization").([]string), Country: data.Get("country").([]string), @@ -588,6 +595,7 @@ type roleEntry struct { RequireCN bool `json:"require_cn" mapstructure:"require_cn"` AllowedOtherSANs []string `json:"allowed_other_sans" mapstructure:"allowed_other_sans"` PolicyIdentifiers []string `json:"policy_identifiers" mapstructure:"policy_identifiers"` + ExtKeyUsageOIDs []string `json:"ext_key_usage_oids" mapstructure:"ext_key_usage_oids"` BasicConstraintsValidForNonCA bool `json:"basic_constraints_valid_for_non_ca" mapstructure:"basic_constraints_valid_for_non_ca"` // Used internally for signing intermediates @@ -616,6 +624,7 @@ func (r *roleEntry) ToResponseData() map[string]interface{} { "key_type": r.KeyType, "key_bits": r.KeyBits, "key_usage": r.KeyUsage, + "ext_key_usage_oids": r.ExtKeyUsageOIDs, "ou": r.OU, "organization": r.Organization, "country": r.Country, diff --git a/ui/app/models/role-pki.js b/ui/app/models/role-pki.js index 9b7dd34480c5..062738f56a9e 100644 --- a/ui/app/models/role-pki.js +++ b/ui/app/models/role-pki.js @@ -55,6 +55,10 @@ export default DS.Model.extend({ defaultValue: 'DigitalSignature,KeyAgreement,KeyEncipherment', editType: 'stringArray', }), + extKeyUsageOIDs: attr({ + label: 'Custom extended key usage OIDs', + editType: 'stringArray', + }), requireCn: attr('boolean', { label: 'Require common name', defaultValue: true, @@ -223,7 +227,7 @@ export default DS.Model.extend({ 'allowedDomains', ], }, - { 'Extended Key Usage': ['serverFlag', 'clientFlag', 'codeSigningFlag', 'emailProtectionFlag'] }, + { 'Extended Key Usage': ['serverFlag', 'clientFlag', 'codeSigningFlag', 'emailProtectionFlag', 'extKeyUsageOIDs'] }, { Advanced: ['generateLease', 'noStore', 'basicConstraintsValidForNonCA', 'policyIdentifiers'], }, From f9814616b577cf38cba508a62911caaf374d92c6 Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Thu, 31 May 2018 16:53:49 -0500 Subject: [PATCH 2/4] Added safety check for EKU OIDs and updated casing --- builtin/logical/pki/path_roles.go | 9 +++++++++ ui/app/models/role-pki.js | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/builtin/logical/pki/path_roles.go b/builtin/logical/pki/path_roles.go index 518da5bb8351..18c0b143a801 100644 --- a/builtin/logical/pki/path_roles.go +++ b/builtin/logical/pki/path_roles.go @@ -502,6 +502,15 @@ func (b *backend) pathRoleCreate(ctx context.Context, req *logical.Request, data return errResp, nil } + if len(entry.ExtKeyUsageOIDs) > 0 { + for _, oidstr := range entry.ExtKeyUsageOIDs { + _, err := stringToOid(oidstr) + if err != nil { + return logical.ErrorResponse(fmt.Sprintf("%q could not be parsed as a valid oid for an extended key usage", oidstr)), nil + } + } + } + if len(entry.PolicyIdentifiers) > 0 { for _, oidstr := range entry.PolicyIdentifiers { _, err := stringToOid(oidstr) diff --git a/ui/app/models/role-pki.js b/ui/app/models/role-pki.js index 062738f56a9e..a06d690abe16 100644 --- a/ui/app/models/role-pki.js +++ b/ui/app/models/role-pki.js @@ -55,7 +55,7 @@ export default DS.Model.extend({ defaultValue: 'DigitalSignature,KeyAgreement,KeyEncipherment', editType: 'stringArray', }), - extKeyUsageOIDs: attr({ + extKeyUsageOids: attr({ label: 'Custom extended key usage OIDs', editType: 'stringArray', }), @@ -227,7 +227,7 @@ export default DS.Model.extend({ 'allowedDomains', ], }, - { 'Extended Key Usage': ['serverFlag', 'clientFlag', 'codeSigningFlag', 'emailProtectionFlag', 'extKeyUsageOIDs'] }, + { 'Extended Key Usage': ['serverFlag', 'clientFlag', 'codeSigningFlag', 'emailProtectionFlag', 'extKeyUsageOids'] }, { Advanced: ['generateLease', 'noStore', 'basicConstraintsValidForNonCA', 'policyIdentifiers'], }, From bfc87005ab3e5324c5a49c0f8eafcb131640e3ca Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Thu, 31 May 2018 17:34:15 -0500 Subject: [PATCH 3/4] Added EKU OID when signing cert as well. --- builtin/logical/pki/cert_util.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/builtin/logical/pki/cert_util.go b/builtin/logical/pki/cert_util.go index bfdc32aff05d..788e10d0df06 100644 --- a/builtin/logical/pki/cert_util.go +++ b/builtin/logical/pki/cert_util.go @@ -1268,6 +1268,8 @@ func signCertificate(data *dataBundle) (*certutil.ParsedCertBundle, error) { addKeyUsages(data, certTemplate) + addExtKeyUsageOids(data, certTemplate) + var certBytes []byte certTemplate.IssuingCertificateURL = data.params.URLs.IssuingCertificates From ac2f7efe8c16bb30f9926fcce00476bd21ef8694 Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Thu, 31 May 2018 21:19:42 -0500 Subject: [PATCH 4/4] Removed default val for eku oids & go fmt --- builtin/logical/pki/cert_util.go | 2 +- builtin/logical/pki/path_roles.go | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/builtin/logical/pki/cert_util.go b/builtin/logical/pki/cert_util.go index 788e10d0df06..f4e25235a32e 100644 --- a/builtin/logical/pki/cert_util.go +++ b/builtin/logical/pki/cert_util.go @@ -1268,7 +1268,7 @@ func signCertificate(data *dataBundle) (*certutil.ParsedCertBundle, error) { addKeyUsages(data, certTemplate) - addExtKeyUsageOids(data, certTemplate) + addExtKeyUsageOids(data, certTemplate) var certBytes []byte diff --git a/builtin/logical/pki/path_roles.go b/builtin/logical/pki/path_roles.go index 18c0b143a801..e9baf731847f 100644 --- a/builtin/logical/pki/path_roles.go +++ b/builtin/logical/pki/path_roles.go @@ -168,7 +168,6 @@ this value to an empty list.`, "ext_key_usage_oids": &framework.FieldSchema{ Type: framework.TypeCommaStringSlice, - Default: []string{}, Description: `A comma-separated string or list of extended key usage oids.`, },