diff --git a/cmd/msa-keygen/main.go b/cmd/msa-keygen/main.go index caed954..197f570 100644 --- a/cmd/msa-keygen/main.go +++ b/cmd/msa-keygen/main.go @@ -39,7 +39,7 @@ func main() { flag.Parse() // The signing key is Ed25519 for challenge-response at the relay and for signing responses. - _, signingKey, err := ed25519.GenerateKey(rand.Reader) + signingPublic, signingKey, err := ed25519.GenerateKey(rand.Reader) check(err) // The key-agreement key is raw X25519: clamping is the curve library's job, and a stored key // that had already been clamped would be a second, non-standard encoding to keep in sync across @@ -88,13 +88,25 @@ func main() { check(err) encoded = append(encoded, '\n') + // The relay registration carries the agent's *public* signing key as well as the bearer token. + // Both are required: the token is only an abuse-control handle, and the signature over the relay's + // challenge is what proves the caller holds the node's private key. A registration without the + // key makes the relay refuse to start rather than start and reject every node, which is the + // failure mode that shipped when the key was omitted. + registration, err := json.Marshal(map[string]string{ + "nodeID": id, + "token": token, + "signKey": base64.StdEncoding.EncodeToString(signingPublic), + }) + check(err) + if *write == "" { // The relay's own registration is printed alongside, because the two files have to agree on // the node id and token and copying them by hand is where that agreement breaks. fmt.Fprintf(os.Stderr, "# agent config (paste into %s, then add \"nodePassword\" if the node is protected)\n", "/etc/msa-agent/config.json") os.Stdout.Write(encoded) fmt.Fprintf(os.Stderr, "\n# relay registration: add this entry to MSA_AGENTS\n") - fmt.Fprintf(os.Stderr, "{\"nodeID\":%q,\"token\":%q}\n", id, token) + fmt.Fprintf(os.Stderr, "%s\n", registration) fmt.Fprintf(os.Stderr, "\n# pairing secret (unprotected nodes only; protected ones use nodePassword): %s\n", pairingSecret) fmt.Fprintf(os.Stderr, "# next: run `msa-agent --pair` on the node once, then pair the phone from the app\n") return @@ -107,7 +119,7 @@ func main() { check(err) } fmt.Printf("wrote %s (mode 0600)\n", *write) - fmt.Printf("relay registration: {\"nodeID\":%q,\"token\":%q}\n", id, token) + fmt.Printf("relay registration: %s\n", registration) } func randomHex(bytes int) string {