Open shilohshi opened 7 months ago
You're using it correctly. The problem lies in the botan CLI tool that, unfortunately, does not fully support client certificates at the moment.
You can enable it via the require_client_certificate_authentication = true
policy setting, however, there's currently no way to specify one or more "trusted CAs" when starting a ./botan tls_server
. A (hypothetical) ./botan tls_server --trusted-cas=
argument would be needed here.
As a result, the server will request client-auth during the handshake (because of the policy setting), but won't indicate any acceptable CA. Additionally, the ./botan tls_client
currently relies on this server-provided list of acceptable CAs to decide which client certificate to present. For an empty list, it will simply claim that it doesn't have a matching client certificate. The result is the behavior you describe.
Note, however, that the limitation is within Botan's CLI tool. The library does support client authentication even if a server does not indicate their acceptable CAs. Typically, users would override the Credentials_Manager::find_cert_chain()
callback (also linked above) and add their client certificate selection logic as they see fit.
Many thanks for your explanation, hope this feature can be added in the future.
Hi, if I want to build a project that validates client certificates based on this project: https://github.com/reneme/botan-tls-testserver
which part of this project do I need to modify to achieve this? Thanks.
Note to self: we should add an example showcasing a server with client authentication.
Anyway, until then:
Basic_Credentials_Manager
Add a member variable Botan::Certificate_Store_In_Memory m_trusted_roots
and fill this with the issuer certificate(s) your server is supposed to trust, using .add_certificate()
. You can do that in the constructor of Basic_Credentials_Manager
, for instance. Right there, you'll also find some code to load certificates from PEM files.
Then, add an override of trusted_certificate_authorities()
, roughly like that:
std::vector<Botan::Certificate_Store*> trusted_certificate_authorities(const std::string& type,
const std::string& hostname) override {
if(type == "tls-server") {
return {&m_trusted_roots};
} else {
return {};
}
}
require_client_certificate_authentication
in the PolicyIn the relevant policy file (passed via ./testserver --policy
), enable client authentication. Like you did before for the CLI tool:
require_client_certificate_authentication = true
Your server should now mandate client authentication.
In case you need fine-grained access to the client certificate validation your server is performing, call tls_ctx->set_verify_callback()
in the do_listen()
co-routine. Note, though, that no automatic certificate path validation will be done by the library in this case.
tls_ctx->set_verify_callback([](const std::vector<Botan::X509_Certificate>& cert_chain,
const std::vector<std::optional<Botan::OCSP::Response>>& ocsp_responses,
const std::vector<Botan::Certificate_Store*>& trusted_roots,
Botan::Usage_Type usage,
std::string_view hostname,
const Botan::TLS::Policy& policy) {
// Check whatever you need here, and throw an exception if you're not
// happy with the certificate chain presented by the client.
});
Hi, I followed the steps above to operate and recompile, but during testing, it still prompts Alert: certificate_required
as usual. Would you mind upload a complete modified version or a website like https://pq.botan-crypto.org/ but built using this method to enable client cert authentication? Thank you very much.
Here's a complete example that worked for me.
Here's a script that generates a some test certificates (using Botan's CLI tool):
./botan keygen --algo=ECDSA --params=secp256r1 --output=ca_priv.pem
./botan keygen --algo=ECDSA --params=secp256r1 --output=server_priv.pem
./botan keygen --algo=ECDSA --params=secp256r1 --output=client_priv.pem
./botan gen_self_signed ca_priv.pem "CA" --ca --country=DE --dns=ca.example --hash=SHA-384 --output=ca_cert.pem
./botan gen_pkcs10 server_priv.pem localhost --output=server_csr.pem
./botan gen_pkcs10 client_priv.pem client --output=client_csr.pem
./botan sign_cert ca_cert.pem ca_priv.pem server_csr.pem --output=server_cert.pem
./botan sign_cert ca_cert.pem ca_priv.pem client_csr.pem --output=client_cert.pem
Here's a branch that allows for client authentication: https://github.com/reneme/botan-tls-testserver/tree/spike/client_auth
Compile it.
I'm assuming that the server is run from the repository's root directory and that the test certificates generated in step 1 are located in this folder as well. Please adapt the file paths as needed:
./testserver --cert server_cert.pem --key server_priv.pem --port 50443 --policy policies/clientauth.txt --client-auth-ca ca_cert.pem
This uses Botan's CLI-tool to connect to the test server. In its outputs it should mention "Performing client authentication" before "Handshake complete". Again, I'm assuming that the test certificates of step 1 are available in the same directory.
./botan tls_client --port=50443 localhost --client-cert=client_cert.pem --client-cert-key=client_priv.pem --trusted-cas=ca_cert.pem
Yeah it works now, thanks for your help!
I'm trying to start a TLS server that requires the client to send certificates. I'm launching it using the following command:
where the content of policy.conf is:
Then I try to use the following command to let the client connect to the server:
At this point, both the client and the server are indicating that the client did not send a certificate:
I'd like to inquire whether my usage is not correct or if there's an issue with the corresponding implementation. Many thanks.