laudrup / boost-wintls

Native Windows TLS stream wrapper for use with Asio
https://wintls.dev
Boost Software License 1.0
55 stars 13 forks source link

[server] Is it possible to use a Windows Certificate Store certificate on a server? #68

Open meastp opened 2 years ago

meastp commented 2 years ago

I have a few questions when trying to evaluate if we can use this library for our http server (written in Boost.Beast):

When creating a context for server usage, a certificate is required as well as private key. Unlike OpenSSL Windows has the concept of a certificate with an associated private key that must be available to the process or user running the server process. Such a certificate can be used using context::use_certificate().

  1. We have our certificates in Windows Certificate Store (Personal). I was hoping to use this certificate directly in the store without having to export it / the private key. Is that possible?
  2. The server example does not get the certificate or the private key from the windows certificate store, it seems. Is this possible?
  3. Is it possible for me to retrieve the CERT_CONTEXT* from Windows Certificate Store (using the CryptoAPI perhaps?) directly, and then use it with context::use_certificate without having to separately import a private key (after all, it is stored in the Windows Certificate Store on the system)?

Lots of questions... :) I'm missing a server example using the Windows Certificate Store...

laudrup commented 2 years ago

Hi @meastp

Thank you for your interest in this library.

I don't think it is possible to use a Windows Certificate Store with the current implementation but it sounds like it should definitely be something that ought to be possible.

To be honest I don't know much about how Windows handles certificates apart from the work I've done with this library,, so since this is something that has to be implemented I would very much appreciate you input on which kind of interface you would like for this.

If you have an idea of how you would like the interface to look we can discuss that and hopefully I'll have some time to implement it at some point. Otherwise, pull requests are of course very welcome if you want to try and implement it yourself.

meastp commented 2 years ago

@laudrup I see. I'm just a user, unfortunately with no expertise on tls or CryptoAPI, so I can't really help much.

The ideal interface would be to be able to point to a certificate in the Windows Certificate Store by using it's thumbprint (it's the usual and a sound way to pick a specific certificate on windows, at least). If this could be a certificate with a non-exportable private key, it would be the most secure (but requiring an exportable private key is also ok).

laudrup commented 2 years ago

Hi again @meastp,

This library is very much modeled after how the existing asio::ssl implementation which uses OpenSSL works so that's why I initially implemented it this way.

I don't use Windows myself but most often things are quite a bit different/complicated on that platform so any user input is very much appreciated.

I've looked a bit into it and it seems like the certificate could be provided by adding an overload to the use_certificate function that takes an additional HCERTSTORE parameter to the store containing the certificate.

I think that ought to work if you call such a function with the handle to the "Personal Certificate Store" in addition to the CERT_CONTEXT pointer for the certificate to use from that store. Hopefully that should work even with a non-exportable private key. It should also be fairly simple for me to add a test for that functionality.

I don't think using a thumbprint is the correct approach here. A thumbprint is most often used for validating whether a certficiate/key matches the expected one. Of course on Windows things are quite often different from the norm though.

What do you think about adding such a function the the context class?

meastp commented 2 years ago

@laudrup

So, what you are suggesting is an overload use_certificate(HCERTSTORE*, CERT_CONTEXT*) ? The user is required to both acquire the HCERTSTORE* (with CertOpenStore, which is flexible and can also open e.g. Personal and Web Hosting in the same HCERTSTORE*, which is perfect) and the CERT_CONTEXT* - finding the exact certificate (CERT_CONTEXT) in the Windows Certificate Store using CertFindCertificateInStore or CertEnumCertificatesInStore - the user can choose freely how to locate the certificate (e.g. by thumbprint, issuer, subject etc.).

I think that would be a very nice interface. If there is a particular method that is more common, you can provide overload(s) that does the heavy lifting in boost-wintls as future additions (e.g use_certificate("MY" /* Personal cert store name */, "Cert_subject_1" /* certificate subject, used as argument to CertFindCertificateInStore */).

If this also works with certificates in the store that have a non-exportable private key, that's a nice bonus (but not a hard requirement, imho).

laudrup commented 2 years ago

@meastp That's exactly what I'm suggesting. Good to hear you like that interface. Of course the most important aspect of designing APIs is that they are easy for the users to use correctly.

I'm working on implementing that and will update this issue once I have something working (or not).

laudrup commented 2 years ago

@meastp

I've looked more into this and it seems like I've been a bit confused. As far as I can tell there's no need to add another member function to the context. If you have a CERT_CONTEXT which has an associated private key you should be able to simply use the code as it is.

I'm looking into extending the tests to verify that and the documentation should definitely be updated to make it more clear that this is the case.

I'm also looking into whether it's possible to verify that the CERT_CONTEXT has a usable private key associated and make the function fail if not. Currently the handshake will simply timeout if the certificate doesn't have a private key associated which is not very intuitive.

But please do feel free to use the code as it now and please do let me know if you experience any issues.

meastp commented 2 years ago

@laudrup That's great news - and I think, like you, that a documentation update is really needed ;)

which has an associated private key Have you been able to confirm if the (associated) private key has to be exportable?

laudrup commented 2 years ago

@meastp

I've added some code for ensuring that a private key is referenced when setting the certificate using use_certificate. It will now fail if the certificate doesn't reference a private key or the private key doesn't match the public key used in the certificate.

I've also added some tests for ensuring that as well as for using a certificate created by CertCreateSelfSignCertificate which I think should create a certificate similar to the one you're trying to use. I'm fairly certain this also works with a non-exportable private key.

Additionally I've tried to clarify the documentation for use_certificate a bit. Do you think you could have a look at that here and see if that makes things clearer?

Of course feel free to have a look at the branch in general and let me know what you think.

Thanks.

meastp commented 1 year ago

@laudrup Great work, thank you! :) I'm on parental leave, will get back to this when I return to work (easter, next year) :)