blob: 1ce53ef343753f2f898efce8b09fafb1d655f98c [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"
Ankur021e38e2014-09-26 10:26:45 -07009 "encoding/pem"
10 "errors"
Ankurf044a8d2014-09-05 17:05:24 -070011 "fmt"
Tilak Sharmad6ade0e2014-08-20 16:28:32 -070012 "io"
Ankur021e38e2014-09-26 10:26:45 -070013 "io/ioutil"
Tilak Sharmad6ade0e2014-08-20 16:28:32 -070014
Jiri Simsa519c5072014-09-17 21:37:57 -070015 "veyron.io/veyron/veyron2/security"
16 "veyron.io/veyron/veyron2/vom"
Tilak Sharmad6ade0e2014-08-20 16:28:32 -070017)
18
Ankur021e38e2014-09-26 10:26:45 -070019const ecPrivateKeyPEMType = "EC PRIVATE KEY"
20
Suharsh Sivakumar4684f4e2014-10-24 13:42:06 -070021var PassphraseErr = errors.New("passphrase incorrect for decrypting private key")
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070022
gauthamta134eda2014-11-05 17:57:42 -080023// NewPrincipalKey generates an ECDSA (public, private) key pair.
24func NewPrincipalKey() (security.PublicKey, *ecdsa.PrivateKey, error) {
25 priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
26 if err != nil {
27 return nil, nil, err
28 }
29 return security.NewECDSAPublicKey(&priv.PublicKey), priv, nil
30}
31
Ankur73e7a932014-10-24 15:57:03 -070032// LoadPEMKey loads a key from 'r'. returns PassphraseErr for incorrect Passphrase.
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070033// If the key held in 'r' is unencrypted, 'passphrase' will be ignored.
Ankur73e7a932014-10-24 15:57:03 -070034func LoadPEMKey(r io.Reader, passphrase []byte) (interface{}, error) {
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070035 pemBlockBytes, err := ioutil.ReadAll(r)
Ankur021e38e2014-09-26 10:26:45 -070036 if err != nil {
37 return nil, err
38 }
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070039 pemBlock, _ := pem.Decode(pemBlockBytes)
40 if pemBlock == nil {
Ankur021e38e2014-09-26 10:26:45 -070041 return nil, errors.New("no PEM key block read")
42 }
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070043 var data []byte
44 if x509.IsEncryptedPEMBlock(pemBlock) {
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070045 data, err = x509.DecryptPEMBlock(pemBlock, passphrase)
46 if err != nil {
Suharsh Sivakumar4684f4e2014-10-24 13:42:06 -070047 return nil, PassphraseErr
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070048 }
49 } else {
50 data = pemBlock.Bytes
Suharsh Sivakumar0f359042014-10-01 22:53:45 -070051 }
52
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070053 switch pemBlock.Type {
Ankur021e38e2014-09-26 10:26:45 -070054 case ecPrivateKeyPEMType:
Suharsh Sivakumar4684f4e2014-10-24 13:42:06 -070055 key, err := x509.ParseECPrivateKey(data)
56 if err != nil {
57 return nil, PassphraseErr
58 }
59 return key, nil
Ankur021e38e2014-09-26 10:26:45 -070060 }
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070061 return nil, fmt.Errorf("PEM key block has an unrecognized type: %v", pemBlock.Type)
Ankur021e38e2014-09-26 10:26:45 -070062}
63
Ankur73e7a932014-10-24 15:57:03 -070064// SavePEMKey marshals 'key', encrypts it using 'passphrase', and saves the bytes to 'w' in PEM format.
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070065// If passphrase is nil, the key will not be encrypted.
Ankur021e38e2014-09-26 10:26:45 -070066//
67// For example, if key is an ECDSA private key, it will be marshaled
Suharsh Sivakumar0f359042014-10-01 22:53:45 -070068// in ASN.1, DER format, encrypted, and then written in a PEM block.
Ankur73e7a932014-10-24 15:57:03 -070069func SavePEMKey(w io.Writer, key interface{}, passphrase []byte) error {
Suharsh Sivakumar0f359042014-10-01 22:53:45 -070070 var data []byte
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070071 var err error
Ankur021e38e2014-09-26 10:26:45 -070072 switch k := key.(type) {
73 case *ecdsa.PrivateKey:
Suharsh Sivakumar0f359042014-10-01 22:53:45 -070074 if data, err = x509.MarshalECPrivateKey(k); err != nil {
Ankur021e38e2014-09-26 10:26:45 -070075 return err
76 }
77 default:
78 return fmt.Errorf("key of type %T cannot be saved", k)
79 }
Suharsh Sivakumar0f359042014-10-01 22:53:45 -070080
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070081 var pemKey *pem.Block
82 if passphrase != nil {
83 pemKey, err = x509.EncryptPEMBlock(rand.Reader, ecPrivateKeyPEMType, data, passphrase, x509.PEMCipherAES256)
84 if err != nil {
85 return fmt.Errorf("failed to encrypt pem block: %v", err)
86 }
87 } else {
88 pemKey = &pem.Block{
89 Type: ecPrivateKeyPEMType,
90 Bytes: data,
91 }
Suharsh Sivakumar0f359042014-10-01 22:53:45 -070092 }
93
Ankur021e38e2014-09-26 10:26:45 -070094 return pem.Encode(w, pemKey)
95}
96
Ankurf044a8d2014-09-05 17:05:24 -070097// ThirdPartyCaveats returns the set of security.ThirdPartyCaveats
98// that could be successfully decoded from the provided caveat bytes.
Asim Shankarbb0f0c12014-09-09 13:32:28 -070099func ThirdPartyCaveats(caveats ...security.Caveat) []security.ThirdPartyCaveat {
Ankurf044a8d2014-09-05 17:05:24 -0700100 var tpCaveats []security.ThirdPartyCaveat
101 for _, c := range caveats {
102 var t security.ThirdPartyCaveat
Asim Shankarbb0f0c12014-09-09 13:32:28 -0700103 if err := vom.NewDecoder(bytes.NewReader(c.ValidatorVOM)).Decode(&t); err != nil {
Ankurf044a8d2014-09-05 17:05:24 -0700104 continue
105 }
106 tpCaveats = append(tpCaveats, t)
107 }
108 return tpCaveats
109}