Skip to content

Commit

Permalink
Vault 11799 Vault CLI Re-Issue (Templating based on existing certific…
Browse files Browse the repository at this point in the history
…ate) (hashicorp#18499)

* The verify-sign command in it's cleanest existing form.

* Working state

* Updates to proper verification syntax

Co-authored-by: 'Alex Scheel' <alex.scheel@hashicorp.com>

* make fmt

* Base functionality.

* make fmt; changelog

* pki issue command.

* Make fmt. Changelog.

* Error Handling Is Almost A Tutorial

* Issue and ReIssue are Almost the Same Command

* Make Fmt + Changelog.

* Make some of the tests go.

* make fmt

* Merge fix (take 2)

* Fix existing support, add support for use_pss, max_path_length, not_after, permitted_dns_domains and skid

* Good Test which Fails

* Test-correction.

* Fix update to key_type key_bits; allow "," in OU or similar

* More specific includeCNinSANs

* Add tests around trying to use_pss on an ec key.

* GoDoc Test Paragraph thing.

---------

Co-authored-by: 'Alex Scheel' <alex.scheel@hashicorp.com>
  • Loading branch information
kitography and cipherboy authored Feb 10, 2023
1 parent 8901e50 commit d08de3e
Show file tree
Hide file tree
Showing 5 changed files with 517 additions and 11 deletions.
3 changes: 3 additions & 0 deletions changelog/18499.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:improvement
cli/pki: Added "Reissue" command which allows extracting fields from an existing certificate to create a new certificate.
```
5 changes: 5 additions & 0 deletions command/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,11 @@ func initCommands(ui, serverCmdUi cli.Ui, runOpts *RunOptions) map[string]cli.Co
BaseCommand: getBaseCommand(),
}, nil
},
"pki reissue": func() (cli.Command, error) {
return &PKIReIssueCACommand{
BaseCommand: getBaseCommand(),
}, nil
},
"pki verify-sign": func() (cli.Command, error) {
return &PKIVerifySignCommand{
BaseCommand: getBaseCommand(),
Expand Down
28 changes: 17 additions & 11 deletions command/pki_issue_intermediate.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,14 @@ func (c *PKIIssueCACommand) Run(args []string) int {
return 1
}

parentMountIssuer := sanitizePath(args[0]) // /pki/issuer/default

intermediateMount := sanitizePath(args[1])

return pkiIssue(c.BaseCommand, parentMountIssuer, intermediateMount, c.flagNewIssuerName, c.flagKeyStorageSource, data)
}

func pkiIssue(c *BaseCommand, parentMountIssuer string, intermediateMount string, flagNewIssuerName string, flagKeyStorageSource string, data map[string]interface{}) int {
// Check We Have a Client
client, err := c.Client()
if err != nil {
Expand All @@ -97,8 +105,6 @@ func (c *PKIIssueCACommand) Run(args []string) int {
}

// Sanity Check the Parent Issuer
parentMountIssuer := sanitizePath(args[0]) // /pki/issuer/default
_, parentIssuerName := paths.Split(parentMountIssuer)
if !strings.Contains(parentMountIssuer, "/issuer/") {
c.UI.Error(fmt.Sprintf("Parent Issuer %v is Not a PKI Issuer Path of the format /mount/issuer/issuer-ref", parentMountIssuer))
}
Expand All @@ -108,16 +114,15 @@ func (c *PKIIssueCACommand) Run(args []string) int {
}

// Set-up Failure State (Immediately Before First Write Call)
intermediateMount := sanitizePath(args[1])
failureState := inCaseOfFailure{
intermediateMount: intermediateMount,
parentMount: strings.Split(parentMountIssuer, "/issuer/")[0],
parentIssuer: parentMountIssuer,
newName: c.flagNewIssuerName,
newName: flagNewIssuerName,
}

// Generate Certificate Signing Request
csrResp, err := client.Logical().Write(intermediateMount+"/intermediate/generate/"+c.flagKeyStorageSource, data)
csrResp, err := client.Logical().Write(intermediateMount+"/intermediate/generate/"+flagKeyStorageSource, data)
if err != nil {
if strings.Contains(err.Error(), "no handler for route") { // Mount Given Does Not Exist
c.UI.Error(fmt.Sprintf("Given Intermediate Mount %v Does Not Exist: %v", intermediateMount, err))
Expand All @@ -129,21 +134,21 @@ func (c *PKIIssueCACommand) Run(args []string) int {
return 1
}
// Parse CSR Response, Also Verifies that this is a PKI Mount
// (eg. calling the above call on cubbyhole/ won't return an error response)
// (e.g. calling the above call on cubbyhole/ won't return an error response)
csrPemRaw, present := csrResp.Data["csr"]
if !present {
c.UI.Error(fmt.Sprintf("Failed to Generate Intermediate CSR on %v, got response: %v", intermediateMount, csrResp))
return 1
}
keyIdRaw, present := csrResp.Data["key_id"]
if !present && c.flagKeyStorageSource == "internal" {
if !present && flagKeyStorageSource == "internal" {
c.UI.Error(fmt.Sprintf("Failed to Generate Key on %v, got response: %v", intermediateMount, csrResp))
return 1
}

// If that all Parses, then we've successfully generated a CSR! Save It (and the Key-ID)
failureState.csrGenerated = true
if c.flagKeyStorageSource == "internal" {
if flagKeyStorageSource == "internal" {
failureState.createdKeyId = keyIdRaw.(string)
}
csr := csrPemRaw.(string)
Expand Down Expand Up @@ -171,7 +176,7 @@ func (c *PKIIssueCACommand) Run(args []string) int {

// Next Import Certificate
certificate := rootResp.Data["certificate"].(string)
issuerId, err := importIssuerWithName(client, intermediateMount, certificate, c.flagNewIssuerName)
issuerId, err := importIssuerWithName(client, intermediateMount, certificate, flagNewIssuerName)
failureState.certIssuerId = issuerId
if err != nil {
if strings.Contains(err.Error(), "error naming issuer") {
Expand All @@ -189,6 +194,7 @@ func (c *PKIIssueCACommand) Run(args []string) int {

// Then Import Issuing Certificate
issuingCa := rootResp.Data["issuing_ca"].(string)
_, parentIssuerName := paths.Split(parentMountIssuer)
_, err = importIssuerWithName(client, intermediateMount, issuingCa, parentIssuerName)
if err != nil {
if strings.Contains(err.Error(), "error naming issuer") {
Expand All @@ -215,12 +221,12 @@ func (c *PKIIssueCACommand) Run(args []string) int {
failureState.caChainImported = true

// Finally we read our newly issued certificate in order to tell our caller about it
c.readAndOutputNewCertificate(client, intermediateMount, issuerId)
readAndOutputNewCertificate(client, intermediateMount, issuerId, c)

return 0
}

func (c *PKIIssueCACommand) readAndOutputNewCertificate(client *api.Client, intermediateMount string, issuerId string) {
func readAndOutputNewCertificate(client *api.Client, intermediateMount string, issuerId string, c *BaseCommand) {
resp, err := client.Logical().Read(sanitizePath(intermediateMount + "/issuer/" + issuerId))
if err != nil || resp == nil {
c.UI.Error(fmt.Sprintf("Error Reading Fully Imported Certificate from %v : %v",
Expand Down
Loading

0 comments on commit d08de3e

Please sign in to comment.