func fetchCertChains()

in pkg/provider/provider.go [663:760]


func fetchCertChains(data []byte) ([]byte, error) {
	var newCertChain []*x509.Certificate
	var pemData []byte
	nodes := make([]*node, 0)

	currData := data

	for {
		// decode pem to der first
		block, rest := pem.Decode(currData)
		currData = rest

		if block == nil {
			break
		}
		cert, err := x509.ParseCertificate(block.Bytes)
		if err != nil {
			return pemData, err
		}
		// this should not be the case because ParseCertificate should return a non nil
		// certificate when there is no error.
		if cert == nil {
			return pemData, fmt.Errorf("certificate is nil")
		}
		nodes = append(nodes, &node{
			cert:     cert,
			parent:   nil,
			isParent: false,
		})
	}

	// 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
			}

			// a leaf cert SubjectKeyId is optional per RFC3280
			if nodes[i].cert.AuthorityKeyId == nil && nodes[j].cert.SubjectKeyId == nil {
				continue
			}

			// if ith node AuthorityKeyId is same as jth node SubjectKeyId, jth node was used
			// to sign the ith certificate
			if string(nodes[i].cert.AuthorityKeyId) == string(nodes[j].cert.SubjectKeyId) {
				nodes[j].isParent = true
				nodes[i].parent = nodes[j]
				break
			}
		}
	}

	var leaf *node
	for i := range nodes {
		if !nodes[i].isParent {
			// this is the leaf node as it's not a parent for any other node
			// TODO (aramase) handle errors if there are more than 1 leaf nodes
			leaf = nodes[i]
			break
		}
	}

	if leaf == nil {
		return nil, fmt.Errorf("no leaf found")
	}

	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) {
			return pemData, fmt.Errorf("constructing chain resulted in cycle")
		}
		newCertChain = append(newCertChain, leaf.cert)
		leaf = leaf.parent
	}

	if len(nodes) != len(newCertChain) {
		klog.Warning("certificate chain is not complete due to missing intermediate/root certificates in the cert from key vault")
		// if we're unable to construct the full chain, return the original order we got from the key vault
		return data, nil
	}

	for _, cert := range newCertChain {
		b := &pem.Block{
			Type:  types.CertificateType,
			Bytes: cert.Raw,
		}
		pemData = append(pemData, pem.EncodeToMemory(b)...)
	}
	return pemData, nil
}