| // Copyright 2015 The Vanadium 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 security defines types and utilities associated with security. |
| // |
| // Concept: https://github.com/vanadium/docs/blob/master/concepts/security.md |
| // Tutorial: (forthcoming) |
| // |
| // The primitives and APIs defined in this package enable bi-directional, |
| // end-to-end authentication between communicating parties; authorization based |
| // on that authentication; and secrecy and integrity of all communication. |
| // |
| // Overview |
| // |
| // The Vanadium security model is centered around the concepts of principals |
| // and blessings. |
| // |
| // A principal in the Vanadium framework is a public and private key pair. |
| // Every RPC is executed on behalf of a principal. |
| // |
| // A blessing is a binding of a human-readable name to a principal, valid under |
| // some caveats, given by another principal. A principal can have multiple |
| // blessings bound to it. For instance, a television principal may have a |
| // blessing from the manufacturer (e.g., popularcorp:products:tv) as well as |
| // from the owner (e.g., alice:devices:hometv). Principals are authorized for |
| // operations based on the blessings bound to them. |
| // |
| // A principal can "bless" another principal by binding an extension of one of |
| // its own blessings to the other principal. This enables delegation of |
| // authority. For example, a principal with the blessing |
| // "johndoe" can delegate to his phone by blessing the phone as |
| // "johndoe:phone", which in-turn can delegate to the headset by blessing it as |
| // "johndoe:phone:headset". |
| // |
| // Caveats can be added to a blessing in order to restrict the contexts in which |
| // it can be used. Amongst other things, caveats can restrict the duration of use and |
| // the set of peers that can be communicated with using a blessing. |
| // |
| // Navigating the interfaces |
| // |
| // Godoc renders all interfaces in this package in alphabetical order. |
| // However, we recommend the following order in order to introduce yourself to |
| // the API: |
| // |
| // * Principal |
| // * Blessings |
| // * BlessingStore |
| // * BlessingRoots |
| // * NewCaveat |
| // * ThirdPartyCaveat |
| // * NewPublicKeyCaveat |
| // |
| // Examples |
| // |
| // A principal can decide to name itself anything it wants: |
| // // (in process A) |
| // var p1 Principal |
| // alice, _ := p1.BlessSelf("alice") |
| // |
| // This "alice" blessing can be presented to to another principal (typically a |
| // remote process), but that other principal will not recognize this |
| // "self-proclaimed" authority: |
| // // (in process B) |
| // var p2 Principal |
| // ctx, call := GetContextAndCall() // current context and security state |
| // names, rejected := RemoteBlessingNames(ctx, call) |
| // fmt.Printf("%v %v", names, rejected) // Will print [] ["alice": "..."] |
| // |
| // However, p2 can decide to trust the roots of the "alice" blessing and then it |
| // will be able to recognize her delegates as well: |
| // // (in process B) |
| // AddToRoots(p2, call.RemoteBlessings()) |
| // names, rejected := RemoteBlessingNames(ctx, call) |
| // fmt.Printf("%v %v", names, rejected) // Will print ["alice"] [] |
| // |
| // Furthermore, p2 can seek a blessing from "alice": |
| // // (in process A) |
| // call := GetCall() // Call under which p2 is seeking a blessing from alice, call.LocalPrincipal = p1 |
| // key2 := call.RemoteBlessings().PublicKey() |
| // onlyFor10Minutes := NewExpiryCaveat(time.Now().Add(10*time.Minute)) |
| // aliceFriend, _ := p1.Bless(key2, alice, "friend", onlyFor10Minutes) |
| // SendBlessingToProcessB(aliceFriend) |
| // |
| // p2 can then add this blessing to its store such that this blessing will be |
| // presented to "alice" (and her delegates) anytime p2 communicates with it in |
| // the future: |
| // // (in process B) |
| // p2.BlessingStore().Set(aliceFriend, "alice") |
| // |
| // p2 can also choose to present multiple blessings to some servers: |
| // // (in process B) |
| // charlieFriend := ReceiveBlessingFromSomeWhere() |
| // union, _ := UnionOfBlessings(aliceFriend, charlieFriend) |
| // p2.BlessingStore().Set(union, "alice:mom") |
| // |
| // Thus, when communicating with a "server" that presents the blessing "alice:mom", |
| // p2 will declare that he is both "alice's friend" and "charlie's friend" and |
| // the server may authorize actions based on this fact. |
| // |
| // p2 may also choose that it wants to present these two blessings when acting |
| // as a "server", (i.e., when it does not know who the peer is): |
| // // (in process B) |
| // default, _ := UnionOfBlessings(aliceFriend, charlieFriend) |
| // p2.BlessingStore().SetDefault(default) |
| package security |
| |
| import ( |
| "time" |
| |
| "v.io/v23/context" |
| "v.io/v23/naming" |
| "v.io/v23/vdl" |
| ) |
| |
| // Principal represents an entity capable of making or receiving RPCs. |
| // Principals have a unique (public, private) key pair, have (zero or more) |
| // blessings bound to them and can bless other principals. |
| // |
| // Multiple goroutines may invoke methods on a Principal simultaneously. |
| // |
| // See also: https://github.com/vanadium/docs/blob/master/glossary.md#principal |
| type Principal interface { |
| // Bless binds extensions of blessings held by this principal to |
| // another principal (represented by its public key). |
| // |
| // For example, a principal with the blessings "google:alice" |
| // and "v23:alice" can bind the blessings "google:alice:friend" |
| // and "v23:alice:friend" to another principal using: |
| // Bless(<other principal>, <google:alice, v23:alice>, "friend", ...) |
| // |
| // To discourage unconstrained delegation of authority, the interface |
| // requires at least one caveat to be provided. If unconstrained delegation |
| // is desired, the UnconstrainedUse function can be used to produce |
| // this argument. |
| // |
| // with.PublicKey must be the same as the principal's public key. |
| Bless(key PublicKey, with Blessings, extension string, caveat Caveat, additionalCaveats ...Caveat) (Blessings, error) |
| |
| // BlessSelf creates a blessing with the provided name for this principal. |
| BlessSelf(name string, caveats ...Caveat) (Blessings, error) |
| |
| // Sign uses the private key of the principal to sign message. |
| Sign(message []byte) (Signature, error) |
| |
| // MintDischarge generates a discharge for 'tp'. |
| // |
| // It assumes that it is okay to generate a discharge, i.e., any |
| // restrictions encoded within 'tp' are satisfied. |
| // |
| // The returned discharge will be usable only if the provided caveats |
| // are met when using the discharge. |
| MintDischarge(forThirdPartyCaveat, caveatOnDischarge Caveat, additionalCaveatsOnDischarge ...Caveat) (Discharge, error) |
| |
| // PublicKey returns the public key counterpart of the private key held |
| // by the Principal. |
| PublicKey() PublicKey |
| |
| // BlessingStore provides access to the BlessingStore containing blessings |
| // that have been granted to this principal. |
| BlessingStore() BlessingStore |
| |
| // Roots returns the set of recognized authorities (identified by their |
| // public keys) on blessings that match specific patterns |
| Roots() BlessingRoots |
| } |
| |
| // BlessingStore is the interface for storing blessings bound to a |
| // principal and managing the subset of blessings to be presented to |
| // particular peers. |
| // BlessingStore implementations may also cache Discharges for third-party caveats |
| // on blessings, allowing unexpired Discharges to be reused. |
| type BlessingStore interface { |
| // Set marks the set of blessings to be shared with peers. |
| // |
| // Set(b, pattern) marks the intention to reveal b to peers |
| // who present blessings of their own matching pattern. |
| // |
| // If multiple calls to Set are made with the same pattern, the |
| // last call prevails. |
| // |
| // Set(Blessings{}, pattern) can be used to remove the blessings |
| // previously associated with the pattern (by a prior call to Set). |
| // |
| // It is an error to call Set with "blessings" whose public key does |
| // not match the PublicKey of the principal for which this store hosts |
| // blessings. |
| // |
| // Set returns the Blessings object which was previously associated |
| // with the pattern. |
| Set(blessings Blessings, forPeers BlessingPattern) (Blessings, error) |
| |
| // ForPeer returns the set of blessings that have been previously |
| // added to the store with an intent of being shared with peers |
| // that have at least one of the provided blessings. |
| // |
| // If no peerBlessings are provided then blessings marked for all peers |
| // (i.e., added with the AllPrincipals pattern) is returned. |
| // |
| // Returns the zero value if there are no matching blessings in the store. |
| ForPeer(peerBlessings ...string) Blessings |
| |
| // SetDefault sets up the Blessings made available on a subsequent call |
| // to Default. |
| // |
| // It is an error to call SetDefault with a blessings whose public key |
| // does not match the PublicKey of the principal for which this store |
| // hosts blessings. |
| SetDefault(blessings Blessings) error |
| |
| // Default returns the blessings to be shared with peers for which |
| // no other information is available in order to select blessings |
| // from the store. |
| // |
| // For example, Default can be used by servers to identify themselves |
| // to clients before the client has identified itself. |
| // |
| // Default returns the blessings provided to the last call to |
| // SetDefault. |
| // |
| // Returns the zero value if there is no usable blessings. |
| Default() Blessings |
| |
| // PublicKey returns the public key of the Principal for which |
| // this store hosts blessings. |
| PublicKey() PublicKey |
| |
| // PeerBlessings returns all the blessings that the BlessingStore |
| // currently holds for various peers. |
| PeerBlessings() map[BlessingPattern]Blessings |
| |
| // CacheDischarge inserts the discharge for the provided impetus and caveat into the cache. |
| CacheDischarge(discharge Discharge, caveat Caveat, impetus DischargeImpetus) |
| |
| // ClearDischarges clears the input discharges from the BlessingStore's |
| // discharge cache. |
| ClearDischarges(discharges ...Discharge) |
| |
| // Discharge takes a caveat and DischargeImpetus and returns a cached discharge |
| // and the time at which it was cached. Zero values are returned if no |
| // corresponding cached discharge can be found. Note that in certain upgrade |
| // situations a zero cacheTime may be returned if the real cache time cannot |
| // be determined. |
| Discharge(caveat Caveat, impetus DischargeImpetus) (discharge Discharge, cacheTime time.Time) |
| |
| // DebugString return a human-readable string description of the store. |
| // This description is detailed and lists out the contents of the store. |
| // Use fmt.Sprintf("%v", ...) for a more succinct description. |
| DebugString() string |
| } |
| |
| // BlessingRoots hosts the set of authoritative public keys for roots |
| // of blessings. |
| // |
| // See also: https://github.com/vanadium/docs/blob/master/glossary.md#blessing-root |
| type BlessingRoots interface { |
| // Add marks 'root' (a DER-encoded public key) as an authoritative key |
| // for blessings that match 'pattern'. |
| // |
| // Multiple keys can be added for the same pattern, in which |
| // case all those keys are considered authoritative for |
| // blessings that match the pattern. |
| Add(root []byte, pattern BlessingPattern) error |
| |
| // Recognized returns nil iff the provided (DER-encoded) root public |
| // key as an authority on a pattern that is matched by blessing. |
| Recognized(root []byte, blessing string) error |
| |
| // Dump returns the set of recognized roots as a map from |
| // blessing patterns to the set of authoritative keys for that |
| // pattern. |
| Dump() map[BlessingPattern][]PublicKey |
| |
| // DebugString returns a human-readable string description of the roots. |
| // This description is detailed and lists out all the roots. Use |
| // fmt.Sprintf("%v", ...) for a more succinct description. |
| DebugString() string |
| } |
| |
| // Signer is the interface for signing arbitrary length messages using private keys. |
| // |
| // Multiple goroutines may invoke methods on a Signer simultaneously. |
| type Signer interface { |
| // Sign signs an arbitrary length message using the private key associated |
| // with this Signer. |
| // |
| // The provided purpose is used to avoid "type attacks", wherein an honest |
| // entity is cheated into interpreting a field in a message as one with a |
| // type other than the intended one. |
| Sign(purpose, message []byte) (Signature, error) |
| |
| // PublicKey returns the public key corresponding to the Signer's private key. |
| PublicKey() PublicKey |
| } |
| |
| // ThirdPartyCaveat is a restriction on the applicability of a blessing that is |
| // considered satisfied only when accompanied with a specific "discharge" from |
| // the third-party specified in the caveat. (The first two parties are the ones |
| // presenting a blessing and the one making authorization decisions based on |
| // the blessing presented). |
| // |
| // Multiple goroutines may invoke methods on a ThirdPartyCaveat simultaneously. |
| // |
| // See also: https://github.com/vanadium/docs/blob/master/glossary.md#third-party-caveat |
| type ThirdPartyCaveat interface { |
| // ID returns a cryptographically unique identifier for the ThirdPartCaveat. |
| ID() string |
| |
| // Location returns the Vanadium object name of the discharging third-party. |
| Location() string |
| |
| // Requirements lists the information that the third-party requires |
| // in order to issue a discharge. |
| Requirements() ThirdPartyRequirements |
| |
| // Dischargeable validates all restrictions encoded within the third-party |
| // caveat under the current call and returns nil iff they have been satisfied, |
| // and thus ensures that it is okay to generate a discharge for this |
| // ThirdPartyCaveat. |
| // |
| // It assumes that the ThirdPartCaveat was obtained from the remote end of |
| // call. |
| Dischargeable(ctx *context.T, call Call) error |
| } |
| |
| // Call defines the state available for authorizing a principal. |
| type Call interface { |
| // Timestamp returns the time at which the authorization state is to be checked. |
| Timestamp() time.Time |
| // Method returns the method being invoked. |
| Method() string |
| // MethodTags returns the tags attached to the method, typically through the |
| // interface specification in VDL. |
| MethodTags() []*vdl.Value |
| // Suffix returns the object name suffix for the request. |
| Suffix() string |
| // LocalDischarges specify discharges for third-party caveats presented by |
| // the local end of the call. It maps a third-party caveat identifier to the |
| // corresponding discharge. |
| LocalDischarges() map[string]Discharge |
| // RemoteDischarges specify discharges for third-party caveats presented by |
| // the remote end of the call. It maps a third-party caveat identifier to the |
| // corresponding discharge. |
| RemoteDischarges() map[string]Discharge |
| // LocalPrincipal returns the principal used to authenticate to the remote end. |
| LocalPrincipal() Principal |
| // LocalBlessings returns the blessings (bound to the local end) |
| // provided to the remote end for authentication. |
| LocalBlessings() Blessings |
| // RemoteBlessings returns the blessings (bound to the remote end) |
| // provided to the local end during authentication. |
| RemoteBlessings() Blessings |
| // LocalEndpoint() returns the Endpoint of the principal at the local |
| // end of communication. |
| LocalEndpoint() naming.Endpoint |
| // RemoteEndpoint() returns the Endpoint of the principal at the remote end |
| // of communication. |
| RemoteEndpoint() naming.Endpoint |
| } |
| |
| // Authorizer is the interface for performing authorization checks. |
| type Authorizer interface { |
| Authorize(ctx *context.T, call Call) error |
| } |