fetchIntermediates
This post came from a short-lived blog I tried to run (tail-recursion.net) where I wanted to write up a short bit of code I'd written that week.
This code sample is a depth-first search for a valid certificate chain; it's notable in that it's non-recursive and I got it right the first time. It's part of a certificate authority API server, in a package that bundles certificates to hand off to a customer for deployment to their server.
A fetchedIntermediate stores the certificate and the filename,
providing enough information to both use the certificate and remember
what filename it should be stashed as.
type fetchedIntermediate struct {
Cert *x509.Certificate
Name string
}
fetchIntermediate goes through each of the URLs in the AIA "Issuing
CA" extensions and fetches those certificates. If those certificates
are not present in either the root pool or intermediate pool, the
certificate is saved to file and added to the list of intermediates to
be used for verification. This will not add any new certificates to
the root pool; if the ultimate issuer is not trusted, fetching the
certicate here will not change that.
func (b *Bundler) fetchIntermediates(cert *x509.Certificate) (err error) {
intermediateStash is where intermediate certificates that aren't in
the intermediate pool (which is a field of the Bundler type) are
stored so that we can go back later and add them to the intermediate
bundle loaded at start.
_, err = os.Stat(intermedateStash)
if err != nil && os.IsNotExist(err) {
err = os.MkdirAll(intermediateStash, 0755)
}
if err != nil {
return
}
seen is used as a sentinal; a certificate's signature is unique to
that certificate, by definition (if it were replicated, it would be a
breach of security). This will uniquely identify a certificate,
distinguishing even the case where two certificates share a public key
but have different metadata.
seen := map[string]bool{string(cert.Signature): true}
var foundChains int
chain := []*fetchedIntermediate{&fetchedIntermediate{cert, ""}}
for {
if len(chain) == 0 {
if foundChains == 0 {
return errors.New("bundler: no chains found")
}
return nil
}
current := chain[0]
isChainRootNode checks to see whether the certificate is in the root
certificate store or if it has no Issuer fields; it is assumed this is
the end point for the chain. Interestingly enough, it turns out this
is not a valid assumption; while the relevant RFC would suggest it to
good practice, in practice certificate authorities tend to diverge
from the RFCs in subtle and creative ways.
if isChainRootNode(current.Cert) {
if b.verifyChain(chain) {
foundChains++
}
}
var advanced bool
for _, url := range current.Cert.IssuingCertificateURL {
if seen[url] {
continue
}
crt, err := fetchRemoteCertificate(url)
if err != nil {
continue
} else if seen[string(crt.Cert.Signature)] {
continue
}
seen[url] = true
seen[string(crt.Cert.Signature)] = true
chain = append([]*fetchedIntermediate{crt}, chain...)
advanced = true
break
}
if !advanced {
chain = chain[1:]
}
}
return
}
This snippet enabled our certificate authority to still build chains from intermediate certificates that weren't in our pool, and in the first week of running it we gathered several new intermediates where previously bundling would have failed. Obviously, this is a business win -- it's a better solution to the problem of building certificate bundles than what we had. The challenge here was not doing a recursive fetch; there were subtle problems that we had in the first attempt at doing so.
The untransformed code is available.