...

Source file src/github.com/linkerd/linkerd2/pkg/tls/codec.go

Documentation: github.com/linkerd/linkerd2/pkg/tls

     1  package tls
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/ecdsa"
     6  	"crypto/rsa"
     7  	"crypto/x509"
     8  	"encoding/pem"
     9  	"errors"
    10  	"fmt"
    11  	"reflect"
    12  )
    13  
    14  // === ENCODE ===
    15  
    16  // EncodeCertificatesPEM encodes the collection of provided certificates as
    17  // a text blob of PEM-encoded certificates.
    18  func EncodeCertificatesPEM(crts ...*x509.Certificate) string {
    19  	buf := bytes.Buffer{}
    20  	for _, c := range crts {
    21  		encode(&buf, &pem.Block{Type: "CERTIFICATE", Bytes: c.Raw})
    22  	}
    23  	return buf.String()
    24  }
    25  
    26  // EncodePrivateKeyPEM encodes the provided key as PEM-encoded text
    27  func EncodePrivateKeyPEM(k *ecdsa.PrivateKey) ([]byte, error) {
    28  	der, err := x509.MarshalECPrivateKey(k)
    29  	if err != nil {
    30  		return nil, err
    31  	}
    32  
    33  	return pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: der}), nil
    34  }
    35  
    36  // EncodePrivateKeyP8 encodes the provided key as PEM-encoded text
    37  func EncodePrivateKeyP8(k *ecdsa.PrivateKey) []byte {
    38  	p8, err := x509.MarshalPKCS8PrivateKey(k)
    39  	if err != nil {
    40  		panic("ECDSA keys must be encodeable as PKCS8")
    41  	}
    42  	return p8
    43  }
    44  
    45  func encode(buf *bytes.Buffer, blk *pem.Block) {
    46  	if err := pem.Encode(buf, blk); err != nil {
    47  		panic("encoding to memory must not fail")
    48  	}
    49  }
    50  
    51  // === DECODE ===
    52  
    53  // DecodePEMKey parses a PEM-encoded private key from the named path.
    54  func DecodePEMKey(txt string) (GenericPrivateKey, error) {
    55  	block, _ := pem.Decode([]byte(txt))
    56  	if block == nil {
    57  		return nil, errors.New("not PEM-encoded")
    58  	}
    59  	switch block.Type {
    60  	case "EC PRIVATE KEY":
    61  		k, err := x509.ParseECPrivateKey(block.Bytes)
    62  		if err != nil {
    63  			return nil, err
    64  		}
    65  		return privateKeyEC{k}, nil
    66  	case "RSA PRIVATE KEY":
    67  		k, err := x509.ParsePKCS1PrivateKey(block.Bytes)
    68  		if err != nil {
    69  			return nil, err
    70  		}
    71  		return privateKeyRSA{k}, nil
    72  	case "PRIVATE KEY":
    73  		k, err := x509.ParsePKCS8PrivateKey(block.Bytes)
    74  		if err != nil {
    75  			return nil, err
    76  		}
    77  		if ec, ok := k.(*ecdsa.PrivateKey); ok {
    78  			return privateKeyEC{ec}, nil
    79  		}
    80  		if rsa, ok := k.(*rsa.PrivateKey); ok {
    81  			return privateKeyRSA{rsa}, nil
    82  		}
    83  		return nil, fmt.Errorf(
    84  			"unsupported PKCS#8 encoded private key type: '%s', linkerd2 only supports ECDSA and RSA private keys",
    85  			reflect.TypeOf(k))
    86  	default:
    87  		return nil, fmt.Errorf("unsupported block type: '%s'", block.Type)
    88  	}
    89  }
    90  
    91  // DecodePEMCertificates parses a string containing PEM-encoded certificates.
    92  func DecodePEMCertificates(txt string) (certs []*x509.Certificate, err error) {
    93  	buf := []byte(txt)
    94  	for len(buf) > 0 {
    95  		var c *x509.Certificate
    96  		c, buf, err = decodeCertificatePEM(buf)
    97  		if err != nil {
    98  			return
    99  		}
   100  		if c == nil {
   101  			continue // not a CERTIFICATE, skip
   102  		}
   103  		certs = append(certs, c)
   104  	}
   105  	return
   106  }
   107  
   108  // CertificatesToPool converts a slice of certificates into a cert pool
   109  func CertificatesToPool(certs []*x509.Certificate) *x509.CertPool {
   110  	pool := x509.NewCertPool()
   111  	for _, c := range certs {
   112  		pool.AddCert(c)
   113  	}
   114  	return pool
   115  }
   116  
   117  // DecodePEMCertPool parses a string containing PE-encoded certificates into a CertPool.
   118  func DecodePEMCertPool(txt string) (*x509.CertPool, error) {
   119  	certs, err := DecodePEMCertificates(txt)
   120  	if err != nil {
   121  		return nil, err
   122  	}
   123  	if len(certs) == 0 {
   124  		return nil, errors.New("no certificates found")
   125  	}
   126  
   127  	return CertificatesToPool(certs), nil
   128  }
   129  
   130  func decodeCertificatePEM(crtb []byte) (*x509.Certificate, []byte, error) {
   131  	block, crtb := pem.Decode(crtb)
   132  	if block == nil {
   133  		return nil, crtb, errors.New("not a PEM certificate")
   134  	}
   135  	if block.Type != "CERTIFICATE" {
   136  		return nil, nil, nil
   137  	}
   138  	c, err := x509.ParseCertificate(block.Bytes)
   139  	return c, crtb, err
   140  }
   141  

View as plain text