On 07.03.2013 23:05, Richard Moore wrote: > I'm not sure I'm following you here, could you give an example? In the > scenario I describe, the intermediates are not trusted and shouldn't > form part of the trust store, they merely allow you to build a chain > from the leaf to one of the roots. I suspect we're probably describing > the same thing, but I'm not quite sure. Sure. Let's first define a certificate tree with one self-signed certificate A: A -> B -> C -> D A -> E -> F B -> G -> H Or in graphviz notation: digraph certs { A->A; A->B; B->C; C->D; A->E; E->F; B->G; G->H; } You could go to http://sandbox.kidstrythisathome.com/erdos/index.html and it will output a nice graph image or view it at http://imgur.com/Nnf8kFl Now in that graph as the API is currently designed with my patch, it will yield a successful check for the following issuer/subject pairs and will throw an exception for all others: A, A A, B B, C C, D A, E E, F B, G G, H I.e. as you can see it clearly models the tree exactly. This is just a basic building block, however. You would want to extend this to validate whole chains. Now there's some confusion because we use different terms for "truststore". You are talking about the certificates which have ultimate trust (in this case this would be only A) and I talk about certificates with *technical* trust (i.e. all root certificates that end up in the truststore object). The logical truststore only includes A. The technical truststore also includes all intermediate CAs, as they're indirectly also trusted if they have a valid signature from the root. I suggest to change the API to take a tuple of trusted issuers and a subject to verify together with a kwarg parameter that indicates whether the user is only interested in the direct trust relationship (this is something I'm after in my use case) or wants to build a chain of trust. Some examples: This would all pass (direct cert check): verify_cert([ A ], B) verify_cert([ A, B, C ], B) verify_cert([ C, G ], D) This would all fail (direct cert check): verify_cert([ ], A) verify_cert([ B ], A) verify_cert([ C, G, D, H ], F) This would all pass (chain building check): verify_cert([ A, B, G ], H, chain = True) verify_cert([ A, B, C ], D, chain = True) verify_cert([ A ], A, chain = True) verify_cert([ A ], B, chain = True) verify_cert([ A, E ], F, chain = True) This would all fail (chain building check) verify_cert([ ], A, chain = True) verify_cert([ A ], G, chain = True) verify_cert([ A ], H, chain = True) verify_cert([ B, G ], H, chain = True) verify_cert([ B, C ], D, chain = True) All in all, the function would not differentiate between ultimate trust (truststore) and immediate trust (technical truststore). This is something that can be done with simple user functions (or I could write a simple wrapper that does this). But ultimately, I'd like to keep the functionality as simply as possible (reduces the risk of misuse). Now when I see correctly, what you want is something like this: verify_chain(truststore, chain, cert) Which would pass for the following inputs: verify_chain([ A ], [ A, B, G, H ], H) verify_chain([ A ], [ A, B, G, H ], G) verify_chain([ A ], [ B, C ], D) And which should fail for the following: verify_chain([ ], [ A, B, C ], D) verify_chain([ ], [ A, B, G ], G) This is easy to map to the verify_cert. I'll just use pseudo-python-code, this should IMO also be an API function so the user doesn't have to do it herself: def verify_chain(truststore, chain, cert): tech_truststore = list(truststore) # Filter out self-signed from chain! immediate_certs = [ ca for ca in chain if not ca.selfsigned() ] tech_truststore += immediate_certs return verify_cert(tech_truststore, cert) > I think having the ability to verify a whole chain would be a great > improvement to pyopenssl. Definitely. I hope this clears up the confusion a bit and shows what I'm trying to achieve. Would be happy about your comments. Best regards, Johannes