Skip to content

Commit ae4905e

Browse files
committed
New x509 helper
Signed-off-by: apostasie <spam_blackhole@farcloser.world>
1 parent 877f9b3 commit ae4905e

File tree

2 files changed

+168
-161
lines changed
  • mod/tigron/utils
  • pkg/testutil/nerdtest/ca

2 files changed

+168
-161
lines changed

mod/tigron/utils/ca.go

+168
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
/*
2+
Copyright The containerd Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package utils
18+
19+
import (
20+
"crypto/rand"
21+
"crypto/rsa"
22+
"crypto/x509"
23+
"crypto/x509/pkix"
24+
"encoding/pem"
25+
"io"
26+
"math/big"
27+
"net"
28+
"time"
29+
30+
"github.com/containerd/nerdctl/mod/tigron/internal/assertive"
31+
"github.com/containerd/nerdctl/mod/tigron/test"
32+
"github.com/containerd/nerdctl/mod/tigron/tig"
33+
)
34+
35+
const (
36+
keyLength = 4096
37+
caRoot = "ca"
38+
certsRoot = "certs"
39+
organization = "tigron volatile testing organization"
40+
lifetime = 24 * time.Hour
41+
serialSize = 60
42+
)
43+
44+
// NewX509 creates a new, self-signed, signing certificate under data.Temp()/ca
45+
// From that Cert as a CA, you can then generate signed certificates.
46+
// Note that the common name of the cert will be set to the test name.
47+
// PLEASE NOTE THIS IS NOT A PRODUCTION SAFE NOR VERIFIED WAY TO MANAGE CERTIFICATES FOR SERVERS.
48+
func NewX509(data test.Data, helpers test.Helpers) *Cert {
49+
template := &x509.Certificate{
50+
Subject: pkix.Name{
51+
Organization: []string{organization},
52+
CommonName: helpers.T().Name(),
53+
},
54+
NotBefore: time.Now(),
55+
NotAfter: time.Now().Add(lifetime),
56+
IsCA: true,
57+
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
58+
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
59+
BasicConstraintsValid: true,
60+
}
61+
62+
return (&Cert{}).GenerateCustomX509(data, helpers, caRoot, template)
63+
}
64+
65+
// Cert allows the consumer to retrieve the cert and key path, to be used by other processes, like servers for example.
66+
type Cert struct {
67+
KeyPath string
68+
CertPath string
69+
key *rsa.PrivateKey
70+
cert *x509.Certificate
71+
}
72+
73+
// GenerateServerX509 produces a certificate usable by a server.
74+
// additional can be used to provide additional ips to be added to the certificate.
75+
func (ca *Cert) GenerateServerX509(data test.Data, helpers test.Helpers, host string, additional ...string) *Cert {
76+
template := &x509.Certificate{
77+
Subject: pkix.Name{
78+
Organization: []string{organization},
79+
CommonName: host,
80+
},
81+
NotBefore: time.Now(),
82+
NotAfter: time.Now().Add(lifetime),
83+
KeyUsage: x509.KeyUsageCRLSign,
84+
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
85+
DNSNames: additional,
86+
}
87+
88+
additional = append([]string{host}, additional...)
89+
for _, h := range additional {
90+
if ip := net.ParseIP(h); ip != nil {
91+
template.IPAddresses = append(template.IPAddresses, ip)
92+
}
93+
}
94+
95+
return ca.GenerateCustomX509(data, helpers, certsRoot, template)
96+
}
97+
98+
// GenerateCustomX509 signs a random x509 certificate template.
99+
// Note that if SerialNumber is specified, it must be safe to use on the filesystem as this will be used in the name
100+
// of the certificate file.
101+
func (ca *Cert) GenerateCustomX509(
102+
data test.Data,
103+
helpers test.Helpers,
104+
underDirectory string,
105+
template *x509.Certificate,
106+
) *Cert {
107+
silentT := assertive.WithSilentSuccess(helpers.T())
108+
key, certPath, keyPath := createCert(silentT, data, underDirectory, template, ca.cert, ca.key)
109+
110+
return &Cert{
111+
CertPath: certPath,
112+
KeyPath: keyPath,
113+
key: key,
114+
cert: template,
115+
}
116+
}
117+
118+
func createCert(
119+
testing tig.T,
120+
data test.Data,
121+
dir string,
122+
template, caCert *x509.Certificate,
123+
caKey *rsa.PrivateKey,
124+
) (key *rsa.PrivateKey, certPath, keyPath string) {
125+
if caCert == nil {
126+
caCert = template
127+
}
128+
129+
if caKey == nil {
130+
caKey = key
131+
}
132+
133+
key, err := rsa.GenerateKey(rand.Reader, keyLength)
134+
assertive.ErrorIsNil(testing, err, "key generation should succeed")
135+
136+
signedCert, err := x509.CreateCertificate(rand.Reader, template, caCert, &key.PublicKey, caKey)
137+
assertive.ErrorIsNil(testing, err, "certificate creation should succeed")
138+
139+
serial := template.SerialNumber
140+
if serial == nil {
141+
serial = serialNumber()
142+
}
143+
144+
data.Temp().Dir(dir)
145+
certPath = data.Temp().Path(dir, serial.String()+".cert")
146+
keyPath = data.Temp().Path(dir, serial.String()+".key")
147+
148+
data.Temp().SaveToWriter(func(writer io.Writer) error {
149+
return pem.Encode(writer, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)})
150+
}, keyPath)
151+
152+
data.Temp().SaveToWriter(func(writer io.Writer) error {
153+
return pem.Encode(writer, &pem.Block{Type: "CERTIFICATE", Bytes: signedCert})
154+
}, keyPath)
155+
156+
return key, certPath, keyPath
157+
}
158+
159+
func serialNumber() *big.Int {
160+
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), serialSize)
161+
162+
serial, err := rand.Int(rand.Reader, serialNumberLimit)
163+
if err != nil {
164+
panic(err)
165+
}
166+
167+
return serial
168+
}

pkg/testutil/nerdtest/ca/ca.go

-161
This file was deleted.

0 commit comments

Comments
 (0)