I came here when I sensed that some recursion is required, because I was implementing a function that can validate the chain of trust in a certificate chain. This is not X.509 but instead it is just the basics wherein the issuer key of a certificate must match the public key of the signer.
bool verify_chain(std::vector<Cert>& chain, Cert* certificate, unsigned char* pOrigin = nullptr, int depth = 0) { bool flag = false; if (certificate == nullptr) { // use first element in case parameter is null certificate = &chain[0]; } if (pOrigin == nullptr) { pOrigin = certificate->pubkey; } else { if (std::memcmp(pOrigin, certificate->pubkey, 32) == 0) { return false; // detected circular chain } } if (certificate->hasValidSignature()) { if (!certificate->isRootCA()) { Cert* issuerCert = certificate->getIssuer(chain); if (issuerCert) { flag = verify_chain(chain, issuerCert, pOrigin, depth+1); } } else { flag = true; } } if (pOrigin && depth == 1) { pOrigin = nullptr; } return flag; }
I needed to know the recursion depth so that I can correctly clean up pOrigin. at the right stack frame during the unwinding of the call stack.
I used pOrigin to detect a circular chain, without which the recursive call can go on forever. For example,
- cert0 signs cert1
- cert1 signs cert2
- cert2 signs cert0
I later realized that a simple for-loop can do it for simple cases when there is only one common chain.
bool verify_chain2(std::vector<Cert> &chain, Cert& cert) { Cert *pCert = &cert; unsigned char *startkey = cert.pubkey; while (pCert != nullptr) { if (pCert->hasValidSignature()) { if (!pCert->isRootCA()) { pCert = pCert->getIssuer(chain); if (pCert == nullptr || std::memcmp(pCert->pubkey, startkey, 32) == 0) { return false; } continue; } else { return true; } } else { return false; } } return false; }
But recursion is a must when there is not one common chain but instead the chain is within each certificate. I welcome any comments. Thank you.