...

Source file src/github.com/sassoftware/relic/lib/certloader/anyprivkey.go

Documentation: github.com/sassoftware/relic/lib/certloader

     1  //
     2  // Copyright (c) SAS Institute Inc.
     3  //
     4  // Licensed under the Apache License, Version 2.0 (the "License");
     5  // you may not use this file except in compliance with the License.
     6  // You may obtain a copy of the License at
     7  //
     8  //     http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  //
    16  
    17  package certloader
    18  
    19  import (
    20  	"bytes"
    21  	"crypto"
    22  	"crypto/x509"
    23  	"encoding/pem"
    24  	"errors"
    25  	"fmt"
    26  	"io"
    27  	"os"
    28  	"strings"
    29  
    30  	"github.com/sassoftware/relic/lib/passprompt"
    31  	"golang.org/x/crypto/openpgp"
    32  	"golang.org/x/crypto/openpgp/armor"
    33  	"golang.org/x/crypto/openpgp/packet"
    34  )
    35  
    36  // Parse and decrypt a private key. It can be a RSA or ECDA key in PKCS#1 or
    37  // PKCS#8 format and DER or PEM encoding, or it can be a PGP private key. If
    38  // the private key is encrypted then the given prompter will be invoked to ask
    39  // for the passphrase, if provided.
    40  func ParseAnyPrivateKey(blob []byte, prompt passprompt.PasswordGetter) (crypto.PrivateKey, error) {
    41  	if bytes.HasPrefix(blob, []byte("-----BEGIN PGP")) {
    42  		return parsePgpPrivateKey(blob, prompt)
    43  	} else if bytes.HasPrefix(blob, []byte("-----BEGIN")) {
    44  		var block *pem.Block
    45  		for {
    46  			block, blob = pem.Decode(blob)
    47  			if block == nil {
    48  				break
    49  			} else if block.Type == "PRIVATE KEY" || strings.HasSuffix(block.Type, " PRIVATE KEY") {
    50  				return parsePemPrivateKey(block, prompt)
    51  			}
    52  		}
    53  		return nil, errors.New("failed to find any private keys in PEM data")
    54  	} else if blob[0] == asn1Magic {
    55  		return parsePrivateKey(blob)
    56  	} else if blob[0]&0x80 != 0 {
    57  		return parsePgpPrivateKey(blob, prompt)
    58  	} else {
    59  		return nil, errors.New("unrecognized private key format")
    60  	}
    61  }
    62  
    63  func parsePemPrivateKey(block *pem.Block, prompt passprompt.PasswordGetter) (crypto.PrivateKey, error) {
    64  	if !x509.IsEncryptedPEMBlock(block) {
    65  		return parsePrivateKey(block.Bytes)
    66  	}
    67  	if prompt == nil {
    68  		return nil, errors.New("private key is encrypted and no password was provided")
    69  	}
    70  	for {
    71  		password, err := prompt.GetPasswd("Password for private key: ")
    72  		if err != nil {
    73  			return nil, err
    74  		} else if password == "" {
    75  			return nil, errors.New("aborted")
    76  		}
    77  		keyblob, err := x509.DecryptPEMBlock(block, []byte(password))
    78  		if err == x509.IncorrectPasswordError {
    79  			continue
    80  		} else if err != nil {
    81  			return nil, err
    82  		} else {
    83  			return parsePrivateKey(keyblob)
    84  		}
    85  	}
    86  }
    87  
    88  func parsePgpPrivateKey(blob []byte, prompt passprompt.PasswordGetter) (crypto.PrivateKey, error) {
    89  	var reader io.Reader = bytes.NewReader(blob)
    90  	if blob[0] == '-' {
    91  		block, err := armor.Decode(reader)
    92  		if err != nil {
    93  			return nil, err
    94  		}
    95  		reader = block.Body
    96  	}
    97  	entity, err := openpgp.ReadEntity(packet.NewReader(reader))
    98  	if err != nil {
    99  		return nil, err
   100  	}
   101  	if entity.PrivateKey == nil {
   102  		return nil, errors.New("file does not contain a private key")
   103  	}
   104  	if entity.PrivateKey.Encrypted {
   105  		fmt.Fprintln(os.Stderr, "Key fingerprint:", entity.PrimaryKey.KeyIdString())
   106  		for name := range entity.Identities {
   107  			fmt.Fprintln(os.Stderr, "UID:", name)
   108  		}
   109  		fmt.Fprintln(os.Stderr)
   110  		for {
   111  			password, err := prompt.GetPasswd("Passphrase for key: ")
   112  			if err != nil {
   113  				return nil, err
   114  			} else if password == "" {
   115  				return nil, errors.New("Aborted")
   116  			}
   117  			err = entity.PrivateKey.Decrypt([]byte(password))
   118  			if err == nil {
   119  				break
   120  			}
   121  		}
   122  	}
   123  	return entity.PrivateKey.PrivateKey, nil
   124  }
   125  

View as plain text