blob: 75e57576e267914f30694ddc7552a66d073361ce [file] [log] [blame]
Tilak Sharmad6ade0e2014-08-20 16:28:32 -07001package security
2
3import (
Ankur021e38e2014-09-26 10:26:45 -07004 "crypto/ecdsa"
gauthamta134eda2014-11-05 17:57:42 -08005 "crypto/elliptic"
Suharsh Sivakumar0f359042014-10-01 22:53:45 -07006 "crypto/rand"
Ankur021e38e2014-09-26 10:26:45 -07007 "crypto/x509"
Ankur021e38e2014-09-26 10:26:45 -07008 "encoding/pem"
9 "errors"
Ankurf044a8d2014-09-05 17:05:24 -070010 "fmt"
Tilak Sharmad6ade0e2014-08-20 16:28:32 -070011 "io"
Ankur021e38e2014-09-26 10:26:45 -070012 "io/ioutil"
Tilak Sharmad6ade0e2014-08-20 16:28:32 -070013
Jiri Simsa764efb72014-12-25 20:57:03 -080014 "v.io/core/veyron2/security"
Todd Wang3425a902015-01-21 18:43:59 -080015 "v.io/core/veyron2/vom"
Tilak Sharmad6ade0e2014-08-20 16:28:32 -070016)
17
Ankur021e38e2014-09-26 10:26:45 -070018const ecPrivateKeyPEMType = "EC PRIVATE KEY"
19
Suharsh Sivakumar4684f4e2014-10-24 13:42:06 -070020var PassphraseErr = errors.New("passphrase incorrect for decrypting private key")
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070021
gauthamta134eda2014-11-05 17:57:42 -080022// NewPrincipalKey generates an ECDSA (public, private) key pair.
23func NewPrincipalKey() (security.PublicKey, *ecdsa.PrivateKey, error) {
24 priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
25 if err != nil {
26 return nil, nil, err
27 }
28 return security.NewECDSAPublicKey(&priv.PublicKey), priv, nil
29}
30
Ankur73e7a932014-10-24 15:57:03 -070031// LoadPEMKey loads a key from 'r'. returns PassphraseErr for incorrect Passphrase.
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070032// If the key held in 'r' is unencrypted, 'passphrase' will be ignored.
Ankur73e7a932014-10-24 15:57:03 -070033func LoadPEMKey(r io.Reader, passphrase []byte) (interface{}, error) {
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070034 pemBlockBytes, err := ioutil.ReadAll(r)
Ankur021e38e2014-09-26 10:26:45 -070035 if err != nil {
36 return nil, err
37 }
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070038 pemBlock, _ := pem.Decode(pemBlockBytes)
39 if pemBlock == nil {
Ankur021e38e2014-09-26 10:26:45 -070040 return nil, errors.New("no PEM key block read")
41 }
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070042 var data []byte
43 if x509.IsEncryptedPEMBlock(pemBlock) {
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070044 data, err = x509.DecryptPEMBlock(pemBlock, passphrase)
45 if err != nil {
Suharsh Sivakumar4684f4e2014-10-24 13:42:06 -070046 return nil, PassphraseErr
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070047 }
48 } else {
49 data = pemBlock.Bytes
Suharsh Sivakumar0f359042014-10-01 22:53:45 -070050 }
51
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070052 switch pemBlock.Type {
Ankur021e38e2014-09-26 10:26:45 -070053 case ecPrivateKeyPEMType:
Suharsh Sivakumar4684f4e2014-10-24 13:42:06 -070054 key, err := x509.ParseECPrivateKey(data)
55 if err != nil {
56 return nil, PassphraseErr
57 }
58 return key, nil
Ankur021e38e2014-09-26 10:26:45 -070059 }
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070060 return nil, fmt.Errorf("PEM key block has an unrecognized type: %v", pemBlock.Type)
Ankur021e38e2014-09-26 10:26:45 -070061}
62
Ankur73e7a932014-10-24 15:57:03 -070063// SavePEMKey marshals 'key', encrypts it using 'passphrase', and saves the bytes to 'w' in PEM format.
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070064// If passphrase is nil, the key will not be encrypted.
Ankur021e38e2014-09-26 10:26:45 -070065//
66// For example, if key is an ECDSA private key, it will be marshaled
Suharsh Sivakumar0f359042014-10-01 22:53:45 -070067// in ASN.1, DER format, encrypted, and then written in a PEM block.
Ankur73e7a932014-10-24 15:57:03 -070068func SavePEMKey(w io.Writer, key interface{}, passphrase []byte) error {
Suharsh Sivakumar0f359042014-10-01 22:53:45 -070069 var data []byte
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070070 var err error
Ankur021e38e2014-09-26 10:26:45 -070071 switch k := key.(type) {
72 case *ecdsa.PrivateKey:
Suharsh Sivakumar0f359042014-10-01 22:53:45 -070073 if data, err = x509.MarshalECPrivateKey(k); err != nil {
Ankur021e38e2014-09-26 10:26:45 -070074 return err
75 }
76 default:
77 return fmt.Errorf("key of type %T cannot be saved", k)
78 }
Suharsh Sivakumar0f359042014-10-01 22:53:45 -070079
Suharsh Sivakumaraca1c322014-10-21 11:27:32 -070080 var pemKey *pem.Block
81 if passphrase != nil {
82 pemKey, err = x509.EncryptPEMBlock(rand.Reader, ecPrivateKeyPEMType, data, passphrase, x509.PEMCipherAES256)
83 if err != nil {
84 return fmt.Errorf("failed to encrypt pem block: %v", err)
85 }
86 } else {
87 pemKey = &pem.Block{
88 Type: ecPrivateKeyPEMType,
89 Bytes: data,
90 }
Suharsh Sivakumar0f359042014-10-01 22:53:45 -070091 }
92
Ankur021e38e2014-09-26 10:26:45 -070093 return pem.Encode(w, pemKey)
94}
95
Ankurf044a8d2014-09-05 17:05:24 -070096// ThirdPartyCaveats returns the set of security.ThirdPartyCaveats
97// that could be successfully decoded from the provided caveat bytes.
Asim Shankarbb0f0c12014-09-09 13:32:28 -070098func ThirdPartyCaveats(caveats ...security.Caveat) []security.ThirdPartyCaveat {
Ankurf044a8d2014-09-05 17:05:24 -070099 var tpCaveats []security.ThirdPartyCaveat
100 for _, c := range caveats {
101 var t security.ThirdPartyCaveat
Todd Wang3425a902015-01-21 18:43:59 -0800102 if err := vom.Decode(c.ValidatorVOM, &t); err != nil {
Ankurf044a8d2014-09-05 17:05:24 -0700103 continue
104 }
105 tpCaveats = append(tpCaveats, t)
106 }
107 return tpCaveats
108}