@ -18,6 +18,7 @@ import (
"time"
"time"
"github.com/peterbourgon/ff/v3/ffcli"
"github.com/peterbourgon/ff/v3/ffcli"
"tailscale.com/clientupdate/distsign"
"tailscale.com/release/dist"
"tailscale.com/release/dist"
"tailscale.com/release/dist/unixpkgs"
"tailscale.com/release/dist/unixpkgs"
)
)
@ -78,6 +79,20 @@ func CLI(getTargets func(unixpkgs.Signers) ([]dist.Target, error)) *ffcli.Comman
Filters can use glob patterns ( * and ? ) .
Filters can use glob patterns ( * and ? ) .
` ) ,
` ) ,
} ,
} ,
{
Name : "gen-key" ,
Exec : func ( ctx context . Context , args [ ] string ) error {
return runGenKey ( ctx )
} ,
ShortUsage : "dist gen-key" ,
ShortHelp : "Generate root or signing key pair" ,
FlagSet : ( func ( ) * flag . FlagSet {
fs := flag . NewFlagSet ( "gen-key" , flag . ExitOnError )
fs . StringVar ( & genKeyArgs . privPath , "priv-path" , "private-key.pem" , "output path for the private key" )
fs . StringVar ( & genKeyArgs . pubPath , "pub-path" , "public-key.pem" , "output path for the public key" )
return fs
} ) ( ) ,
} ,
} ,
} ,
Exec : func ( context . Context , [ ] string ) error { return flag . ErrHelp } ,
Exec : func ( context . Context , [ ] string ) error { return flag . ErrHelp } ,
}
}
@ -173,3 +188,24 @@ func parseSigningKey(path string) (crypto.Signer, error) {
}
}
return x509 . ParseECPrivateKey ( b . Bytes )
return x509 . ParseECPrivateKey ( b . Bytes )
}
}
var genKeyArgs struct {
privPath string
pubPath string
}
func runGenKey ( ctx context . Context ) error {
priv , pub , err := distsign . GenerateKey ( )
if err != nil {
return err
}
if err := os . WriteFile ( genKeyArgs . privPath , priv , 0400 ) ; err != nil {
return fmt . Errorf ( "failed writing private key: %w" , err )
}
fmt . Println ( "wrote private key to" , genKeyArgs . privPath )
if err := os . WriteFile ( genKeyArgs . pubPath , pub , 0400 ) ; err != nil {
return fmt . Errorf ( "failed writing public key: %w" , err )
}
fmt . Println ( "wrote public key to" , genKeyArgs . pubPath )
return nil
}