Root issuers lack CA Chain + Chain Building Bug Fix (#15306)

* Return the ca_chain response from root issued cert api

* Fix parent selection in cert chain building

When building chains, we'd choose the next neighbor from Go's
unordered map. However, this doesn't necessarily result in the most
optimal path: we want to prefer to visit roots over other
intermediates, as this allows us to have a more consistent chain,
putting roots before their cross-signed equivalents rather than
potentially at the end.

We additionally now ensure chains are stable.

Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>

Co-authored-by: Steve Clark <steven.clark@hashicorp.com>
This commit is contained in:
Alexander Scheel
2022-05-11 13:09:18 -04:00
committed by GitHub
parent 46ffd77ded
commit aa93464b95
6 changed files with 350 additions and 29 deletions

View File

@@ -871,16 +871,25 @@ func createCertificate(data *CreationBundle, randReader io.Reader, privateKeyGen
}
if data.SigningBundle != nil {
if len(data.SigningBundle.Certificate.AuthorityKeyId) > 0 &&
!bytes.Equal(data.SigningBundle.Certificate.AuthorityKeyId, data.SigningBundle.Certificate.SubjectKeyId) {
if (len(data.SigningBundle.Certificate.AuthorityKeyId) > 0 &&
!bytes.Equal(data.SigningBundle.Certificate.AuthorityKeyId, data.SigningBundle.Certificate.SubjectKeyId)) ||
data.Params.ForceAppendCaChain {
var chain []*CertBlock
result.CAChain = []*CertBlock{
{
signingChain := data.SigningBundle.CAChain
// Some bundles already include the root included in the chain, so don't include it twice.
if len(signingChain) == 0 || !bytes.Equal(signingChain[0].Bytes, data.SigningBundle.CertificateBytes) {
chain = append(chain, &CertBlock{
Certificate: data.SigningBundle.Certificate,
Bytes: data.SigningBundle.CertificateBytes,
},
})
}
result.CAChain = append(result.CAChain, data.SigningBundle.CAChain...)
if len(signingChain) > 0 {
chain = append(chain, signingChain...)
}
result.CAChain = chain
}
}
@@ -1158,7 +1167,7 @@ func signCertificate(data *CreationBundle, randReader io.Reader) (*ParsedCertBun
return nil, errutil.InternalError{Err: fmt.Sprintf("unable to parse created certificate: %s", err)}
}
result.CAChain = data.SigningBundle.GetCAChain()
result.CAChain = data.SigningBundle.GetFullChain()
return result, nil
}

View File

@@ -704,13 +704,7 @@ func (b *CAInfoBundle) GetCAChain() []*CertBlock {
(len(b.Certificate.AuthorityKeyId) == 0 &&
!bytes.Equal(b.Certificate.RawIssuer, b.Certificate.RawSubject)) {
chain = append(chain, &CertBlock{
Certificate: b.Certificate,
Bytes: b.CertificateBytes,
})
if b.CAChain != nil && len(b.CAChain) > 0 {
chain = append(chain, b.CAChain...)
}
chain = b.GetFullChain()
}
return chain
@@ -771,6 +765,7 @@ type CreationParameters struct {
PolicyIdentifiers []string
BasicConstraintsValidForNonCA bool
SignatureBits int
ForceAppendCaChain bool
// Only used when signing a CA cert
UseCSRValues bool