예제 #1
0
func (c *GenerateRootCommand) decode(encodedVal, otp string) int {
	tokenBytes, err := xor.XORBase64(encodedVal, otp)
	if err != nil {
		c.Ui.Error(err.Error())
		return 1
	}

	token, err := uuid.FormatUUID(tokenBytes)
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Error formatting base64 token value: %v", err))
		return 1
	}

	c.Ui.Output(fmt.Sprintf("Root token: %s", token))

	return 0
}
예제 #2
0
func testCore_GenerateRoot_Update_OTP_Common(t *testing.T, c *Core, keys [][]byte) {
	otpBytes, err := GenerateRandBytes(16)
	if err != nil {
		t.Fatal(err)
	}

	otp := base64.StdEncoding.EncodeToString(otpBytes)
	// Start a root generation
	err = c.GenerateRootInit(otp, "")
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	// Fetch new config with generated nonce
	rkconf, err := c.GenerateRootConfiguration()
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if rkconf == nil {
		t.Fatalf("bad: no root generation config received")
	}

	// Provide the keys
	var result *GenerateRootResult
	for _, key := range keys {
		result, err = c.GenerateRootUpdate(key, rkconf.Nonce)
		if err != nil {
			t.Fatalf("err: %v", err)
		}
	}
	if result == nil {
		t.Fatalf("Bad, result is nil")
	}

	encodedRootToken := result.EncodedRootToken

	// Should be no progress
	num, err := c.GenerateRootProgress()
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if num != 0 {
		t.Fatalf("bad: %d", num)
	}

	// Should be no config
	conf, err := c.GenerateRootConfiguration()
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if conf != nil {
		t.Fatalf("bad: %v", conf)
	}

	tokenBytes, err := xor.XORBase64(encodedRootToken, otp)
	if err != nil {
		t.Fatal(err)
	}
	token, err := uuid.FormatUUID(tokenBytes)
	if err != nil {
		t.Fatal(err)
	}

	// Ensure that the token is a root token
	te, err := c.tokenStore.Lookup(token)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if te == nil {
		t.Fatalf("token was nil")
	}
	if te.ID != token || te.Parent != "" ||
		len(te.Policies) != 1 || te.Policies[0] != "root" {
		t.Fatalf("bad: %#v", *te)
	}
}
예제 #3
0
// GenerateRootUpdate is used to provide a new key part
func (c *Core) GenerateRootUpdate(key []byte, nonce string) (*GenerateRootResult, error) {
	// Verify the key length
	min, max := c.barrier.KeyLength()
	max += shamir.ShareOverhead
	if len(key) < min {
		return nil, &ErrInvalidKey{fmt.Sprintf("key is shorter than minimum %d bytes", min)}
	}
	if len(key) > max {
		return nil, &ErrInvalidKey{fmt.Sprintf("key is longer than maximum %d bytes", max)}
	}

	// Get the seal configuration
	config, err := c.SealConfig()
	if err != nil {
		return nil, err
	}

	// Ensure the barrier is initialized
	if config == nil {
		return nil, ErrNotInit
	}

	// Ensure we are already unsealed
	c.stateLock.RLock()
	defer c.stateLock.RUnlock()
	if c.sealed {
		return nil, ErrSealed
	}
	if c.standby {
		return nil, ErrStandby
	}

	c.generateRootLock.Lock()
	defer c.generateRootLock.Unlock()

	// Ensure a generateRoot is in progress
	if c.generateRootConfig == nil {
		return nil, fmt.Errorf("no root generation in progress")
	}

	if nonce != c.generateRootConfig.Nonce {
		return nil, fmt.Errorf("incorrect nonce supplied; nonce for this root generation operation is %s", c.generateRootConfig.Nonce)
	}

	// Check if we already have this piece
	for _, existing := range c.generateRootProgress {
		if bytes.Equal(existing, key) {
			return nil, nil
		}
	}

	// Store this key
	c.generateRootProgress = append(c.generateRootProgress, key)
	progress := len(c.generateRootProgress)

	// Check if we don't have enough keys to unlock
	if len(c.generateRootProgress) < config.SecretThreshold {
		c.logger.Printf("[DEBUG] core: cannot generate root, have %d of %d keys",
			progress, config.SecretThreshold)
		return &GenerateRootResult{
			Progress:       progress,
			Required:       config.SecretThreshold,
			PGPFingerprint: c.generateRootConfig.PGPFingerprint,
		}, nil
	}

	// Recover the master key
	var masterKey []byte
	if config.SecretThreshold == 1 {
		masterKey = c.generateRootProgress[0]
		c.generateRootProgress = nil
	} else {
		masterKey, err = shamir.Combine(c.generateRootProgress)
		c.generateRootProgress = nil
		if err != nil {
			return nil, fmt.Errorf("failed to compute master key: %v", err)
		}
	}

	// Verify the master key
	if err := c.barrier.VerifyMaster(masterKey); err != nil {
		c.logger.Printf("[ERR] core: root generation aborted, master key verification failed: %v", err)
		return nil, err
	}

	te, err := c.tokenStore.rootToken()
	if err != nil {
		c.logger.Printf("[ERR] core: root token generation failed: %v", err)
		return nil, err
	}
	if te == nil {
		c.logger.Printf("[ERR] core: got nil token entry back from root generation")
		return nil, fmt.Errorf("got nil token entry back from root generation")
	}

	uuidBytes, err := uuid.ParseUUID(te.ID)
	if err != nil {
		c.tokenStore.Revoke(te.ID)
		c.logger.Printf("[ERR] core: error getting generated token bytes: %v", err)
		return nil, err
	}
	if uuidBytes == nil {
		c.tokenStore.Revoke(te.ID)
		c.logger.Printf("[ERR] core: got nil parsed UUID bytes")
		return nil, fmt.Errorf("got nil parsed UUID bytes")
	}

	var tokenBytes []byte
	// Get the encoded value first so that if there is an error we don't create
	// the root token.
	switch {
	case len(c.generateRootConfig.OTP) > 0:
		// This function performs decoding checks so rather than decode the OTP,
		// just encode the value we're passing in.
		tokenBytes, err = xor.XORBase64(c.generateRootConfig.OTP, base64.StdEncoding.EncodeToString(uuidBytes))
		if err != nil {
			c.tokenStore.Revoke(te.ID)
			c.logger.Printf("[ERR] core: xor of root token failed: %v", err)
			return nil, err
		}

	case len(c.generateRootConfig.PGPKey) > 0:
		_, tokenBytesArr, err := pgpkeys.EncryptShares([][]byte{[]byte(te.ID)}, []string{c.generateRootConfig.PGPKey})
		if err != nil {
			c.tokenStore.Revoke(te.ID)
			c.logger.Printf("[ERR] core: error encrypting new root token: %v", err)
			return nil, err
		}
		tokenBytes = tokenBytesArr[0]

	default:
		c.tokenStore.Revoke(te.ID)
		return nil, fmt.Errorf("unreachable condition")
	}

	results := &GenerateRootResult{
		Progress:         progress,
		Required:         config.SecretThreshold,
		EncodedRootToken: base64.StdEncoding.EncodeToString(tokenBytes),
		PGPFingerprint:   c.generateRootConfig.PGPFingerprint,
	}

	c.logger.Printf("[INFO] core: root generation finished (nonce: %s)",
		c.generateRootConfig.Nonce)

	c.generateRootProgress = nil
	c.generateRootConfig = nil
	return results, nil
}
func TestSysGenerateRoot_Update_OTP(t *testing.T) {
	core, master, token := vault.TestCoreUnsealed(t)
	ln, addr := TestServer(t, core)
	defer ln.Close()
	TestServerAuth(t, addr, token)

	otpBytes, err := vault.GenerateRandBytes(16)
	if err != nil {
		t.Fatal(err)
	}
	otp := base64.StdEncoding.EncodeToString(otpBytes)

	resp := testHttpPut(t, token, addr+"/v1/sys/generate-root/attempt", map[string]interface{}{
		"otp": otp,
	})
	var rootGenerationStatus map[string]interface{}
	testResponseStatus(t, resp, 200)
	testResponseBody(t, resp, &rootGenerationStatus)

	resp = testHttpPut(t, token, addr+"/v1/sys/generate-root/update", map[string]interface{}{
		"nonce": rootGenerationStatus["nonce"].(string),
		"key":   hex.EncodeToString(master),
	})

	var actual map[string]interface{}
	expected := map[string]interface{}{
		"complete":        true,
		"nonce":           rootGenerationStatus["nonce"].(string),
		"progress":        float64(1),
		"required":        float64(1),
		"started":         true,
		"pgp_fingerprint": "",
	}
	testResponseStatus(t, resp, 200)
	testResponseBody(t, resp, &actual)

	if actual["encoded_root_token"] == nil {
		t.Fatalf("no encoded root token found in response")
	}
	expected["encoded_root_token"] = actual["encoded_root_token"]

	if !reflect.DeepEqual(actual, expected) {
		t.Fatalf("\nexpected: %#v\nactual: %#v", expected, actual)
	}

	decodedToken, err := xor.XORBase64(otp, actual["encoded_root_token"].(string))
	if err != nil {
		t.Fatal(err)
	}
	newRootToken, err := uuid.FormatUUID(decodedToken)
	if err != nil {
		t.Fatal(err)
	}

	actual = map[string]interface{}{}
	expected = map[string]interface{}{
		"id":           newRootToken,
		"display_name": "root",
		"meta":         interface{}(nil),
		"num_uses":     float64(0),
		"policies":     []interface{}{"root"},
		"orphan":       true,
		"creation_ttl": float64(0),
		"ttl":          float64(0),
		"path":         "auth/token/root",
		"role":         "",
	}

	resp = testHttpGet(t, newRootToken, addr+"/v1/auth/token/lookup-self")
	testResponseStatus(t, resp, 200)
	testResponseBody(t, resp, &actual)

	expected["creation_time"] = actual["data"].(map[string]interface{})["creation_time"]
	expected["accessor"] = actual["data"].(map[string]interface{})["accessor"]

	if !reflect.DeepEqual(actual["data"], expected) {
		t.Fatalf("\nexpected: %#v\nactual: %#v", expected, actual["data"])
	}
}
예제 #5
0
func TestGenerateRoot_OTP(t *testing.T) {
	core, ts, key, _ := vault.TestCoreWithTokenStore(t)
	ln, addr := http.TestServer(t, core)
	defer ln.Close()

	ui := new(cli.MockUi)
	c := &GenerateRootCommand{
		Key: hex.EncodeToString(key),
		Meta: Meta{
			Ui: ui,
		},
	}

	// Generate an OTP
	otpBytes, err := vault.GenerateRandBytes(16)
	if err != nil {
		t.Fatal(err)
	}
	otp := base64.StdEncoding.EncodeToString(otpBytes)

	// Init the attempt
	args := []string{
		"-address", addr,
		"-init",
		"-otp", otp,
	}
	if code := c.Run(args); code != 0 {
		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
	}

	config, err := core.GenerateRootConfiguration()
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	c.Nonce = config.Nonce

	// Provide the key
	args = []string{
		"-address", addr,
	}
	if code := c.Run(args); code != 0 {
		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
	}

	beforeNAfter := strings.Split(ui.OutputWriter.String(), "Encoded root token: ")
	if len(beforeNAfter) != 2 {
		t.Fatalf("did not find encoded root token in %s", ui.OutputWriter.String())
	}
	encodedToken := strings.TrimSpace(beforeNAfter[1])

	decodedToken, err := xor.XORBase64(encodedToken, otp)
	if err != nil {
		t.Fatal(err)
	}

	token, err := uuid.FormatUUID(decodedToken)
	if err != nil {
		t.Fatal(err)
	}

	req := logical.TestRequest(t, logical.ReadOperation, "lookup-self")
	req.ClientToken = token

	resp, err := ts.HandleRequest(req)
	if err != nil {
		t.Fatalf("error running token lookup-self: %v", err)
	}
	if resp == nil {
		t.Fatalf("got nil resp with token lookup-self")
	}
	if resp.Data == nil {
		t.Fatalf("got nil resp.Data with token lookup-self")
	}

	if resp.Data["orphan"].(bool) != true ||
		resp.Data["ttl"].(int64) != 0 ||
		resp.Data["num_uses"].(int) != 0 ||
		resp.Data["meta"].(map[string]string) != nil ||
		len(resp.Data["policies"].([]string)) != 1 ||
		resp.Data["policies"].([]string)[0] != "root" {
		t.Fatalf("bad: %#v", resp.Data)
	}

	// Clear the output and run a decode to verify we get the same result
	ui.OutputWriter.Reset()
	args = []string{
		"-address", addr,
		"-decode", encodedToken,
		"-otp", otp,
	}
	if code := c.Run(args); code != 0 {
		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
	}
	beforeNAfter = strings.Split(ui.OutputWriter.String(), "Root token: ")
	if len(beforeNAfter) != 2 {
		t.Fatalf("did not find decoded root token in %s", ui.OutputWriter.String())
	}

	outToken := strings.TrimSpace(beforeNAfter[1])
	if outToken != token {
		t.Fatalf("tokens do not match:\n%s\n%s", token, outToken)
	}
}