diff --git a/command/init.go b/command/init.go index f0fdd7bad7..4ed9e67879 100644 --- a/command/init.go +++ b/command/init.go @@ -329,13 +329,16 @@ Init Options: -pgp-keys If provided, must be a comma-separated list of files on disk containing binary- or base64-format public PGP keys, or Keybase usernames specified as - "keybase:". The number of given entries - must match 'key-shares'. The output unseal keys will + "keybase:". The output unseal keys will be encrypted and base64-encoded, in order, with the given public keys. If you want to use them with the 'vault unseal' command, you will need to base64- decode and decrypt; this will be the plaintext - unseal key. + unseal key. When 'stored-shares' are not used, the + number of entries in this field must match 'key-shares'. + When 'stored-shares' are used, the number of entries + should match the difference between 'key-shares' + and 'stored-shares'. -root-token-pgp-key If provided, a file on disk with a binary- or base64-format public PGP key, or a Keybase username diff --git a/http/sys_init.go b/http/sys_init.go index 134687ab90..c29b040a6a 100644 --- a/http/sys_init.go +++ b/http/sys_init.go @@ -81,6 +81,18 @@ func handleSysInitPut(core *vault.Core, w http.ResponseWriter, r *http.Request) } } + if len(barrierConfig.PGPKeys) > 0 && len(barrierConfig.PGPKeys) != barrierConfig.SecretShares-barrierConfig.StoredShares { + respondError(w, http.StatusBadRequest, fmt.Errorf("incorrect number of PGP keys")) + return + } + + if core.SealAccess().RecoveryKeySupported() { + if len(recoveryConfig.PGPKeys) > 0 && len(recoveryConfig.PGPKeys) != recoveryConfig.SecretShares-recoveryConfig.StoredShares { + respondError(w, http.StatusBadRequest, fmt.Errorf("incorrect number of PGP keys for recovery")) + return + } + } + initParams := &vault.InitParams{ BarrierConfig: barrierConfig, RecoveryConfig: recoveryConfig, diff --git a/http/sys_init_test.go b/http/sys_init_test.go index b3dec904dc..9dfa776393 100644 --- a/http/sys_init_test.go +++ b/http/sys_init_test.go @@ -53,6 +53,39 @@ func TestSysInit_get(t *testing.T) { } } +// Test to check if the API errors out when wrong number of PGP keys are +// supplied +func TestSysInit_pgpKeysEntries(t *testing.T) { + core := vault.TestCore(t) + ln, addr := TestServer(t, core) + defer ln.Close() + + resp := testHttpPut(t, "", addr+"/v1/sys/init", map[string]interface{}{ + "secret_shares": 5, + "secret_threhold": 3, + "pgp_keys": []string{"pgpkey1"}, + }) + testResponseStatus(t, resp, 400) +} + +// Test to check if the API errors out when wrong number of PGP keys are +// supplied for recovery config +func TestSysInit_pgpKeysEntriesForRecovery(t *testing.T) { + core := vault.TestCoreNewSeal(t) + ln, addr := TestServer(t, core) + defer ln.Close() + + resp := testHttpPut(t, "", addr+"/v1/sys/init", map[string]interface{}{ + "secret_shares": 1, + "secret_threshold": 1, + "stored_shares": 1, + "recovery_shares": 5, + "recovery_threshold": 3, + "recovery_pgp_keys": []string{"pgpkey1"}, + }) + testResponseStatus(t, resp, 400) +} + func TestSysInit_put(t *testing.T) { core := vault.TestCore(t) ln, addr := TestServer(t, core) diff --git a/http/sys_rekey.go b/http/sys_rekey.go index 43dcd95ab6..86d0d5dd19 100644 --- a/http/sys_rekey.go +++ b/http/sys_rekey.go @@ -113,6 +113,11 @@ func handleSysRekeyInitPut(core *vault.Core, recovery bool, w http.ResponseWrite return } + if len(req.PGPKeys) > 0 && len(req.PGPKeys) != req.SecretShares-req.StoredShares { + respondError(w, http.StatusBadRequest, fmt.Errorf("incorrect number of PGP keys for rekey")) + return + } + // Initialize the rekey err := core.RekeyInit(&vault.SealConfig{ SecretShares: req.SecretShares, diff --git a/http/sys_rekey_test.go b/http/sys_rekey_test.go index 4811bd2411..52729628e0 100644 --- a/http/sys_rekey_test.go +++ b/http/sys_rekey_test.go @@ -10,6 +10,22 @@ import ( "github.com/hashicorp/vault/vault" ) +// Test to check if the API errors out when wrong number of PGP keys are +// supplied for rekey +func TestSysRekeyInit_pgpKeysEntriesForRekey(t *testing.T) { + core, _, token := vault.TestCoreUnsealed(t) + ln, addr := TestServer(t, core) + defer ln.Close() + TestServerAuth(t, addr, token) + + resp := testHttpPut(t, token, addr+"/v1/sys/rekey/init", map[string]interface{}{ + "secret_shares": 5, + "secret_threshold": 3, + "pgp_keys": []string{"pgpkey1"}, + }) + testResponseStatus(t, resp, 400) +} + func TestSysRekeyInit_Status(t *testing.T) { core, _, token := vault.TestCoreUnsealed(t) ln, addr := TestServer(t, core) diff --git a/vault/testing.go b/vault/testing.go index 3851915079..a0273db593 100644 --- a/vault/testing.go +++ b/vault/testing.go @@ -70,6 +70,12 @@ func TestCore(t *testing.T) *Core { return TestCoreWithSeal(t, nil) } +// TestCoreNewSeal returns an in-memory, ininitialized core with the new seal +// configuration. +func TestCoreNewSeal(t *testing.T) *Core { + return TestCoreWithSeal(t, &TestSeal{}) +} + // TestCoreWithSeal returns a pure in-memory, uninitialized core with the // specified seal for testing. func TestCoreWithSeal(t *testing.T, testSeal Seal) *Core {