diff options
author | danieldg <danieldg@e03df62e-2008-0410-955e-edbf42e46eb7> | 2009-09-13 20:32:48 +0000 |
---|---|---|
committer | danieldg <danieldg@e03df62e-2008-0410-955e-edbf42e46eb7> | 2009-09-13 20:32:48 +0000 |
commit | f4ccba3b6cfe45b7763440e2e69a9a0b7d98aba1 (patch) | |
tree | 80a1dcb4181d64b25c5a1a22ad6d819bab8a2af9 | |
parent | 069a2ef21425007d092342c8c11ec28da2f410d7 (diff) |
GnuTLS: Send SSL client certificate when requested
git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@11708 e03df62e-2008-0410-955e-edbf42e46eb7
-rw-r--r-- | src/modules/extra/m_ssl_gnutls.cpp | 55 |
1 files changed, 45 insertions, 10 deletions
diff --git a/src/modules/extra/m_ssl_gnutls.cpp b/src/modules/extra/m_ssl_gnutls.cpp index 97a5ebe0e..f458f5da1 100644 --- a/src/modules/extra/m_ssl_gnutls.cpp +++ b/src/modules/extra/m_ssl_gnutls.cpp @@ -30,6 +30,20 @@ enum issl_status { ISSL_NONE, ISSL_HANDSHAKING_READ, ISSL_HANDSHAKING_WRITE, ISSL_HANDSHAKEN, ISSL_CLOSING, ISSL_CLOSED }; +static gnutls_x509_crt_t x509_cert; +static gnutls_x509_privkey_t x509_key; +static int cert_callback (gnutls_session_t session, const gnutls_datum_t * req_ca_rdn, int nreqs, + const gnutls_pk_algorithm_t * sign_algos, int sign_algos_length, gnutls_retr_st * st) { + + st->type = GNUTLS_CRT_X509; + st->ncerts = 1; + st->cert.x509 = &x509_cert; + st->key.x509 = x509_key; + st->deinit_all = 0; + + return 0; +} + /** Represents an SSL user's extra data */ class issl_session : public classbase @@ -48,8 +62,9 @@ public: class CommandStartTLS : public Command { public: - CommandStartTLS (InspIRCd* Instance, Module* mod) : Command(Instance, mod, "STARTTLS", 0, 0, true) + CommandStartTLS (Module* mod) : Command(mod, "STARTTLS") { + works_before_reg = true; } CmdResult Handle (const std::vector<std::string> ¶meters, User *user) @@ -102,13 +117,15 @@ class ModuleSSLGnuTLS : public Module public: ModuleSSLGnuTLS(InspIRCd* Me) - : Module(Me), starttls(Me, this), capHandler(this, "tls") + : Module(Me), starttls(this), capHandler(this, "tls") { ServerInstance->Modules->PublishInterface("BufferedSocketHook", this); sessions = new issl_session[ServerInstance->SE->GetMaxFds()]; gnutls_global_init(); // This must be called once in the program + gnutls_x509_crt_init(&x509_cert); + gnutls_x509_privkey_init(&x509_key); cred_alloc = false; // Needs the flag as it ignores a plain /rehash @@ -213,20 +230,36 @@ class ModuleSSLGnuTLS : public Module if((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) ServerInstance->Logs->Log("m_ssl_gnutls",DEBUG, "m_ssl_gnutls.so: Failed to allocate certificate credentials: %s", gnutls_strerror(ret)); - if((ret = gnutls_dh_params_init(&dh_params)) < 0) - ServerInstance->Logs->Log("m_ssl_gnutls",DEBUG, "m_ssl_gnutls.so: Failed to initialise DH parameters: %s", gnutls_strerror(ret)); - if((ret =gnutls_certificate_set_x509_trust_file(x509_cred, cafile.c_str(), GNUTLS_X509_FMT_PEM)) < 0) ServerInstance->Logs->Log("m_ssl_gnutls",DEBUG, "m_ssl_gnutls.so: Failed to set X.509 trust file '%s': %s", cafile.c_str(), gnutls_strerror(ret)); if((ret = gnutls_certificate_set_x509_crl_file (x509_cred, crlfile.c_str(), GNUTLS_X509_FMT_PEM)) < 0) ServerInstance->Logs->Log("m_ssl_gnutls",DEBUG, "m_ssl_gnutls.so: Failed to set X.509 CRL file '%s': %s", crlfile.c_str(), gnutls_strerror(ret)); - if((ret = gnutls_certificate_set_x509_key_file (x509_cred, certfile.c_str(), keyfile.c_str(), GNUTLS_X509_FMT_PEM)) < 0) - { - // If this fails, no SSL port will work. At all. So, do the smart thing - throw a ModuleException - throw ModuleException("Unable to load GnuTLS server certificate (" + certfile + ", key: " + keyfile + "): " + std::string(gnutls_strerror(ret))); - } + FileReader reader(ServerInstance); + + reader.LoadFile(certfile); + std::string cert_string = reader.Contents(); + gnutls_datum_t cert_datum = { (unsigned char*)cert_string.data(), cert_string.length() }; + + reader.LoadFile(keyfile); + std::string key_string = reader.Contents(); + gnutls_datum_t key_datum = { (unsigned char*)key_string.data(), key_string.length() }; + + // If this fails, no SSL port will work. At all. So, do the smart thing - throw a ModuleException + if((ret = gnutls_x509_crt_import(x509_cert, &cert_datum, GNUTLS_X509_FMT_PEM)) < 0) + throw ModuleException("Unable to load GnuTLS server certificate (" + certfile + "): " + std::string(gnutls_strerror(ret))); + + if((ret = gnutls_x509_privkey_import(x509_key, &key_datum, GNUTLS_X509_FMT_PEM)) < 0) + throw ModuleException("Unable to load GnuTLS server private key (" + keyfile + "): " + std::string(gnutls_strerror(ret))); + + if((ret = gnutls_certificate_set_x509_key(x509_cred, &x509_cert, 1, x509_key)) < 0) + throw ModuleException("Unable to set GnuTLS cert/key pair: " + std::string(gnutls_strerror(ret))); + + gnutls_certificate_client_set_retrieve_function (x509_cred, cert_callback); + + if((ret = gnutls_dh_params_init(&dh_params)) < 0) + ServerInstance->Logs->Log("m_ssl_gnutls",DEFAULT, "m_ssl_gnutls.so: Failed to initialise DH parameters: %s", gnutls_strerror(ret)); // This may be on a large (once a day or week) timer eventually. GenerateDHParams(); @@ -247,6 +280,8 @@ class ModuleSSLGnuTLS : public Module virtual ~ModuleSSLGnuTLS() { + gnutls_x509_crt_deinit(x509_cert); + gnutls_x509_privkey_deinit(x509_key); gnutls_dh_params_deinit(dh_params); gnutls_certificate_free_credentials(x509_cred); gnutls_global_deinit(); |