Address comments from review.

This commit is contained in:
Jeff Mitchell 2015-08-25 15:33:58 -07:00
parent 0b580d0521
commit cc232e6f79
12 changed files with 47 additions and 76 deletions

View File

@ -14,17 +14,8 @@ func (c *Sys) InitStatus() (bool, error) {
} }
func (c *Sys) Init(opts *InitRequest) (*InitResponse, error) { func (c *Sys) Init(opts *InitRequest) (*InitResponse, error) {
body := map[string]interface{}{
"secret_shares": opts.SecretShares,
"secret_threshold": opts.SecretThreshold,
}
if len(opts.SecretPGPKeys) != 0 {
body["secret_pgp_keys"] = opts.SecretPGPKeys
}
r := c.c.NewRequest("PUT", "/v1/sys/init") r := c.c.NewRequest("PUT", "/v1/sys/init")
if err := r.SetJSONBody(body); err != nil { if err := r.SetJSONBody(opts); err != nil {
return nil, err return nil, err
} }
@ -40,9 +31,9 @@ func (c *Sys) Init(opts *InitRequest) (*InitResponse, error) {
} }
type InitRequest struct { type InitRequest struct {
SecretShares int SecretShares int `json:"secret_shares"`
SecretThreshold int SecretThreshold int `json:"secret_threshold"`
SecretPGPKeys []string PGPKeys []string `json:"pgp_keys"`
} }
type InitStatusResponse struct { type InitStatusResponse struct {

View File

@ -57,7 +57,7 @@ func (c *Sys) RekeyUpdate(shard string) (*RekeyUpdateResponse, error) {
type RekeyInitRequest struct { type RekeyInitRequest struct {
SecretShares int `json:"secret_shares"` SecretShares int `json:"secret_shares"`
SecretThreshold int `json:"secret_threshold"` SecretThreshold int `json:"secret_threshold"`
SecretPGPKeys []string `json:"secret_pgp_keys"` PGPKeys []string `json:"pgp_keys"`
} }
type RekeyStatusResponse struct { type RekeyStatusResponse struct {

View File

@ -18,7 +18,7 @@ func (c *InitCommand) Run(args []string) int {
var pgpKeys pgpkeys.PubKeyFilesFlag var pgpKeys pgpkeys.PubKeyFilesFlag
flags := c.Meta.FlagSet("init", FlagSetDefault) flags := c.Meta.FlagSet("init", FlagSetDefault)
flags.Usage = func() { c.Ui.Error(c.Help()) } flags.Usage = func() { c.Ui.Error(c.Help()) }
flags.IntVar(&shares, "key-shares", 0, "") flags.IntVar(&shares, "key-shares", 5, "")
flags.IntVar(&threshold, "key-threshold", 3, "") flags.IntVar(&threshold, "key-threshold", 3, "")
flags.Var(&pgpKeys, "pgp-keys", "") flags.Var(&pgpKeys, "pgp-keys", "")
if err := flags.Parse(args); err != nil { if err := flags.Parse(args); err != nil {
@ -32,18 +32,10 @@ func (c *InitCommand) Run(args []string) int {
return 1 return 1
} }
if shares == 0 {
if pgpKeys == nil {
shares = 5
} else {
shares = len(pgpKeys)
}
}
resp, err := client.Sys().Init(&api.InitRequest{ resp, err := client.Sys().Init(&api.InitRequest{
SecretShares: shares, SecretShares: shares,
SecretThreshold: threshold, SecretThreshold: threshold,
SecretPGPKeys: pgpKeys, PGPKeys: pgpKeys,
}) })
if err != nil { if err != nil {
c.Ui.Error(fmt.Sprintf( c.Ui.Error(fmt.Sprintf(
@ -104,8 +96,7 @@ Init Options:
-pgp-keys If provided, must be a comma-separated list of -pgp-keys If provided, must be a comma-separated list of
files on disk containing binary-format public PGP files on disk containing binary-format public PGP
keys. The number of files must match 'key-shares', keys. The number of files must match 'key-shares'.
or you can omit 'key-shares' if using this option.
The output unseal keys will be hex-encoded and The output unseal keys will be hex-encoded and
encrypted, in order, with the given public keys. encrypted, in order, with the given public keys.
If you want to use them with the 'vault unseal' If you want to use them with the 'vault unseal'

View File

@ -147,6 +147,7 @@ func TestInit_PGP(t *testing.T) {
args = []string{ args = []string{
"-address", addr, "-address", addr,
"-key-shares", "3",
"-pgp-keys", pubFiles[0] + ",@" + pubFiles[1] + "," + pubFiles[2], "-pgp-keys", pubFiles[0] + ",@" + pubFiles[1] + "," + pubFiles[2],
"-key-threshold", "2", "-key-threshold", "2",
} }
@ -177,7 +178,7 @@ func TestInit_PGP(t *testing.T) {
if !reflect.DeepEqual(expected, sealConf) { if !reflect.DeepEqual(expected, sealConf) {
t.Fatalf("bad:\nexpected: %#v\ngot: %#v", expected, sealConf) t.Fatalf("bad:\nexpected: %#v\ngot: %#v", expected, sealConf)
} }
re, err := regexp.Compile("\\s+Initial Root Token:\\s+(.*)") re, err := regexp.Compile("\\s+Initial Root Token:\\s+(.*)")
if err != nil { if err != nil {
t.Fatalf("Error compiling regex: %s", err) t.Fatalf("Error compiling regex: %s", err)

View File

@ -27,7 +27,7 @@ func (c *RekeyCommand) Run(args []string) int {
flags.BoolVar(&init, "init", false, "") flags.BoolVar(&init, "init", false, "")
flags.BoolVar(&cancel, "cancel", false, "") flags.BoolVar(&cancel, "cancel", false, "")
flags.BoolVar(&status, "status", false, "") flags.BoolVar(&status, "status", false, "")
flags.IntVar(&shares, "key-shares", 0, "") flags.IntVar(&shares, "key-shares", 5, "")
flags.IntVar(&threshold, "key-threshold", 3, "") flags.IntVar(&threshold, "key-threshold", 3, "")
flags.Var(&pgpKeys, "pgp-keys", "") flags.Var(&pgpKeys, "pgp-keys", "")
flags.Usage = func() { c.Ui.Error(c.Help()) } flags.Usage = func() { c.Ui.Error(c.Help()) }
@ -42,14 +42,6 @@ func (c *RekeyCommand) Run(args []string) int {
return 2 return 2
} }
if shares == 0 {
if pgpKeys == nil {
shares = 5
} else {
shares = len(pgpKeys)
}
}
// Check if we are running doing any restricted variants // Check if we are running doing any restricted variants
if init { if init {
return c.initRekey(client, shares, threshold, pgpKeys) return c.initRekey(client, shares, threshold, pgpKeys)
@ -71,7 +63,7 @@ func (c *RekeyCommand) Run(args []string) int {
err := client.Sys().RekeyInit(&api.RekeyInitRequest{ err := client.Sys().RekeyInit(&api.RekeyInitRequest{
SecretShares: shares, SecretShares: shares,
SecretThreshold: threshold, SecretThreshold: threshold,
SecretPGPKeys: pgpKeys, PGPKeys: pgpKeys,
}) })
if err != nil { if err != nil {
c.Ui.Error(fmt.Sprintf("Error initializing rekey: %s", err)) c.Ui.Error(fmt.Sprintf("Error initializing rekey: %s", err))
@ -153,7 +145,7 @@ func (c *RekeyCommand) initRekey(client *api.Client, shares, threshold int, pgpK
err := client.Sys().RekeyInit(&api.RekeyInitRequest{ err := client.Sys().RekeyInit(&api.RekeyInitRequest{
SecretShares: shares, SecretShares: shares,
SecretThreshold: threshold, SecretThreshold: threshold,
SecretPGPKeys: pgpKeys, PGPKeys: pgpKeys,
}) })
if err != nil { if err != nil {
c.Ui.Error(fmt.Sprintf("Error initializing rekey: %s", err)) c.Ui.Error(fmt.Sprintf("Error initializing rekey: %s", err))
@ -241,8 +233,7 @@ Unseal Options:
-pgp-keys If provided, must be a comma-separated list of -pgp-keys If provided, must be a comma-separated list of
files on disk containing binary-format public PGP files on disk containing binary-format public PGP
keys. The number of files must match 'key-shares', keys. The number of files must match 'key-shares'.
or you can omit 'key-shares' if using this option.
The output unseal keys will be hex-encoded and The output unseal keys will be hex-encoded and
encrypted, in order, with the given public keys. encrypted, in order, with the given public keys.
If you want to use them with the 'vault unseal' If you want to use them with the 'vault unseal'

View File

@ -176,8 +176,9 @@ func TestRekey_init_pgp(t *testing.T) {
args := []string{ args := []string{
"-address", addr, "-address", addr,
"-init", "-init",
"-key-shares", "3",
"-pgp-keys", pubFiles[0] + ",@" + pubFiles[1] + "," + pubFiles[2], "-pgp-keys", pubFiles[0] + ",@" + pubFiles[1] + "," + pubFiles[2],
"-key-threshold=2", "-key-threshold", "2",
} }
if code := c.Run(args); code != 0 { if code := c.Run(args); code != 0 {

View File

@ -15,30 +15,31 @@ import (
// //
// Note: There is no corresponding test function; this functionality is // Note: There is no corresponding test function; this functionality is
// thoroughly tested in the init and rekey command unit tests // thoroughly tested in the init and rekey command unit tests
func EncryptShares(secretShares *[][]byte, pgpKeys *[]string) error { func EncryptShares(secretShares [][]byte, pgpKeys []string) ([][]byte, error) {
if len(*secretShares) != len(*pgpKeys) { if len(secretShares) != len(pgpKeys) {
return fmt.Errorf("Mismatch between number of generated shares and number of PGP keys") return nil, fmt.Errorf("Mismatch between number of generated shares and number of PGP keys")
} }
for i, keystring := range *pgpKeys { encryptedShares := [][]byte{}
for i, keystring := range pgpKeys {
data, err := base64.StdEncoding.DecodeString(keystring) data, err := base64.StdEncoding.DecodeString(keystring)
if err != nil { if err != nil {
return fmt.Errorf("Error decoding given PGP key: %s", err) return nil, fmt.Errorf("Error decoding given PGP key: %s", err)
} }
entity, err := openpgp.ReadEntity(packet.NewReader(bytes.NewBuffer(data))) entity, err := openpgp.ReadEntity(packet.NewReader(bytes.NewBuffer(data)))
if err != nil { if err != nil {
return fmt.Errorf("Error parsing given PGP key: %s", err) return nil, fmt.Errorf("Error parsing given PGP key: %s", err)
} }
ctBuf := bytes.NewBuffer(nil) ctBuf := bytes.NewBuffer(nil)
pt, err := openpgp.Encrypt(ctBuf, []*openpgp.Entity{entity}, nil, nil, nil) pt, err := openpgp.Encrypt(ctBuf, []*openpgp.Entity{entity}, nil, nil, nil)
if err != nil { if err != nil {
return fmt.Errorf("Error setting up encryption for PGP message: %s", err) return nil, fmt.Errorf("Error setting up encryption for PGP message: %s", err)
} }
_, err = pt.Write((*secretShares)[i]) _, err = pt.Write(secretShares[i])
if err != nil { if err != nil {
return fmt.Errorf("Error encrypting PGP message: %s", err) return nil, fmt.Errorf("Error encrypting PGP message: %s", err)
} }
pt.Close() pt.Close()
(*secretShares)[i] = ctBuf.Bytes() encryptedShares = append(encryptedShares, ctBuf.Bytes())
} }
return nil return encryptedShares, nil
} }

View File

@ -2,7 +2,6 @@ package http
import ( import (
"encoding/hex" "encoding/hex"
"fmt"
"net/http" "net/http"
"github.com/hashicorp/vault/vault" "github.com/hashicorp/vault/vault"
@ -41,19 +40,11 @@ func handleSysInitPut(core *vault.Core, w http.ResponseWriter, r *http.Request)
return return
} }
switch {
case req.SecretShares > 0 && len(req.SecretPGPKeys) > 0 && len(req.SecretPGPKeys) != req.SecretShares:
respondError(w, http.StatusBadRequest, fmt.Errorf("Mismatch between key-shares and length of pgp-keys (you can specify pgp-keys alone)"))
return
case req.SecretShares == 0 && len(req.SecretPGPKeys) > 0:
req.SecretShares = len(req.SecretPGPKeys)
}
// Initialize // Initialize
result, err := core.Initialize(&vault.SealConfig{ result, err := core.Initialize(&vault.SealConfig{
SecretShares: req.SecretShares, SecretShares: req.SecretShares,
SecretThreshold: req.SecretThreshold, SecretThreshold: req.SecretThreshold,
SecretPGPKeys: req.SecretPGPKeys, PGPKeys: req.PGPKeys,
}) })
if err != nil { if err != nil {
respondError(w, http.StatusBadRequest, err) respondError(w, http.StatusBadRequest, err)
@ -75,7 +66,7 @@ func handleSysInitPut(core *vault.Core, w http.ResponseWriter, r *http.Request)
type InitRequest struct { type InitRequest struct {
SecretShares int `json:"secret_shares"` SecretShares int `json:"secret_shares"`
SecretThreshold int `json:"secret_threshold"` SecretThreshold int `json:"secret_threshold"`
SecretPGPKeys []string `json:"secret_pgp_keys"` PGPKeys []string `json:"pgp_keys"`
} }
type InitResponse struct { type InitResponse struct {

View File

@ -79,7 +79,7 @@ func handleSysRekeyInitPut(core *vault.Core, w http.ResponseWriter, r *http.Requ
err := core.RekeyInit(&vault.SealConfig{ err := core.RekeyInit(&vault.SealConfig{
SecretShares: req.SecretShares, SecretShares: req.SecretShares,
SecretThreshold: req.SecretThreshold, SecretThreshold: req.SecretThreshold,
SecretPGPKeys: req.SecretPGPKeys, PGPKeys: req.PGPKeys,
}) })
if err != nil { if err != nil {
respondError(w, http.StatusBadRequest, err) respondError(w, http.StatusBadRequest, err)
@ -152,7 +152,7 @@ func handleSysRekeyUpdate(core *vault.Core) http.Handler {
type RekeyRequest struct { type RekeyRequest struct {
SecretShares int `json:"secret_shares"` SecretShares int `json:"secret_shares"`
SecretThreshold int `json:"secret_threshold"` SecretThreshold int `json:"secret_threshold"`
SecretPGPKeys []string `json:"secret_pgp_keys"` PGPKeys []string `json:"pgp_keys"`
} }
type RekeyStatusResponse struct { type RekeyStatusResponse struct {

View File

@ -86,11 +86,11 @@ type SealConfig struct {
// split into. This is the N value of Shamir. // split into. This is the N value of Shamir.
SecretShares int `json:"secret_shares"` SecretShares int `json:"secret_shares"`
// SecretPGPKeys is the array of public PGP keys used, // PGPKeys is the array of public PGP keys used,
// if requested, to encrypt the output unseal tokens. If // if requested, to encrypt the output unseal tokens. If
// provided, it sets the value of SecretShares. Ordering // provided, it sets the value of SecretShares. Ordering
// is important. // is important.
SecretPGPKeys []string `json:"-"` PGPKeys []string `json:"-"`
// SecretThreshold is the number of parts required // SecretThreshold is the number of parts required
// to open the vault. This is the T value of Shamir // to open the vault. This is the T value of Shamir
@ -117,11 +117,11 @@ func (s *SealConfig) Validate() error {
if s.SecretThreshold > s.SecretShares { if s.SecretThreshold > s.SecretShares {
return fmt.Errorf("secret threshold cannot be larger than secret shares") return fmt.Errorf("secret threshold cannot be larger than secret shares")
} }
if len(s.SecretPGPKeys) > 0 && len(s.SecretPGPKeys) != s.SecretShares { if len(s.PGPKeys) > 0 && len(s.PGPKeys) != s.SecretShares {
return fmt.Errorf("count mismatch between number of provided PGP keys and number of shares") return fmt.Errorf("count mismatch between number of provided PGP keys and number of shares")
} }
if len(s.SecretPGPKeys) > 0 { if len(s.PGPKeys) > 0 {
for _, keystring := range s.SecretPGPKeys { for _, keystring := range s.PGPKeys {
data, err := base64.StdEncoding.DecodeString(keystring) data, err := base64.StdEncoding.DecodeString(keystring)
if err != nil { if err != nil {
return fmt.Errorf("Error decoding given PGP key: %s", err) return fmt.Errorf("Error decoding given PGP key: %s", err)
@ -739,10 +739,12 @@ func (c *Core) Initialize(config *SealConfig) (*InitResult, error) {
results.SecretShares = shares results.SecretShares = shares
} }
if len(config.SecretPGPKeys) > 0 { if len(config.PGPKeys) > 0 {
if err := pgpkeys.EncryptShares(&results.SecretShares, &config.SecretPGPKeys); err != nil { encryptedShares, err := pgpkeys.EncryptShares(results.SecretShares, config.PGPKeys)
if err != nil {
return nil, err return nil, err
} }
results.SecretShares = encryptedShares
} }
// Initialize the barrier // Initialize the barrier
@ -1217,10 +1219,12 @@ func (c *Core) RekeyUpdate(key []byte) (*RekeyResult, error) {
results.SecretShares = shares results.SecretShares = shares
} }
if len(c.rekeyConfig.SecretPGPKeys) > 0 { if len(c.rekeyConfig.PGPKeys) > 0 {
if err := pgpkeys.EncryptShares(&results.SecretShares, &c.rekeyConfig.SecretPGPKeys); err != nil { encryptedShares, err := pgpkeys.EncryptShares(results.SecretShares, c.rekeyConfig.PGPKeys)
if err != nil {
return nil, err return nil, err
} }
results.SecretShares = encryptedShares
} }
// Encode the seal configuration // Encode the seal configuration

View File

@ -61,7 +61,7 @@ description: |-
This must be less than or equal to <code>secret_shares</code>. This must be less than or equal to <code>secret_shares</code>.
</li> </li>
<li> <li>
<spam class="param">secret_pgp_keys</span> <spam class="param">pgp_keys</span>
<span class="param-flags">optional</spam> <span class="param-flags">optional</spam>
An array of PGP public keys used to encrypt the output unseal keys. An array of PGP public keys used to encrypt the output unseal keys.
Ordering is preserved. The keys must be base64-encoded from their Ordering is preserved. The keys must be base64-encoded from their

View File

@ -78,7 +78,7 @@ description: |-
This must be less than or equal to <code>secret_shares</code>. This must be less than or equal to <code>secret_shares</code>.
</li> </li>
<li> <li>
<spam class="param">secret_pgp_keys</span> <spam class="param">pgp_keys</span>
<span class="param-flags">optional</spam> <span class="param-flags">optional</spam>
An array of PGP public keys used to encrypt the output unseal keys. An array of PGP public keys used to encrypt the output unseal keys.
Ordering is preserved. The keys must be base64-encoded from their Ordering is preserved. The keys must be base64-encoded from their