1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package token
18
19 import (
20 "errors"
21 "fmt"
22 "os"
23 "strings"
24 "time"
25
26 "github.com/sassoftware/relic/cmdline/shared"
27 "github.com/sassoftware/relic/config"
28 "github.com/sassoftware/relic/lib/passprompt"
29 "github.com/sassoftware/relic/signers/sigerrors"
30 "github.com/sassoftware/relic/token"
31 "github.com/sassoftware/relic/token/open"
32 "github.com/spf13/cobra"
33 )
34
35 var (
36 argFile string
37 argKeyName string
38 argToken string
39 argLabel string
40 argRsaBits uint
41 argEcdsaBits uint
42 )
43
44 var tokenMap map[string]token.Token
45
46 func addKeyFlags(cmd *cobra.Command) {
47 cmd.Flags().StringVarP(&argKeyName, "key", "k", "", "Name of key section in config file to use")
48 }
49
50 func addSelectOrGenerateFlags(cmd *cobra.Command) {
51 addKeyFlags(cmd)
52 cmd.Flags().StringVarP(&argToken, "token", "t", "", "Name of token to generate key in")
53 cmd.Flags().StringVarP(&argLabel, "label", "l", "", "Label to attach to generated key")
54 cmd.Flags().UintVar(&argRsaBits, "generate-rsa", 0, "Generate a RSA key of the specified bit size, if needed")
55 cmd.Flags().UintVar(&argEcdsaBits, "generate-ecdsa", 0, "Generate an ECDSA key of the specified curve size, if needed")
56 }
57
58
59 func newKeyConfig() (*config.KeyConfig, error) {
60 if err := shared.InitConfig(); err != nil {
61 return nil, err
62 }
63 var keyConf *config.KeyConfig
64 if argKeyName != "" {
65 var err error
66 keyConf, err = shared.CurrentConfig.GetKey(argKeyName)
67 if err != nil {
68 return nil, err
69 }
70 } else {
71 if argToken == "" || argLabel == "" {
72 return nil, errors.New("Either --key, or --token and --label, must be set")
73 }
74 argKeyName = fmt.Sprintf("new-key-%d", time.Now().UnixNano())
75 keyConf = shared.CurrentConfig.NewKey(argKeyName)
76 }
77 if argToken != "" {
78 tokenConf, err := shared.CurrentConfig.GetToken(argToken)
79 if err != nil {
80 return nil, err
81 }
82 keyConf.SetToken(tokenConf)
83 }
84 if argLabel != "" {
85 keyConf.Label = argLabel
86 keyConf.ID = ""
87 }
88 return keyConf, nil
89 }
90
91 func selectOrGenerate() (key token.Key, err error) {
92 keyConf, err := newKeyConfig()
93 if err != nil {
94 return nil, err
95 }
96 tok, err := openToken(keyConf.Token)
97 if err != nil {
98 return nil, err
99 }
100 key, err = tok.GetKey(argKeyName)
101 if err == nil {
102 fmt.Fprintln(os.Stderr, "Using existing key in token")
103 return key, nil
104 } else if _, ok := err.(sigerrors.KeyNotFoundError); !ok {
105 return nil, err
106 }
107 fmt.Fprintln(os.Stderr, "Generating a new key in token")
108 if argRsaBits != 0 {
109 return tok.Generate(argKeyName, token.KeyTypeRsa, argRsaBits)
110 } else if argEcdsaBits != 0 {
111 return tok.Generate(argKeyName, token.KeyTypeEcdsa, argEcdsaBits)
112 } else {
113 return nil, errors.New("No matching key exists, specify --generate-rsa or --generate-ecdsa to generate one")
114 }
115 }
116
117 func openToken(tokenName string) (token.Token, error) {
118 tok, ok := tokenMap[tokenName]
119 if ok {
120 return tok, nil
121 }
122 err := shared.InitConfig()
123 if err != nil {
124 return nil, err
125 }
126 prompt := new(passprompt.PasswordPrompt)
127 tok, err = open.Token(shared.CurrentConfig, tokenName, prompt)
128 if err != nil {
129 return nil, err
130 }
131 if tokenMap == nil {
132 tokenMap = make(map[string]token.Token)
133 }
134 tokenMap[tokenName] = tok
135 return tok, nil
136 }
137
138 func openTokenByKey(keyName string) (token.Token, error) {
139 if keyName == "" {
140 return nil, errors.New("--key is a required parameter")
141 }
142 err := shared.InitConfig()
143 if err != nil {
144 return nil, err
145 }
146 keyConf, err := shared.CurrentConfig.GetKey(keyName)
147 if err != nil {
148 return nil, err
149 }
150 tok, err := openToken(keyConf.Token)
151 if err != nil {
152 return nil, err
153 }
154 return tok, nil
155 }
156
157 func openKey(keyName string) (token.Key, error) {
158 tok, err := openTokenByKey(keyName)
159 if err != nil {
160 return nil, err
161 }
162 key, err := tok.GetKey(keyName)
163 if err != nil {
164 tok.Close()
165 return nil, err
166 }
167 return key, err
168 }
169
170 func formatKeyID(keyID []byte) string {
171 chunks := make([]string, len(keyID))
172 for i, j := range keyID {
173 chunks[i] = fmt.Sprintf("%02x", j)
174 }
175 return strings.Join(chunks, ":")
176 }
177
View as plain text