github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/rpc/tls/common/utils.go (about)

     1  package common
     2  
     3  import (
     4  	"crypto"
     5  	"crypto/ecdsa"
     6  	"crypto/rsa"
     7  	"crypto/tls"
     8  	"crypto/x509"
     9  	"encoding/pem"
    10  	"fmt"
    11  	"github.com/bigzoro/my_simplechain/log"
    12  	"github.com/pkg/errors"
    13  	"io/ioutil"
    14  	"os"
    15  	"strings"
    16  	"time"
    17  )
    18  
    19  // FileExists checks to see if a file exists
    20  func FileExists(name string) bool {
    21  	if _, err := os.Stat(name); err != nil {
    22  		if os.IsNotExist(err) {
    23  			return false
    24  		}
    25  	}
    26  	return true
    27  }
    28  
    29  // GetX509CertificateFromPEM get an X509 certificate from bytes in PEM format
    30  func GetX509CertificateFromPEM(cert []byte) (*x509.Certificate, error) {
    31  	block, _ := pem.Decode(cert)
    32  	if block == nil {
    33  		return nil, errors.New("Failed to PEM decode certificate")
    34  	}
    35  	x509Cert, err := x509.ParseCertificate(block.Bytes)
    36  	if err != nil {
    37  		return nil, errors.Wrap(err, "Error parsing certificate")
    38  	}
    39  	return x509Cert, nil
    40  }
    41  
    42  // LoadX509KeyPair reads and parses a public/private key pair from a pair
    43  // of files. The files must contain PEM encoded data. The certificate file
    44  // may contain intermediate certificates following the leaf certificate to
    45  // form a certificate chain. On successful return, Certificate.Leaf will
    46  // be nil because the parsed form of the certificate is not retained.
    47  func LoadX509KeyPair(certFile, keyFile string) (*tls.Certificate, error) {
    48  	certPEMBlock, err := ioutil.ReadFile(certFile)
    49  	if err != nil {
    50  		return nil, err
    51  	}
    52  	keyPEMBlock, err := ioutil.ReadFile(keyFile)
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  	return X509KeyPair(certPEMBlock, keyPEMBlock)
    57  }
    58  
    59  // X509KeyPair parses a public/private key pair from a pair of
    60  // PEM encoded data. On successful return, Certificate.Leaf will be nil because
    61  // the parsed form of the certificate is not retained.
    62  func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (*tls.Certificate, error) {
    63  	fail := func(err error) (*tls.Certificate, error) { return nil, err }
    64  
    65  	var cert tls.Certificate
    66  	var skippedBlockTypes []string
    67  	for {
    68  		var certDERBlock *pem.Block
    69  		certDERBlock, certPEMBlock = pem.Decode(certPEMBlock)
    70  		if certDERBlock == nil {
    71  			break
    72  		}
    73  		if certDERBlock.Type == "CERTIFICATE" {
    74  			cert.Certificate = append(cert.Certificate, certDERBlock.Bytes)
    75  		} else {
    76  			skippedBlockTypes = append(skippedBlockTypes, certDERBlock.Type)
    77  		}
    78  	}
    79  
    80  	if len(cert.Certificate) == 0 {
    81  		if len(skippedBlockTypes) == 0 {
    82  			return fail(errors.New("tls: failed to find any PEM data in certificate input"))
    83  		}
    84  		if len(skippedBlockTypes) == 1 && strings.HasSuffix(skippedBlockTypes[0], "PRIVATE KEY") {
    85  			return fail(errors.New("tls: failed to find certificate PEM data in certificate input, but did find a private key; PEM inputs may have been switched"))
    86  		}
    87  		return fail(fmt.Errorf("tls: failed to find \"CERTIFICATE\" PEM block in certificate input after skipping PEM blocks of the following types: %v", skippedBlockTypes))
    88  	}
    89  
    90  	skippedBlockTypes = skippedBlockTypes[:0]
    91  	var keyDERBlock *pem.Block
    92  	for {
    93  		keyDERBlock, keyPEMBlock = pem.Decode(keyPEMBlock)
    94  		if keyDERBlock == nil {
    95  			if len(skippedBlockTypes) == 0 {
    96  				return fail(errors.New("tls: failed to find any PEM data in key input"))
    97  			}
    98  			if len(skippedBlockTypes) == 1 && skippedBlockTypes[0] == "CERTIFICATE" {
    99  				return fail(errors.New("tls: found a certificate rather than a key in the PEM for the private key"))
   100  			}
   101  			return fail(fmt.Errorf("tls: failed to find PEM block with type ending in \"PRIVATE KEY\" in key input after skipping PEM blocks of the following types: %v", skippedBlockTypes))
   102  		}
   103  		if keyDERBlock.Type == "PRIVATE KEY" || strings.HasSuffix(keyDERBlock.Type, " PRIVATE KEY") {
   104  			break
   105  		}
   106  		skippedBlockTypes = append(skippedBlockTypes, keyDERBlock.Type)
   107  	}
   108  
   109  	// We don't need to parse the public key for TLS, but we so do anyway
   110  	// to check that it looks sane and matches the private key.
   111  	x509Cert, err := x509.ParseCertificate(cert.Certificate[0])
   112  	if err != nil {
   113  		return fail(err)
   114  	}
   115  
   116  	cert.PrivateKey, err = parsePrivateKey(keyDERBlock.Bytes)
   117  	if err != nil {
   118  		return fail(err)
   119  	}
   120  
   121  	switch pub := x509Cert.PublicKey.(type) {
   122  	case *rsa.PublicKey:
   123  		priv, ok := cert.PrivateKey.(*rsa.PrivateKey)
   124  		if !ok {
   125  			return fail(errors.New("tls: private key type does not match public key type"))
   126  		}
   127  		if pub.N.Cmp(priv.N) != 0 {
   128  			return fail(errors.New("tls: private key does not match public key"))
   129  		}
   130  	case *ecdsa.PublicKey:
   131  		priv, ok := cert.PrivateKey.(*ecdsa.PrivateKey)
   132  		if !ok {
   133  			return fail(errors.New("tls: private key type does not match public key type"))
   134  		}
   135  		if pub.X.Cmp(priv.X) != 0 || pub.Y.Cmp(priv.Y) != 0 {
   136  			return fail(errors.New("tls: private key does not match public key"))
   137  		}
   138  	default:
   139  		return fail(errors.New("tls: unknown public key algorithm"))
   140  	}
   141  
   142  	return &cert, nil
   143  }
   144  
   145  // Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates
   146  // PKCS#1 private keys by default, while OpenSSL 1.0.0 generates PKCS#8 keys.
   147  // OpenSSL ecparam generates SEC1 EC private keys for ECDSA. We try all three.
   148  func parsePrivateKey(der []byte) (crypto.PrivateKey, error) {
   149  	if key, err := x509.ParsePKCS1PrivateKey(der); err == nil {
   150  		return key, nil
   151  	}
   152  	if key, err := x509.ParsePKCS8PrivateKey(der); err == nil {
   153  		switch key := key.(type) {
   154  		case *rsa.PrivateKey, *ecdsa.PrivateKey:
   155  			return key, nil
   156  		default:
   157  			return nil, errors.New("tls: found unknown private key type in PKCS#8 wrapping")
   158  		}
   159  	}
   160  	if key, err := x509.ParseECPrivateKey(der); err == nil {
   161  		return key, nil
   162  	}
   163  
   164  	return nil, errors.New("tls: failed to parse private key")
   165  }
   166  
   167  // LoadPEMCertPool loads a pool of PEM certificates from list of files
   168  func LoadPEMCertPool(certFiles []string) (*x509.CertPool, error) {
   169  	certPool := x509.NewCertPool()
   170  
   171  	if len(certFiles) > 0 {
   172  		for _, cert := range certFiles {
   173  			log.Debug("Reading cert", "file", cert)
   174  			pemCerts, err := ioutil.ReadFile(cert)
   175  			if err != nil {
   176  				return nil, err
   177  			}
   178  
   179  			log.Debug("Appending cert", cert, "to pool")
   180  			if !certPool.AppendCertsFromPEM(pemCerts) {
   181  				return nil, errors.New("Failed to load cert pool")
   182  			}
   183  		}
   184  	}
   185  
   186  	return certPool, nil
   187  }
   188  
   189  func CheckCertDates(certFile string) error {
   190  	log.Debug("Check client TLS certificate for valid dates")
   191  	certPEM, err := ioutil.ReadFile(certFile)
   192  	if err != nil {
   193  		return errors.Wrapf(err, "Failed to read file '%s'", certFile)
   194  	}
   195  
   196  	cert, err := GetX509CertificateFromPEM(certPEM)
   197  	if err != nil {
   198  		return err
   199  	}
   200  
   201  	notAfter := cert.NotAfter
   202  	currentTime := time.Now().UTC()
   203  
   204  	if currentTime.After(notAfter) {
   205  		return errors.New("Certificate provided has expired")
   206  	}
   207  
   208  	notBefore := cert.NotBefore
   209  	if currentTime.Before(notBefore) {
   210  		return errors.New("Certificate provided not valid until later date")
   211  	}
   212  
   213  	return nil
   214  }