Skip to content

Commit 858a9e8

Browse files
added utility code for extracting CA from cert+chain.
1 parent 3d870ea commit 858a9e8

File tree

1 file changed

+56
-2
lines changed

1 file changed

+56
-2
lines changed

cert_util.go

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"context"
1515
"crypto/rand"
1616
"crypto/rsa"
17+
"crypto/sha1"
1718
"crypto/x509"
1819
"crypto/x509/pkix"
1920
"encoding/asn1"
@@ -45,9 +46,11 @@ func fetchCAInfo(ctx context.Context, req *logical.Request, b *keyfactorBackend)
4546
}
4647

4748
caEntry, err := req.Storage.Get(ctx, "ca")
49+
4850
if err != nil {
4951
return logical.ErrorResponse("error fetching ca: %s", err), nil
5052
}
53+
5154
if caEntry != nil {
5255
var r map[string]interface{}
5356
json.Unmarshal(caEntry.Value, &r)
@@ -59,8 +62,13 @@ func fetchCAInfo(ctx context.Context, req *logical.Request, b *keyfactorBackend)
5962
return resp, nil
6063
}
6164

62-
// if not we search certs for 'CA -eq "<ca_name>" AND CertState -eq "6"'
63-
//
65+
// if not, we retreive the CA entry from the "CertificateAuthorities" endpoint
66+
67+
// then we look up certs with CertificateAuthorityId = the CA ID.
68+
69+
// if at least one exists, we download the cert and chain
70+
71+
// if not; we can't get it yet; return appropriate error
6472

6573
caId, err := getCAId(ctx, req, b)
6674
if err != nil {
@@ -404,6 +412,52 @@ func normalizeSerial(serial string) string {
404412
return strings.Replace(strings.ToLower(serial), ":", "-", -1)
405413
}
406414

415+
// ensureCorrectOrder ensures the correct order of the certificate chain using a known leaf thumbprint
416+
func ensureCorrectOrder(chain []*x509.Certificate, leafThumbprint string) []*x509.Certificate {
417+
var leaf *x509.Certificate
418+
var intermediates []*x509.Certificate
419+
var root *x509.Certificate
420+
421+
// Identify the leaf, intermediate(s), and root
422+
for _, cert := range chain {
423+
if cert.CheckSignatureFrom(cert) == nil {
424+
root = cert // Verified self-signed root
425+
} else if getCertThumbprint(cert) == leafThumbprint {
426+
leaf = cert
427+
} else {
428+
intermediates = append(intermediates, cert)
429+
}
430+
}
431+
432+
// Sort intermediates by issuer-subject relationship
433+
sortedIntermediates := make([]*x509.Certificate, 0, len(intermediates))
434+
remaining := append([]*x509.Certificate{}, intermediates...)
435+
436+
for len(remaining) > 0 {
437+
for i, cert := range remaining {
438+
if len(sortedIntermediates) == 0 || sortedIntermediates[len(sortedIntermediates)-1].Subject.String() == cert.Issuer.String() {
439+
sortedIntermediates = append(sortedIntermediates, cert)
440+
remaining = append(remaining[:i], remaining[i+1:]...)
441+
break
442+
}
443+
}
444+
}
445+
446+
// Construct ordered chain
447+
orderedChain := []*x509.Certificate{leaf}
448+
orderedChain = append(orderedChain, sortedIntermediates...)
449+
if root != nil {
450+
orderedChain = append(orderedChain, root)
451+
}
452+
return orderedChain
453+
}
454+
455+
// getCertThumbprint computes the SHA-1 thumbprint of a certificate
456+
func getCertThumbprint(cert *x509.Certificate) string {
457+
hash := sha1.Sum(cert.Raw)
458+
return fmt.Sprintf("%x", hash)
459+
}
460+
407461
type KeyfactorCertResponse []struct {
408462
ID int `json:"Id"`
409463
Thumbprint string `json:"Thumbprint"`

0 commit comments

Comments
 (0)