github.com/searKing/golang/go@v1.2.117/crypto/tls/cert_helper.go (about)

     1  // Copyright 2020 The searKing Author. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package tls
     6  
     7  import (
     8  	"crypto/ecdsa"
     9  	"crypto/rand"
    10  	"crypto/rsa"
    11  	"crypto/tls"
    12  	"crypto/x509"
    13  	"crypto/x509/pkix"
    14  	"encoding/pem"
    15  	"errors"
    16  	"fmt"
    17  	"math/big"
    18  	"time"
    19  )
    20  
    21  // PublicKey returns the public key for a given key or nul.
    22  func PublicKey(key any) any {
    23  	switch k := key.(type) {
    24  	case *rsa.PrivateKey:
    25  		return &k.PublicKey
    26  	case *ecdsa.PrivateKey:
    27  		return &k.PublicKey
    28  	default:
    29  		return nil
    30  	}
    31  }
    32  
    33  // CreateSelfSignedTLSCertificate creates a self-signed TLS certificate.
    34  // key is parsed by PublicKey()
    35  func CreateSelfSignedTLSCertificate(key any, organizations []string, commonName string) (*tls.Certificate, error) {
    36  	c, err := CreateSelfSignedCertificate(key, organizations, commonName)
    37  	if err != nil {
    38  		return nil, err
    39  	}
    40  
    41  	block, err := PEMBlockForKey(key)
    42  	if err != nil {
    43  		return nil, err
    44  	}
    45  
    46  	pemCert := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: c.Raw})
    47  	pemKey := pem.EncodeToMemory(block)
    48  	cert, err := tls.X509KeyPair(pemCert, pemKey)
    49  	if err != nil {
    50  		return nil, err
    51  	}
    52  
    53  	return &cert, nil
    54  }
    55  
    56  // CreateSelfSignedCertificate creates a self-signed x509 certificate.
    57  // key is parsed by PublicKey()
    58  func CreateSelfSignedCertificate(key any, organizations []string, commonName string) (cert *x509.Certificate, err error) {
    59  	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
    60  	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
    61  	if err != nil {
    62  		return cert, fmt.Errorf("failed to generate serial number: %s", err)
    63  	}
    64  
    65  	certificate := &x509.Certificate{
    66  		SerialNumber: serialNumber,
    67  		Subject: pkix.Name{
    68  			Organization: organizations,
    69  			CommonName:   commonName,
    70  		},
    71  		Issuer: pkix.Name{
    72  			Organization: organizations,
    73  			CommonName:   commonName,
    74  		},
    75  		NotBefore:             time.Now().UTC(),
    76  		NotAfter:              time.Now().UTC().Add(time.Hour * 24 * 31),
    77  		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
    78  		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
    79  		BasicConstraintsValid: true,
    80  	}
    81  
    82  	certificate.IsCA = true
    83  	certificate.KeyUsage |= x509.KeyUsageCertSign
    84  	certificate.DNSNames = append(certificate.DNSNames, "localhost")
    85  	der, err := x509.CreateCertificate(rand.Reader, certificate, certificate, PublicKey(key), key)
    86  	if err != nil {
    87  		return cert, fmt.Errorf("failed to create certificate: %s", err)
    88  	}
    89  
    90  	cert, err = x509.ParseCertificate(der)
    91  	if err != nil {
    92  		return cert, fmt.Errorf("failed to encode private key: %s", err)
    93  	}
    94  	return cert, nil
    95  }
    96  
    97  // PEMBlockForKey returns a PEM-encoded block for key.
    98  // key is parsed by PublicKey()
    99  func PEMBlockForKey(key any) (*pem.Block, error) {
   100  	switch k := key.(type) {
   101  	case *rsa.PrivateKey:
   102  		return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}, nil
   103  	case *ecdsa.PrivateKey:
   104  		b, err := x509.MarshalECPrivateKey(k)
   105  		if err != nil {
   106  			return nil, err
   107  		}
   108  		return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}, nil
   109  	default:
   110  		return nil, errors.New("invalid key type")
   111  	}
   112  }