Skip to content

Commit

Permalink
Add hook for entreprise support for PKI name constraints extension.
Browse files Browse the repository at this point in the history
  • Loading branch information
victorr committed Dec 17, 2024
1 parent 2984e0f commit fc18ed0
Show file tree
Hide file tree
Showing 8 changed files with 53 additions and 7 deletions.
8 changes: 8 additions & 0 deletions builtin/logical/pki/cert_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,14 @@ func (cb CreationBundleInputFromFieldData) GetUserIds() []string {
return cb.data.Get("user_ids").([]string)
}

func (cb CreationBundleInputFromFieldData) GetPathNameConstraints() (*pkix.Extension, error) {
jsonString, exists := cb.data.GetOk("name_constraints")
if !exists {
return nil, nil
}
return entParseNameConstraintsJson(jsonString.(string))
}

// generateCreationBundle is a shared function that reads parameters supplied
// from the various endpoints and generates a CreationParameters with the
// parameters that can be used to issue or sign
Expand Down
6 changes: 6 additions & 0 deletions builtin/logical/pki/fields.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,12 @@ The value format should be given in UTC format YYYY-MM-ddTHH:MM:SSZ`,
},
}

fields["name_constraints"] = &framework.FieldSchema{
Type: framework.TypeString,
Default: "",
Description: `Names Constraints extension, see https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.10 ; formatted as a JSON tree of permitted and excluded subtrees.`,
}

return fields
}

Expand Down
4 changes: 2 additions & 2 deletions builtin/logical/pki/issuing/cert_verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ func VerifyCertificate(ctx context.Context, storage logical.Storage, issuerId Is
DisableTimeChecks: true,
DisableEKUChecks: true,
DisableCriticalExtensionChecks: false,
DisableNameChecks: false,
DisableNameChecks: false, // issuer name check
DisablePathLenChecks: false,
DisableNameConstraintChecks: false,
DisableNameConstraintChecks: false, // path name constraints extension
}

if err := entSetCertVerifyOptions(ctx, storage, issuerId, &options); err != nil {
Expand Down
7 changes: 7 additions & 0 deletions builtin/logical/pki/issuing/issue_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ type CreationBundleInput interface {
IsUserIdInSchema() (interface{}, bool)
GetUserIds() []string
IgnoreCSRSignature() bool
GetPathNameConstraints() (*pkix.Extension, error)
}

// GenerateCreationBundle is a shared function that reads parameters supplied
Expand Down Expand Up @@ -408,6 +409,11 @@ func GenerateCreationBundle(b logical.SystemView, role *RoleEntry, entityInfo En
}
}

pathNameConstraints, err := cb.GetPathNameConstraints()
if err != nil {
return nil, nil, errutil.UserError{Err: fmt.Sprintf("requested name_constraints cannot be populated: %s", err)}
}

creation := &certutil.CreationBundle{
Params: &certutil.CreationParameters{
Subject: subject,
Expand All @@ -430,6 +436,7 @@ func GenerateCreationBundle(b logical.SystemView, role *RoleEntry, entityInfo En
ForceAppendCaChain: caSign != nil,
SKID: skid,
IgnoreCSRSignature: cb.IgnoreCSRSignature(),
NameConstraints: pathNameConstraints,
},
SigningBundle: caSign,
CSR: csr,
Expand Down
5 changes: 5 additions & 0 deletions builtin/logical/pki/issuing/sign_cert.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"crypto/ed25519"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"fmt"

"github.com/hashicorp/vault/sdk/helper/certutil"
Expand Down Expand Up @@ -113,6 +114,10 @@ func (b BasicSignCertInput) GetPermittedDomains() []string {
return []string{}
}

func (b BasicSignCertInput) GetPathNameConstraints() (*pkix.Extension, error) {
return nil, nil
}

func SignCert(b logical.SystemView, role *RoleEntry, entityInfo EntityInfo, caSign *certutil.CAInfoBundle, signInput SignCertInput) (*certutil.ParsedCertBundle, []string, error) {
if role == nil {
return nil, nil, errutil.InternalError{Err: "no role found in data bundle"}
Expand Down
2 changes: 1 addition & 1 deletion builtin/logical/pki/path_issue_sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ func (b *backend) pathIssueSignCert(ctx context.Context, req *logical.Request, d
}
}

if err := issuing.VerifyCertificate(sc.GetContext(), sc.GetStorage(), issuerId, parsedBundle); err != nil {
if err = issuing.VerifyCertificate(sc.GetContext(), sc.GetStorage(), issuerId, parsedBundle); err != nil {
return nil, err
}

Expand Down
25 changes: 21 additions & 4 deletions sdk/helper/certutil/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -1069,8 +1069,9 @@ func selectSignatureAlgorithmForECDSA(pub crypto.PublicKey, signatureBits int) x
}

var (
ExtensionBasicConstraintsOID = []int{2, 5, 29, 19}
ExtensionSubjectAltNameOID = []int{2, 5, 29, 17}
ExtensionBasicConstraintsOID = []int{2, 5, 29, 19}
ExtensionSubjectAltNameOID = []int{2, 5, 29, 17}
ExtensionPathNameConstraintOID = []int{2, 5, 29, 30}
)

// CreateCSR creates a CSR with the default rand.Reader to
Expand Down Expand Up @@ -1296,6 +1297,8 @@ func signCertificate(data *CreationBundle, randReader io.Reader) (*ParsedCertBun
}
}

hasPathNameExtension := ""

if data.Params.UseCSRValues {
certTemplate.Subject = data.CSR.Subject
certTemplate.Subject.ExtraNames = certTemplate.Subject.Names
Expand All @@ -1309,6 +1312,10 @@ func signCertificate(data *CreationBundle, randReader io.Reader) (*ParsedCertBun
if !name.Id.Equal(ExtensionBasicConstraintsOID) && !(len(data.Params.OtherSANs) > 0 && name.Id.Equal(ExtensionSubjectAltNameOID)) {
certTemplate.ExtraExtensions = append(certTemplate.ExtraExtensions, name)
}
if name.Id.Equal(ExtensionPathNameConstraintOID) {
certTemplate.ExtraExtensions = append(certTemplate.ExtraExtensions, name)
hasPathNameExtension = "has path name extension on CSR and UseCSRValues is true"
}
}

} else {
Expand Down Expand Up @@ -1352,9 +1359,19 @@ func signCertificate(data *CreationBundle, randReader io.Reader) (*ParsedCertBun
certTemplate.IsCA = false
}

if data.Params.NameConstraints != nil {
if hasPathNameExtension == "" {
certTemplate.ExtraExtensions = append(certTemplate.ExtraExtensions, *data.Params.NameConstraints)
hasPathNameExtension = "path name constraints parameter passed in"
}
}
if len(data.Params.PermittedDNSDomains) > 0 {
certTemplate.PermittedDNSDomains = data.Params.PermittedDNSDomains
certTemplate.PermittedDNSDomainsCritical = true
if hasPathNameExtension == "" {
certTemplate.PermittedDNSDomains = data.Params.PermittedDNSDomains
certTemplate.PermittedDNSDomainsCritical = true
} else {
return nil, errutil.UserError{Err: fmt.Sprintf("permitted domains were set, but would be overrridden by path name constraints: %v", hasPathNameExtension)}
}
}

certBytes, err = x509.CreateCertificate(randReader, certTemplate, caCert, data.CSR.PublicKey, data.SigningBundle.PrivateKey)
Expand Down
3 changes: 3 additions & 0 deletions sdk/helper/certutil/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -810,6 +810,9 @@ type CreationParameters struct {
UseCSRValues bool
PermittedDNSDomains []string

// The path NameConstraints extension for issued certificates.
NameConstraints *pkix.Extension

// URLs to encode into the certificate
URLs *URLEntries

Expand Down

0 comments on commit fc18ed0

Please sign in to comment.