New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SSL Pinning: What Should Be Certificate Chain Validation Expected Behavior? #2744

Closed
kcharwood opened this Issue May 22, 2015 · 21 comments

Comments

Projects
None yet
7 participants
@kcharwood
Copy link
Contributor

kcharwood commented May 22, 2015

I've been spending some time deep in the AFSecurityPolicy class lately, and I'm wanting to get some feedback from the AFNetworking community on what the various needs are out there.

In AFNetworking, you can currently either pin against the leaf certificate, or the entire chain itself. There is no way to pin against only an intermediate certificate (B in the diagram below), or a subset of the chain (A and B in the diagram below). It's my understanding that there are some people who would want to only pin against an intermediate certificate, or a subset of chain, to allow for production/development certs, and the exchange of new certificates, while limiting the scope of authenticated connections to only be from the intermediate chain.

  • A (root)
    • B
      • C (leaf)

The big question: Is this something worth supporting? Are there any major security cons to this approach?

Follow up question: Should you be able to provide multiple pinning chains to check against? For example, in #2733 there is the concept of providing a backup key should one be needed in the future. Would it make sense to expose a backup chain, and allow the developer to provide multiple valid chains to check (essentially ORing them together?) That could potentially make dev server/production server management a bit easier as well.

@kcharwood

This comment has been minimized.

Copy link
Contributor Author

kcharwood commented May 22, 2015

#2646 is one way to solve this.

@reedloden

This comment has been minimized.

Copy link

reedloden commented May 22, 2015

@kcharwood, as requested, questions answered below.

Is this something worth supporting?

Definitely. It's not a good idea at all to pin to an EE (end-entity aka leaf) cert except in very limited circumstances. EE certs are meant to be short-lived (only a few years at max), which means old clients will just stop working once they expire. As such, it's way better to pin to a set of root CAs or intermediate CAs (root CAs are greatly preferred, unless the intermediate CA is specific to your company/organization).

My comment in #1852 (comment) explains some of the finer points, including linking to several blog posts from experts in this field about how pinning should work.

Are there any major security cons to this approach?

Obviously, the higher you pin, the more possible it is for another (possibly malicious) entity to also get a certificate that would be valid under your pinning configuration. However, pinning to just a few root CAs is far better than permitting all 200+ root CAs to be able to MITM your connection. It's a risk trade-off. The closer you go to the actual cert, the more likely it is that you'll need to update more frequently and potentially have broken clients.

Should you be able to provide multiple pinning chains to check against?

Yes, should support multiple pins. Take a look here to see how Twitter, Google, Dropbox, Facebook, and others all have a number of root CAs they pin to. This helps in an emergency when your main CA has issues (or changes their chain for some reason, causing your pinning to have issues).

Hope this helps!

@kcharwood

This comment has been minimized.

Copy link
Contributor Author

kcharwood commented May 22, 2015

Thanks @reedloden. Is there any value in pinning the entire chain, or a subset of the chain? Or should we just be pinning against a single cert somewhere in the chain (the higher up you go, the less secure)?

@reedloden

This comment has been minimized.

Copy link

reedloden commented May 22, 2015

I don't really see value in that, and I worry it might cause people to make decisions that only hurt them later (especially if they pin too much and really hurt themselves). Single certs are generally fine and are what is used by most other pinning implementations (basically, start at the leaf, and walk up the chain until you find a match (or not)). The only other counter-example I can think of off the top of my head is that nginx does something different for validating client certificates and OCSP responses (they require the full chain from EE to root CA).

@iOSGeekster

This comment has been minimized.

Copy link

iOSGeekster commented May 22, 2015

We're currently in a situation, where a customer (a department in a bigger corporation) is now talking about pinning. But since the department who owns the app that we're making, does not control the leaf certificates fully, pinning was skipped previously due to the fact that @reedloden mentions: the risk of broken clients due to renewal of the certificates. So what we are thinking, is to validate against the intermediate certificates instead, hence the PR #2646

@reedloden

This comment has been minimized.

Copy link

reedloden commented May 22, 2015

@Jesper84, intermediates aren't generally meant to be long-lived, so I would be careful with using them vs. the actual root CAs themselves. You should talk to your CA and find out what their policy is regarding lifetime of intermediates.

@iOSGeekster

This comment has been minimized.

Copy link

iOSGeekster commented May 23, 2015

Thanks for the advice. The guys responsible (and those with the knowledge) of the certificates are right know discussing the case. We might go after the root certificates, which we originally intended.

Den 23/05/2015 kl. 00.22 skrev Reed Loden notifications@github.com:

@Jesper84, intermediates aren't generally meant to be long-lived, so I would be careful with using them vs. the actual root CAs themselves. You should talk to your CA and find out what their policy is regarding lifetime of intermediates.


Reply to this email directly or view it on GitHub.

@arein

This comment has been minimized.

Copy link

arein commented May 26, 2015

Hi,

I address various of your points in 2733:

  1. Backup keys are supported when validatesCertificateChain is set to NO (complies with the current implementation)
  2. Any certificate in the chain can be pinned when validatesCertificateChain is set to NO

I like my implementation as it is backwards compatible.

Whaddaya think?

@kcharwood

This comment has been minimized.

Copy link
Contributor Author

kcharwood commented May 26, 2015

@OliverLetterer, would love your thoughts here as well.

@kcharwood

This comment has been minimized.

Copy link
Contributor Author

kcharwood commented May 27, 2015

@reedloden I'd also like your take on domain name validation, and some of the nuances there. If a developer passes in a domain name, we create a SecPolicyCreateSSL, which takes in an optional hostname parameter:

hostname If you specify a value for this parameter, the policy will require the specified value to match the host name in the leaf certificate.

That definition makes me believe that is only for leaf certificates, not intermediate or root certificates. Can you comment on the value of host/domain name validation on the client side, and what are the best cases to use that feature?

I'd also like your feedback on when it is not worth using (if there is a case). Thanks again!

@OliverLetterer

This comment has been minimized.

Copy link
Contributor

OliverLetterer commented May 27, 2015

@kcharwood thanks for reaching out. I happy to share my two cents on this topic :) I agree with very much of what @reedloden said:

Is this something worth supporting?

Definitely. It's not a good idea at all to pin to an EE (end-entity aka leaf) cert except in very limited circumstances. EE certs are meant to be short-lived (only a few years at max), which means old clients will just stop working once they expire. As such, it's way better to pin to a set of root CAs or intermediate CAs (root CAs are greatly preferred, unless the intermediate CA is specific to your company/organization).

I believe being able to pin specific leaf certificates is actually a good idea in more than "very limited circumstances" if one imagines to pin the leaf certificate's public key instead of the actual certificate itself. The certificate itself might be short lived but not necessarily the public key. Another use case I can think of are banking apps which probably don't care about old clients breaking but rather ensuring the user that they are communicating with the correct host.

Should you be able to provide multiple pinning chains to check against?

Yes, should support multiple pins. Take a look here to see how Twitter, Google, Dropbox, Facebook, and others all have a number of root CAs they pin to. This helps in an emergency when your main CA has issues (or changes their chain for some reason, causing your pinning to have issues).

Huge +1 from my end on multiple pinning chains. Because of different parties having different needs for certificate pinning (everything between pinning a single leaf's public key to pinning multiple whole certificate chains for different backends), my idea would be to make AFSecurityPolicy more open, composable and maybe extensible. Single certs are generally fine and are what is used by most other pinning implementations. I totally agree with the general case and I believe that should be the default case. But I would love to be able to define a chains of trust based on certificates, public keys and domain names I explicitly whitelist. Similar to how NSCompoundPredicate allows concatenating predicates with and or or, I can imaging being able to specify chains of trust, where a single chain can for example contain public key of leaf certificate C and be originated from root certificate A, and then trust any of such defined chains.

@kcharwood

This comment has been minimized.

Copy link
Contributor Author

kcharwood commented May 28, 2015

Thanks @OliverLetterer!

I'm also interested in knowing if there is a specific security vulnerability that is addressed by pinning against an entire chain (or a subset of the chain), vs pinning against a single certificate in the chain. In my example in the original post, if you pin against B or C, is there any actual value in also pinning against A? Since B and C are derived from A, what value would a developer get out of also pinning against A, other than feeling "super, duper" secure. I would love some specific security holes that that technique addresses.

Maybe @reedloden has an opinion there too. And thanks again! This issue is very enlightening so far.

@arein

This comment has been minimized.

Copy link

arein commented May 28, 2015

@OliverLetterer: Thanks!

About Public Key Pinning: As far as I understand it is best practice to pin not just the public key but the SPKI (see Adam's blog post). This is also how Chromium is implemented.

Am I right that this does not provide any security benefit when validatesDomainName is set to YES as the domain name is already validated?

@kcharwood

This comment has been minimized.

Copy link
Contributor Author

kcharwood commented Jun 2, 2015

pinging @OliverLetterer and @reedloden in case you guys have a chance to view my follow up questions above!

Thanks.

@OliverLetterer

This comment has been minimized.

Copy link
Contributor

OliverLetterer commented Jun 6, 2015

@arein +1 on checking SubjectPublicKeyInfo instead of the public key.

@kcharwood I think there is an advantage greater that feeling "super, duper" secure when pinning an entire chain instead of a subset. Imagine a larger corporation with a complete private chain who is pinning all public keys to prevent any kind of private key theft. Well this is actually a case of feeling "super, duper" secure but I think a legitimate one.

@reedloden

This comment has been minimized.

Copy link

reedloden commented Jun 6, 2015

Agree on use of SPKI. Sorry for not clarifying that earlier.

While I don't have any issues with supporting pinning of a full chain, I'm skeptical about people doing it right and not shooting themselves in the foot. Definitely something to warn against unless they are really, really sure they know what they are doing. It really sucks to add TLS pinning and then 12 months down the road find you're now screwed and might lose a lot of users still using old client versions because of bad design decisions. Definitely seen that happen, so just don't want to see documentation or examples that give people bad ideas of what a good/reasonable pinning implementation should be like.

@OliverLetterer

This comment has been minimized.

Copy link
Contributor

OliverLetterer commented Jun 6, 2015

Totally agree with not shooting themselves in the foot. How about by default, the new implementation trusts any public key that is contained in any bundle of the application (thinking about the main app's bundle, any extension bundles and any shipping framework bundles). So the default case involves not writing any code at all. From there on, writing any code and more specialized pinning behavior requires you to read into the documentation where we warn about pinning dangers.

@kcharwood

This comment has been minimized.

Copy link
Contributor Author

kcharwood commented Jun 15, 2015

I spoke with the Apple Engineering Security team in depth last week in the WWDC labs, and they agreed there was no additional security value in validating the entire chain. Their own implementation pins against only one certificate in the chain. It's important to understand the trade offs of what level to pin against, but once that decision is made, there is no value in pinning against a higher cert once that has been done.

Unless someone can provide a specific vulnerability that pinning against the entire chain would provide more security than pinning against a single cert, I'll be deprecating the entire chain validation in a future release.

@corocraft

This comment has been minimized.

Copy link

corocraft commented Jul 7, 2015

I have a question regarding validatesCertificateChain.
When this configuration in AFSSLPinningMode.PublicKey and validatesCertificateChain = true is verified the entire SSL certificate chain, right? and when validatesCertificateChain = false is just validated the first certificate chain?

I don't know because when validatesCertificateChain = false work for me. Maybe the form of the entire chain is incorrect. is it correct to use the following code to get the entire chain and work validatesCertificateChain = true?
openssl s_client -connect example.com:443 </dev/null 2>/dev/null | openssl x509 -outform DER > example.cer

@paventuri

This comment has been minimized.

Copy link

paventuri commented Jul 21, 2015

@kcharwood - I would like to know how far you guys have improved it so far. Is there any branch being updated? Do you have any ETA for 2.6.0?

Thank you.

@kcharwood

This comment has been minimized.

Copy link
Contributor Author

kcharwood commented Jul 24, 2015

#2856 is now up for review. Please direct all conversation to that pull request.

🍻

@kcharwood kcharwood closed this Jul 24, 2015

kcharwood referenced this issue Nov 10, 2015

- Removed Certificate Chain Validation
- Refactored Security Tests
- Updated Documentation
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment