blob: 0ae070f6d11f583650b0275f0faf192f6ccf9408 [file] [log] [blame]
Tilak Sharmad6ade0e2014-08-20 16:28:32 -07001package security
2
3import (
Ankurf044a8d2014-09-05 17:05:24 -07004 "bytes"
Ankur021e38e2014-09-26 10:26:45 -07005 "crypto/ecdsa"
Suharsh Sivakumar0f359042014-10-01 22:53:45 -07006 "crypto/rand"
Ankur021e38e2014-09-26 10:26:45 -07007 "crypto/x509"
Tilak Sharmad6ade0e2014-08-20 16:28:32 -07008 "encoding/base64"
9 "encoding/json"
Ankur021e38e2014-09-26 10:26:45 -070010 "encoding/pem"
11 "errors"
Ankurf044a8d2014-09-05 17:05:24 -070012 "fmt"
Tilak Sharmad6ade0e2014-08-20 16:28:32 -070013 "io"
Ankur021e38e2014-09-26 10:26:45 -070014 "io/ioutil"
Tilak Sharmad6ade0e2014-08-20 16:28:32 -070015
Jiri Simsa519c5072014-09-17 21:37:57 -070016 "veyron.io/veyron/veyron2/security"
17 "veyron.io/veyron/veyron2/vom"
Tilak Sharmad6ade0e2014-08-20 16:28:32 -070018)
19
Ankur021e38e2014-09-26 10:26:45 -070020const ecPrivateKeyPEMType = "EC PRIVATE KEY"
21
Tilak Sharmad6ade0e2014-08-20 16:28:32 -070022var nullACL security.ACL
23
Gautham82bb9952014-08-28 14:11:51 -070024// OpenACL creates an ACL that grants access to all principals.
25func OpenACL() security.ACL {
26 acl := security.ACL{}
27 acl.In = map[security.BlessingPattern]security.LabelSet{security.AllPrincipals: security.AllLabels}
28 return acl
29}
30
Suharsh Sivakumar0f359042014-10-01 22:53:45 -070031// LoadPEMKey loads a key from 'r', assuming that it was saved using SavePEMKey
32// and the specified passphrase 'passphrase'.
33// If passphrase is nil, the key will still be encrypted with a random salt, but
34// this will offer no protection as the salt is stored with the PEMKey.
35func LoadPEMKey(r io.Reader, passphrase []byte) (interface{}, error) {
Ankur021e38e2014-09-26 10:26:45 -070036 pemKeyBytes, err := ioutil.ReadAll(r)
37 if err != nil {
38 return nil, err
39 }
40
41 pemKey, _ := pem.Decode(pemKeyBytes)
42 if pemKey == nil {
43 return nil, errors.New("no PEM key block read")
44 }
45
Suharsh Sivakumar0f359042014-10-01 22:53:45 -070046 data, err := x509.DecryptPEMBlock(pemKey, passphrase)
47 if err != nil {
48 return nil, err
49 }
50
Ankur021e38e2014-09-26 10:26:45 -070051 switch pemKey.Type {
52 case ecPrivateKeyPEMType:
Suharsh Sivakumar0f359042014-10-01 22:53:45 -070053 return x509.ParseECPrivateKey(data)
Ankur021e38e2014-09-26 10:26:45 -070054 }
55 return nil, fmt.Errorf("PEM key block has an unrecognized type: %v", pemKey.Type)
56}
57
Suharsh Sivakumar0f359042014-10-01 22:53:45 -070058// SavePEMKey marshals 'key', encrypts it using 'passphrase', and saves the bytes to 'w' in PEM format.
Ankur021e38e2014-09-26 10:26:45 -070059//
60// For example, if key is an ECDSA private key, it will be marshaled
Suharsh Sivakumar0f359042014-10-01 22:53:45 -070061// in ASN.1, DER format, encrypted, and then written in a PEM block.
62func SavePEMKey(w io.Writer, key interface{}, passphrase []byte) error {
63 var data []byte
Ankur021e38e2014-09-26 10:26:45 -070064 switch k := key.(type) {
65 case *ecdsa.PrivateKey:
66 var err error
Suharsh Sivakumar0f359042014-10-01 22:53:45 -070067 if data, err = x509.MarshalECPrivateKey(k); err != nil {
Ankur021e38e2014-09-26 10:26:45 -070068 return err
69 }
70 default:
71 return fmt.Errorf("key of type %T cannot be saved", k)
72 }
Suharsh Sivakumar0f359042014-10-01 22:53:45 -070073
74 pemKey, err := x509.EncryptPEMBlock(rand.Reader, ecPrivateKeyPEMType, data, passphrase, x509.PEMCipherAES256)
75 if err != nil {
76 return fmt.Errorf("failed to encrypt pem block: %v", err)
77 }
78
Ankur021e38e2014-09-26 10:26:45 -070079 return pem.Encode(w, pemKey)
80}
81
Tilak Sharmad6ade0e2014-08-20 16:28:32 -070082// LoadIdentity reads a PrivateID from r, assuming that it was written using
83// SaveIdentity.
Asim Shankar45c89552014-09-18 10:58:10 -070084//
85// TODO(ashankar): The extra arguments is a hack that is needed to keep identities
86// generated before the "veyron.io" code move working with binaries built after.
87// This hack should go away when we make the backward-incompatible change to the
88// new security API anyway.
89func LoadIdentity(r io.Reader, hack ...security.PrivateID) (security.PrivateID, error) {
Tilak Sharmad6ade0e2014-08-20 16:28:32 -070090 var id security.PrivateID
Asim Shankar45c89552014-09-18 10:58:10 -070091 if len(hack) > 0 {
92 id = hack[0]
93 }
Tilak Sharmad6ade0e2014-08-20 16:28:32 -070094 if err := vom.NewDecoder(base64.NewDecoder(base64.URLEncoding, r)).Decode(&id); err != nil {
95 return nil, err
96 }
97 return id, nil
98}
99
100// SaveIdentity writes a serialized form of a PrivateID to w, which can be
101// recovered using LoadIdentity.
102func SaveIdentity(w io.Writer, id security.PrivateID) error {
103 closer := base64.NewEncoder(base64.URLEncoding, w)
104 if err := vom.NewEncoder(closer).Encode(id); err != nil {
105 return err
106 }
107 // Must close the base64 encoder to flush out any partially written blocks.
108 if err := closer.Close(); err != nil {
109 return err
110 }
111 return nil
112}
113
114// LoadACL reads an ACL from the provided Reader containing a JSON encoded ACL.
115func LoadACL(r io.Reader) (security.ACL, error) {
116 var acl security.ACL
117 if err := json.NewDecoder(r).Decode(&acl); err != nil {
118 return nullACL, err
119 }
120 return acl, nil
121}
122
123// SaveACL encodes an ACL in JSON format and writes it to the provided Writer.
124func SaveACL(w io.Writer, acl security.ACL) error {
125 return json.NewEncoder(w).Encode(acl)
126}
Ankurf044a8d2014-09-05 17:05:24 -0700127
Ankurf044a8d2014-09-05 17:05:24 -0700128// CaveatValidators returns the set of security.CaveatValidators
129// obtained by decoding the provided caveat bytes.
130//
131// It is an error if any of the provided caveat bytes cannot
132// be decoded into a security.CaveatValidator.
Asim Shankarbb0f0c12014-09-09 13:32:28 -0700133func CaveatValidators(caveats ...security.Caveat) ([]security.CaveatValidator, error) {
Ankurf044a8d2014-09-05 17:05:24 -0700134 if len(caveats) == 0 {
135 return nil, nil
136 }
137 validators := make([]security.CaveatValidator, len(caveats))
138 for i, c := range caveats {
139 var v security.CaveatValidator
Asim Shankarbb0f0c12014-09-09 13:32:28 -0700140 if err := vom.NewDecoder(bytes.NewReader(c.ValidatorVOM)).Decode(&v); err != nil {
Ankurf044a8d2014-09-05 17:05:24 -0700141 return nil, fmt.Errorf("caveat bytes could not be VOM-decoded: %s", err)
142 }
143 validators[i] = v
144 }
145 return validators, nil
146}
147
148// ThirdPartyCaveats returns the set of security.ThirdPartyCaveats
149// that could be successfully decoded from the provided caveat bytes.
Asim Shankarbb0f0c12014-09-09 13:32:28 -0700150func ThirdPartyCaveats(caveats ...security.Caveat) []security.ThirdPartyCaveat {
Ankurf044a8d2014-09-05 17:05:24 -0700151 var tpCaveats []security.ThirdPartyCaveat
152 for _, c := range caveats {
153 var t security.ThirdPartyCaveat
Asim Shankarbb0f0c12014-09-09 13:32:28 -0700154 if err := vom.NewDecoder(bytes.NewReader(c.ValidatorVOM)).Decode(&t); err != nil {
Ankurf044a8d2014-09-05 17:05:24 -0700155 continue
156 }
157 tpCaveats = append(tpCaveats, t)
158 }
159 return tpCaveats
160}