-
Notifications
You must be signed in to change notification settings - Fork 0
/
certgen_test.go
122 lines (108 loc) · 3.65 KB
/
certgen_test.go
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
122
// Copyright (c) 2013-2015 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package cashutil_test
import (
"crypto/x509"
"encoding/pem"
"net"
"testing"
"time"
"github.com/bcext/cashutil"
)
// TestNewTLSCertPair ensures the NewTLSCertPair function works as expected.
func TestNewTLSCertPair(t *testing.T) {
// Certs don't support sub-second precision, so truncate it now to
// ensure the checks later don't fail due to nanosecond precision
// differences.
validUntil := time.Unix(time.Now().Add(10*365*24*time.Hour).Unix(), 0)
org := "test autogenerated cert"
extraHosts := []string{"testtlscert.bogus", "localhost", "127.0.0.1"}
cert, key, err := cashutil.NewTLSCertPair(org, validUntil, extraHosts)
if err != nil {
t.Fatalf("failed with unexpected error: %v", err)
}
// Ensure the PEM-encoded cert that is returned can be decoded.
pemCert, _ := pem.Decode(cert)
if pemCert == nil {
t.Fatalf("pem.Decode was unable to decode the certificate")
}
// Ensure the PEM-encoded key that is returned can be decoded.
pemKey, _ := pem.Decode(key)
if pemCert == nil {
t.Fatalf("pem.Decode was unable to decode the key")
}
// Ensure the DER-encoded key bytes can be successfully parsed.
_, err = x509.ParseECPrivateKey(pemKey.Bytes)
if err != nil {
t.Fatalf("failed with unexpected error: %v", err)
}
// Ensure the DER-encoded cert bytes can be successfully into an X.509
// certificate.
x509Cert, err := x509.ParseCertificate(pemCert.Bytes)
if err != nil {
t.Fatalf("failed with unexpected error: %v", err)
}
// Ensure the specified organization is correct.
x509Orgs := x509Cert.Subject.Organization
if len(x509Orgs) == 0 || x509Orgs[0] != org {
x509Org := "<no organization>"
if len(x509Orgs) > 0 {
x509Org = x509Orgs[0]
}
t.Fatalf("generated cert organization field mismatch, got "+
"'%v', want '%v'", x509Org, org)
}
// Ensure the specified valid until value is correct.
if !x509Cert.NotAfter.Equal(validUntil) {
t.Fatalf("generated cert valid until field mismatch, got %v, "+
"want %v", x509Cert.NotAfter, validUntil)
}
// Ensure the specified extra hosts are present.
for _, host := range extraHosts {
if err := x509Cert.VerifyHostname(host); err != nil {
t.Fatalf("failed to verify extra host '%s'", host)
}
}
// Ensure that the Common Name is also the first SAN DNS name.
cn := x509Cert.Subject.CommonName
san0 := x509Cert.DNSNames[0]
if cn != san0 {
t.Errorf("common name %s does not match first SAN %s", cn, san0)
}
// Ensure there are no duplicate hosts or IPs.
hostCounts := make(map[string]int)
for _, host := range x509Cert.DNSNames {
hostCounts[host]++
}
ipCounts := make(map[string]int)
for _, ip := range x509Cert.IPAddresses {
ipCounts[string(ip)]++
}
for host, count := range hostCounts {
if count != 1 {
t.Errorf("host %s appears %d times in certificate", host, count)
}
}
for ipStr, count := range ipCounts {
if count != 1 {
t.Errorf("ip %s appears %d times in certificate", net.IP(ipStr), count)
}
}
// Ensure the cert can be use for the intended purposes.
if !x509Cert.IsCA {
t.Fatal("generated cert is not a certificate authority")
}
if x509Cert.KeyUsage&x509.KeyUsageKeyEncipherment == 0 {
t.Fatal("generated cert can't be used for key encipherment")
}
if x509Cert.KeyUsage&x509.KeyUsageDigitalSignature == 0 {
t.Fatal("generated cert can't be used for digital signatures")
}
if x509Cert.KeyUsage&x509.KeyUsageCertSign == 0 {
t.Fatal("generated cert can't be used for signing other certs")
}
if !x509Cert.BasicConstraintsValid {
t.Fatal("generated cert does not have valid basic constraints")
}
}