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 }
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) } }
// 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"]) } }
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) } }