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 }