-
-
Notifications
You must be signed in to change notification settings - Fork 27
-
-
Notifications
You must be signed in to change notification settings - Fork 27
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
Issue client cert #35
Comments
That would be useful! The only problem is that I've never used client certs myself though, so I'm not very clear on what exactly a good fake client cert would look like :-). Do you have an example of the kind of client cert you use? (See also #33) |
@dpeschman submitted a number of example certificates to Cheroot a while back: https://github.com/cherrypy/cheroot/tree/cbb2b2e/cheroot/test/ssl. But I don't know how he created them. Info on the Internet looks no different from server cert creation either: https://kb.op5.com/pages/viewpage.action?pageId=19073746 Googling has also lead me to https://github.com/python-hyper/pep543/blob/a7c5089/test/conftest.py#L365-L375 which, at glance, suggests that client cert is built the same way as server cert I guess. |
Yeah, I just read a bit more on this, and I can't find any evidence that client and server certs are actually different in any meaningful way. For example, those cheroot test certs appear to be totally normal server certs with associated hostnames and everything. So, the good news is that trustme already supports issuing client certs :-). Just call But this is kind of confusing. So I guess we should rename that to |
Oh, I did not see the request for review here. Anyway, the PR looked good, so I merged it. Thanks! |
Oh.. I was sleeping :) Different time zone. But I tried using the server cert (before your PR) in our tests and they've failed. I'll try out your changes now. |
@njsmith It worked This change probably additionally needs tests + docs + deprecation warning. |
So just to confirm, this is working for you now without further changes? I guess we could issue a deprecation warning when people use the old name. I was lazy about it because the maintenance burden for keeping the old alias is basically nil, and the benefits of switching for end users are nil, so why hassle people about it. For docs and tests though, I think I already updated those – is there something you noticed as missing? |
It works but I'll need to test a few more things in our test suite. I think docs might benefit from a tutorial-like example of client cert auth with requests or similar lib. Even though I'm somewhat familiar with TLS I still had to read the source code in order to understand how to integrate |
Okay, it looks like you use both |
I've also tested creating a cert with |
Oh.. And my testing needs me to create an invalid certificate As in https://github.com/cherrypy/cheroot/blob/cbb2b2e771b35a91d11c80e00d667faa267ef27d/cheroot/test/ssl/client_wrong_ca.cert which doesn't have locality in the issuer field as opposed to all other certs in that folder (
@njsmith is this something that I mean, how about some public API like |
That would be great, yeah. I guess the requests part is pretty trivial (now that you figured out how to do it!), but for an example we'd also need to show the server side. Do you have any ideas how to do that in a minimal tutorial-style way? From a quick search it doesn't look like flask/werkzeug has any standard way to handle client auth. Maybe we could hack together something good enough for an example using
That's because
I think this is a red herring? AFAIK locality isn't a required field, and in fact trustme certs never contain a locality field in its names. Based on the name and looking at the cert, I think the point of that cert is that it's signed by a different CA than the rest of your test certs, and that the CA it uses isn't trusted. So to reproduce it with trustme you can just create a second CA, and then use that CA to issue the cert: ca_untrusted = trustme.CA()
client_wrong_ca = ca_untrusted.issue_cert(...) |
Oh right, of course! I think I copied that from some example and then forgot about it. That does explain things. I guess this is fine. Maybe at some point someone will need to configure that and we'll add more kwargs or something, but it seems like a reasonable default and we can wait for that to happen before worrying about it. |
So the main reason I started messing around with client certs is that I'm a maintainer of CherryPy. And we have Cheroot now which is HTTP+WSGI server part factored out of CherryPy. A contributor implemented client auth a while back and submitted tests with static cert and key files.
I don't think it's deprecated for client certs. It looks like you should be able to put any text as identity info: this example https://github.com/python-hyper/pep543/blob/a7c5089/test/conftest.py#L365 puts "PEP 543 Client Certificate" (any string) for a client cert in place where it puts "localhost" (FQDN) for a server cert. Client cert with
Yes, you're right. I came to the same conclusion after all and it worked :) |
Well, it's a bit complicated :-). It's not that trustme is explicitly trying to stop you from sticking "not_localhost" in a client cert. It's a side-effect of some other decisions. The central issue is that x.509 certs have two totally different places where you can put the identity information: there's a free-form string called "common name" (CN), which traditionally used to be where people put hostnames, but really you can put anything there (including "PEP 543 Client Certificate"). And, there's a structured set of fields called "subject alternative name" (SAN), which is the new place to put hostnames and such. SAN is way better than CN, because it allows multiple names in the same cert, and it's just better defined – e.g. names are explicitly tagged to be hostname vs. ip vs. email address vs. whatever, and if a CA signs a cert with a given hostname in the SAN, that explicitly means "whoever owns this cert is the valid owner of this hostname", while technically all a CA is promising if it signs a cert with a CN field is that whatever string is in that CN field is somehow, someway related to the owner of the cert; maybe they own that hostname, maybe not, no-one knows. You can see how this bothers the security people. And at this point, major software like Chrome has started ignoring the CN field entirely, and you should expect other packages to follow over the next few years. So anyway, because of all this, trustme uses the SAN field by default, rather than the CN field. This isn't some judgement on whether it's OK to have a client cert with "not_localhost" in the name or anything; it's just that the SAN field is generally what people want, especially if they're trying to test that their software can properly handle modern certificates. But, since the SAN field is more strictly defined and explicitly typed than the CN field was, the side-effect of using SAN is that we end up being unable to support "not_localhost" as a plain identity passed into issue_cert(). Your old certs got away with this, because they were just using CN for everything. This isn't good practice (and will probably stop working entirely at some point), but it's very common if you look at tutorials for making test certs, because most people writing these tutorials aren't experts in x.509, and the openssl command-line tool makes it very annoying to use SAN properly. So uh.... yeah, aren't you glad you asked? x.509 is super annoying. Anyway the bottom line is:
|
I'm trying to google some mentions of CN being discouraged for client certs but no doc explicitly points to it, only server certs. |
@njsmith I felt like client certs use-case is a bit different from server cert. Why can't I put some JSON string to CN there, for example? It never gets checked by the SSL itself. So I kept digging. Now, I've found a documented use-case for CN which turned out to be the original case of why @dpeschman submitted client-side auth to us. It's LDAP. Here's RFCs giving some examples: And SO answer: |
Hi,
It'd be nice to have a public API for creating client certificates as well. Just like
issue_server_cert()
butissue_client_cert()
.It's useful when testing client cert TLS auth in frameworks.
The text was updated successfully, but these errors were encountered: