github.com/letsencrypt/trillian@v1.1.2-0.20180615153820-ae375a99d36a/crypto/keys/pem/pem.go (about)

     1  // Copyright 2017 Google Inc. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package pem
    16  
    17  import (
    18  	"crypto"
    19  	"crypto/x509"
    20  	"encoding/pem"
    21  	"errors"
    22  	"fmt"
    23  	"io/ioutil"
    24  
    25  	"github.com/google/trillian/crypto/keys/der"
    26  	"github.com/google/trillian/crypto/keyspb"
    27  )
    28  
    29  // FromProto takes a PEMKeyFile protobuf message and loads the private key it specifies.
    30  func FromProto(pb *keyspb.PEMKeyFile) (crypto.Signer, error) {
    31  	return ReadPrivateKeyFile(pb.GetPath(), pb.GetPassword())
    32  }
    33  
    34  // ReadPrivateKeyFile reads a PEM-encoded private key from a file.
    35  // The key must be protected by a password.
    36  func ReadPrivateKeyFile(file, password string) (crypto.Signer, error) {
    37  	if password == "" {
    38  		return nil, fmt.Errorf("pemfile: empty password for file %q", file)
    39  	}
    40  
    41  	keyPEM, err := ioutil.ReadFile(file)
    42  	if err != nil {
    43  		return nil, fmt.Errorf("pemfile: error reading file %q: %v", file, err)
    44  	}
    45  
    46  	k, err := UnmarshalPrivateKey(string(keyPEM), password)
    47  	if err != nil {
    48  		return nil, fmt.Errorf("pemfile: error decoding private key from file %q: %v", file, err)
    49  	}
    50  
    51  	return k, nil
    52  }
    53  
    54  // ReadPublicKeyFile reads a PEM-encoded public key from a file.
    55  func ReadPublicKeyFile(file string) (crypto.PublicKey, error) {
    56  	keyPEM, err := ioutil.ReadFile(file)
    57  	if err != nil {
    58  		return nil, fmt.Errorf("pemfile: error reading %q: %v", file, err)
    59  	}
    60  
    61  	return UnmarshalPublicKey(string(keyPEM))
    62  }
    63  
    64  // UnmarshalPrivateKey reads a PEM-encoded private key from a string.
    65  // The key may be protected by a password.
    66  func UnmarshalPrivateKey(keyPEM, password string) (crypto.Signer, error) {
    67  	block, rest := pem.Decode([]byte(keyPEM))
    68  	if block == nil {
    69  		return nil, errors.New("pemfile: invalid private key PEM")
    70  	}
    71  	if len(rest) > 0 {
    72  		return nil, errors.New("pemfile: extra data found after first PEM block")
    73  	}
    74  
    75  	keyDER := block.Bytes
    76  	if password != "" {
    77  		pwdDer, err := x509.DecryptPEMBlock(block, []byte(password))
    78  		if err != nil {
    79  			return nil, fmt.Errorf("pemfile: failed to decrypt: %v", err)
    80  		}
    81  		keyDER = pwdDer
    82  	}
    83  
    84  	return der.UnmarshalPrivateKey(keyDER)
    85  }
    86  
    87  // UnmarshalPublicKey reads a PEM-encoded public key from a string.
    88  func UnmarshalPublicKey(keyPEM string) (crypto.PublicKey, error) {
    89  	block, rest := pem.Decode([]byte(keyPEM))
    90  	if block == nil {
    91  		return nil, errors.New("pemfile: invalid public key PEM")
    92  	}
    93  	if len(rest) > 0 {
    94  		return nil, errors.New("pemfile: extra data found after first PEM block")
    95  	}
    96  
    97  	return der.UnmarshalPublicKey(block.Bytes)
    98  }