blob: 6e1f848f1c6e6f864c4c24c62f0894c4f2a6e4dc [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"
gauthamta134eda2014-11-05 17:57:42 -08006 "crypto/elliptic"
Suharsh Sivakumar0f359042014-10-01 22:53:45 -07007 "crypto/rand"
Ankur021e38e2014-09-26 10:26:45 -07008 "crypto/x509"
Tilak Sharmad6ade0e2014-08-20 16:28:32 -07009 "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 Sivakumar4684f4e2014-10-24 13:42:06 -070031var PassphraseErr = errors.New("passphrase incorrect for decrypting private key")
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070032
gauthamta134eda2014-11-05 17:57:42 -080033// NewPrincipalKey generates an ECDSA (public, private) key pair.
34func NewPrincipalKey() (security.PublicKey, *ecdsa.PrivateKey, error) {
35 priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
36 if err != nil {
37 return nil, nil, err
38 }
39 return security.NewECDSAPublicKey(&priv.PublicKey), priv, nil
40}
41
Ankur73e7a932014-10-24 15:57:03 -070042// LoadPEMKey loads a key from 'r'. returns PassphraseErr for incorrect Passphrase.
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070043// If the key held in 'r' is unencrypted, 'passphrase' will be ignored.
Ankur73e7a932014-10-24 15:57:03 -070044func LoadPEMKey(r io.Reader, passphrase []byte) (interface{}, error) {
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070045 pemBlockBytes, err := ioutil.ReadAll(r)
Ankur021e38e2014-09-26 10:26:45 -070046 if err != nil {
47 return nil, err
48 }
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070049 pemBlock, _ := pem.Decode(pemBlockBytes)
50 if pemBlock == nil {
Ankur021e38e2014-09-26 10:26:45 -070051 return nil, errors.New("no PEM key block read")
52 }
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070053 var data []byte
54 if x509.IsEncryptedPEMBlock(pemBlock) {
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070055 data, err = x509.DecryptPEMBlock(pemBlock, passphrase)
56 if err != nil {
Suharsh Sivakumar4684f4e2014-10-24 13:42:06 -070057 return nil, PassphraseErr
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070058 }
59 } else {
60 data = pemBlock.Bytes
Suharsh Sivakumar0f359042014-10-01 22:53:45 -070061 }
62
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070063 switch pemBlock.Type {
Ankur021e38e2014-09-26 10:26:45 -070064 case ecPrivateKeyPEMType:
Suharsh Sivakumar4684f4e2014-10-24 13:42:06 -070065 key, err := x509.ParseECPrivateKey(data)
66 if err != nil {
67 return nil, PassphraseErr
68 }
69 return key, nil
Ankur021e38e2014-09-26 10:26:45 -070070 }
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070071 return nil, fmt.Errorf("PEM key block has an unrecognized type: %v", pemBlock.Type)
Ankur021e38e2014-09-26 10:26:45 -070072}
73
Ankur73e7a932014-10-24 15:57:03 -070074// SavePEMKey marshals 'key', encrypts it using 'passphrase', and saves the bytes to 'w' in PEM format.
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070075// If passphrase is nil, the key will not be encrypted.
Ankur021e38e2014-09-26 10:26:45 -070076//
77// For example, if key is an ECDSA private key, it will be marshaled
Suharsh Sivakumar0f359042014-10-01 22:53:45 -070078// in ASN.1, DER format, encrypted, and then written in a PEM block.
Ankur73e7a932014-10-24 15:57:03 -070079func SavePEMKey(w io.Writer, key interface{}, passphrase []byte) error {
Suharsh Sivakumar0f359042014-10-01 22:53:45 -070080 var data []byte
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070081 var err error
Ankur021e38e2014-09-26 10:26:45 -070082 switch k := key.(type) {
83 case *ecdsa.PrivateKey:
Suharsh Sivakumar0f359042014-10-01 22:53:45 -070084 if data, err = x509.MarshalECPrivateKey(k); err != nil {
Ankur021e38e2014-09-26 10:26:45 -070085 return err
86 }
87 default:
88 return fmt.Errorf("key of type %T cannot be saved", k)
89 }
Suharsh Sivakumar0f359042014-10-01 22:53:45 -070090
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070091 var pemKey *pem.Block
92 if passphrase != nil {
93 pemKey, err = x509.EncryptPEMBlock(rand.Reader, ecPrivateKeyPEMType, data, passphrase, x509.PEMCipherAES256)
94 if err != nil {
95 return fmt.Errorf("failed to encrypt pem block: %v", err)
96 }
97 } else {
98 pemKey = &pem.Block{
99 Type: ecPrivateKeyPEMType,
100 Bytes: data,
101 }
Suharsh Sivakumar0f359042014-10-01 22:53:45 -0700102 }
103
Ankur021e38e2014-09-26 10:26:45 -0700104 return pem.Encode(w, pemKey)
105}
106
Tilak Sharmad6ade0e2014-08-20 16:28:32 -0700107// LoadACL reads an ACL from the provided Reader containing a JSON encoded ACL.
108func LoadACL(r io.Reader) (security.ACL, error) {
109 var acl security.ACL
110 if err := json.NewDecoder(r).Decode(&acl); err != nil {
111 return nullACL, err
112 }
113 return acl, nil
114}
115
116// SaveACL encodes an ACL in JSON format and writes it to the provided Writer.
117func SaveACL(w io.Writer, acl security.ACL) error {
118 return json.NewEncoder(w).Encode(acl)
119}
Ankurf044a8d2014-09-05 17:05:24 -0700120
Ankurf044a8d2014-09-05 17:05:24 -0700121// CaveatValidators returns the set of security.CaveatValidators
122// obtained by decoding the provided caveat bytes.
123//
124// It is an error if any of the provided caveat bytes cannot
125// be decoded into a security.CaveatValidator.
Asim Shankarbb0f0c12014-09-09 13:32:28 -0700126func CaveatValidators(caveats ...security.Caveat) ([]security.CaveatValidator, error) {
Ankurf044a8d2014-09-05 17:05:24 -0700127 if len(caveats) == 0 {
128 return nil, nil
129 }
130 validators := make([]security.CaveatValidator, len(caveats))
131 for i, c := range caveats {
132 var v security.CaveatValidator
Asim Shankarbb0f0c12014-09-09 13:32:28 -0700133 if err := vom.NewDecoder(bytes.NewReader(c.ValidatorVOM)).Decode(&v); err != nil {
Ankurf044a8d2014-09-05 17:05:24 -0700134 return nil, fmt.Errorf("caveat bytes could not be VOM-decoded: %s", err)
135 }
136 validators[i] = v
137 }
138 return validators, nil
139}
140
141// ThirdPartyCaveats returns the set of security.ThirdPartyCaveats
142// that could be successfully decoded from the provided caveat bytes.
Asim Shankarbb0f0c12014-09-09 13:32:28 -0700143func ThirdPartyCaveats(caveats ...security.Caveat) []security.ThirdPartyCaveat {
Ankurf044a8d2014-09-05 17:05:24 -0700144 var tpCaveats []security.ThirdPartyCaveat
145 for _, c := range caveats {
146 var t security.ThirdPartyCaveat
Asim Shankarbb0f0c12014-09-09 13:32:28 -0700147 if err := vom.NewDecoder(bytes.NewReader(c.ValidatorVOM)).Decode(&t); err != nil {
Ankurf044a8d2014-09-05 17:05:24 -0700148 continue
149 }
150 tpCaveats = append(tpCaveats, t)
151 }
152 return tpCaveats
153}