mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 11:44:31 +00:00
118 lines
2.7 KiB
Go
118 lines
2.7 KiB
Go
package template
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/x509"
|
|
"encoding/pem"
|
|
"fmt"
|
|
)
|
|
|
|
const (
|
|
errNilCert = "certificate is nil"
|
|
errFoundDisjunctCert = "found multiple leaf or disjunct certificates"
|
|
errNoLeafFound = "no leaf certificate found"
|
|
errChainCycle = "constructing chain resulted in cycle"
|
|
)
|
|
|
|
type node struct {
|
|
cert *x509.Certificate
|
|
parent *node
|
|
isParent bool
|
|
}
|
|
|
|
func fetchX509CertChains(data []byte) []*x509.Certificate {
|
|
var newCertChain []*x509.Certificate
|
|
nodes := pemToNodes(data)
|
|
|
|
// at the end of this computation, the output will be a single linked list
|
|
// the tail of the list will be the root node (which has no parents)
|
|
// the head of the list will be the leaf node (whose parent will be intermediate certs)
|
|
// (head) leaf -> intermediates -> root (tail)
|
|
for i := range nodes {
|
|
for j := range nodes {
|
|
// ignore same node to prevent generating a cycle
|
|
if i == j {
|
|
continue
|
|
}
|
|
// if ith node AuthorityKeyId is same as jth node SubjectKeyId, jth node was used
|
|
// to sign the ith certificate
|
|
if bytes.Equal(nodes[i].cert.AuthorityKeyId, nodes[j].cert.SubjectKeyId) {
|
|
nodes[j].isParent = true
|
|
nodes[i].parent = nodes[j]
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
var foundLeaf bool
|
|
var leaf *node
|
|
for i := range nodes {
|
|
if !nodes[i].isParent {
|
|
if foundLeaf {
|
|
panic(fmt.Sprintf("[fetchX509CertChains] Error: %v", errFoundDisjunctCert))
|
|
}
|
|
// this is the leaf node as it's not a parent for any other node
|
|
leaf = nodes[i]
|
|
foundLeaf = true
|
|
}
|
|
}
|
|
|
|
if leaf == nil {
|
|
panic(fmt.Sprintf("[fetchX509CertChains] Error: %v", errNoLeafFound))
|
|
}
|
|
|
|
processedNodes := 0
|
|
// iterate through the directed list and append the nodes to new cert chain
|
|
for leaf != nil {
|
|
processedNodes++
|
|
// ensure we aren't stuck in a cyclic loop
|
|
if processedNodes > len(nodes) {
|
|
panic(fmt.Sprintf("[fetchX509CertChains] Error: %v", errChainCycle))
|
|
}
|
|
newCertChain = append(newCertChain, leaf.cert)
|
|
leaf = leaf.parent
|
|
}
|
|
return newCertChain
|
|
}
|
|
|
|
func fetchCertChains(data []byte) []byte {
|
|
var pemData []byte
|
|
newCertChain := fetchX509CertChains(data)
|
|
|
|
for _, cert := range newCertChain {
|
|
b := &pem.Block{
|
|
Type: pemTypeCertificate,
|
|
Bytes: cert.Raw,
|
|
}
|
|
pemData = append(pemData, pem.EncodeToMemory(b)...)
|
|
}
|
|
return pemData
|
|
}
|
|
|
|
func pemToNodes(data []byte) []*node {
|
|
nodes := make([]*node, 0)
|
|
for {
|
|
// decode pem to der first
|
|
block, rest := pem.Decode(data)
|
|
data = rest
|
|
|
|
if block == nil {
|
|
break
|
|
}
|
|
cert, err := x509.ParseCertificate(block.Bytes)
|
|
if err != nil {
|
|
panic(fmt.Sprintf("[pemToNodes] Error: %v", err))
|
|
}
|
|
|
|
if cert == nil {
|
|
panic(fmt.Sprintf("[pemToNodes] Error: %v", errNilCert))
|
|
}
|
|
nodes = append(nodes, &node{
|
|
cert: cert,
|
|
parent: nil,
|
|
isParent: false,
|
|
})
|
|
}
|
|
return nodes
|
|
}
|