...

Source file src/github.com/sassoftware/relic/lib/certloader/certloader.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/ecdsa"
    23  	"crypto/rsa"
    24  	"crypto/tls"
    25  	"crypto/x509"
    26  	"encoding/pem"
    27  	"errors"
    28  	"fmt"
    29  	"io/ioutil"
    30  
    31  	"golang.org/x/crypto/openpgp"
    32  	"golang.org/x/crypto/openpgp/packet"
    33  
    34  	"github.com/sassoftware/relic/lib/pkcs7"
    35  	"github.com/sassoftware/relic/lib/pkcs9"
    36  	"github.com/sassoftware/relic/lib/x509tools"
    37  )
    38  
    39  const asn1Magic = 0x30 // weak but good enough?
    40  var pkcs7SignedData = []byte{0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02}
    41  
    42  // A bundle of X509 certificate chain and/or PGP certificate, with optional private key
    43  type Certificate struct {
    44  	Leaf         *x509.Certificate
    45  	Certificates []*x509.Certificate
    46  	PgpKey       *openpgp.Entity
    47  	PrivateKey   crypto.PrivateKey
    48  	Timestamper  pkcs9.Timestamper
    49  	KeyName      string
    50  }
    51  
    52  // Return the X509 certificates in the chain up to, but not including, the root CA certificate
    53  func (s *Certificate) Chain() []*x509.Certificate {
    54  	var chain []*x509.Certificate
    55  	if s.Leaf != nil {
    56  		// ensure leaf comes first
    57  		chain = append(chain, s.Leaf)
    58  	}
    59  	for i, cert := range s.Certificates {
    60  		if i > 0 && bytes.Equal(cert.RawIssuer, cert.RawSubject) {
    61  			// omit root CA
    62  			continue
    63  		} else if cert == s.Leaf {
    64  			// already in list
    65  			continue
    66  		}
    67  		chain = append(chain, cert)
    68  	}
    69  	return chain
    70  }
    71  
    72  // Return the certificate that issued the leaf certificate
    73  func (s *Certificate) Issuer() *x509.Certificate {
    74  	if s.Leaf == nil {
    75  		return nil
    76  	}
    77  	for _, cert := range s.Certificates {
    78  		if bytes.Equal(cert.RawSubject, s.Leaf.RawIssuer) {
    79  			return cert
    80  		}
    81  	}
    82  	return nil
    83  }
    84  
    85  // Return the private key in the form of a crypto.Signer
    86  func (s *Certificate) Signer() crypto.Signer {
    87  	if s.PrivateKey == nil {
    88  		return nil
    89  	}
    90  	return s.PrivateKey.(crypto.Signer)
    91  }
    92  
    93  // Return a tls.Certificate structure containing the X509 certificate chain and
    94  // private key
    95  func (s *Certificate) TLS() tls.Certificate {
    96  	var raw [][]byte
    97  	for _, cert := range s.Certificates {
    98  		raw = append(raw, cert.Raw)
    99  	}
   100  	return tls.Certificate{Leaf: s.Leaf, Certificate: raw, PrivateKey: s.PrivateKey}
   101  }
   102  
   103  // Parse a private key from a DER block
   104  // See crypto/tls.parsePrivateKey
   105  func parsePrivateKey(der []byte) (crypto.PrivateKey, error) {
   106  	if key, err := x509.ParsePKCS1PrivateKey(der); err == nil {
   107  		return key, nil
   108  	}
   109  	if key, err := x509.ParsePKCS8PrivateKey(der); err == nil {
   110  		switch key := key.(type) {
   111  		case *rsa.PrivateKey, *ecdsa.PrivateKey:
   112  			return key, nil
   113  		default:
   114  			return nil, errors.New("tls: found unknown private key type in PKCS#8 wrapping")
   115  		}
   116  	}
   117  	if key, err := x509.ParseECPrivateKey(der); err == nil {
   118  		return key, nil
   119  	}
   120  
   121  	return nil, errors.New("tls: failed to parse private key")
   122  }
   123  
   124  // Parse a list of certificates, PEM or DER, X509 or PKCS#7
   125  func parseCertificates(pemData []byte) (*Certificate, error) {
   126  	if len(pemData) >= 1 && pemData[0] == asn1Magic {
   127  		// already in DER form
   128  		return parseCertificatesDer(pemData)
   129  	}
   130  	var certs []*x509.Certificate
   131  	for {
   132  		var block *pem.Block
   133  		block, pemData = pem.Decode(pemData)
   134  		if block == nil {
   135  			break
   136  		} else if block.Type == "CERTIFICATE" || block.Type == "PKCS7" {
   137  			newcerts, err := parseCertificatesDer(block.Bytes)
   138  			if err != nil {
   139  				return nil, err
   140  			}
   141  			certs = append(certs, newcerts.Certificates...)
   142  		}
   143  	}
   144  	if len(certs) == 0 {
   145  		return nil, ErrNoCerts
   146  	}
   147  	return &Certificate{Leaf: certs[0], Certificates: certs}, nil
   148  }
   149  
   150  // Parse certificates from DER
   151  func parseCertificatesDer(der []byte) (*Certificate, error) {
   152  	var certs []*x509.Certificate
   153  	var err error
   154  	if bytes.Contains(der[:32], pkcs7SignedData) {
   155  		psd, err := pkcs7.Unmarshal(der)
   156  		if err != nil {
   157  			return nil, err
   158  		}
   159  		certs, err = psd.Content.Certificates.Parse()
   160  	} else {
   161  		certs, err = x509.ParseCertificates(der)
   162  	}
   163  	if err != nil {
   164  		return nil, err
   165  	} else if len(certs) == 0 {
   166  		return nil, ErrNoCerts
   167  	} else {
   168  		return &Certificate{Leaf: certs[0], Certificates: certs}, nil
   169  	}
   170  }
   171  
   172  // ParseX509Certificates parses a blob in PEM or DER, X509 or PKCS#7 format and returns a list of certificates
   173  func ParseX509Certificates(blob []byte) ([]*x509.Certificate, error) {
   174  	cert, err := parseCertificates(blob)
   175  	if err != nil {
   176  		return nil, err
   177  	}
   178  	return cert.Certificates, nil
   179  }
   180  
   181  // Load a X509 private key and certificate
   182  func LoadX509KeyPair(certFile, keyFile string) (*Certificate, error) {
   183  	keyblob, err := ioutil.ReadFile(keyFile)
   184  	if err != nil {
   185  		return nil, err
   186  	}
   187  	certblob, err := ioutil.ReadFile(certFile)
   188  	if err != nil {
   189  		return nil, err
   190  	}
   191  	key, err := ParseAnyPrivateKey(keyblob, nil)
   192  	if err != nil {
   193  		return nil, err
   194  	}
   195  	cert, err := parseCertificates(certblob)
   196  	if err != nil {
   197  		return nil, err
   198  	}
   199  	if !x509tools.SameKey(cert.Leaf.PublicKey, key) {
   200  		return nil, errors.New("Private key does not match certificate")
   201  	}
   202  	cert.PrivateKey = key
   203  	return cert, nil
   204  }
   205  
   206  // Load X509 and/or PGP certificates from named paths and return a Certificate
   207  // structure together with the given private key
   208  func LoadTokenCertificates(key crypto.PrivateKey, x509cert, pgpcert string) (*Certificate, error) {
   209  	var cert *Certificate
   210  	if x509cert != "" {
   211  		blob, err := ioutil.ReadFile(x509cert)
   212  		if err != nil {
   213  			return nil, err
   214  		}
   215  		cert, err = parseCertificates(blob)
   216  		if err != nil {
   217  			return nil, err
   218  		}
   219  		if !x509tools.SameKey(key, cert.Leaf.PublicKey) {
   220  			return nil, errors.New("certificate does not match key in token")
   221  		}
   222  		cert.PrivateKey = key
   223  	} else {
   224  		cert = &Certificate{PrivateKey: key}
   225  	}
   226  	if pgpcert != "" {
   227  		blob, err := ioutil.ReadFile(pgpcert)
   228  		if err != nil {
   229  			return nil, err
   230  		}
   231  		keyring, err := parsePGP(blob)
   232  		if err != nil {
   233  			return nil, err
   234  		}
   235  		if len(keyring) != 1 {
   236  			return nil, fmt.Errorf("expected exactly 1 entity in pgp certificate %s", pgpcert)
   237  		}
   238  		entity := keyring[0]
   239  		priv := &packet.PrivateKey{
   240  			PublicKey:  *entity.PrimaryKey,
   241  			Encrypted:  false,
   242  			PrivateKey: key,
   243  		}
   244  		if !x509tools.SameKey(key, priv.PublicKey.PublicKey) {
   245  			return nil, errors.New("certificate does not match key in token")
   246  		}
   247  		entity.PrivateKey = priv
   248  		cert.PgpKey = entity
   249  	}
   250  	return cert, nil
   251  }
   252  
   253  type errNoCerts struct{}
   254  
   255  func (errNoCerts) Error() string {
   256  	return "failed to find any certificates in PEM file"
   257  }
   258  
   259  var ErrNoCerts = errNoCerts{}
   260  

View as plain text