blob: e1eaadfaef293314c569edf555f114a9f916ba5b [file] [log] [blame]
Jiri Simsad7616c92015-03-24 23:44:30 -07001// Copyright 2015 The Vanadium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Suharsh Sivakumar1d61f642015-02-17 20:56:14 -08005// The following enables go generate to generate the doc.go file.
Jiri Simsa32f76fb2015-04-07 15:39:23 -07006//go:generate go run $V23_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go .
Suharsh Sivakumar1d61f642015-02-17 20:56:14 -08007
Ankurcf6a89f2014-10-06 18:33:03 -07008package main
9
10import (
11 "bytes"
Asim Shankarf11b1bc2014-11-12 17:18:45 -080012 "crypto/rand"
13 "crypto/subtle"
Asim Shankarb3a82ba2014-10-29 11:41:27 -070014 "encoding/base64"
Suharsh Sivakumarab21eb02015-04-01 12:58:20 -070015 "encoding/json"
Ankurcf6a89f2014-10-06 18:33:03 -070016 "fmt"
17 "io"
Suharsh Sivakumarab21eb02015-04-01 12:58:20 -070018 "io/ioutil"
Ankurcf6a89f2014-10-06 18:33:03 -070019 "os"
20 "os/user"
Suharsh Sivakumar2b22fc12015-04-15 19:38:04 -070021 "strings"
Ankurcf6a89f2014-10-06 18:33:03 -070022 "time"
23
Jiri Simsa6ac95222015-02-23 16:11:49 -080024 "v.io/v23"
25 "v.io/v23/context"
Asim Shankar263c73b2015-03-19 18:31:26 -070026 "v.io/v23/options"
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070027 "v.io/v23/rpc"
Jiri Simsa6ac95222015-02-23 16:11:49 -080028 "v.io/v23/security"
29 "v.io/v23/vom"
Todd Wang9560b9c2015-05-11 13:27:58 -070030 "v.io/x/lib/cmdline"
Todd Wang8123b5e2015-05-14 18:44:43 -070031 "v.io/x/ref"
Todd Wangb3511492015-04-07 23:32:34 -070032 vsecurity "v.io/x/ref/lib/security"
Todd Wangf1550cf2015-05-11 10:58:41 -070033 "v.io/x/ref/lib/v23cmd"
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -070034 "v.io/x/ref/lib/xrpc"
Suharsh Sivakumardcc11d72015-05-11 12:19:20 -070035 _ "v.io/x/ref/runtime/factories/static"
Ankurcf6a89f2014-10-06 18:33:03 -070036)
37
38var (
39 // Flags for the "blessself" command
Suharsh Sivakumar1d61f642015-02-17 20:56:14 -080040 flagBlessSelfCaveats caveatsFlag
41 flagBlessSelfFor time.Duration
Ankurcf6a89f2014-10-06 18:33:03 -070042
Asim Shankar66c52f92014-10-15 23:39:10 -070043 // Flags for the "bless" command
Asim Shankara0bba462015-02-20 22:50:51 -080044 flagBlessCaveats caveatsFlag
45 flagBlessFor time.Duration
46 flagBlessRequireCaveats bool
47 flagBlessWith string
48 flagBlessRemoteKey string
49 flagBlessRemoteToken string
Asim Shankar66c52f92014-10-15 23:39:10 -070050
Robin Thellend5396eae2015-04-13 09:57:06 -070051 // Flags for the "dump" command
52 flagDumpShort bool
53
Ankur77c32ac2014-12-18 14:18:19 -080054 // Flags for the "fork" command
Asim Shankara0bba462015-02-20 22:50:51 -080055 flagForkCaveats caveatsFlag
56 flagForkFor time.Duration
57 flagForkRequireCaveats bool
58 flagForkWith string
Ankur77c32ac2014-12-18 14:18:19 -080059
Asim Shankar66c52f92014-10-15 23:39:10 -070060 // Flags for the "seekblessings" command
61 flagSeekBlessingsFrom string
62 flagSeekBlessingsSetDefault bool
63 flagSeekBlessingsForPeer string
Suharsh Sivakumara76dba62014-12-22 16:00:34 -080064 flagSeekBlessingsBrowser bool
Asim Shankar66c52f92014-10-15 23:39:10 -070065
66 // Flags common to many commands
Ankurc24ff422014-12-16 17:59:26 -080067 flagAddToRoots bool
68 flagCreateOverwrite bool
Suharsh Sivakumarab21eb02015-04-01 12:58:20 -070069 flagRemoteArgFile string
Ankur1d46f552014-10-09 12:13:31 -070070
Ankure548f392014-12-08 18:42:41 -080071 // Flags for the "recvblessings" command
72 flagRecvBlessingsSetDefault bool
73 flagRecvBlessingsForPeer string
74
Suharsh Sivakumar2b22fc12015-04-15 19:38:04 -070075 // Flags for the commands that get blessings
76 flagBlessingsNames bool
77 flagBlessingsRootKey string
78 flagBlessingsCaveats string
Suharsh Sivakumar4bbe8ed2015-04-09 14:21:44 -070079
Asim Shankarde6fda52015-04-22 21:20:24 -070080 // Flags for the get publickey command.
81 flagGetPublicKeyPretty bool
82
Suharsh Sivakumared5be1d2015-04-01 17:45:35 -070083 errNoCaveats = fmt.Errorf("no caveats provided: it is generally dangerous to bless another principal without any caveats as that gives them almost unrestricted access to the blesser's credentials. If you really want to do this, set --require-caveats=false")
Suharsh Sivakumar2b22fc12015-04-15 19:38:04 -070084
Todd Wang9560b9c2015-05-11 13:27:58 -070085 cmdDump = &cmdline.Command{
Ankur1615a7d2014-10-09 11:58:02 -070086 Name: "dump",
87 Short: "Dump out information about the principal",
88 Long: `
Asim Shankar66c52f92014-10-15 23:39:10 -070089Prints out information about the principal specified by the environment
Asim Shankar1789b8a2014-10-31 17:31:41 -070090that this tool is running in.
Ankur1615a7d2014-10-09 11:58:02 -070091`,
Todd Wang9560b9c2015-05-11 13:27:58 -070092 Runner: v23cmd.RunnerFunc(func(ctx *context.T, env *cmdline.Env, args []string) error {
Jiri Simsa6ac95222015-02-23 16:11:49 -080093 p := v23.GetPrincipal(ctx)
Robin Thellend5396eae2015-04-13 09:57:06 -070094 if flagDumpShort {
Bogdan Caprita4ab95412015-05-13 13:37:46 -070095 fmt.Printf("%s\n", printAnnotatedBlessingsNames(p.BlessingStore().Default()))
Robin Thellend5396eae2015-04-13 09:57:06 -070096 return nil
97 }
Ankur1615a7d2014-10-09 11:58:02 -070098 fmt.Printf("Public key : %v\n", p.PublicKey())
Bogdan Caprita4ab95412015-05-13 13:37:46 -070099 // NOTE(caprita): We print the default blessings name
100 // twice (it's also printed as part of the blessing
101 // store below) -- the reason we print it here is to
102 // expose whether the blessings are expired. Ideally,
103 // the blessings store would print the expiry
104 // information about each blessing in the store, but
105 // that would require deeper changes beyond the
106 // principal tool.
107 fmt.Printf("Default Blessings : %s\n", printAnnotatedBlessingsNames(p.BlessingStore().Default()))
Ankur1615a7d2014-10-09 11:58:02 -0700108 fmt.Println("---------------- BlessingStore ----------------")
109 fmt.Printf("%v", p.BlessingStore().DebugString())
Ankur1615a7d2014-10-09 11:58:02 -0700110 fmt.Println("---------------- BlessingRoots ----------------")
111 fmt.Printf("%v", p.Roots().DebugString())
112 return nil
Todd Wangf1550cf2015-05-11 10:58:41 -0700113 }),
Ankur1615a7d2014-10-09 11:58:02 -0700114 }
115
Todd Wang9560b9c2015-05-11 13:27:58 -0700116 cmdDumpBlessings = &cmdline.Command{
Asim Shankar66c52f92014-10-15 23:39:10 -0700117 Name: "dumpblessings",
118 Short: "Dump out information about the provided blessings",
Ankurcf6a89f2014-10-06 18:33:03 -0700119 Long: `
Asim Shankar66c52f92014-10-15 23:39:10 -0700120Prints out information about the blessings (typically obtained from this tool)
Ankurcf6a89f2014-10-06 18:33:03 -0700121encoded in the provided file.
122`,
123 ArgsName: "<file>",
124 ArgsLong: `
Asim Shankar66c52f92014-10-15 23:39:10 -0700125<file> is the path to a file containing blessings typically obtained from
Ankurcf6a89f2014-10-06 18:33:03 -0700126this tool. - is used for STDIN.
127`,
Todd Wang9560b9c2015-05-11 13:27:58 -0700128 Runner: cmdline.RunnerFunc(func(env *cmdline.Env, args []string) error {
Ankurcf6a89f2014-10-06 18:33:03 -0700129 if len(args) != 1 {
130 return fmt.Errorf("requires exactly one argument, <file>, provided %d", len(args))
131 }
132 blessings, err := decodeBlessings(args[0])
133 if err != nil {
134 return fmt.Errorf("failed to decode provided blessings: %v", err)
135 }
Asim Shankarb07ec692015-02-27 23:40:44 -0800136 wire, err := blessings2wire(blessings)
137 if err != nil {
138 return fmt.Errorf("failed to decode certificate chains: %v", err)
139 }
Bogdan Caprita4ab95412015-05-13 13:37:46 -0700140 fmt.Printf("Blessings : %s\n", printAnnotatedBlessingsNames(blessings))
Asim Shankar66c52f92014-10-15 23:39:10 -0700141 fmt.Printf("PublicKey : %v\n", blessings.PublicKey())
Asim Shankardf88a2e2014-10-21 17:20:28 -0700142 fmt.Printf("Certificate chains : %d\n", len(wire.CertificateChains))
Asim Shankar66c52f92014-10-15 23:39:10 -0700143 for idx, chain := range wire.CertificateChains {
Asim Shankardf88a2e2014-10-21 17:20:28 -0700144 fmt.Printf("Chain #%d (%d certificates). Root certificate public key: %v\n", idx, len(chain), rootkey(chain))
145 for certidx, cert := range chain {
146 fmt.Printf(" Certificate #%d: %v with ", certidx, cert.Extension)
147 switch n := len(cert.Caveats); n {
148 case 1:
149 fmt.Printf("1 caveat")
150 default:
151 fmt.Printf("%d caveats", n)
152 }
153 fmt.Println("")
154 for cavidx, cav := range cert.Caveats {
155 fmt.Printf(" (%d) %v\n", cavidx, &cav)
156 }
Asim Shankar66c52f92014-10-15 23:39:10 -0700157 }
Asim Shankar66c52f92014-10-15 23:39:10 -0700158 }
Ankurcf6a89f2014-10-06 18:33:03 -0700159 return nil
Todd Wangf1550cf2015-05-11 10:58:41 -0700160 }),
Ankurcf6a89f2014-10-06 18:33:03 -0700161 }
162
Todd Wang9560b9c2015-05-11 13:27:58 -0700163 cmdBlessSelf = &cmdline.Command{
Ankurcf6a89f2014-10-06 18:33:03 -0700164 Name: "blessself",
165 Short: "Generate a self-signed blessing",
166 Long: `
Asim Shankar1789b8a2014-10-31 17:31:41 -0700167Returns a blessing with name <name> and self-signed by the principal specified
168by the environment that this tool is running in. Optionally, the blessing can
Suharsh Sivakumar1d61f642015-02-17 20:56:14 -0800169be restricted with an expiry caveat specified using the --for flag. Additional
170caveats can be added with the --caveat flag.
Ankurcf6a89f2014-10-06 18:33:03 -0700171`,
172 ArgsName: "[<name>]",
173 ArgsLong: `
174<name> is the name used to create the self-signed blessing. If not
175specified, a name will be generated based on the hostname of the
176machine and the name of the user running this command.
177`,
Todd Wang9560b9c2015-05-11 13:27:58 -0700178 Runner: v23cmd.RunnerFunc(func(ctx *context.T, env *cmdline.Env, args []string) error {
Ankurcf6a89f2014-10-06 18:33:03 -0700179 var name string
180 switch len(args) {
181 case 0:
182 name = defaultBlessingName()
183 case 1:
184 name = args[0]
185 default:
186 return fmt.Errorf("requires at most one argument, provided %d", len(args))
187 }
Asim Shankara0bba462015-02-20 22:50:51 -0800188 caveats, err := caveatsFromFlags(flagBlessSelfFor, &flagBlessSelfCaveats)
Suharsh Sivakumar1d61f642015-02-17 20:56:14 -0800189 if err != nil {
Asim Shankara0bba462015-02-20 22:50:51 -0800190 return err
Suharsh Sivakumar1d61f642015-02-17 20:56:14 -0800191 }
Jiri Simsa6ac95222015-02-23 16:11:49 -0800192 principal := v23.GetPrincipal(ctx)
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800193 blessing, err := principal.BlessSelf(name, caveats...)
Ankurcf6a89f2014-10-06 18:33:03 -0700194 if err != nil {
195 return fmt.Errorf("failed to create self-signed blessing for name %q: %v", name, err)
196 }
197
198 return dumpBlessings(blessing)
Todd Wangf1550cf2015-05-11 10:58:41 -0700199 }),
Ankurcf6a89f2014-10-06 18:33:03 -0700200 }
201
Todd Wang9560b9c2015-05-11 13:27:58 -0700202 cmdBless = &cmdline.Command{
Asim Shankar66c52f92014-10-15 23:39:10 -0700203 Name: "bless",
204 Short: "Bless another principal",
205 Long: `
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800206Bless another principal.
Asim Shankar66c52f92014-10-15 23:39:10 -0700207
Ankurc24ff422014-12-16 17:59:26 -0800208The blesser is obtained from the runtime this tool is using. The blessing that
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800209will be extended is the default one from the blesser's store, or specified by
Suharsh Sivakumar1d61f642015-02-17 20:56:14 -0800210the --with flag. Expiration on the blessing are controlled via the --for flag.
211Additional caveats are controlled with the --caveat flag.
Asim Shankar66c52f92014-10-15 23:39:10 -0700212
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800213For example, let's say a principal "alice" wants to bless another principal "bob"
214as "alice/friend", the invocation would be:
Asim Shankar59b8b692015-03-30 01:23:36 -0700215 V23_CREDENTIALS=<path to alice> principal bless <path to bob> friend
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800216and this will dump the blessing to STDOUT.
217
Suharsh Sivakumared5be1d2015-04-01 17:45:35 -0700218With the --remote-key and --remote-token flags, this command can be used to
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800219bless a principal on a remote machine as well. In this case, the blessing is
220not dumped to STDOUT but sent to the remote end. Use 'principal help
221recvblessings' for more details on that.
Suharsh Sivakumarab21eb02015-04-01 12:58:20 -0700222
Suharsh Sivakumared5be1d2015-04-01 17:45:35 -0700223When --remote-arg-file is specified, only the blessing extension is required, as all other
Suharsh Sivakumarab21eb02015-04-01 12:58:20 -0700224arguments will be extracted from the specified file.
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800225`,
Asim Shankar2a32dd22015-05-29 15:45:22 -0700226 ArgsName: "[<principal to bless>] [<extension>]",
Asim Shankar66c52f92014-10-15 23:39:10 -0700227 ArgsLong: `
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800228<principal to bless> represents the principal to be blessed (i.e., whose public
229key will be provided with a name). This can be either:
230(a) The directory containing credentials for that principal,
231OR
232(b) The filename (- for STDIN) containing any other blessings of that
233 principal,
234OR
235(c) The object name produced by the 'recvblessings' command of this tool
Suharsh Sivakumared5be1d2015-04-01 17:45:35 -0700236 running on behalf of another principal (if the --remote-key and
237 --remote-token flags are specified).
Suharsh Sivakumarab21eb02015-04-01 12:58:20 -0700238OR
Suharsh Sivakumared5be1d2015-04-01 17:45:35 -0700239(d) None (if the --remote-arg-file flag is specified, only <extension> should be provided
Suharsh Sivakumarab21eb02015-04-01 12:58:20 -0700240 to bless).
Asim Shankar66c52f92014-10-15 23:39:10 -0700241
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800242<extension> is the string extension that will be applied to create the
243blessing.
Suharsh Sivakumarab21eb02015-04-01 12:58:20 -0700244
Asim Shankar66c52f92014-10-15 23:39:10 -0700245 `,
Todd Wang9560b9c2015-05-11 13:27:58 -0700246 Runner: v23cmd.RunnerFunc(func(ctx *context.T, env *cmdline.Env, args []string) error {
Asim Shankar2a32dd22015-05-29 15:45:22 -0700247 if len(flagRemoteArgFile) > 0 {
248 if len(args) > 1 {
249 return fmt.Errorf("when --remote-arg-file is provided, only <extension> is expected, provided %d", len(args))
250 }
251 if (len(flagBlessRemoteKey) + len(flagBlessRemoteToken)) > 0 {
252 return fmt.Errorf("--remote-key and --remote-token should not be specified when --remote-arg-file is")
253 }
254 } else if len(args) > 2 {
255 return fmt.Errorf("got %d arguments, require at most 2", len(args))
256 } else if (len(flagBlessRemoteKey) == 0) != (len(flagBlessRemoteToken) == 0) {
257 return fmt.Errorf("either both --remote-key and --remote-token should be set, or neither should")
Asim Shankar66c52f92014-10-15 23:39:10 -0700258 }
Jiri Simsa6ac95222015-02-23 16:11:49 -0800259 p := v23.GetPrincipal(ctx)
Asim Shankar66c52f92014-10-15 23:39:10 -0700260
Suharsh Sivakumar1d61f642015-02-17 20:56:14 -0800261 var (
262 err error
263 with security.Blessings
264 )
Asim Shankar66c52f92014-10-15 23:39:10 -0700265 if len(flagBlessWith) > 0 {
266 if with, err = decodeBlessings(flagBlessWith); err != nil {
267 return fmt.Errorf("failed to read blessings from --with=%q: %v", flagBlessWith, err)
268 }
269 } else {
270 with = p.BlessingStore().Default()
271 }
Asim Shankara0bba462015-02-20 22:50:51 -0800272 caveats, err := caveatsFromFlags(flagBlessFor, &flagBlessCaveats)
Suharsh Sivakumar1d61f642015-02-17 20:56:14 -0800273 if err != nil {
Asim Shankara0bba462015-02-20 22:50:51 -0800274 return err
Suharsh Sivakumar1d61f642015-02-17 20:56:14 -0800275 }
Asim Shankar2a32dd22015-05-29 15:45:22 -0700276 if len(caveats) == 0 {
277 if flagBlessRequireCaveats {
278 if err := confirmNoCaveats(env); err != nil {
279 return err
280 }
281 }
Asim Shankara0bba462015-02-20 22:50:51 -0800282 caveats = []security.Caveat{security.UnconstrainedUse()}
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800283 }
Bogdan Caprita553e5822015-02-20 14:50:41 -0800284 if len(caveats) == 0 {
Asim Shankara0bba462015-02-20 22:50:51 -0800285 return errNoCaveats
Bogdan Caprita553e5822015-02-20 14:50:41 -0800286 }
Suharsh Sivakumarab21eb02015-04-01 12:58:20 -0700287
Asim Shankar2a32dd22015-05-29 15:45:22 -0700288 tobless, extension, remoteKey, remoteToken, err := blessArgs(env, args)
Asim Shankar66c52f92014-10-15 23:39:10 -0700289 if err != nil {
Suharsh Sivakumarab21eb02015-04-01 12:58:20 -0700290 return err
291 }
292
293 // Send blessings to a "server" started by a "recvblessings" command, either
Suharsh Sivakumared5be1d2015-04-01 17:45:35 -0700294 // with the --remote-arg-file flag, or with --remote-key and --remote-token flags.
Suharsh Sivakumarab21eb02015-04-01 12:58:20 -0700295 if len(remoteKey) > 0 {
Ankurdda16492015-04-07 12:35:42 -0700296 granter := &granter{with, extension, caveats, remoteKey}
Suharsh Sivakumarab21eb02015-04-01 12:58:20 -0700297 return blessOverNetwork(ctx, tobless, granter, remoteToken)
298 }
299
300 // Blessing a principal whose key is available locally.
301 blessings, err := blessOverFileSystem(p, tobless, with, extension, caveats)
302 if err != nil {
303 return err
Asim Shankar66c52f92014-10-15 23:39:10 -0700304 }
305 return dumpBlessings(blessings)
Todd Wangf1550cf2015-05-11 10:58:41 -0700306 }),
Asim Shankar66c52f92014-10-15 23:39:10 -0700307 }
308
Todd Wang9560b9c2015-05-11 13:27:58 -0700309 cmdGetPublicKey = &cmdline.Command{
Suharsh Sivakumar2b22fc12015-04-15 19:38:04 -0700310 Name: "publickey",
311 Short: "Prints the public key of the principal.",
312 Long: `
313Prints out the public key of the principal specified by the environment
314that this tool is running in.
Asim Shankarde6fda52015-04-22 21:20:24 -0700315
316The key is printed as a base64 encoded bytes of the DER-format representation
Asim Shankar562b2302015-04-27 13:52:43 -0700317of the key (suitable to be provided as an argument to the 'recognize' command
Asim Shankar1213ab22015-04-23 10:11:07 -0700318for example).
Asim Shankarde6fda52015-04-22 21:20:24 -0700319
Asim Shankar1213ab22015-04-23 10:11:07 -0700320With --pretty, a 16-byte fingerprint of the key instead. This format is easier
321for humans to read and is used in output of other commands in this program, but
Asim Shankar562b2302015-04-27 13:52:43 -0700322is not suitable as an argument to the 'recognize' command.
Suharsh Sivakumar2b22fc12015-04-15 19:38:04 -0700323`,
Todd Wang9560b9c2015-05-11 13:27:58 -0700324 Runner: v23cmd.RunnerFunc(func(ctx *context.T, env *cmdline.Env, args []string) error {
Asim Shankarde6fda52015-04-22 21:20:24 -0700325 key := v23.GetPrincipal(ctx).PublicKey()
326 if flagGetPublicKeyPretty {
327 fmt.Println(key)
328 return nil
329 }
330 der, err := key.MarshalBinary()
331 if err != nil {
332 return fmt.Errorf("corrupted key: %v", err)
333 }
334 fmt.Println(base64.URLEncoding.EncodeToString(der))
Suharsh Sivakumar2b22fc12015-04-15 19:38:04 -0700335 return nil
Todd Wangf1550cf2015-05-11 10:58:41 -0700336 }),
Suharsh Sivakumar2b22fc12015-04-15 19:38:04 -0700337 }
338
Todd Wang9560b9c2015-05-11 13:27:58 -0700339 cmdGetTrustedRoots = &cmdline.Command{
Suharsh Sivakumar4bbe8ed2015-04-09 14:21:44 -0700340 Name: "recognizedroots",
341 Short: "Return recognized blessings, and their associated public key.",
342 Long: `
343Shows list of blessing names that the principal recognizes, and their associated
344public key. If the principal is operating as a client, contacted servers must
345appear on this list. If the principal is operating as a server, clients must
346present blessings derived from this list.
347`,
Todd Wang9560b9c2015-05-11 13:27:58 -0700348 Runner: v23cmd.RunnerFunc(func(ctx *context.T, env *cmdline.Env, args []string) error {
Suharsh Sivakumar4bbe8ed2015-04-09 14:21:44 -0700349 fmt.Printf(v23.GetPrincipal(ctx).Roots().DebugString())
350 return nil
Todd Wangf1550cf2015-05-11 10:58:41 -0700351 }),
Suharsh Sivakumar4bbe8ed2015-04-09 14:21:44 -0700352 }
353
Todd Wang9560b9c2015-05-11 13:27:58 -0700354 cmdGetPeerMap = &cmdline.Command{
Suharsh Sivakumar4bbe8ed2015-04-09 14:21:44 -0700355 Name: "peermap",
356 Short: "Shows the map from peer pattern to which blessing name to present.",
357 Long: `
358Shows the map from peer pattern to which blessing name to present.
359If the principal operates as a server, it presents its default blessing to all peers.
360If the principal operates as a client, it presents the map value associated with
361the peer it contacts.
362`,
Todd Wang9560b9c2015-05-11 13:27:58 -0700363 Runner: v23cmd.RunnerFunc(func(ctx *context.T, env *cmdline.Env, args []string) error {
Suharsh Sivakumar4bbe8ed2015-04-09 14:21:44 -0700364 fmt.Printf(v23.GetPrincipal(ctx).BlessingStore().DebugString())
365 return nil
Todd Wangf1550cf2015-05-11 10:58:41 -0700366 }),
Suharsh Sivakumar4bbe8ed2015-04-09 14:21:44 -0700367 }
368
Todd Wang9560b9c2015-05-11 13:27:58 -0700369 cmdGetForPeer = &cmdline.Command{
Asim Shankar66c52f92014-10-15 23:39:10 -0700370 Name: "forpeer",
Ankurcf6a89f2014-10-06 18:33:03 -0700371 Short: "Return blessings marked for the provided peer",
372 Long: `
373Returns blessings that are marked for the provided peer in the
Asim Shankar1789b8a2014-10-31 17:31:41 -0700374BlessingStore specified by the environment that this tool is
375running in.
Suharsh Sivakumar2b22fc12015-04-15 19:38:04 -0700376Providing --names will print the blessings' chain names.
377Providing --rootkey <chain_name> will print the root key of the certificate chain
378with chain_name.
379Providing --caveats <chain_name> will print the caveats on the certificate chain
380with chain_name.
Ankurcf6a89f2014-10-06 18:33:03 -0700381`,
382 ArgsName: "[<peer_1> ... <peer_k>]",
383 ArgsLong: `
384<peer_1> ... <peer_k> are the (human-readable string) blessings bound
385to the peer. The returned blessings are marked with a pattern that is
386matched by at least one of these. If no arguments are specified,
387store.forpeer returns the blessings that are marked for all peers (i.e.,
388blessings set on the store with the "..." pattern).
389`,
Todd Wang9560b9c2015-05-11 13:27:58 -0700390 Runner: v23cmd.RunnerFunc(func(ctx *context.T, env *cmdline.Env, args []string) error {
Suharsh Sivakumar4bbe8ed2015-04-09 14:21:44 -0700391 return printBlessingsInfo(v23.GetPrincipal(ctx).BlessingStore().ForPeer(args...))
Todd Wangf1550cf2015-05-11 10:58:41 -0700392 }),
Ankurcf6a89f2014-10-06 18:33:03 -0700393 }
394
Todd Wang9560b9c2015-05-11 13:27:58 -0700395 cmdGetDefault = &cmdline.Command{
Asim Shankar66c52f92014-10-15 23:39:10 -0700396 Name: "default",
Ankurcf6a89f2014-10-06 18:33:03 -0700397 Short: "Return blessings marked as default",
398 Long: `
Asim Shankar1789b8a2014-10-31 17:31:41 -0700399Returns blessings that are marked as default in the BlessingStore specified by
400the environment that this tool is running in.
Suharsh Sivakumar2b22fc12015-04-15 19:38:04 -0700401Providing --names will print the default blessings' chain names.
402Providing --rootkey <chain_name> will print the root key of the certificate chain
403with chain_name.
404Providing --caveats <chain_name> will print the caveats on the certificate chain
405with chain_name.
Ankurcf6a89f2014-10-06 18:33:03 -0700406`,
Todd Wang9560b9c2015-05-11 13:27:58 -0700407 Runner: v23cmd.RunnerFunc(func(ctx *context.T, env *cmdline.Env, args []string) error {
Suharsh Sivakumar4bbe8ed2015-04-09 14:21:44 -0700408 return printBlessingsInfo(v23.GetPrincipal(ctx).BlessingStore().Default())
Todd Wangf1550cf2015-05-11 10:58:41 -0700409 }),
Ankurcf6a89f2014-10-06 18:33:03 -0700410 }
Ankur8d304122014-10-07 10:43:43 -0700411
Todd Wang9560b9c2015-05-11 13:27:58 -0700412 cmdSetForPeer = &cmdline.Command{
Suharsh Sivakumar32c8e752015-03-31 19:26:28 -0700413 Name: "forpeer",
Ankur8d304122014-10-07 10:43:43 -0700414 Short: "Set provided blessings for peer",
415 Long: `
Asim Shankar1789b8a2014-10-31 17:31:41 -0700416Marks the provided blessings to be shared with the provided peers on the
417BlessingStore specified by the environment that this tool is running in.
Ankur8d304122014-10-07 10:43:43 -0700418
419'set b pattern' marks the intention to reveal b to peers who
420present blessings of their own matching 'pattern'.
421
422'set nil pattern' can be used to remove the blessings previously
423associated with the pattern (by a prior 'set' command).
424
Suharsh Sivakumar32c8e752015-03-31 19:26:28 -0700425It is an error to call 'set forpeer' with blessings whose public
Ankur8d304122014-10-07 10:43:43 -0700426key does not match the public key of this principal specified
427by the environment.
428`,
429 ArgsName: "<file> <pattern>",
430 ArgsLong: `
431<file> is the path to a file containing a blessing typically obtained
432from this tool. - is used for STDIN.
433
434<pattern> is the BlessingPattern used to identify peers with whom this
435blessing can be shared with.
436`,
Todd Wang9560b9c2015-05-11 13:27:58 -0700437 Runner: v23cmd.RunnerFunc(func(ctx *context.T, env *cmdline.Env, args []string) error {
Ankur8d304122014-10-07 10:43:43 -0700438 if len(args) != 2 {
Asim Shankar66c52f92014-10-15 23:39:10 -0700439 return fmt.Errorf("requires exactly two arguments <file>, <pattern>, provided %d", len(args))
Ankur8d304122014-10-07 10:43:43 -0700440 }
441 blessings, err := decodeBlessings(args[0])
442 if err != nil {
443 return fmt.Errorf("failed to decode provided blessings: %v", err)
444 }
445 pattern := security.BlessingPattern(args[1])
Matt Rosencrantz574d5e12014-11-26 10:01:37 -0800446
Jiri Simsa6ac95222015-02-23 16:11:49 -0800447 p := v23.GetPrincipal(ctx)
Asim Shankar66c52f92014-10-15 23:39:10 -0700448 if _, err := p.BlessingStore().Set(blessings, pattern); err != nil {
Ankur8d304122014-10-07 10:43:43 -0700449 return fmt.Errorf("failed to set blessings %v for peers %v: %v", blessings, pattern, err)
450 }
Asim Shankar66c52f92014-10-15 23:39:10 -0700451 if flagAddToRoots {
452 if err := p.AddToRoots(blessings); err != nil {
453 return fmt.Errorf("AddToRoots failed: %v", err)
454 }
455 }
Ankur8d304122014-10-07 10:43:43 -0700456 return nil
Todd Wangf1550cf2015-05-11 10:58:41 -0700457 }),
Ankur8d304122014-10-07 10:43:43 -0700458 }
459
Todd Wang9560b9c2015-05-11 13:27:58 -0700460 cmdRecognize = &cmdline.Command{
Asim Shankar562b2302015-04-27 13:52:43 -0700461 Name: "recognize",
462 Short: "Add to the set of identity providers recognized by this principal",
463 Long: `
464Adds an identity provider to the set of recognized roots public keys for this principal.
465
466It accepts either a single argument (which points to a file containing a blessing)
467or two arguments (a name and a base64-encoded DER-encoded public key).
468
469For example, to make the principal in credentials directory A recognize the
470root of the default blessing in credentials directory B:
471 principal -v23.credentials=B bless A some_extension |
472 principal -v23.credentials=A recognize -
473The extension 'some_extension' has no effect in the command above.
474
475Or to make the principal in credentials directory A recognize the base64-encoded
476public key KEY for blessing pattern P:
477 principal -v23.credentials=A recognize P KEY
478`,
479 ArgsName: "<key|blessing> [<blessing pattern>]",
480 ArgsLong: `
481<blessing> is the path to a file containing a blessing typically obtained from
482this tool. - is used for STDIN.
483
484<key> is a base64-encoded, DER-encoded public key.
485
486<blessing pattern> is the blessing pattern for which <key> should be recognized.
487`,
Todd Wang9560b9c2015-05-11 13:27:58 -0700488 Runner: v23cmd.RunnerFunc(func(ctx *context.T, env *cmdline.Env, args []string) error {
Asim Shankar562b2302015-04-27 13:52:43 -0700489 if len(args) != 1 && len(args) != 2 {
490 return fmt.Errorf("requires either one argument <file>, or two arguments <key> <blessing pattern>, provided %d", len(args))
491 }
Asim Shankar562b2302015-04-27 13:52:43 -0700492 p := v23.GetPrincipal(ctx)
493 if len(args) == 1 {
494 blessings, err := decodeBlessings(args[0])
495 if err != nil {
496 return fmt.Errorf("failed to decode provided blessings: %v", err)
497 }
498 if err := p.AddToRoots(blessings); err != nil {
499 return fmt.Errorf("AddToRoots failed: %v", err)
500 }
501 return nil
502 }
503 // len(args) == 2
504 der, err := base64.URLEncoding.DecodeString(args[1])
505 if err != nil {
506 return fmt.Errorf("invalid base64 encoding of public key: %v", err)
507 }
508 key, err := security.UnmarshalPublicKey(der)
509 if err != nil {
510 return fmt.Errorf("invalid DER encoding of public key: %v", err)
511 }
512 return p.Roots().Add(key, security.BlessingPattern(args[0]))
Todd Wangf1550cf2015-05-11 10:58:41 -0700513 }),
Asim Shankar562b2302015-04-27 13:52:43 -0700514 }
Mike Burrows367515e2014-12-02 11:30:18 -0800515
Todd Wang9560b9c2015-05-11 13:27:58 -0700516 cmdSetDefault = &cmdline.Command{
Suharsh Sivakumar32c8e752015-03-31 19:26:28 -0700517 Name: "default",
Ankur8d304122014-10-07 10:43:43 -0700518 Short: "Set provided blessings as default",
519 Long: `
Asim Shankar1789b8a2014-10-31 17:31:41 -0700520Sets the provided blessings as default in the BlessingStore specified by the
521environment that this tool is running in.
Ankur8d304122014-10-07 10:43:43 -0700522
Suharsh Sivakumar32c8e752015-03-31 19:26:28 -0700523It is an error to call 'set default' with blessings whose public key does
Asim Shankar1789b8a2014-10-31 17:31:41 -0700524not match the public key of the principal specified by the environment.
Ankur8d304122014-10-07 10:43:43 -0700525`,
526 ArgsName: "<file>",
527 ArgsLong: `
528<file> is the path to a file containing a blessing typically obtained from
529this tool. - is used for STDIN.
530`,
Todd Wang9560b9c2015-05-11 13:27:58 -0700531 Runner: v23cmd.RunnerFunc(func(ctx *context.T, env *cmdline.Env, args []string) error {
Ankur8d304122014-10-07 10:43:43 -0700532 if len(args) != 1 {
Asim Shankar66c52f92014-10-15 23:39:10 -0700533 return fmt.Errorf("requires exactly one argument, <file>, provided %d", len(args))
Ankur8d304122014-10-07 10:43:43 -0700534 }
535 blessings, err := decodeBlessings(args[0])
536 if err != nil {
537 return fmt.Errorf("failed to decode provided blessings: %v", err)
538 }
Matt Rosencrantz574d5e12014-11-26 10:01:37 -0800539
Jiri Simsa6ac95222015-02-23 16:11:49 -0800540 p := v23.GetPrincipal(ctx)
Asim Shankar1789b8a2014-10-31 17:31:41 -0700541 if err := p.BlessingStore().SetDefault(blessings); err != nil {
Ankur8d304122014-10-07 10:43:43 -0700542 return fmt.Errorf("failed to set blessings %v as default: %v", blessings, err)
543 }
Asim Shankar66c52f92014-10-15 23:39:10 -0700544 if flagAddToRoots {
545 if err := p.AddToRoots(blessings); err != nil {
546 return fmt.Errorf("AddToRoots failed: %v", err)
547 }
548 }
549 return nil
Todd Wangf1550cf2015-05-11 10:58:41 -0700550 }),
Asim Shankar66c52f92014-10-15 23:39:10 -0700551 }
552
Todd Wang9560b9c2015-05-11 13:27:58 -0700553 cmdCreate = &cmdline.Command{
Asim Shankar66c52f92014-10-15 23:39:10 -0700554 Name: "create",
555 Short: "Create a new principal and persist it into a directory",
556 Long: `
Ankur4704f5f2014-10-23 12:40:54 -0700557Creates a new principal with a single self-blessed blessing and writes it out
Ankurc24ff422014-12-16 17:59:26 -0800558to the provided directory. The same directory can then be used to set the
Asim Shankar59b8b692015-03-30 01:23:36 -0700559V23_CREDENTIALS environment variable for other vanadium applications.
Ankur4704f5f2014-10-23 12:40:54 -0700560
561The operation fails if the directory already contains a principal. In this case
Ankurc24ff422014-12-16 17:59:26 -0800562the --overwrite flag can be provided to clear the directory and write out the
gauthamtb7bb39b2014-11-10 11:40:41 -0800563new principal.
Ankur4704f5f2014-10-23 12:40:54 -0700564`,
Asim Shankar66c52f92014-10-15 23:39:10 -0700565 ArgsName: "<directory> <blessing>",
566 ArgsLong: `
Todd Wangf1550cf2015-05-11 10:58:41 -0700567<directory> is the directory to which the new principal will be persisted.
568
569<blessing> is the self-blessed blessing that the principal will be setup to use by default.
Asim Shankar66c52f92014-10-15 23:39:10 -0700570 `,
Todd Wang9560b9c2015-05-11 13:27:58 -0700571 Runner: cmdline.RunnerFunc(func(env *cmdline.Env, args []string) error {
Asim Shankar66c52f92014-10-15 23:39:10 -0700572 if len(args) != 2 {
573 return fmt.Errorf("requires exactly two arguments: <directory> and <blessing>, provided %d", len(args))
574 }
575 dir, name := args[0], args[1]
Ankur4704f5f2014-10-23 12:40:54 -0700576 if flagCreateOverwrite {
Ankurc24ff422014-12-16 17:59:26 -0800577 if err := os.RemoveAll(dir); err != nil {
gauthamtb7bb39b2014-11-10 11:40:41 -0800578 return err
579 }
Ankur4704f5f2014-10-23 12:40:54 -0700580 }
Ankurc24ff422014-12-16 17:59:26 -0800581 p, err := vsecurity.CreatePersistentPrincipal(dir, nil)
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -0700582 if err != nil {
583 return err
Asim Shankar66c52f92014-10-15 23:39:10 -0700584 }
585 blessings, err := p.BlessSelf(name)
586 if err != nil {
587 return fmt.Errorf("BlessSelf(%q) failed: %v", name, err)
588 }
Ankurc24ff422014-12-16 17:59:26 -0800589 if err := vsecurity.SetDefaultBlessings(p, blessings); err != nil {
590 return fmt.Errorf("could not set blessings %v as default: %v", blessings, err)
Asim Shankar66c52f92014-10-15 23:39:10 -0700591 }
Ankurc24ff422014-12-16 17:59:26 -0800592 return nil
Todd Wangf1550cf2015-05-11 10:58:41 -0700593 }),
Ankurc24ff422014-12-16 17:59:26 -0800594 }
595
Todd Wang9560b9c2015-05-11 13:27:58 -0700596 cmdFork = &cmdline.Command{
Ankurc24ff422014-12-16 17:59:26 -0800597 Name: "fork",
598 Short: "Fork a new principal from the principal that this tool is running as and persist it into a directory",
599 Long: `
600Creates a new principal with a blessing from the principal specified by the
601environment that this tool is running in, and writes it out to the provided
602directory. The blessing that will be extended is the default one from the
Suharsh Sivakumar1d61f642015-02-17 20:56:14 -0800603blesser's store, or specified by the --with flag. Expiration on the blessing
604are controlled via the --for flag. Additional caveats on the blessing are
605controlled with the --caveat flag. The blessing is marked as default and
Ankurc24ff422014-12-16 17:59:26 -0800606shareable with all peers on the new principal's blessing store.
607
608The operation fails if the directory already contains a principal. In this case
609the --overwrite flag can be provided to clear the directory and write out the
610forked principal.
611`,
612 ArgsName: "<directory> <extension>",
613 ArgsLong: `
Todd Wangf1550cf2015-05-11 10:58:41 -0700614<directory> is the directory to which the forked principal will be persisted.
615
616<extension> is the extension under which the forked principal is blessed.
Ankurc24ff422014-12-16 17:59:26 -0800617 `,
Todd Wang9560b9c2015-05-11 13:27:58 -0700618 Runner: v23cmd.RunnerFunc(func(ctx *context.T, env *cmdline.Env, args []string) error {
Ankurc24ff422014-12-16 17:59:26 -0800619 if len(args) != 2 {
620 return fmt.Errorf("requires exactly two arguments: <directory> and <extension>, provided %d", len(args))
Asim Shankar66c52f92014-10-15 23:39:10 -0700621 }
Ankurc24ff422014-12-16 17:59:26 -0800622 dir, extension := args[0], args[1]
Asim Shankara0bba462015-02-20 22:50:51 -0800623 caveats, err := caveatsFromFlags(flagForkFor, &flagForkCaveats)
624 if err != nil {
625 return err
626 }
627 if !flagForkRequireCaveats && len(caveats) == 0 {
628 caveats = []security.Caveat{security.UnconstrainedUse()}
629 }
630 if len(caveats) == 0 {
631 return errNoCaveats
632 }
633 var with security.Blessings
634 if len(flagForkWith) > 0 {
635 if with, err = decodeBlessings(flagForkWith); err != nil {
636 return fmt.Errorf("failed to read blessings from --with=%q: %v", flagForkWith, err)
637 }
638 } else {
Jiri Simsa6ac95222015-02-23 16:11:49 -0800639 with = v23.GetPrincipal(ctx).BlessingStore().Default()
Asim Shankara0bba462015-02-20 22:50:51 -0800640 }
641
Ankurc24ff422014-12-16 17:59:26 -0800642 if flagCreateOverwrite {
643 if err := os.RemoveAll(dir); err != nil {
644 return err
645 }
646 }
647 p, err := vsecurity.CreatePersistentPrincipal(dir, nil)
648 if err != nil {
649 return err
650 }
651
Ankurc24ff422014-12-16 17:59:26 -0800652 key := p.PublicKey()
Jiri Simsa6ac95222015-02-23 16:11:49 -0800653 rp := v23.GetPrincipal(ctx)
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800654 blessings, err := rp.Bless(key, with, extension, caveats[0], caveats[1:]...)
Ankurc24ff422014-12-16 17:59:26 -0800655 if err != nil {
656 return fmt.Errorf("Bless(%v, %v, %q, ...) failed: %v", key, with, extension, err)
657 }
658 if err := vsecurity.SetDefaultBlessings(p, blessings); err != nil {
659 return fmt.Errorf("could not set blessings %v as default: %v", blessings, err)
Asim Shankar66c52f92014-10-15 23:39:10 -0700660 }
Ankur8d304122014-10-07 10:43:43 -0700661 return nil
Todd Wangf1550cf2015-05-11 10:58:41 -0700662 }),
Ankur8d304122014-10-07 10:43:43 -0700663 }
Ankur1d46f552014-10-09 12:13:31 -0700664
Todd Wang9560b9c2015-05-11 13:27:58 -0700665 cmdSeekBlessings = &cmdline.Command{
Ankur1d46f552014-10-09 12:13:31 -0700666 Name: "seekblessings",
Suharsh Sivakumard1cc6e02015-03-16 13:58:49 -0700667 Short: "Seek blessings from a web-based Vanadium blessing service",
Ankur1d46f552014-10-09 12:13:31 -0700668 Long: `
Suharsh Sivakumard1cc6e02015-03-16 13:58:49 -0700669Seeks blessings from a web-based Vanadium blesser which
Ankur1d46f552014-10-09 12:13:31 -0700670requires the caller to first authenticate with Google using OAuth. Simply
671run the command to see what happens.
672
Asim Shankar1789b8a2014-10-31 17:31:41 -0700673The blessings are sought for the principal specified by the environment that
674this tool is running in.
Ankur1d46f552014-10-09 12:13:31 -0700675
Suharsh Sivakumared5be1d2015-04-01 17:45:35 -0700676The blessings obtained are set as default, unless the --set-default flag is
Ankure548f392014-12-08 18:42:41 -0800677set to true, and are also set for sharing with all peers, unless a more
Suharsh Sivakumared5be1d2015-04-01 17:45:35 -0700678specific peer pattern is provided using the --for-peer flag.
Ankur1d46f552014-10-09 12:13:31 -0700679`,
Todd Wang9560b9c2015-05-11 13:27:58 -0700680 Runner: v23cmd.RunnerFunc(func(ctx *context.T, env *cmdline.Env, args []string) error {
Ankuraf98e572015-05-05 14:18:50 -0700681 p := v23.GetPrincipal(ctx)
682
Ankur1d46f552014-10-09 12:13:31 -0700683 blessedChan := make(chan string)
684 defer close(blessedChan)
Ankuraf98e572015-05-05 14:18:50 -0700685 macaroonChan, err := getMacaroonForBlessRPC(p.PublicKey(), flagSeekBlessingsFrom, blessedChan, flagSeekBlessingsBrowser)
Ankur1d46f552014-10-09 12:13:31 -0700686 if err != nil {
Suharsh Sivakumard1cc6e02015-03-16 13:58:49 -0700687 return fmt.Errorf("failed to get macaroon from Vanadium blesser: %v", err)
Ankur1d46f552014-10-09 12:13:31 -0700688 }
Ankur1d46f552014-10-09 12:13:31 -0700689
Suharsh Sivakumar67ef84a2015-02-13 13:04:44 -0800690 blessings, err := exchangeMacaroonForBlessing(ctx, macaroonChan)
Ankur1d46f552014-10-09 12:13:31 -0700691 if err != nil {
Suharsh Sivakumar67ef84a2015-02-13 13:04:44 -0800692 return err
Ankur1d46f552014-10-09 12:13:31 -0700693 }
694 blessedChan <- fmt.Sprint(blessings)
695 // Wait for getTokenForBlessRPC to clean up:
696 <-macaroonChan
697
Asim Shankar66c52f92014-10-15 23:39:10 -0700698 if flagSeekBlessingsSetDefault {
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800699 if err := p.BlessingStore().SetDefault(blessings); err != nil {
Ankur1d46f552014-10-09 12:13:31 -0700700 return fmt.Errorf("failed to set blessings %v as default: %v", blessings, err)
701 }
702 }
Asim Shankar66c52f92014-10-15 23:39:10 -0700703 if pattern := security.BlessingPattern(flagSeekBlessingsForPeer); len(pattern) > 0 {
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800704 if _, err := p.BlessingStore().Set(blessings, pattern); err != nil {
Asim Shankar66c52f92014-10-15 23:39:10 -0700705 return fmt.Errorf("failed to set blessings %v for peers %v: %v", blessings, pattern, err)
706 }
707 }
708 if flagAddToRoots {
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800709 if err := p.AddToRoots(blessings); err != nil {
Asim Shankar66c52f92014-10-15 23:39:10 -0700710 return fmt.Errorf("AddToRoots failed: %v", err)
711 }
Ankur1d46f552014-10-09 12:13:31 -0700712 }
Todd Wangf1550cf2015-05-11 10:58:41 -0700713 fmt.Fprintf(env.Stdout, "Received blessings: %v\n", blessings)
Jiri Simsa37b0a092015-02-13 09:32:39 -0800714 return nil
Todd Wangf1550cf2015-05-11 10:58:41 -0700715 }),
Ankur1d46f552014-10-09 12:13:31 -0700716 }
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800717
Todd Wang9560b9c2015-05-11 13:27:58 -0700718 cmdRecvBlessings = &cmdline.Command{
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800719 Name: "recvblessings",
720 Short: "Receive blessings sent by another principal and use them as the default",
721 Long: `
722Allow another principal (likely a remote process) to bless this one.
723
724This command sets up the invoker (this process) to wait for a blessing
725from another invocation of this tool (remote process) and prints out the
726command to be run as the remote principal.
727
Suharsh Sivakumared5be1d2015-04-01 17:45:35 -0700728The received blessings are set as default, unless the --set-default flag is
Ankure548f392014-12-08 18:42:41 -0800729set to true, and are also set for sharing with all peers, unless a more
Suharsh Sivakumared5be1d2015-04-01 17:45:35 -0700730specific peer pattern is provided using the --for-peer flag.
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800731
732TODO(ashankar,cnicolaou): Make this next paragraph possible! Requires
733the ability to obtain the proxied endpoint.
734
735Typically, this command should require no arguments.
736However, if the sender and receiver are on different network domains, it may
Asim Shankarf32d24d2015-04-01 16:34:26 -0700737make sense to use the --v23.proxy flag:
738 principal --v23.proxy=proxy recvblessings
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800739
740The command to be run at the sender is of the form:
Suharsh Sivakumared5be1d2015-04-01 17:45:35 -0700741 principal bless --remote-key=KEY --remote-token=TOKEN ADDRESS EXTENSION
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800742
Suharsh Sivakumared5be1d2015-04-01 17:45:35 -0700743The --remote-key flag is used to by the sender to "authenticate" the receiver,
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800744ensuring it blesses the intended recipient and not any attacker that may have
745taken over the address.
746
Suharsh Sivakumared5be1d2015-04-01 17:45:35 -0700747The --remote-token flag is used by the sender to authenticate itself to the
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800748receiver. This helps ensure that the receiver rejects blessings from senders
749who just happened to guess the network address of the 'recvblessings'
750invocation.
Suharsh Sivakumarab21eb02015-04-01 12:58:20 -0700751
Suharsh Sivakumared5be1d2015-04-01 17:45:35 -0700752If the --remote-arg-file flag is provided to recvblessings, the remote key, remote token
Suharsh Sivakumarab21eb02015-04-01 12:58:20 -0700753and object address of this principal will be written to the specified location.
754This file can be supplied to bless:
Suharsh Sivakumared5be1d2015-04-01 17:45:35 -0700755 principal bless --remote-arg-file FILE EXTENSION
Suharsh Sivakumarab21eb02015-04-01 12:58:20 -0700756
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800757`,
Todd Wang9560b9c2015-05-11 13:27:58 -0700758 Runner: v23cmd.RunnerFunc(func(ctx *context.T, env *cmdline.Env, args []string) error {
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800759 if len(args) != 0 {
760 return fmt.Errorf("command accepts no arguments")
761 }
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800762 var token [24]byte
763 if _, err := rand.Read(token[:]); err != nil {
764 return fmt.Errorf("unable to generate token: %v", err)
765 }
Jiri Simsa6ac95222015-02-23 16:11:49 -0800766 p := v23.GetPrincipal(ctx)
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800767 service := &recvBlessingsService{
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800768 principal: p,
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800769 token: base64.URLEncoding.EncodeToString(token[:]),
770 notify: make(chan error),
771 }
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700772 server, err := xrpc.NewServer(ctx, "", service, security.AllowEveryone())
773 if err != nil {
774 return fmt.Errorf("failed to create server to listen for blessings: %v", err)
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800775 }
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700776 name := server.Status().Endpoints[0].Name()
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800777 fmt.Println("Run the following command on behalf of the principal that will send blessings:")
778 fmt.Println("You may want to adjust flags affecting the caveats on this blessing, for example using")
Asim Shankar2a32dd22015-05-29 15:45:22 -0700779 fmt.Println("the --for flag")
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800780 fmt.Println()
Suharsh Sivakumarab21eb02015-04-01 12:58:20 -0700781 if len(flagRemoteArgFile) > 0 {
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700782 if err := writeRecvBlessingsInfo(flagRemoteArgFile, p.PublicKey().String(), service.token, name); err != nil {
Suharsh Sivakumarab21eb02015-04-01 12:58:20 -0700783 return fmt.Errorf("failed to write recvblessings info to %v: %v", flagRemoteArgFile, err)
784 }
785 fmt.Printf("make %q accessible to the blesser, possibly by copying the file over and then run:\n", flagRemoteArgFile)
Asim Shankar2a32dd22015-05-29 15:45:22 -0700786 fmt.Printf("principal bless --remote-arg-file=%v", flagRemoteArgFile)
Suharsh Sivakumarab21eb02015-04-01 12:58:20 -0700787 } else {
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700788 fmt.Printf("principal bless --remote-key=%v --remote-token=%v %v\n", p.PublicKey(), service.token, name)
Suharsh Sivakumarab21eb02015-04-01 12:58:20 -0700789 }
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800790 fmt.Println()
791 fmt.Println("...waiting for sender..")
792 return <-service.notify
Todd Wangf1550cf2015-05-11 10:58:41 -0700793 }),
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800794 }
Ankurcf6a89f2014-10-06 18:33:03 -0700795)
796
Bogdan Caprita4ab95412015-05-13 13:37:46 -0700797func printAnnotatedBlessingsNames(b security.Blessings) string {
798 // If the Blessings are expired, print a message saying so.
799 expiredMessage := ""
800 if exp := b.Expiry(); !exp.IsZero() && exp.Before(time.Now()) {
801 expiredMessage = " [EXPIRED]"
802 }
803 return fmt.Sprintf("%v%s", b, expiredMessage)
804}
805
Asim Shankar2a32dd22015-05-29 15:45:22 -0700806func blessArgs(env *cmdline.Env, args []string) (tobless, extension, remoteKey, remoteToken string, err error) {
807 extensionInArgs := false
Suharsh Sivakumarab21eb02015-04-01 12:58:20 -0700808 if len(flagRemoteArgFile) == 0 {
Asim Shankar2a32dd22015-05-29 15:45:22 -0700809 tobless = args[0]
Suharsh Sivakumarab21eb02015-04-01 12:58:20 -0700810 remoteKey = flagBlessRemoteKey
811 remoteToken = flagBlessRemoteToken
Asim Shankar2a32dd22015-05-29 15:45:22 -0700812 extensionInArgs = len(args) > 1
Suharsh Sivakumarab21eb02015-04-01 12:58:20 -0700813 } else if len(flagRemoteArgFile) > 0 {
Suharsh Sivakumarab21eb02015-04-01 12:58:20 -0700814 remoteKey, remoteToken, tobless, err = blessArgsFromFile(flagRemoteArgFile)
Asim Shankar2a32dd22015-05-29 15:45:22 -0700815 extensionInArgs = len(args) > 0
816 }
817 if extensionInArgs {
818 extension = args[len(args)-1]
819 } else {
820 extension, err = readFromStdin(env, "Extension to use for blessing:")
Suharsh Sivakumarab21eb02015-04-01 12:58:20 -0700821 }
822 return
823}
824
Asim Shankar2a32dd22015-05-29 15:45:22 -0700825func confirmNoCaveats(env *cmdline.Env) error {
826 text, err := readFromStdin(env, `WARNING: No caveats provided
827It is generally dangerous to bless another principal without any caveats as
828that gives them unrestricted access to the blesser's credentials.
829
830Caveats can be specified with the --for or --caveat flags.
831
832Do you really wish to bless without caveats? (YES to confirm)`)
833 if err != nil || strings.ToUpper(text) != "YES" {
834 return errNoCaveats
835 }
836 return nil
837}
838
839func readFromStdin(env *cmdline.Env, prompt string) (string, error) {
840 fmt.Fprintf(env.Stdout, "%v ", prompt)
841 os.Stdout.Sync()
842 // Cannot use bufio because that may "lose" data beyond the line (the
843 // remainder in the buffer).
844 // Do the inefficient byte-by-byte scan for now - shouldn't be a problem
845 // given the common use case. If that becomes a problem, switch to bufio
846 // and share the bufio.Reader between multiple calls to readFromStdin.
847 buf := make([]byte, 0, 100)
848 r := make([]byte, 1)
849 for {
850 n, err := env.Stdin.Read(r)
851 if n == 1 && r[0] == '\n' {
852 break
853 }
854 if n == 1 {
855 buf = append(buf, r[0])
856 continue
857 }
858 if err != nil {
859 return "", err
860 }
861 }
862 return strings.TrimSpace(string(buf)), nil
863}
864
Suharsh Sivakumarab21eb02015-04-01 12:58:20 -0700865func blessOverFileSystem(p security.Principal, tobless string, with security.Blessings, extension string, caveats []security.Caveat) (security.Blessings, error) {
866 var key security.PublicKey
867 if finfo, err := os.Stat(tobless); err == nil && finfo.IsDir() {
868 other, err := vsecurity.LoadPersistentPrincipal(tobless, nil)
869 if err != nil {
870 if other, err = vsecurity.CreatePersistentPrincipal(tobless, nil); err != nil {
871 return security.Blessings{}, fmt.Errorf("failed to read principal in directory %q: %v", tobless, err)
872 }
873 }
874 key = other.PublicKey()
875 } else if other, err := decodeBlessings(tobless); err != nil {
876 return security.Blessings{}, fmt.Errorf("failed to decode blessings in %q: %v", tobless, err)
877 } else {
878 key = other.PublicKey()
879 }
880 return p.Bless(key, with, extension, caveats[0], caveats[1:]...)
881}
882
883type recvBlessingsInfo struct {
Asim Shankarfe4899f2015-05-08 13:23:28 -0700884 RemoteKey string `json:"remote_key"`
885 RemoteToken string `json:"remote_token"`
886 Name string `json:"name"`
Suharsh Sivakumarab21eb02015-04-01 12:58:20 -0700887}
888
889func writeRecvBlessingsInfo(fname string, remoteKey, remoteToken, name string) error {
890 f, err := os.OpenFile(fname, os.O_WRONLY|os.O_CREATE, 0666)
891 if err != nil {
892 return err
893 }
894 b, err := json.Marshal(recvBlessingsInfo{remoteKey, remoteToken, name})
895 if err != nil {
896 return err
897 }
898 if _, err := f.Write(b); err != nil {
899 return err
900 }
901 return nil
902}
903
904func blessArgsFromFile(fname string) (remoteKey, remoteToken, tobless string, err error) {
905 blessJSON, err := ioutil.ReadFile(fname)
906 if err != nil {
907 return "", "", "", err
908 }
909 var binfo recvBlessingsInfo
910 if err := json.Unmarshal(blessJSON, &binfo); err != nil {
911 return "", "", "", err
912 }
913 return binfo.RemoteKey, binfo.RemoteToken, binfo.Name, err
914}
915
Ankurcf6a89f2014-10-06 18:33:03 -0700916func main() {
Todd Wang9560b9c2015-05-11 13:27:58 -0700917 cmdline.HideGlobalFlagsExcept()
Suharsh Sivakumar1d61f642015-02-17 20:56:14 -0800918 cmdBlessSelf.Flags.Var(&flagBlessSelfCaveats, "caveat", flagBlessSelfCaveats.usage())
Asim Shankara0bba462015-02-20 22:50:51 -0800919 cmdBlessSelf.Flags.DurationVar(&flagBlessSelfFor, "for", 0, "Duration of blessing validity (zero implies no expiration)")
920
Suharsh Sivakumar2b22fc12015-04-15 19:38:04 -0700921 cmdDump.Flags.BoolVar(&flagDumpShort, "s", false, "If true, show only the default blessing names")
Robin Thellend5396eae2015-04-13 09:57:06 -0700922
Ankur77c32ac2014-12-18 14:18:19 -0800923 cmdFork.Flags.BoolVar(&flagCreateOverwrite, "overwrite", false, "If true, any existing principal data in the directory will be overwritten")
Suharsh Sivakumar1d61f642015-02-17 20:56:14 -0800924 cmdFork.Flags.Var(&flagForkCaveats, "caveat", flagForkCaveats.usage())
Asim Shankara0bba462015-02-20 22:50:51 -0800925 cmdFork.Flags.DurationVar(&flagForkFor, "for", 0, "Duration of blessing validity (zero implies no expiration caveat)")
Suharsh Sivakumared5be1d2015-04-01 17:45:35 -0700926 cmdFork.Flags.BoolVar(&flagForkRequireCaveats, "require-caveats", true, "If false, allow blessing without any caveats. This is typically not advised as the principal wielding the blessing will be almost as powerful as its blesser")
Ankur77c32ac2014-12-18 14:18:19 -0800927 cmdFork.Flags.StringVar(&flagForkWith, "with", "", "Path to file containing blessing to extend")
928
Suharsh Sivakumar1d61f642015-02-17 20:56:14 -0800929 cmdBless.Flags.Var(&flagBlessCaveats, "caveat", flagBlessCaveats.usage())
Asim Shankara0bba462015-02-20 22:50:51 -0800930 cmdBless.Flags.DurationVar(&flagBlessFor, "for", 0, "Duration of blessing validity (zero implies no expiration caveat)")
Suharsh Sivakumared5be1d2015-04-01 17:45:35 -0700931 cmdBless.Flags.BoolVar(&flagBlessRequireCaveats, "require-caveats", true, "If false, allow blessing without any caveats. This is typically not advised as the principal wielding the blessing will be almost as powerful as its blesser")
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800932 cmdBless.Flags.StringVar(&flagBlessWith, "with", "", "Path to file containing blessing to extend")
Suharsh Sivakumared5be1d2015-04-01 17:45:35 -0700933 cmdBless.Flags.StringVar(&flagBlessRemoteKey, "remote-key", "", "Public key of the remote principal to bless (obtained from the 'recvblessings' command run by the remote principal")
934 cmdBless.Flags.StringVar(&flagBlessRemoteToken, "remote-token", "", "Token provided by principal running the 'recvblessings' command")
Suharsh Sivakumar4bbe8ed2015-04-09 14:21:44 -0700935 cmdBless.Flags.StringVar(&flagRemoteArgFile, "remote-arg-file", "", "File containing bless arguments written by 'principal recvblessings -remote-arg-file FILE EXTENSION' command. This can be provided to bless in place of --remote-key, --remote-token, and <principal>")
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800936
Robin Thellend157e2aa2015-04-17 14:04:40 -0700937 defaultFrom := "https://dev.v.io/auth/google"
Todd Wang8123b5e2015-05-14 18:44:43 -0700938 if e := os.Getenv(ref.EnvOAuthIdentityProvider); e != "" {
Robin Thellend157e2aa2015-04-17 14:04:40 -0700939 defaultFrom = e
940 }
941 cmdSeekBlessings.Flags.StringVar(&flagSeekBlessingsFrom, "from", defaultFrom, "URL to use to begin the seek blessings process")
Suharsh Sivakumared5be1d2015-04-01 17:45:35 -0700942 cmdSeekBlessings.Flags.BoolVar(&flagSeekBlessingsSetDefault, "set-default", true, "If true, the blessings obtained will be set as the default blessing in the store")
943 cmdSeekBlessings.Flags.StringVar(&flagSeekBlessingsForPeer, "for-peer", string(security.AllPrincipals), "If non-empty, the blessings obtained will be marked for peers matching this pattern in the store")
Suharsh Sivakumara76dba62014-12-22 16:00:34 -0800944 cmdSeekBlessings.Flags.BoolVar(&flagSeekBlessingsBrowser, "browser", true, "If false, the seekblessings command will not open the browser and only print the url to visit.")
Suharsh Sivakumared5be1d2015-04-01 17:45:35 -0700945 cmdSeekBlessings.Flags.BoolVar(&flagAddToRoots, "add-to-roots", true, "If true, the root certificate of the blessing will be added to the principal's set of recognized root certificates")
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800946
Suharsh Sivakumared5be1d2015-04-01 17:45:35 -0700947 cmdSetForPeer.Flags.BoolVar(&flagAddToRoots, "add-to-roots", true, "If true, the root certificate of the blessing will be added to the principal's set of recognized root certificates")
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800948
Suharsh Sivakumared5be1d2015-04-01 17:45:35 -0700949 cmdSetDefault.Flags.BoolVar(&flagAddToRoots, "add-to-roots", true, "If true, the root certificate of the blessing will be added to the principal's set of recognized root certificates")
Asim Shankarf11b1bc2014-11-12 17:18:45 -0800950
Ankur4704f5f2014-10-23 12:40:54 -0700951 cmdCreate.Flags.BoolVar(&flagCreateOverwrite, "overwrite", false, "If true, any existing principal data in the directory will be overwritten")
Asim Shankar66c52f92014-10-15 23:39:10 -0700952
Suharsh Sivakumared5be1d2015-04-01 17:45:35 -0700953 cmdRecvBlessings.Flags.BoolVar(&flagRecvBlessingsSetDefault, "set-default", true, "If true, the blessings received will be set as the default blessing in the store")
954 cmdRecvBlessings.Flags.StringVar(&flagRecvBlessingsForPeer, "for-peer", string(security.AllPrincipals), "If non-empty, the blessings received will be marked for peers matching this pattern in the store")
Suharsh Sivakumar4bbe8ed2015-04-09 14:21:44 -0700955 cmdRecvBlessings.Flags.StringVar(&flagRemoteArgFile, "remote-arg-file", "", "If non-empty, the remote key, remote token, and principal will be written to the specified file in a JSON object. This can be provided to 'principal bless --remote-arg-file FILE EXTENSION'")
956
Suharsh Sivakumar2b22fc12015-04-15 19:38:04 -0700957 cmdGetForPeer.Flags.BoolVar(&flagBlessingsNames, "names", false, "If true, shows the value of the blessing name to be presented to the peer")
958 cmdGetForPeer.Flags.StringVar(&flagBlessingsRootKey, "rootkey", "", "Shows the value of the root key of the provided certificate chain name.")
959 cmdGetForPeer.Flags.StringVar(&flagBlessingsCaveats, "caveats", "", "Shows the caveats on the provided certificate chain name.")
Suharsh Sivakumar4bbe8ed2015-04-09 14:21:44 -0700960
Suharsh Sivakumar2b22fc12015-04-15 19:38:04 -0700961 cmdGetDefault.Flags.BoolVar(&flagBlessingsNames, "names", false, "If true, shows the value of the blessing name to be presented to the peer")
962 cmdGetDefault.Flags.StringVar(&flagBlessingsRootKey, "rootkey", "", "Shows the value of the root key of the provided certificate chain name.")
963 cmdGetDefault.Flags.StringVar(&flagBlessingsCaveats, "caveats", "", "Shows the caveats on the provided certificate chain name.")
Ankure548f392014-12-08 18:42:41 -0800964
Asim Shankarde6fda52015-04-22 21:20:24 -0700965 cmdGetPublicKey.Flags.BoolVar(&flagGetPublicKeyPretty, "pretty", false, "If true, print the key out in a more human-readable but lossy representation.")
966
Todd Wang9560b9c2015-05-11 13:27:58 -0700967 cmdSet := &cmdline.Command{
Suharsh Sivakumar32c8e752015-03-31 19:26:28 -0700968 Name: "set",
969 Short: "Mutate the principal's blessings.",
Asim Shankar66c52f92014-10-15 23:39:10 -0700970 Long: `
Suharsh Sivakumar32c8e752015-03-31 19:26:28 -0700971Commands to mutate the blessings of the principal.
Asim Shankar66c52f92014-10-15 23:39:10 -0700972
Suharsh Sivakumar32c8e752015-03-31 19:26:28 -0700973All input blessings are expected to be serialized using base64-VOM-encoding.
974See 'principal get'.
Asim Shankar66c52f92014-10-15 23:39:10 -0700975`,
Todd Wang9560b9c2015-05-11 13:27:58 -0700976 Children: []*cmdline.Command{cmdSetDefault, cmdSetForPeer},
Suharsh Sivakumar32c8e752015-03-31 19:26:28 -0700977 }
978
Todd Wang9560b9c2015-05-11 13:27:58 -0700979 cmdGet := &cmdline.Command{
Suharsh Sivakumar32c8e752015-03-31 19:26:28 -0700980 Name: "get",
981 Short: "Read the principal's blessings.",
982 Long: `
983Commands to inspect the blessings of the principal.
984
985All blessings are printed to stdout using base64-VOM-encoding.
986`,
Todd Wang9560b9c2015-05-11 13:27:58 -0700987 Children: []*cmdline.Command{cmdGetDefault, cmdGetForPeer, cmdGetPublicKey, cmdGetTrustedRoots, cmdGetPeerMap},
Ankurcf6a89f2014-10-06 18:33:03 -0700988 }
Ankurcf6a89f2014-10-06 18:33:03 -0700989
Todd Wang9560b9c2015-05-11 13:27:58 -0700990 root := &cmdline.Command{
Ankurcf6a89f2014-10-06 18:33:03 -0700991 Name: "principal",
Todd Wang6ed3b6c2015-04-08 14:37:04 -0700992 Short: "creates and manages Vanadium principals and blessings",
Ankurcf6a89f2014-10-06 18:33:03 -0700993 Long: `
Todd Wang6ed3b6c2015-04-08 14:37:04 -0700994Command principal creates and manages Vanadium principals and blessings.
Ankurcf6a89f2014-10-06 18:33:03 -0700995
996All objects are printed using base64-VOM-encoding.
997`,
Todd Wang9560b9c2015-05-11 13:27:58 -0700998 Children: []*cmdline.Command{cmdCreate, cmdFork, cmdSeekBlessings, cmdRecvBlessings, cmdDump, cmdDumpBlessings, cmdBlessSelf, cmdBless, cmdSet, cmdGet, cmdRecognize},
Matt Rosencrantz92303e12015-01-21 09:02:42 -0800999 }
Todd Wang9560b9c2015-05-11 13:27:58 -07001000 cmdline.Main(root)
Ankurcf6a89f2014-10-06 18:33:03 -07001001}
1002
Ankurcf6a89f2014-10-06 18:33:03 -07001003func decodeBlessings(fname string) (security.Blessings, error) {
Asim Shankarb07ec692015-02-27 23:40:44 -08001004 var b security.Blessings
1005 err := decode(fname, &b)
1006 return b, err
Ankurcf6a89f2014-10-06 18:33:03 -07001007}
1008
1009func dumpBlessings(blessings security.Blessings) error {
Asim Shankar2bf7b1e2015-02-27 00:45:12 -08001010 if blessings.IsZero() {
1011 return fmt.Errorf("no blessings found")
Ankurcf6a89f2014-10-06 18:33:03 -07001012 }
Asim Shankarb07ec692015-02-27 23:40:44 -08001013 str, err := base64VomEncode(blessings)
Ankurcf6a89f2014-10-06 18:33:03 -07001014 if err != nil {
1015 return fmt.Errorf("base64-VOM encoding failed: %v", err)
1016 }
1017 fmt.Println(str)
1018 return nil
1019}
1020
Suharsh Sivakumar4bbe8ed2015-04-09 14:21:44 -07001021func printBlessingsInfo(blessings security.Blessings) error {
1022 if blessings.IsZero() {
1023 return fmt.Errorf("no blessings found")
1024 }
Suharsh Sivakumar2b22fc12015-04-15 19:38:04 -07001025 if flagBlessingsNames {
1026 fmt.Println(strings.Replace(fmt.Sprint(blessings), ",", "\n", -1))
Suharsh Sivakumar4bbe8ed2015-04-09 14:21:44 -07001027 return nil
Suharsh Sivakumar2b22fc12015-04-15 19:38:04 -07001028 } else if len(flagBlessingsRootKey) > 0 {
1029 chain, err := getChainByName(blessings, flagBlessingsRootKey)
Suharsh Sivakumar4bbe8ed2015-04-09 14:21:44 -07001030 if err != nil {
1031 return err
1032 }
Suharsh Sivakumar2b22fc12015-04-15 19:38:04 -07001033 fmt.Println(rootkey(chain))
1034 return nil
1035 } else if len(flagBlessingsCaveats) > 0 {
1036 chain, err := getChainByName(blessings, flagBlessingsCaveats)
1037 if err != nil {
1038 return err
1039 }
1040 cavs, err := prettyPrintCaveats(chain)
1041 if err != nil {
1042 return err
1043 }
1044 for _, c := range cavs {
1045 fmt.Println(c)
1046 }
Suharsh Sivakumar4bbe8ed2015-04-09 14:21:44 -07001047 return nil
1048 }
1049 return dumpBlessings(blessings)
1050}
1051
Suharsh Sivakumar2b22fc12015-04-15 19:38:04 -07001052func prettyPrintCaveats(chain []security.Certificate) ([]string, error) {
1053 var cavs []security.Caveat
1054 for _, cert := range chain {
1055 cavs = append(cavs, cert.Caveats...)
1056 }
1057 var s []string
1058 for _, cav := range cavs {
Suharsh Sivakumar60b78e92015-04-23 21:36:49 -07001059 if cav.Id == security.PublicKeyThirdPartyCaveat.Id {
Suharsh Sivakumar2b22fc12015-04-15 19:38:04 -07001060 c := cav.ThirdPartyDetails()
1061 s = append(s, fmt.Sprintf("ThirdPartyCaveat: Requires discharge from %v (ID=%q)", c.Location(), c.ID()))
1062 continue
1063 }
1064 var param interface{}
1065 if err := vom.Decode(cav.ParamVom, &param); err != nil {
1066 return nil, err
1067 }
1068 switch cav.Id {
1069 case security.ConstCaveat.Id:
1070 // In the case a ConstCaveat is specified, we only want to print it
1071 // if it never validates.
1072 if !param.(bool) {
1073 s = append(s, fmt.Sprintf("Never validates"))
1074 }
Suharsh Sivakumar60b78e92015-04-23 21:36:49 -07001075 case security.ExpiryCaveat.Id:
Suharsh Sivakumar2b22fc12015-04-15 19:38:04 -07001076 s = append(s, fmt.Sprintf("Expires at %v", param))
Suharsh Sivakumar60b78e92015-04-23 21:36:49 -07001077 case security.MethodCaveat.Id:
Suharsh Sivakumar2b22fc12015-04-15 19:38:04 -07001078 s = append(s, fmt.Sprintf("Restricted to methods %v", param))
1079 case security.PeerBlessingsCaveat.Id:
1080 s = append(s, fmt.Sprintf("Restricted to peers with blessings %v", param))
1081 default:
1082 s = append(s, cav.String())
1083 }
1084 }
1085 return s, nil
1086}
1087
1088func getChainByName(b security.Blessings, name string) ([]security.Certificate, error) {
1089 wire, err := blessings2wire(b)
1090 if err != nil {
1091 return nil, err
1092 }
1093 for _, chain := range wire.CertificateChains {
1094 if chainName(chain) == name {
1095 return chain, nil
1096 }
1097 }
1098 return nil, fmt.Errorf("no chains of name %v in %v", name, b)
1099}
1100
Ankurcf6a89f2014-10-06 18:33:03 -07001101func read(fname string) (string, error) {
1102 if len(fname) == 0 {
1103 return "", nil
1104 }
1105 f := os.Stdin
1106 if fname != "-" {
1107 var err error
1108 if f, err = os.Open(fname); err != nil {
1109 return "", fmt.Errorf("failed to open %q: %v", fname, err)
1110 }
1111 }
1112 defer f.Close()
1113 var buf bytes.Buffer
1114 if _, err := io.Copy(&buf, f); err != nil {
1115 return "", fmt.Errorf("failed to read %q: %v", fname, err)
1116 }
1117 return buf.String(), nil
1118}
1119
1120func decode(fname string, val interface{}) error {
1121 str, err := read(fname)
1122 if err != nil {
1123 return err
1124 }
Asim Shankarb3a82ba2014-10-29 11:41:27 -07001125 if err := base64VomDecode(str, val); err != nil || val == nil {
Ankurcf6a89f2014-10-06 18:33:03 -07001126 return fmt.Errorf("failed to decode %q: %v", fname, err)
1127 }
1128 return nil
1129}
1130
1131func defaultBlessingName() string {
1132 var name string
1133 if user, _ := user.Current(); user != nil && len(user.Username) > 0 {
1134 name = user.Username
1135 } else {
1136 name = "anonymous"
1137 }
1138 if host, _ := os.Hostname(); len(host) > 0 {
1139 name = name + "@" + host
1140 }
1141 return name
1142}
Asim Shankardf88a2e2014-10-21 17:20:28 -07001143
1144func rootkey(chain []security.Certificate) string {
1145 if len(chain) == 0 {
1146 return "<empty certificate chain>"
1147 }
1148 key, err := security.UnmarshalPublicKey(chain[0].PublicKey)
1149 if err != nil {
1150 return fmt.Sprintf("<invalid PublicKey: %v>", err)
1151 }
1152 return fmt.Sprintf("%v", key)
1153}
Asim Shankarb3a82ba2014-10-29 11:41:27 -07001154
Suharsh Sivakumar2b22fc12015-04-15 19:38:04 -07001155func chainName(chain []security.Certificate) string {
1156 exts := make([]string, len(chain))
1157 for i, cert := range chain {
1158 exts[i] = cert.Extension
1159 }
1160 return strings.Join(exts, security.ChainSeparator)
1161}
1162
Asim Shankarb3a82ba2014-10-29 11:41:27 -07001163func base64VomEncode(i interface{}) (string, error) {
1164 buf := &bytes.Buffer{}
1165 closer := base64.NewEncoder(base64.URLEncoding, buf)
Jungho Ahn5d1fe972015-04-27 17:51:32 -07001166 enc := vom.NewEncoder(closer)
Suharsh Sivakumar12b089d2015-01-02 14:17:12 -08001167 if err := enc.Encode(i); err != nil {
Asim Shankarb3a82ba2014-10-29 11:41:27 -07001168 return "", err
1169 }
1170 // Must close the base64 encoder to flush out any partially written
1171 // blocks.
1172 if err := closer.Close(); err != nil {
1173 return "", err
1174 }
1175 return buf.String(), nil
1176}
1177
1178func base64VomDecode(s string, i interface{}) error {
1179 b, err := base64.URLEncoding.DecodeString(s)
1180 if err != nil {
1181 return err
1182 }
Jungho Ahn5d1fe972015-04-27 17:51:32 -07001183 dec := vom.NewDecoder(bytes.NewBuffer(b))
Suharsh Sivakumar12b089d2015-01-02 14:17:12 -08001184 return dec.Decode(i)
Asim Shankarb3a82ba2014-10-29 11:41:27 -07001185}
Asim Shankarf11b1bc2014-11-12 17:18:45 -08001186
1187type recvBlessingsService struct {
1188 principal security.Principal
1189 notify chan error
1190 token string
1191}
1192
Todd Wang54feabe2015-04-15 23:38:26 -07001193func (r *recvBlessingsService) Grant(_ *context.T, call rpc.ServerCall, token string) error {
Suharsh Sivakumar380bf342015-02-27 15:38:27 -08001194 b := call.GrantedBlessings()
Asim Shankar2bf7b1e2015-02-27 00:45:12 -08001195 if b.IsZero() {
Asim Shankarf11b1bc2014-11-12 17:18:45 -08001196 return fmt.Errorf("no blessings granted by sender")
1197 }
1198 if len(token) != len(r.token) {
1199 // A timing attack can be used to figure out the length
1200 // of the token, but then again, so can looking at the
1201 // source code. So, it's okay.
1202 return fmt.Errorf("blessings received from unexpected sender")
1203 }
1204 if subtle.ConstantTimeCompare([]byte(token), []byte(r.token)) != 1 {
1205 return fmt.Errorf("blessings received from unexpected sender")
1206 }
Ankure548f392014-12-08 18:42:41 -08001207 if flagRecvBlessingsSetDefault {
1208 if err := r.principal.BlessingStore().SetDefault(b); err != nil {
1209 return fmt.Errorf("failed to set blessings %v as default: %v", b, err)
1210 }
Asim Shankarf11b1bc2014-11-12 17:18:45 -08001211 }
Ankure548f392014-12-08 18:42:41 -08001212 if pattern := security.BlessingPattern(flagRecvBlessingsForPeer); len(pattern) > 0 {
1213 if _, err := r.principal.BlessingStore().Set(b, pattern); err != nil {
1214 return fmt.Errorf("failed to set blessings %v for peers %v: %v", b, pattern, err)
1215 }
Asim Shankarf11b1bc2014-11-12 17:18:45 -08001216 }
1217 if flagAddToRoots {
1218 if err := r.principal.AddToRoots(b); err != nil {
1219 return fmt.Errorf("failed to add blessings to recognized roots: %v", err)
1220 }
1221 }
1222 fmt.Println("Received blessings:", b)
1223 r.notify <- nil
1224 return nil
1225}
1226
Asim Shankarf11b1bc2014-11-12 17:18:45 -08001227type granter struct {
Asim Shankarf11b1bc2014-11-12 17:18:45 -08001228 with security.Blessings
1229 extension string
1230 caveats []security.Caveat
1231 serverKey string
1232}
1233
Todd Wang4264e4b2015-04-16 22:43:40 -07001234func (g *granter) Grant(ctx *context.T, call security.Call) (security.Blessings, error) {
Ankurdda16492015-04-07 12:35:42 -07001235 server := call.RemoteBlessings()
1236 p := call.LocalPrincipal()
Asim Shankarf11b1bc2014-11-12 17:18:45 -08001237 if got := fmt.Sprintf("%v", server.PublicKey()); got != g.serverKey {
Matt Rosencrantz94502cf2015-03-18 09:43:44 -07001238 // If the granter returns an error, the RPC framework should
Asim Shankarf11b1bc2014-11-12 17:18:45 -08001239 // abort the RPC before sending the request to the server.
1240 // Thus, there is no concern about leaking the token to an
1241 // imposter server.
Asim Shankar2bf7b1e2015-02-27 00:45:12 -08001242 return security.Blessings{}, fmt.Errorf("key mismatch: Remote end has public key %v, want %v", got, g.serverKey)
Asim Shankarf11b1bc2014-11-12 17:18:45 -08001243 }
Ankurdda16492015-04-07 12:35:42 -07001244 return p.Bless(server.PublicKey(), g.with, g.extension, g.caveats[0], g.caveats[1:]...)
Asim Shankarf11b1bc2014-11-12 17:18:45 -08001245}
Matt Rosencrantz94502cf2015-03-18 09:43:44 -07001246func (*granter) RPCCallOpt() {}
Asim Shankarf11b1bc2014-11-12 17:18:45 -08001247
Suharsh Sivakumarab21eb02015-04-01 12:58:20 -07001248func blessOverNetwork(ctx *context.T, object string, granter *granter, remoteToken string) error {
Jiri Simsa6ac95222015-02-23 16:11:49 -08001249 client := v23.GetClient(ctx)
Asim Shankar263c73b2015-03-19 18:31:26 -07001250 // The receiver is being authorized based on the hash of its public key
1251 // (see Grant), so it should be fine to ignore the blessing names in the endpoint
1252 // (which are likely to not be recognized by the sender anyway).
1253 //
1254 // At worst, there is a privacy leak of the senders intent to send some
1255 // blessings. That could be addressed by making the full public key of
1256 // the recipeint available to the sender and using
1257 // options.ServerPublicKey instead of providing a "hash" of the
1258 // recipients public key and verifying in the Granter implementation.
Suharsh Sivakumar1abd5a82015-04-10 00:24:14 -07001259 if err := client.Call(ctx, object, "Grant", []interface{}{remoteToken}, nil, granter, options.SkipServerEndpointAuthorization{}); err != nil {
1260 return fmt.Errorf("failed to make RPC to %q: %v", object, err)
Asim Shankarf11b1bc2014-11-12 17:18:45 -08001261 }
Todd Wange77f9952015-02-18 13:20:50 -08001262 return nil
Asim Shankarf11b1bc2014-11-12 17:18:45 -08001263}
Asim Shankara0bba462015-02-20 22:50:51 -08001264
1265func caveatsFromFlags(expiry time.Duration, caveatsFlag *caveatsFlag) ([]security.Caveat, error) {
1266 caveats, err := caveatsFlag.Compile()
1267 if err != nil {
1268 return nil, fmt.Errorf("failed to parse caveats: %v", err)
1269 }
Suharsh Sivakumar7e80c862015-05-11 15:33:55 -07001270 if expiry != 0 {
Suharsh Sivakumar60b78e92015-04-23 21:36:49 -07001271 ecav, err := security.NewExpiryCaveat(time.Now().Add(expiry))
Asim Shankara0bba462015-02-20 22:50:51 -08001272 if err != nil {
1273 return nil, fmt.Errorf("failed to create expiration caveat: %v", err)
1274 }
1275 caveats = append(caveats, ecav)
1276 }
1277 return caveats, nil
1278}
Asim Shankarb07ec692015-02-27 23:40:44 -08001279
1280// Circuitous route to get to the certificate chains.
1281// See comments on why security.MarshalBlessings is discouraged.
1282// Though, a better alternative is worth looking into.
1283func blessings2wire(b security.Blessings) (security.WireBlessings, error) {
1284 var wire security.WireBlessings
1285 data, err := vom.Encode(b)
1286 if err != nil {
1287 return wire, err
1288 }
1289 err = vom.Decode(data, &wire)
1290 return wire, err
1291}