-
Notifications
You must be signed in to change notification settings - Fork 291
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
certgen: Support Ed25519 cert generation on Go 1.13
This adds the function NewEd25519TLSCertPair which uses Ed25519 keys rather than ECDSA keys as required by NewTLSCertPair. Conditional compilation is used to provide the function only on Go 1.13. It also updates the documentation accordingly.
- Loading branch information
Showing
4 changed files
with
160 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
// Copyright (c) 2013-2015 The btcsuite developers | ||
// Copyright (c) 2015-2019 The Decred developers | ||
// Use of this source code is governed by an ISC | ||
// license that can be found in the LICENSE file. | ||
|
||
//+build go1.13 | ||
|
||
package certgen | ||
|
||
import ( | ||
"bytes" | ||
"crypto/ed25519" | ||
"crypto/rand" | ||
"crypto/x509" | ||
"crypto/x509/pkix" | ||
"encoding/pem" | ||
"errors" | ||
"fmt" | ||
"math/big" | ||
"net" | ||
"os" | ||
"time" | ||
) | ||
|
||
// NewEd25519TLSCertPair returns a new PEM-encoded x.509 certificate pair with | ||
// new Ed25519 keys. The machine's local interface addresses and all variants | ||
// of IPv4 and IPv6 localhost are included as valid IP addresses. | ||
func NewEd25519TLSCertPair(organization string, validUntil time.Time, extraHosts []string) (cert, key []byte, err error) { | ||
now := time.Now() | ||
if validUntil.Before(now) { | ||
return nil, nil, errors.New("validUntil would create an already-expired certificate") | ||
} | ||
|
||
seed := make([]byte, ed25519.SeedSize) | ||
_, err = rand.Read(seed) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
priv := ed25519.NewKeyFromSeed(seed) | ||
|
||
// end of ASN.1 time | ||
endOfTime := time.Date(2049, 12, 31, 23, 59, 59, 0, time.UTC) | ||
if validUntil.After(endOfTime) { | ||
validUntil = endOfTime | ||
} | ||
|
||
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) | ||
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) | ||
if err != nil { | ||
return nil, nil, fmt.Errorf("failed to generate serial number: %s", err) | ||
} | ||
|
||
host, err := os.Hostname() | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
ipAddresses := []net.IP{net.ParseIP("127.0.0.1"), net.ParseIP("::1")} | ||
dnsNames := []string{host} | ||
if host != "localhost" { | ||
dnsNames = append(dnsNames, "localhost") | ||
} | ||
|
||
addIP := func(ipAddr net.IP) { | ||
for _, ip := range ipAddresses { | ||
if bytes.Equal(ip, ipAddr) { | ||
return | ||
} | ||
} | ||
ipAddresses = append(ipAddresses, ipAddr) | ||
} | ||
addHost := func(host string) { | ||
for _, dnsName := range dnsNames { | ||
if host == dnsName { | ||
return | ||
} | ||
} | ||
dnsNames = append(dnsNames, host) | ||
} | ||
|
||
addrs, err := interfaceAddrs() | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
for _, a := range addrs { | ||
ipAddr, _, err := net.ParseCIDR(a.String()) | ||
if err == nil { | ||
addIP(ipAddr) | ||
} | ||
} | ||
|
||
for _, hostStr := range extraHosts { | ||
host, _, err := net.SplitHostPort(hostStr) | ||
if err != nil { | ||
host = hostStr | ||
} | ||
if ip := net.ParseIP(host); ip != nil { | ||
addIP(ip) | ||
} else { | ||
addHost(host) | ||
} | ||
} | ||
|
||
template := x509.Certificate{ | ||
SerialNumber: serialNumber, | ||
Subject: pkix.Name{ | ||
Organization: []string{organization}, | ||
CommonName: host, | ||
}, | ||
NotBefore: now.Add(-time.Hour * 24), | ||
NotAfter: validUntil, | ||
|
||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | | ||
x509.KeyUsageCertSign, | ||
IsCA: true, // so can sign self. | ||
BasicConstraintsValid: true, | ||
|
||
DNSNames: dnsNames, | ||
IPAddresses: ipAddresses, | ||
} | ||
|
||
derBytes, err := x509.CreateCertificate(rand.Reader, &template, | ||
&template, priv.Public(), priv) | ||
if err != nil { | ||
return nil, nil, fmt.Errorf("failed to create certificate: %v", err) | ||
} | ||
|
||
certBuf := &bytes.Buffer{} | ||
err = pem.Encode(certBuf, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) | ||
if err != nil { | ||
return nil, nil, fmt.Errorf("failed to encode certificate: %v", err) | ||
} | ||
|
||
keybytes, err := x509.MarshalPKCS8PrivateKey(priv) | ||
if err != nil { | ||
return nil, nil, fmt.Errorf("failed to marshal private key: %v", err) | ||
} | ||
|
||
keyBuf := &bytes.Buffer{} | ||
err = pem.Encode(keyBuf, &pem.Block{Type: "PRIVATE KEY", Bytes: keybytes}) | ||
if err != nil { | ||
return nil, nil, fmt.Errorf("failed to encode private key: %v", err) | ||
} | ||
|
||
return certBuf.Bytes(), keyBuf.Bytes(), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters