Vault 11796 vault cli list intermediates (#18463)
* Base functionality. * make fmt; changelog * What I thought empty issuers response fix would be. * Fix null response data for listing empty issuers causing a crash. * Update command/pki_list_children_command.go Fix double specifier Co-authored-by: Steven Clark <steven.clark@hashicorp.com> * Add test for pki_list_children. * Fix tests. * Update descriptions for correctness based on PR reviews. Co-authored-by: Steven Clark <steven.clark@hashicorp.com>
This commit is contained in:
parent
fbed961190
commit
416f8bd898
3
changelog/18463.txt
Normal file
3
changelog/18463.txt
Normal file
@ -0,0 +1,3 @@
|
||||
```release-note:improvement
|
||||
cli/pki: Add List-Intermediates functionality to pki client.
|
||||
```
|
@ -543,6 +543,11 @@ func initCommands(ui, serverCmdUi cli.Ui, runOpts *RunOptions) {
|
||||
BaseCommand: getBaseCommand(),
|
||||
}, nil
|
||||
},
|
||||
"pki list-intermediates": func() (cli.Command, error) {
|
||||
return &PKIListChildrenCommand{
|
||||
BaseCommand: getBaseCommand(),
|
||||
}, nil
|
||||
},
|
||||
"pki verify-sign": func() (cli.Command, error) {
|
||||
return &PKIVerifySignCommand{
|
||||
BaseCommand: getBaseCommand(),
|
||||
|
288
command/pki_list_children_command.go
Normal file
288
command/pki_list_children_command.go
Normal file
@ -0,0 +1,288 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/vault/api"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/ryanuber/columnize"
|
||||
)
|
||||
|
||||
type PKIListChildrenCommand struct {
|
||||
*BaseCommand
|
||||
|
||||
flagConfig string
|
||||
flagReturnIndicator string
|
||||
flagDefaultDisabled bool
|
||||
flagList bool
|
||||
|
||||
flagUseNames bool
|
||||
|
||||
flagSignatureMatch bool
|
||||
flagIndirectSignMatch bool
|
||||
flagKeyIdMatch bool
|
||||
flagSubjectMatch bool
|
||||
flagPathMatch bool
|
||||
}
|
||||
|
||||
func (c *PKIListChildrenCommand) Synopsis() string {
|
||||
return "Determine Which (of a List) of Certificates Were Issued by A Given Parent Certificate"
|
||||
}
|
||||
|
||||
func (c *PKIListChildrenCommand) Help() string {
|
||||
helpText := `
|
||||
Usage: vault pki list-intermediates PARENT [CHILD] [CHILD] [CHILD] ...
|
||||
PARENT is the certificate that might be the issuer that everything should be verified against.
|
||||
CHILD is a list of paths to certificates to be compared to the PARENT, or pki mounts to look for certificates on.
|
||||
If CHILD is omitted entirely, the list will be constructed from all accessible pki mounts.
|
||||
This returns a list of issuing certificates, and whether they are a match.
|
||||
By default, the type of match required is whether the PARENT has the expected subject, key_id, and could have (directly)
|
||||
signed this issuer. The match criteria can be updated by changed the corresponding flag.
|
||||
`
|
||||
return strings.TrimSpace(helpText)
|
||||
}
|
||||
|
||||
func (c *PKIListChildrenCommand) Flags() *FlagSets {
|
||||
set := c.flagSet(FlagSetHTTP | FlagSetOutputFormat)
|
||||
f := set.NewFlagSet("Command Options")
|
||||
|
||||
f.BoolVar(&BoolVar{
|
||||
Name: "subject_match",
|
||||
Target: &c.flagSubjectMatch,
|
||||
Default: true,
|
||||
EnvVar: "",
|
||||
Usage: `Whether the subject name of the potential parent cert matches the issuer name of the child cert`,
|
||||
})
|
||||
|
||||
f.BoolVar(&BoolVar{
|
||||
Name: "key_id_match",
|
||||
Target: &c.flagKeyIdMatch,
|
||||
Default: true,
|
||||
EnvVar: "",
|
||||
Usage: `Whether the subject key_id of the potential parent cert matches the issuing key id of the child cert`,
|
||||
})
|
||||
|
||||
f.BoolVar(&BoolVar{
|
||||
Name: "path_match",
|
||||
Target: &c.flagPathMatch,
|
||||
Default: false,
|
||||
EnvVar: "",
|
||||
Usage: `Whether the potential parent appears in the certificate chain of the issued cert`,
|
||||
})
|
||||
|
||||
f.BoolVar(&BoolVar{
|
||||
Name: "direct_sign",
|
||||
Target: &c.flagSignatureMatch,
|
||||
Default: true,
|
||||
EnvVar: "",
|
||||
Usage: `Whether the key of the potential parent signed this issued certificate`,
|
||||
})
|
||||
|
||||
f.BoolVar(&BoolVar{
|
||||
Name: "indirect_sign",
|
||||
Target: &c.flagIndirectSignMatch,
|
||||
Default: true,
|
||||
EnvVar: "",
|
||||
Usage: `Whether trusting the parent certificate is sufficient to trust the child certificate`,
|
||||
})
|
||||
|
||||
f.BoolVar(&BoolVar{
|
||||
Name: "use_names",
|
||||
Target: &c.flagUseNames,
|
||||
Default: false,
|
||||
EnvVar: "",
|
||||
Usage: `Whether the list of issuers returned is referred to by name when it exists rather than uuid`,
|
||||
})
|
||||
|
||||
return set
|
||||
}
|
||||
|
||||
func (c *PKIListChildrenCommand) Run(args []string) int {
|
||||
f := c.Flags()
|
||||
if err := f.Parse(args); err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
args = f.Args()
|
||||
|
||||
if len(args) < 1 {
|
||||
c.UI.Error("Not enough arguments (expected potential parent, got nothing)")
|
||||
return 1
|
||||
} else if len(args) > 2 {
|
||||
for _, arg := range args {
|
||||
if strings.HasPrefix(arg, "-") {
|
||||
c.UI.Warn(fmt.Sprintf("Options (%v) must be specified before positional arguments (%v)", arg, args[0]))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
client, err := c.Client()
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Failed to obtain client: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
issuer := sanitizePath(args[0])
|
||||
var issued []string
|
||||
if len(args) > 1 {
|
||||
for _, arg := range args[1:] {
|
||||
cleanPath := sanitizePath(arg)
|
||||
// Arg Might be a Fully Qualified Path
|
||||
if strings.Contains(cleanPath, "/issuer/") ||
|
||||
strings.Contains(cleanPath, "/certs/") ||
|
||||
strings.Contains(cleanPath, "/revoked/") {
|
||||
issued = append(issued, cleanPath)
|
||||
} else { // Or Arg Might be a Mount
|
||||
mountCaList, err := c.getIssuerListFromMount(client, arg)
|
||||
if err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
issued = append(issued, mountCaList...)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mountListRaw, err := client.Logical().Read("/sys/mounts/")
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Failed to Read List of Mounts With Potential Issuers: %v", err))
|
||||
return 1
|
||||
}
|
||||
for path, rawValueMap := range mountListRaw.Data {
|
||||
valueMap := rawValueMap.(map[string]interface{})
|
||||
if valueMap["type"].(string) == "pki" {
|
||||
mountCaList, err := c.getIssuerListFromMount(client, sanitizePath(path))
|
||||
if err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
issued = append(issued, mountCaList...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
childrenMatches := make(map[string]bool)
|
||||
|
||||
constraintMap := map[string]bool{
|
||||
// This comparison isn't strictly correct, despite a standard ordering these are sets
|
||||
"subject_match": c.flagSubjectMatch,
|
||||
"path_match": c.flagPathMatch,
|
||||
"trust_match": c.flagIndirectSignMatch,
|
||||
"key_id_match": c.flagKeyIdMatch,
|
||||
"signature_match": c.flagSignatureMatch,
|
||||
}
|
||||
|
||||
for _, child := range issued {
|
||||
path := sanitizePath(child)
|
||||
if path != "" {
|
||||
err, verifyResults := verifySignBetween(client, issuer, path)
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Failed to run verification on path %v: %v", path, err))
|
||||
return 1
|
||||
}
|
||||
childrenMatches[path] = checkIfResultsMatchFilters(verifyResults, constraintMap)
|
||||
}
|
||||
}
|
||||
|
||||
err = c.outputResults(childrenMatches)
|
||||
if err != nil {
|
||||
c.UI.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func (c *PKIListChildrenCommand) getIssuerListFromMount(client *api.Client, mountString string) ([]string, error) {
|
||||
var issuerList []string
|
||||
issuerListEndpoint := sanitizePath(mountString) + "/issuers"
|
||||
rawIssuersResp, err := client.Logical().List(issuerListEndpoint)
|
||||
if err != nil {
|
||||
return issuerList, fmt.Errorf("failed to read list of issuers within mount %v: %v", mountString, err)
|
||||
}
|
||||
if rawIssuersResp == nil { // No Issuers (Empty Mount)
|
||||
return issuerList, nil
|
||||
}
|
||||
issuersMap := rawIssuersResp.Data["keys"]
|
||||
certList := issuersMap.([]interface{})
|
||||
for _, certId := range certList {
|
||||
identifier := certId.(string)
|
||||
if c.flagUseNames {
|
||||
issuerReadResp, err := client.Logical().Read(sanitizePath(mountString) + "/issuer/" + identifier)
|
||||
if err != nil {
|
||||
c.UI.Warn(fmt.Sprintf("Unable to Fetch Issuer to Recover Name at: %v", sanitizePath(mountString)+"/issuer/"+identifier))
|
||||
}
|
||||
if issuerReadResp != nil {
|
||||
issuerName := issuerReadResp.Data["issuer_name"].(string)
|
||||
if issuerName != "" {
|
||||
identifier = issuerName
|
||||
}
|
||||
}
|
||||
}
|
||||
issuerList = append(issuerList, sanitizePath(mountString)+"/issuer/"+identifier)
|
||||
}
|
||||
return issuerList, nil
|
||||
}
|
||||
|
||||
func checkIfResultsMatchFilters(verifyResults, constraintMap map[string]bool) bool {
|
||||
for key, required := range constraintMap {
|
||||
if required == true {
|
||||
if verifyResults[key] == false {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *PKIListChildrenCommand) outputResults(results map[string]bool) error {
|
||||
switch Format(c.UI) {
|
||||
case "", "table":
|
||||
return c.outputResultsTable(results)
|
||||
case "json":
|
||||
return c.outputResultsJSON(results)
|
||||
case "yaml":
|
||||
return c.outputResultsYAML(results)
|
||||
default:
|
||||
return fmt.Errorf("unknown output format: %v", Format(c.UI))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *PKIListChildrenCommand) outputResultsTable(results map[string]bool) error {
|
||||
data := []string{"intermediate" + hopeDelim + "match?"}
|
||||
for field, finding := range results {
|
||||
row := field + hopeDelim + strconv.FormatBool(finding)
|
||||
data = append(data, row)
|
||||
}
|
||||
c.UI.Output(tableOutput(data, &columnize.Config{
|
||||
Delim: hopeDelim,
|
||||
}))
|
||||
c.UI.Output("\n")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *PKIListChildrenCommand) outputResultsJSON(results map[string]bool) error {
|
||||
bytes, err := json.MarshalIndent(results, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.UI.Output(string(bytes))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *PKIListChildrenCommand) outputResultsYAML(results map[string]bool) error {
|
||||
bytes, err := yaml.Marshal(results)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.UI.Output(string(bytes))
|
||||
return nil
|
||||
}
|
237
command/pki_list_children_test.go
Normal file
237
command/pki_list_children_test.go
Normal file
@ -0,0 +1,237 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPKIListChildren(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
client, closer := testVaultServer(t)
|
||||
defer closer()
|
||||
|
||||
// Relationship Map to Create
|
||||
// pki-root | pki-newroot | pki-empty
|
||||
// RootX1 RootX2 RootX4 RootX3
|
||||
// | |
|
||||
// ----------------------------------------------
|
||||
// v v
|
||||
// IntX1 IntX2 pki-int
|
||||
// | |
|
||||
// v v
|
||||
// IntX3 (-----------------------) IntX3(also)
|
||||
//
|
||||
// Here X1,X2 have the same name (same mount)
|
||||
// RootX4 uses the same key as RootX1 (but a different common_name/subject)
|
||||
// RootX3 has the same name, and is on a different mount
|
||||
// RootX1 has issued IntX1; RootX3 has issued IntX2
|
||||
createComplicatedIssuerSetUp(t, client)
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
args []string
|
||||
expectedMatches map[string]bool
|
||||
jsonOut bool
|
||||
shouldError bool
|
||||
expectErrorCont string
|
||||
expectErrorNotCont string
|
||||
nonJsonOutputCont string
|
||||
}{
|
||||
{
|
||||
"rootX1-match-everything-no-constraints",
|
||||
[]string{
|
||||
"pki", "list-intermediates", "-format=json", "-use_names=true",
|
||||
"-subject_match=false", "-key_id_match=false", "-direct_sign=false", "-indirect_sign=false", "-path_match=false",
|
||||
"pki-root/issuer/rootX1",
|
||||
},
|
||||
map[string]bool{
|
||||
"pki-root/issuer/rootX1": true,
|
||||
"pki-root/issuer/rootX2": true,
|
||||
"pki-newroot/issuer/rootX3": true,
|
||||
"pki-root/issuer/rootX4": true,
|
||||
"pki-int/issuer/intX1": true,
|
||||
"pki-int/issuer/intX2": true,
|
||||
"pki-int/issuer/intX3": true,
|
||||
"pki-int/issuer/intX3also": true,
|
||||
"pki-int/issuer/rootX1": true,
|
||||
"pki-int/issuer/rootX3": true,
|
||||
},
|
||||
true,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
},
|
||||
{
|
||||
"rootX1-default-children",
|
||||
[]string{"pki", "list-intermediates", "-format=json", "-use_names=true", "pki-root/issuer/rootX1"},
|
||||
map[string]bool{
|
||||
"pki-root/issuer/rootX1": true,
|
||||
"pki-root/issuer/rootX2": false,
|
||||
"pki-newroot/issuer/rootX3": false,
|
||||
"pki-root/issuer/rootX4": false,
|
||||
"pki-int/issuer/intX1": true,
|
||||
"pki-int/issuer/intX2": false,
|
||||
"pki-int/issuer/intX3": false,
|
||||
"pki-int/issuer/intX3also": false,
|
||||
"pki-int/issuer/rootX1": true,
|
||||
"pki-int/issuer/rootX3": false,
|
||||
},
|
||||
true,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
},
|
||||
{
|
||||
"rootX1-subject-match-only",
|
||||
[]string{
|
||||
"pki", "list-intermediates", "-format=json", "-use_names=true",
|
||||
"-key_id_match=false", "-direct_sign=false", "-indirect_sign=false",
|
||||
"pki-root/issuer/rootX1",
|
||||
},
|
||||
map[string]bool{
|
||||
"pki-root/issuer/rootX1": true,
|
||||
"pki-root/issuer/rootX2": true,
|
||||
"pki-newroot/issuer/rootX3": true,
|
||||
"pki-root/issuer/rootX4": false,
|
||||
"pki-int/issuer/intX1": true,
|
||||
"pki-int/issuer/intX2": true,
|
||||
"pki-int/issuer/intX3": false,
|
||||
"pki-int/issuer/intX3also": false,
|
||||
"pki-int/issuer/rootX1": true,
|
||||
"pki-int/issuer/rootX3": true,
|
||||
},
|
||||
true,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
},
|
||||
{
|
||||
"rootX1-in-path",
|
||||
[]string{
|
||||
"pki", "list-intermediates", "-format=json", "-use_names=true",
|
||||
"-subject_match=false", "-key_id_match=false", "-direct_sign=false", "-indirect_sign=false", "-path_match=true",
|
||||
"pki-root/issuer/rootX1",
|
||||
},
|
||||
map[string]bool{
|
||||
"pki-root/issuer/rootX1": true,
|
||||
"pki-root/issuer/rootX2": false,
|
||||
"pki-newroot/issuer/rootX3": false,
|
||||
"pki-root/issuer/rootX4": false,
|
||||
"pki-int/issuer/intX1": true,
|
||||
"pki-int/issuer/intX2": false,
|
||||
"pki-int/issuer/intX3": true,
|
||||
"pki-int/issuer/intX3also": false,
|
||||
"pki-int/issuer/rootX1": true,
|
||||
"pki-int/issuer/rootX3": false,
|
||||
},
|
||||
true,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
},
|
||||
{
|
||||
"rootX1-only-int-mount",
|
||||
[]string{
|
||||
"pki", "list-intermediates", "-format=json", "-use_names=true",
|
||||
"-subject_match=false", "-key_id_match=false", "-direct_sign=false", "-indirect_sign=false", "-path_match=true",
|
||||
"pki-root/issuer/rootX1", "pki-int/",
|
||||
},
|
||||
map[string]bool{
|
||||
"pki-int/issuer/intX1": true,
|
||||
"pki-int/issuer/intX2": false,
|
||||
"pki-int/issuer/intX3": true,
|
||||
"pki-int/issuer/intX3also": false,
|
||||
"pki-int/issuer/rootX1": true,
|
||||
"pki-int/issuer/rootX3": false,
|
||||
},
|
||||
true,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
},
|
||||
{
|
||||
"rootX1-subject-match-root-mounts-only",
|
||||
[]string{
|
||||
"pki", "list-intermediates", "-format=json", "-use_names=true",
|
||||
"-key_id_match=false", "-direct_sign=false", "-indirect_sign=false",
|
||||
"pki-root/issuer/rootX1", "pki-root/", "pki-newroot", "pki-empty",
|
||||
},
|
||||
map[string]bool{
|
||||
"pki-root/issuer/rootX1": true,
|
||||
"pki-root/issuer/rootX2": true,
|
||||
"pki-newroot/issuer/rootX3": true,
|
||||
"pki-root/issuer/rootX4": false,
|
||||
},
|
||||
true,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
},
|
||||
{
|
||||
"rootX1-subject-match-these-certs-only",
|
||||
[]string{
|
||||
"pki", "list-intermediates", "-format=json", "-use_names=true",
|
||||
"-key_id_match=false", "-direct_sign=false", "-indirect_sign=false",
|
||||
"pki-root/issuer/rootX1", "pki-root/issuer/rootX2", "pki-newroot/issuer/rootX3", "pki-root/issuer/rootX4",
|
||||
},
|
||||
map[string]bool{
|
||||
"pki-root/issuer/rootX2": true,
|
||||
"pki-newroot/issuer/rootX3": true,
|
||||
"pki-root/issuer/rootX4": false,
|
||||
},
|
||||
true,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
},
|
||||
}
|
||||
for _, testCase := range cases {
|
||||
var errString string
|
||||
var results map[string]interface{}
|
||||
var stdOut string
|
||||
|
||||
if testCase.jsonOut {
|
||||
results, errString = execPKIVerifyJson(t, client, false, testCase.shouldError, testCase.args)
|
||||
} else {
|
||||
stdOut, errString = execPKIVerifyNonJson(t, client, testCase.shouldError, testCase.args)
|
||||
}
|
||||
|
||||
// Verify Error Behavior
|
||||
if testCase.shouldError {
|
||||
if errString == "" {
|
||||
t.Fatalf("Expected error in Testcase %s : no error produced, got results %s", testCase.name, results)
|
||||
}
|
||||
if testCase.expectErrorCont != "" && !strings.Contains(errString, testCase.expectErrorCont) {
|
||||
t.Fatalf("Expected error in Testcase %s to contain %s, but got error %s", testCase.name, testCase.expectErrorCont, errString)
|
||||
}
|
||||
if testCase.expectErrorNotCont != "" && strings.Contains(errString, testCase.expectErrorNotCont) {
|
||||
t.Fatalf("Expected error in Testcase %s to not contain %s, but got error %s", testCase.name, testCase.expectErrorNotCont, errString)
|
||||
}
|
||||
} else {
|
||||
if errString != "" {
|
||||
t.Fatalf("Error in Testcase %s : no error expected, but got error: %s", testCase.name, errString)
|
||||
}
|
||||
}
|
||||
|
||||
// Verify Output
|
||||
if testCase.jsonOut {
|
||||
isMatch, errString := verifyExpectedJson(testCase.expectedMatches, results)
|
||||
if !isMatch {
|
||||
t.Fatalf("Expected Results for Testcase %s, do not match returned results %s", testCase.name, errString)
|
||||
}
|
||||
} else {
|
||||
if !strings.Contains(stdOut, testCase.nonJsonOutputCont) {
|
||||
t.Fatalf("Expected standard output for Testcase %s to contain %s, but got %s", testCase.name, testCase.nonJsonOutputCont, stdOut)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -115,7 +115,7 @@ func verifySignBetween(client *api.Client, issuerPath string, issuedPath string)
|
||||
return fmt.Errorf("error: unable to fetch issuer %v: %w", issuerPath, err), nil
|
||||
}
|
||||
if len(issuedPath) <= 2 {
|
||||
return fmt.Errorf(fmt.Sprintf("%v", issuedPath)), nil
|
||||
return fmt.Errorf("%v", issuedPath), nil
|
||||
}
|
||||
caChainRaw := issuedCertResp.Data["ca_chain"]
|
||||
if caChainRaw == nil {
|
||||
|
@ -2,6 +2,7 @@ package command
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
@ -159,7 +160,7 @@ func convertListOfInterfaceToString(list []interface{}, sep string) string {
|
||||
|
||||
func createComplicatedIssuerSetUp(t *testing.T, client *api.Client) {
|
||||
// Relationship Map to Create
|
||||
// pki-root | pki-newroot
|
||||
// pki-root | pki-newroot | pki-empty
|
||||
// RootX1 RootX2 RootX4 RootX3
|
||||
// | |
|
||||
// ----------------------------------------------
|
||||
@ -201,6 +202,14 @@ func createComplicatedIssuerSetUp(t *testing.T, client *api.Client) {
|
||||
t.Fatalf("pki mount error: %#v", err)
|
||||
}
|
||||
|
||||
// Used to check handling empty list responses: Not Used for Any Issuers / Certificates
|
||||
if err := client.Sys().Mount("pki-empty", &api.MountInput{
|
||||
Type: "pki",
|
||||
Config: api.MountConfigInput{},
|
||||
}); err != nil {
|
||||
t.Fatalf("pki mount error: %#v", err)
|
||||
}
|
||||
|
||||
resp, err := client.Logical().Write("pki-root/root/generate/internal", map[string]interface{}{
|
||||
"key_type": "ec",
|
||||
"common_name": "Root X",
|
||||
@ -208,7 +217,7 @@ func createComplicatedIssuerSetUp(t *testing.T, client *api.Client) {
|
||||
"issuer_name": "rootX1",
|
||||
"key_name": "rootX1",
|
||||
})
|
||||
t.Logf("%s", resp.Data)
|
||||
|
||||
if err != nil || resp == nil {
|
||||
t.Fatalf("failed to prime CA: %v", err)
|
||||
}
|
||||
@ -219,7 +228,7 @@ func createComplicatedIssuerSetUp(t *testing.T, client *api.Client) {
|
||||
"ttl": "3650d",
|
||||
"issuer_name": "rootX2",
|
||||
})
|
||||
t.Logf("%s", resp.Data)
|
||||
|
||||
if err != nil || resp == nil {
|
||||
t.Fatalf("failed to prime CA: %v", err)
|
||||
}
|
||||
@ -251,6 +260,10 @@ func createComplicatedIssuerSetUp(t *testing.T, client *api.Client) {
|
||||
if err != nil || int1CsrResp == nil {
|
||||
t.Fatalf("failed to generate CSR: %v", err)
|
||||
}
|
||||
int1KeyId, ok := int1CsrResp.Data["key_id"]
|
||||
if !ok {
|
||||
t.Fatalf("no key_id produced when generating csr, response %v", int1CsrResp.Data)
|
||||
}
|
||||
int1CsrRaw, ok := int1CsrResp.Data["csr"]
|
||||
if !ok {
|
||||
t.Fatalf("no csr produced when generating intermediate, resp: %v", int1CsrResp)
|
||||
@ -277,18 +290,24 @@ func createComplicatedIssuerSetUp(t *testing.T, client *api.Client) {
|
||||
if !ok {
|
||||
t.Fatalf("no mapping data returned on issuer import: %v", importInt1Resp)
|
||||
}
|
||||
importIssuerId := ""
|
||||
for key, value := range importIssuerIdMap.(map[string]interface{}) {
|
||||
if value != nil && len(value.(string)) > 0 {
|
||||
importIssuerId = key
|
||||
break
|
||||
if value != int1KeyId {
|
||||
t.Fatalf("Expected exactly one key_match to %v, got multiple: %v", int1KeyId, importIssuerIdMap)
|
||||
}
|
||||
if resp, err := client.Logical().JSONMergePatch(context.Background(), "pki-int/issuer/"+key, map[string]interface{}{
|
||||
"issuer_name": "intX1",
|
||||
}); err != nil || resp == nil {
|
||||
t.Fatalf("error naming issuer %v", err)
|
||||
}
|
||||
} else {
|
||||
if resp, err := client.Logical().JSONMergePatch(context.Background(), "pki-int/issuer/"+key, map[string]interface{}{
|
||||
"issuer_name": "rootX1",
|
||||
}); err != nil || resp == nil {
|
||||
t.Fatalf("error naming issuer parent %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
if resp, err := client.Logical().Write("pki-int/issuer/"+importIssuerId, map[string]interface{}{
|
||||
"issuer_name": "intX1",
|
||||
}); err != nil || resp == nil {
|
||||
t.Fatalf("error naming issuer %v", err)
|
||||
}
|
||||
|
||||
// Intermediate X2
|
||||
int2CsrResp, err := client.Logical().Write("pki-int/intermediate/generate/internal", map[string]interface{}{
|
||||
@ -299,6 +318,10 @@ func createComplicatedIssuerSetUp(t *testing.T, client *api.Client) {
|
||||
if err != nil || int2CsrResp == nil {
|
||||
t.Fatalf("failed to generate CSR: %v", err)
|
||||
}
|
||||
int2KeyId, ok := int2CsrResp.Data["key_id"]
|
||||
if !ok {
|
||||
t.Fatalf("no key material returned from producing csr, resp: %v", int2CsrResp)
|
||||
}
|
||||
int2CsrRaw, ok := int2CsrResp.Data["csr"]
|
||||
if !ok {
|
||||
t.Fatalf("no csr produced when generating intermediate, resp: %v", int2CsrResp)
|
||||
@ -316,8 +339,7 @@ func createComplicatedIssuerSetUp(t *testing.T, client *api.Client) {
|
||||
}
|
||||
int2CertChain := convertListOfInterfaceToString(int2CertChainRaw.([]interface{}), "\n")
|
||||
importInt2Resp, err := client.Logical().Write("pki-int/issuers/import/cert", map[string]interface{}{
|
||||
"pem_bundle": int2CertChain,
|
||||
"issuer_name": "intX2",
|
||||
"pem_bundle": int2CertChain,
|
||||
})
|
||||
if err != nil || importInt2Resp == nil {
|
||||
t.Fatalf("failed to import certificate: %v", err)
|
||||
@ -326,18 +348,24 @@ func createComplicatedIssuerSetUp(t *testing.T, client *api.Client) {
|
||||
if !ok {
|
||||
t.Fatalf("no mapping data returned on issuer import: %v", importInt2Resp)
|
||||
}
|
||||
importIssuer2Id := ""
|
||||
for key, value := range importIssuer2IdMap.(map[string]interface{}) {
|
||||
if value != nil && len(value.(string)) > 0 {
|
||||
importIssuer2Id = key
|
||||
break
|
||||
if value != int2KeyId {
|
||||
t.Fatalf("unexpected key_match with ca_chain, expected only %v, got %v", int2KeyId, importIssuer2IdMap)
|
||||
}
|
||||
if resp, err := client.Logical().JSONMergePatch(context.Background(), "pki-int/issuer/"+key, map[string]interface{}{
|
||||
"issuer_name": "intX2",
|
||||
}); err != nil || resp == nil {
|
||||
t.Fatalf("error naming issuer %v", err)
|
||||
}
|
||||
} else {
|
||||
if resp, err := client.Logical().Write("pki-int/issuer/"+key, map[string]interface{}{
|
||||
"issuer_name": "rootX3",
|
||||
}); err != nil || resp == nil {
|
||||
t.Fatalf("error naming parent issuer %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
if resp, err := client.Logical().Write("pki-int/issuer/"+importIssuer2Id, map[string]interface{}{
|
||||
"issuer_name": "intX2",
|
||||
}); err != nil || resp == nil {
|
||||
t.Fatalf("error naming issuer %v", err)
|
||||
}
|
||||
|
||||
// Intermediate X3
|
||||
int3CsrResp, err := client.Logical().Write("pki-int/intermediate/generate/internal", map[string]interface{}{
|
||||
@ -348,6 +376,7 @@ func createComplicatedIssuerSetUp(t *testing.T, client *api.Client) {
|
||||
if err != nil || int3CsrResp == nil {
|
||||
t.Fatalf("failed to generate CSR: %v", err)
|
||||
}
|
||||
int3KeyId, ok := int3CsrResp.Data["key_id"]
|
||||
int3CsrRaw, ok := int3CsrResp.Data["csr"]
|
||||
if !ok {
|
||||
t.Fatalf("no csr produced when generating intermediate, resp: %v", int3CsrResp)
|
||||
@ -375,18 +404,16 @@ func createComplicatedIssuerSetUp(t *testing.T, client *api.Client) {
|
||||
if !ok {
|
||||
t.Fatalf("no mapping data returned on issuer import: %v", importInt2Resp)
|
||||
}
|
||||
importIssuer3Id1 := ""
|
||||
for key, value := range importIssuer3IdMap1.(map[string]interface{}) {
|
||||
if value != nil && len(value.(string)) > 0 {
|
||||
importIssuer3Id1 = key
|
||||
if value != nil && len(value.(string)) > 0 && value == int3KeyId {
|
||||
if resp, err := client.Logical().JSONMergePatch(context.Background(), "pki-int/issuer/"+key, map[string]interface{}{
|
||||
"issuer_name": "intX3",
|
||||
}); err != nil || resp == nil {
|
||||
t.Fatalf("error naming issuer %v", err)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if resp, err := client.Logical().Write("pki-int/issuer/"+importIssuer3Id1, map[string]interface{}{
|
||||
"issuer_name": "intX3",
|
||||
}); err != nil || resp == nil {
|
||||
t.Fatalf("error naming issuer %v", err)
|
||||
}
|
||||
// sign by intX2 and import
|
||||
int3CertResp2, err := client.Logical().Write("pki-int/issuer/intX2/sign-intermediate", map[string]interface{}{
|
||||
"csr": int3Csr,
|
||||
@ -409,18 +436,16 @@ func createComplicatedIssuerSetUp(t *testing.T, client *api.Client) {
|
||||
if !ok {
|
||||
t.Fatalf("no mapping data returned on issuer import: %v", importInt2Resp)
|
||||
}
|
||||
importIssuer3Id2 := ""
|
||||
for key, value := range importIssuer3IdMap2.(map[string]interface{}) {
|
||||
if value != nil && len(value.(string)) > 0 {
|
||||
importIssuer3Id2 = key
|
||||
break
|
||||
if value != nil && len(value.(string)) > 0 && value == int3KeyId {
|
||||
if resp, err := client.Logical().JSONMergePatch(context.Background(), "pki-int/issuer/"+key, map[string]interface{}{
|
||||
"issuer_name": "intX3also",
|
||||
}); err != nil || resp == nil {
|
||||
t.Fatalf("error naming issuer %v", err)
|
||||
}
|
||||
break // Parent Certs Already Named
|
||||
}
|
||||
}
|
||||
if resp, err := client.Logical().Write("pki-int/issuer/"+importIssuer3Id2, map[string]interface{}{
|
||||
"issuer_name": "intX3also",
|
||||
}); err != nil || resp == nil {
|
||||
t.Fatalf("error naming issuer %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func verifyExpectedJson(expectedResults map[string]bool, results map[string]interface{}) (isMatch bool, error string) {
|
||||
|
Loading…
Reference in New Issue
Block a user