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