1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package integration
16
17 import (
18 "crypto"
19 "crypto/ecdsa"
20 "crypto/elliptic"
21 "crypto/rand"
22 "errors"
23 "fmt"
24 "time"
25
26 "github.com/google/certificate-transparency-go/trillian/ctfe/configpb"
27 "github.com/google/certificate-transparency-go/x509"
28
29 ct "github.com/google/certificate-transparency-go"
30 )
31
32
33 type ChainGenerator interface {
34
35 CertChain() ([]ct.ASN1Cert, error)
36
37 PreCertChain() ([]ct.ASN1Cert, []byte, error)
38 }
39
40
41 type GeneratorFactory func(c *configpb.LogConfig) (ChainGenerator, error)
42
43
44
45 type SyntheticChainGenerator struct {
46 chain []ct.ASN1Cert
47 leafCert *x509.Certificate
48 caCert *x509.Certificate
49
50 signer crypto.Signer
51 notAfter time.Time
52 }
53
54
55
56 func NewSyntheticChainGenerator(chain []ct.ASN1Cert, signer crypto.Signer, notAfter time.Time) (ChainGenerator, error) {
57 if len(chain) < 2 {
58 return nil, fmt.Errorf("chain too short (%d)", len(chain))
59 }
60 leaf, err := x509.ParseCertificate(chain[0].Data)
61 if err != nil {
62 return nil, fmt.Errorf("failed to parse leaf cert: %v", err)
63 }
64 issuer, err := x509.ParseCertificate(chain[1].Data)
65 if err != nil {
66 return nil, fmt.Errorf("failed to parse issuer cert: %v", err)
67 }
68 if notAfter.IsZero() {
69 notAfter = time.Now().Add(24 * time.Hour)
70 }
71 return &SyntheticChainGenerator{
72 chain: chain,
73 leafCert: leaf,
74 caCert: issuer,
75 signer: signer,
76 notAfter: notAfter,
77 }, nil
78 }
79
80
81 func (g *SyntheticChainGenerator) CertChain() ([]ct.ASN1Cert, error) {
82 cert := *g.leafCert
83 cert.NotAfter = g.notAfter
84 chain := make([]ct.ASN1Cert, len(g.chain))
85 copy(chain[1:], g.chain[1:])
86
87
88 randData := make([]byte, 128)
89 if _, err := rand.Read(randData); err != nil {
90 return nil, fmt.Errorf("failed to read random data: %v", err)
91 }
92 cert.SubjectKeyId = randData
93
94
95 var err error
96 chain[0].Data, err = x509.CreateCertificate(rand.Reader, &cert, g.caCert, cert.PublicKey, g.signer)
97 if err != nil {
98 return nil, fmt.Errorf("failed to create certificate: %v", err)
99 }
100
101 return chain, nil
102 }
103
104
105 func (g *SyntheticChainGenerator) PreCertChain() ([]ct.ASN1Cert, []byte, error) {
106 prechain := make([]ct.ASN1Cert, len(g.chain))
107 copy(prechain[1:], g.chain[1:])
108
109 cert, err := x509.ParseCertificate(g.chain[0].Data)
110 if err != nil {
111 return nil, nil, fmt.Errorf("failed to parse certificate to build precert from: %v", err)
112 }
113 cert.NotAfter = g.notAfter
114
115 prechain[0].Data, err = buildNewPrecertData(cert, g.caCert, g.signer)
116 if err != nil {
117 return nil, nil, fmt.Errorf("failed to create certificate: %v", err)
118 }
119
120
121 tbs, err := buildLeafTBS(prechain[0].Data, nil)
122 if err != nil {
123 return nil, nil, fmt.Errorf("failed to build leaf TBSCertificate: %v", err)
124 }
125 return prechain, tbs, nil
126 }
127
128
129
130 func buildLeafTBS(precertData []byte, preIssuer *x509.Certificate) ([]byte, error) {
131 reparsed, err := x509.ParseCertificate(precertData)
132 if err != nil {
133 return nil, fmt.Errorf("failed to re-parse created precertificate: %v", err)
134 }
135 return x509.BuildPrecertTBS(reparsed.RawTBSCertificate, preIssuer)
136 }
137
138
139
140 func makePreIssuerPrecertChain(chain []ct.ASN1Cert, issuer *x509.Certificate, signer crypto.Signer) ([]ct.ASN1Cert, []byte, error) {
141 prechain := make([]ct.ASN1Cert, len(chain)+1)
142 copy(prechain[2:], chain[1:])
143
144
145 preSigner, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
146 if err != nil {
147 return nil, nil, fmt.Errorf("failed to create pre-issuer private key: %v", err)
148 }
149
150 preIssuerTemplate := *issuer
151 preIssuerTemplate.RawSubject = nil
152 preIssuerTemplate.Subject.CommonName += "PrecertIssuer"
153 preIssuerTemplate.PublicKeyAlgorithm = x509.ECDSA
154 preIssuerTemplate.PublicKey = preSigner.Public()
155 preIssuerTemplate.ExtKeyUsage = append(preIssuerTemplate.ExtKeyUsage, x509.ExtKeyUsageCertificateTransparency)
156
157
158
159 randData := make([]byte, 128)
160 if _, err := rand.Read(randData); err != nil {
161 return nil, nil, fmt.Errorf("failed to read random data: %v", err)
162 }
163 preIssuerTemplate.SubjectKeyId = randData
164 prechain[1].Data, err = x509.CreateCertificate(rand.Reader, &preIssuerTemplate, issuer, preIssuerTemplate.PublicKey, signer)
165 if err != nil {
166 return nil, nil, fmt.Errorf("failed to create pre-issuer certificate: %v", err)
167 }
168
169
170 preIssuer, err := x509.ParseCertificate(prechain[1].Data)
171 if err != nil {
172 return nil, nil, fmt.Errorf("failed to re-parse generated pre-issuer: %v", err)
173 }
174
175 cert, err := x509.ParseCertificate(chain[0].Data)
176 if err != nil {
177 return nil, nil, fmt.Errorf("failed to parse certificate to build precert from: %v", err)
178 }
179
180 prechain[0].Data, err = buildNewPrecertData(cert, preIssuer, preSigner)
181 if err != nil {
182 return nil, nil, fmt.Errorf("failed to create certificate: %v", err)
183 }
184
185 if err := verifyChain(prechain); err != nil {
186 return nil, nil, fmt.Errorf("failed to verify just-created prechain: %v", err)
187 }
188
189
190 tbs, err := buildLeafTBS(prechain[0].Data, preIssuer)
191 if err != nil {
192 return nil, nil, fmt.Errorf("failed to build leaf TBSCertificate: %v", err)
193 }
194 return prechain, tbs, nil
195 }
196
197
198 func verifyChain(rawChain []ct.ASN1Cert) error {
199 chain := make([]*x509.Certificate, 0, len(rawChain))
200 for i, c := range rawChain {
201 cert, err := x509.ParseCertificate(c.Data)
202 if err != nil {
203 return fmt.Errorf("failed to parse rawChain[%d]: %v", i, err)
204 }
205 chain = append(chain, cert)
206 }
207
208
209 for i := 1; i < len(chain); i++ {
210 issuer := chain[i]
211 cert := chain[i-1]
212 if err := cert.CheckSignatureFrom(issuer); err != nil {
213 return fmt.Errorf("failed to check signature on rawChain[%d] using rawChain[%d]: %v", i-1, i, err)
214 }
215 }
216
217
218 intermediatePool := x509.NewCertPool()
219 for i := 1; i < len(chain); i++ {
220
221 chain[i].MaxPathLen = -1
222 intermediatePool.AddCert(chain[i])
223 }
224 rootPool := x509.NewCertPool()
225 rootPool.AddCert(chain[len(chain)-1])
226 opts := x509.VerifyOptions{
227 Roots: rootPool,
228 Intermediates: intermediatePool,
229 DisableTimeChecks: true,
230 KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
231 }
232
233 chain[0].UnhandledCriticalExtensions = nil
234 chains, err := chain[0].Verify(opts)
235 if err != nil {
236 return fmt.Errorf("chain[0].Verify(%+v) failed: %v", opts, err)
237 }
238 if len(chains) == 0 {
239 return errors.New("no path to root found when trying to validate chains")
240 }
241
242 return nil
243 }
244
245
246
247 func SyntheticGeneratorFactory(testDir, leafNotAfter string) (GeneratorFactory, error) {
248 leafChain, err := GetChain(testDir, "leaf01.chain")
249 if err != nil {
250 return nil, fmt.Errorf("failed to load certificate: %v", err)
251 }
252 signer, err := MakeSigner(testDir)
253 if err != nil {
254 return nil, fmt.Errorf("failed to retrieve signer for re-signing: %v", err)
255 }
256 var notAfterOverride time.Time
257 if leafNotAfter != "" {
258 notAfterOverride, err = time.Parse(time.RFC3339, leafNotAfter)
259 if err != nil {
260 return nil, fmt.Errorf("failed to parse leaf notAfter: %v", err)
261 }
262 }
263
264 return func(c *configpb.LogConfig) (ChainGenerator, error) {
265 notAfter := notAfterOverride
266 if notAfter.IsZero() {
267 var err error
268 notAfter, err = NotAfterForLog(c)
269 if err != nil {
270 return nil, fmt.Errorf("failed to determine notAfter for %s: %v", c.Prefix, err)
271 }
272 }
273 return NewSyntheticChainGenerator(leafChain, signer, notAfter)
274 }, nil
275 }
276
View as plain text