diff --git a/util/cert/io.go b/util/cert/io.go index a41f8054..374e8cae 100644 --- a/util/cert/io.go +++ b/util/cert/io.go @@ -17,7 +17,11 @@ limitations under the License. package cert import ( + "crypto" + "crypto/ecdsa" + "crypto/rsa" "crypto/x509" + "encoding/pem" "fmt" "io/ioutil" "os" @@ -101,6 +105,27 @@ func LoadOrGenerateKeyFile(keyPath string) (data []byte, wasGenerated bool, err return generatedData, true, nil } +// MarshalPrivateKeyToPEM converts a known private key type of RSA or ECDSA to +// a PEM encoded block or returns an error. +func MarshalPrivateKeyToPEM(privateKey crypto.PrivateKey) ([]byte, error) { + switch t := privateKey.(type) { + case *ecdsa.PrivateKey: + derBytes, err := x509.MarshalECPrivateKey(t) + if err != nil { + return nil, err + } + privateKeyPemBlock := &pem.Block{ + Type: ECPrivateKeyBlockType, + Bytes: derBytes, + } + return pem.EncodeToMemory(privateKeyPemBlock), nil + case *rsa.PrivateKey: + return EncodePrivateKeyPEM(t), nil + default: + return nil, fmt.Errorf("private key is not a recognized type: %T", privateKey) + } +} + // NewPool returns an x509.CertPool containing the certificates in the given PEM-encoded file. // Returns an error if the file could not be read, a certificate could not be parsed, or if the file does not contain any certificates func NewPool(filename string) (*x509.CertPool, error) { diff --git a/util/certificate/certificate_store.go b/util/certificate/certificate_store.go index 42a40dcd..f54bd658 100644 --- a/util/certificate/certificate_store.go +++ b/util/certificate/certificate_store.go @@ -46,6 +46,15 @@ type fileStore struct { keyFile string } +// FileStore is a store that provides certificate retrieval as well as +// the path on disk of the current PEM. +type FileStore interface { + Store + // CurrentPath returns the path on disk of the current certificate/key + // pair encoded as PEM files. + CurrentPath() string +} + // NewFileStore returns a concrete implementation of a Store that is based on // storing the cert/key pairs in a single file per pair on disk in the // designated directory. When starting up it will look for the currently @@ -64,7 +73,7 @@ func NewFileStore( certDirectory string, keyDirectory string, certFile string, - keyFile string) (Store, error) { + keyFile string) (FileStore, error) { s := fileStore{ pairNamePrefix: pairNamePrefix, @@ -79,6 +88,11 @@ func NewFileStore( return &s, nil } +// CurrentPath returns the path to the current version of these certificates. +func (s *fileStore) CurrentPath() string { + return filepath.Join(s.certDirectory, s.filename(currentPair)) +} + // recover checks if there is a certificate rotation that was interrupted while // progress, and if so, attempts to recover to a good state. func (s *fileStore) recover() error {