github.com/pion/dtls/v2@v2.2.12/pkg/crypto/selfsign/selfsign.go (about)

     1  // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
     2  // SPDX-License-Identifier: MIT
     3  
     4  // Package selfsign is a test helper that generates self signed certificate.
     5  package selfsign
     6  
     7  import (
     8  	"crypto"
     9  	"crypto/ecdsa"
    10  	"crypto/ed25519"
    11  	"crypto/elliptic"
    12  	"crypto/rand"
    13  	"crypto/rsa"
    14  	"crypto/tls"
    15  	"crypto/x509"
    16  	"crypto/x509/pkix"
    17  	"errors"
    18  	"math/big"
    19  	"time"
    20  )
    21  
    22  var errInvalidPrivateKey = errors.New("selfsign: invalid private key type")
    23  
    24  // GenerateSelfSigned creates a self-signed certificate
    25  func GenerateSelfSigned() (tls.Certificate, error) {
    26  	priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
    27  	if err != nil {
    28  		return tls.Certificate{}, err
    29  	}
    30  
    31  	return SelfSign(priv)
    32  }
    33  
    34  // GenerateSelfSignedWithDNS creates a self-signed certificate
    35  func GenerateSelfSignedWithDNS(cn string, sans ...string) (tls.Certificate, error) {
    36  	priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
    37  	if err != nil {
    38  		return tls.Certificate{}, err
    39  	}
    40  
    41  	return WithDNS(priv, cn, sans...)
    42  }
    43  
    44  // SelfSign creates a self-signed certificate from a elliptic curve key
    45  func SelfSign(key crypto.PrivateKey) (tls.Certificate, error) {
    46  	return WithDNS(key, "self-signed cert")
    47  }
    48  
    49  // WithDNS creates a self-signed certificate from a elliptic curve key
    50  func WithDNS(key crypto.PrivateKey, cn string, sans ...string) (tls.Certificate, error) {
    51  	var (
    52  		pubKey    crypto.PublicKey
    53  		maxBigInt = new(big.Int) // Max random value, a 130-bits integer, i.e 2^130 - 1
    54  	)
    55  
    56  	switch k := key.(type) {
    57  	case ed25519.PrivateKey:
    58  		pubKey = k.Public()
    59  	case *ecdsa.PrivateKey:
    60  		pubKey = k.Public()
    61  	case *rsa.PrivateKey:
    62  		pubKey = k.Public()
    63  	default:
    64  		return tls.Certificate{}, errInvalidPrivateKey
    65  	}
    66  
    67  	/* #nosec */
    68  	maxBigInt.Exp(big.NewInt(2), big.NewInt(130), nil).Sub(maxBigInt, big.NewInt(1))
    69  	/* #nosec */
    70  	serialNumber, err := rand.Int(rand.Reader, maxBigInt)
    71  	if err != nil {
    72  		return tls.Certificate{}, err
    73  	}
    74  
    75  	names := []string{cn}
    76  	names = append(names, sans...)
    77  
    78  	keyUsage := x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign
    79  	if _, isRSA := key.(*rsa.PrivateKey); isRSA {
    80  		keyUsage |= x509.KeyUsageKeyEncipherment
    81  	}
    82  
    83  	template := x509.Certificate{
    84  		ExtKeyUsage: []x509.ExtKeyUsage{
    85  			x509.ExtKeyUsageClientAuth,
    86  			x509.ExtKeyUsageServerAuth,
    87  		},
    88  		BasicConstraintsValid: true,
    89  		NotBefore:             time.Now(),
    90  		KeyUsage:              keyUsage,
    91  		NotAfter:              time.Now().AddDate(0, 1, 0),
    92  		SerialNumber:          serialNumber,
    93  		Version:               2,
    94  		IsCA:                  true,
    95  		DNSNames:              names,
    96  		Subject: pkix.Name{
    97  			CommonName: cn,
    98  		},
    99  	}
   100  
   101  	raw, err := x509.CreateCertificate(rand.Reader, &template, &template, pubKey, key)
   102  	if err != nil {
   103  		return tls.Certificate{}, err
   104  	}
   105  
   106  	leaf, err := x509.ParseCertificate(raw)
   107  	if err != nil {
   108  		return tls.Certificate{}, err
   109  	}
   110  
   111  	return tls.Certificate{
   112  		Certificate: [][]byte{raw},
   113  		PrivateKey:  key,
   114  		Leaf:        leaf,
   115  	}, nil
   116  }