blob: 6501b72f5b81b0e7236a32bb4f6413f64860195a [file] [log] [blame]
// Copyright 2016 The Upspin Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
// This file contains the implementation of the keygen command.
import (
"flag"
"fmt"
"io/ioutil"
"path/filepath"
"strings"
"upspin.io/errors"
"upspin.io/key/keygen"
"upspin.io/subcmd"
)
func (s *State) keygen(args ...string) {
const help = `
Keygen creates a new Upspin key pair and stores the pair in local files
secret.upspinkey and public.upspinkey in the specified directory.
Existing key pairs are appended to secret2.upspinkey.
Keygen does not update the information in the key server;
use the "user -put" command for that.
New users should instead use the "signup" command to create their first key.
See the description for rotate for information about updating keys.
`
// Keep flags in sync with signup.go. New flags here should appear
// there as well.
fs := flag.NewFlagSet("keygen", flag.ExitOnError)
var (
curve = fs.String("curve", "p256", "cryptographic curve `name`: p256, p384, or p521")
secretSeed = fs.String("secretseed", "", "the seed containing a 128-bit secret in proquint format or a file that contains it")
rotate = fs.Bool("rotate", false, "back up the existing keys and replace them with new ones")
)
s.ParseFlags(fs, args, help, "keygen [-curve=256] [-secretseed=seed] <directory>")
if fs.NArg() != 1 {
usageAndExit(fs)
}
s.keygenCommand(fs.Arg(0), *curve, *secretSeed, *rotate)
}
func (s *State) keygenCommand(where, curve, secretseed string, rotate bool) {
switch curve {
case "p256", "p384", "p521":
// ok
default:
s.Exitf("no such curve %q", curve)
}
public, private, secretStr, err := s.createKeys(curve, secretseed)
if err != nil {
s.Exitf("creating keys: %v", err)
}
err = keygen.SaveKeys(where, rotate, public, private, secretStr)
if err != nil {
s.Exitf("keys not generated: %s", err)
}
if rotate {
archiveFile := filepath.Join(where, "secret2.upspinkey")
fmt.Fprintf(s.Stderr, "Saved previous key pair to:\n\t%s\n", archiveFile)
}
fmt.Fprintln(s.Stderr, "Upspin private/public key pair written to:")
fmt.Fprintf(s.Stderr, "\t%s\n", filepath.Join(where, "public.upspinkey"))
fmt.Fprintf(s.Stderr, "\t%s\n", filepath.Join(where, "secret.upspinkey"))
fmt.Fprintln(s.Stderr, "This key pair provides access to your Upspin identity and data.")
if secretseed == "" {
fmt.Fprintln(s.Stderr, "If you lose the keys you can re-create them by running this command:")
fmt.Fprintf(s.Stderr, "\tupspin keygen -curve %s -secretseed %s %s\n", curve, secretStr, where)
fmt.Fprintln(s.Stderr, "Write this command down and store it in a secure, private place.")
fmt.Fprintln(s.Stderr, "Do not share your private key or this command with anyone.")
}
if rotate {
fmt.Fprintln(s.Stderr, "\nTo install new keys in the key server, see 'upspin rotate -help'.")
}
fmt.Fprintln(s.Stderr)
}
func (s *State) createKeys(curveName, secretFlag string) (public, private, secretStr string, err error) {
// There are three cases:
// 1) No secretFlag was given. Create a new secret seed.
// 2) A secretFlag looks valid. Accept it.
// 3) The secretFlag must be a file. Try to read it.
if secretFlag == "" {
return keygen.Generate(curveName)
}
if !keygen.ValidSecretSeed(secretFlag) {
data, err := ioutil.ReadFile(subcmd.Tilde(secretFlag))
if err != nil {
return "", "", "", errors.E(errors.Op("keygen"), errors.IO, err)
}
secretFlag = strings.TrimSpace(string(data))
}
return keygen.FromSecret(curveName, secretFlag)
}