github.com/mit-dci/lit@v0.0.0-20221102210550-8c3d3b49f2ce/btcutil/certgen.go (about) 1 // Copyright (c) 2013-2015 The btcsuite developers 2 // Use of this source code is governed by an ISC 3 // license that can be found in the LICENSE file. 4 5 package btcutil 6 7 import ( 8 "bytes" 9 "crypto/ecdsa" 10 "crypto/elliptic" 11 "crypto/rand" 12 _ "crypto/sha512" // Needed for RegisterHash in init 13 "crypto/x509" 14 "crypto/x509/pkix" 15 "encoding/pem" 16 "errors" 17 "fmt" 18 "math/big" 19 "net" 20 "os" 21 "time" 22 ) 23 24 // NewTLSCertPair returns a new PEM-encoded x.509 certificate pair 25 // based on a 521-bit ECDSA private key. The machine's local interface 26 // addresses and all variants of IPv4 and IPv6 localhost are included as 27 // valid IP addresses. 28 func NewTLSCertPair(organization string, validUntil time.Time, extraHosts []string) (cert, key []byte, err error) { 29 now := time.Now() 30 if validUntil.Before(now) { 31 return nil, nil, errors.New("validUntil would create an already-expired certificate") 32 } 33 34 priv, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader) 35 if err != nil { 36 return nil, nil, err 37 } 38 39 // end of ASN.1 time 40 endOfTime := time.Date(2049, 12, 31, 23, 59, 59, 0, time.UTC) 41 if validUntil.After(endOfTime) { 42 validUntil = endOfTime 43 } 44 45 serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) 46 serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) 47 if err != nil { 48 return nil, nil, fmt.Errorf("failed to generate serial number: %s", err) 49 } 50 51 host, err := os.Hostname() 52 if err != nil { 53 return nil, nil, err 54 } 55 56 ipAddresses := []net.IP{net.ParseIP("127.0.0.1"), net.ParseIP("::1")} 57 dnsNames := []string{host} 58 if host != "localhost" { 59 dnsNames = append(dnsNames, "localhost") 60 } 61 62 addIP := func(ipAddr net.IP) { 63 for _, ip := range ipAddresses { 64 if bytes.Equal(ip, ipAddr) { 65 return 66 } 67 } 68 ipAddresses = append(ipAddresses, ipAddr) 69 } 70 addHost := func(host string) { 71 for _, dnsName := range dnsNames { 72 if host == dnsName { 73 return 74 } 75 } 76 dnsNames = append(dnsNames, host) 77 } 78 79 addrs, err := interfaceAddrs() 80 if err != nil { 81 return nil, nil, err 82 } 83 for _, a := range addrs { 84 ipAddr, _, err := net.ParseCIDR(a.String()) 85 if err == nil { 86 addIP(ipAddr) 87 } 88 } 89 90 for _, hostStr := range extraHosts { 91 host, _, err := net.SplitHostPort(hostStr) 92 if err != nil { 93 host = hostStr 94 } 95 if ip := net.ParseIP(host); ip != nil { 96 addIP(ip) 97 } else { 98 addHost(host) 99 } 100 } 101 102 template := x509.Certificate{ 103 SerialNumber: serialNumber, 104 Subject: pkix.Name{ 105 Organization: []string{organization}, 106 CommonName: host, 107 }, 108 NotBefore: now.Add(-time.Hour * 24), 109 NotAfter: validUntil, 110 111 KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | 112 x509.KeyUsageCertSign, 113 IsCA: true, // so can sign self. 114 BasicConstraintsValid: true, 115 116 DNSNames: dnsNames, 117 IPAddresses: ipAddresses, 118 } 119 120 derBytes, err := x509.CreateCertificate(rand.Reader, &template, 121 &template, &priv.PublicKey, priv) 122 if err != nil { 123 return nil, nil, fmt.Errorf("failed to create certificate: %v", err) 124 } 125 126 certBuf := &bytes.Buffer{} 127 err = pem.Encode(certBuf, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) 128 if err != nil { 129 return nil, nil, fmt.Errorf("failed to encode certificate: %v", err) 130 } 131 132 keybytes, err := x509.MarshalECPrivateKey(priv) 133 if err != nil { 134 return nil, nil, fmt.Errorf("failed to marshal private key: %v", err) 135 } 136 137 keyBuf := &bytes.Buffer{} 138 err = pem.Encode(keyBuf, &pem.Block{Type: "EC PRIVATE KEY", Bytes: keybytes}) 139 if err != nil { 140 return nil, nil, fmt.Errorf("failed to encode private key: %v", err) 141 } 142 143 return certBuf.Bytes(), keyBuf.Bytes(), nil 144 }