6 ms·
Interested in how exactly it was fucked up I looked at crypt32.dll. It's more like (heavily-adjusted to demonstrate the problem without >9k unrelated details):
by rfoo 7y ago
Interested in how exactly it was fucked up I looked at crypt32.dll. It's more like (heavily-adjusted to demonstrate the problem without >9k unrelated details):
from the_heavy_lifting_crypto_heavy_module import verify_signature
def is_known_trusted_ca(cert):
# BOOM
return cert in root_ca_cache[cert.pubkey]
def verify_cert(cert, issuer):
# BOOM
if verified_cache[(cert.pubkey, issuer.pubkey)]:
return True
if not verify_signature(cert, issuer):
return False
verified_cache[(cert.pubkey, issuer.pubkey)] = True
return True
# This has to be a search instead of simple chain-walking because servers
# do not send a "chain", they only send several additional certificates and
# let the client find a trusted path out of them, it is also how cross signing
# works. This justifies using a cache above.
def try_to_build_cert_chain(cert, cert_store):
if is_known_trusted_ca(cert):
return [cert]
for possible_issuer in cert_store.find_certs_with_dn(dn=cert.issuer_dn):
if verify_cert(cert, possible_issuer):
chain = try_to_build_cert_chain(possible_issuer, cert_store)
if chain:
return [cert] + chain
Then someone tasked with (why?!) "adding unnamed curve support" added (correct!) code to `the_heavy_lifting_crypto_heavy_module.verify_signature` but didn't know this breaks an assumption made in another module.
The exact detail does not matter though, you can build up working exploits even if you don't know the details listed above.
- tialaramex 7y agoThe servers are supposed to send a chain ("SHOULD" is the strongest language an RFC uses about chains) but, in practice, the only way to get where you're going as a client is to treat it as one leaf and then everything else is hints that might help you construct the chain. The reason is that a server doesn't know which roots you actually trust, so maybe it thinks you trust X and X->A->B->C so it sends X->A, A->B, B->C but actually you trust A so you only needed to receive A->B, and B->C - X->A doesn't help you make a decision so your code needs to disregard it.
- rfoo 7y agoIn a more convoluted scenario (cross sign) a server can really send you two (or more) chains so I'd take that "SHOULD" with a grain of salt. For example, Let's Encrypt Authority X3 is signed by both ISRG Root X1 (their own root CA) and DST Root CA X3. The server could send you: 1. Server cert 2. Let's Encrypt Authority X3 (Signed by ISRG Root X1) 3. Let's Encrypt Authority X3 (Signed by DST Root CA X3) Combined with: 4. ISRG Root X1 5. DST Root CA X3 If the client trusts 4, then it could form a path of 1-2-4. If it does not but trusts 5, then 1-3-5 would be viable.