store headers only once, refs #7
This commit is contained in:
@@ -1,162 +1,164 @@
|
||||
#include "smartcardauth.h"
|
||||
#include "pindialog.h"
|
||||
#include <QtNetwork/private/qsslsocket_openssl_symbols_p.h>
|
||||
|
||||
#include "engine_sct.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
ENGINE* SmartCardAuth::e=NULL;
|
||||
enum_certs_s* SmartCardAuth::certs_found=NULL;
|
||||
QWidget* SmartCardAuth::parent=0;
|
||||
bool SmartCardAuth::pin_configured=false;
|
||||
bool SmartCardAuth::pin_rejected=false;
|
||||
|
||||
void SmartCardAuth::initialize() {
|
||||
QSslSocketPrivate::ensureInitialized();
|
||||
|
||||
q_ENGINE_load_dynamic();
|
||||
e = q_ENGINE_by_id("dynamic");
|
||||
|
||||
int r=q_ENGINE_ctrl_cmd_string(e, "SO_PATH", "C:\\Windows\\System32\\engine_act.dll", 0);
|
||||
r=q_ENGINE_ctrl_cmd_string(e, "ID", "act", 0);
|
||||
r=q_ENGINE_ctrl_cmd_string(e, "LIST_ADD", "1", 0);
|
||||
r=q_ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0);
|
||||
|
||||
if(!r)
|
||||
{
|
||||
unsigned int err = 0;
|
||||
while((err = q_ERR_get_error()))
|
||||
{
|
||||
char *str = q_ERR_error_string(err, NULL);
|
||||
fprintf(stderr,"%s\n", str);
|
||||
}
|
||||
}
|
||||
|
||||
r=q_ENGINE_init(e);
|
||||
|
||||
}
|
||||
|
||||
void SmartCardAuth::deinitialize() {
|
||||
q_ENGINE_finish(e);
|
||||
q_ENGINE_cleanup();
|
||||
}
|
||||
|
||||
void SmartCardAuth::setPinDlgParent(QWidget* p) {
|
||||
parent=p;
|
||||
}
|
||||
|
||||
int SmartCardAuth::client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
|
||||
{
|
||||
// NB: Keep in mind that this function is called for EVERY SSL connection to be opened.
|
||||
|
||||
for(size_t i=certs_found->num_certs;i--;)
|
||||
{
|
||||
const char *id_p = certs_found->certificate[i].id;
|
||||
|
||||
if(id_p == NULL) continue;
|
||||
|
||||
// Name has the format "slot-x-name-SwissSign_digSig" for the certificate/key we're looking for
|
||||
std::string name(certs_found->certificate[i].name);
|
||||
std::string compare("-name-SwissSign_digSig");
|
||||
|
||||
// Compare the rightmost part of the retrieved name to locate the certificate/keypair
|
||||
size_t pos = name.length() - compare.length();
|
||||
if(name.substr(pos) != compare)
|
||||
continue;
|
||||
|
||||
// // Filter out the correct certificate depending on well-known sorting criteria
|
||||
// // Given example searches for a keyword in the certificate's subject, but since we've got
|
||||
// // the decoded certificate as an X509* structure we can check all the fields.
|
||||
// X509_NAME* subj_name = q_X509_get_subject_name(certs_found->certificate[i].cert);
|
||||
// int maxlen = 2048;
|
||||
// char buf[maxlen+1];
|
||||
// buf[maxlen]=0;
|
||||
// q_X509_NAME_oneline(subj_name, buf, maxlen);
|
||||
// std::string subject(buf);
|
||||
|
||||
// const char *compare="CN=Carsten Pluntke";
|
||||
// if(subject.find(compare) == std::string::npos)
|
||||
// continue;
|
||||
|
||||
// Here we found a suitable certificate.
|
||||
|
||||
// Now prepare the reference to the SmartCard's private key and a copy of the certificate
|
||||
// to pass back to the caller.
|
||||
*x509 = q_X509_dup(certs_found->certificate[i].cert);
|
||||
*pkey = NULL;
|
||||
|
||||
// If we don't have a PIN yet, pop up a dialog, ask for a PIN and pass it along to the engine
|
||||
// for usage.
|
||||
if(!pin_configured)
|
||||
{
|
||||
PinDialog dlg(parent);
|
||||
int ok=dlg.exec();
|
||||
if(ok!=1) return 0; // User cancelled
|
||||
QByteArray pinByteArray=dlg.pin().toAscii();
|
||||
char *pin_str = pinByteArray.data();
|
||||
|
||||
// The engine control command takes a copy and overwrites the source array
|
||||
if(q_ENGINE_ctrl_cmd_string(e, "PIN", pin_str, 0))
|
||||
pin_configured = true;
|
||||
else
|
||||
return 0; // Engine refuses to take the PIN
|
||||
|
||||
*pkey = q_ENGINE_load_private_key(e, id_p, NULL, NULL);
|
||||
|
||||
// We do a test authorization on loading of the private key. If the operation fails at all,
|
||||
// DON'T try again (see below) or we would instantly lock the card in a single session because
|
||||
// of the retries!
|
||||
if(!*pkey)
|
||||
pin_rejected = true;
|
||||
}
|
||||
|
||||
// Second to nth iteration: We skipped the PIN dialog here, now load the key if we don't have the
|
||||
// explicit information not to do it (because the PIN is wrong)
|
||||
if(!*pkey && !pin_rejected)
|
||||
*pkey = q_ENGINE_load_private_key(e, id_p, NULL, NULL);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if(!*x509) {
|
||||
qWarning("Unable to load certificate");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!*pkey) {
|
||||
qWarning("Unable to load key");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool SmartCardAuth::hookInitSslContext(SSL_CTX *ctx)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if(!certs_found)
|
||||
result = (q_ENGINE_ctrl_cmd(e, "ENUM_CERTS", 0, &certs_found, NULL, 0) != 0);
|
||||
else
|
||||
result = true;
|
||||
|
||||
#ifdef USE_CERTIFICATE_FILE
|
||||
// Load a specific intermediate certificate from a file
|
||||
BIO* cert_file= q_BIO_new_file("D:\\QtSmartCardAuth_TMI\\QtSslTest\\swsign_interm.pem", "r");
|
||||
X509* interm=q_PEM_read_bio_X509(cert_file,NULL,NULL, NULL);
|
||||
q_BIO_free(cert_file);
|
||||
|
||||
q_SSL_CTX_add_extra_chain_cert(ctx,interm);
|
||||
#else
|
||||
// Add all of the card's certificates without a private key as intermediate certs
|
||||
for(size_t i=certs_found->num_certs;i--;)
|
||||
{
|
||||
if(certs_found->certificate[i].id == NULL)
|
||||
q_SSL_CTX_add_extra_chain_cert(ctx, q_X509_dup(certs_found->certificate[i].cert));
|
||||
}
|
||||
#endif
|
||||
|
||||
q_SSL_CTX_set_client_cert_cb(ctx,client_cert_cb);
|
||||
return true;
|
||||
}
|
||||
#include "smartcardauth.h"
|
||||
#include "pindialog.h"
|
||||
#include <QtNetwork/private/qsslsocket_openssl_symbols_p.h>
|
||||
|
||||
#include "engine_sct.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
ENGINE* SmartCardAuth::e=NULL;
|
||||
enum_certs_s* SmartCardAuth::certs_found=NULL;
|
||||
QWidget* SmartCardAuth::parent=0;
|
||||
bool SmartCardAuth::pin_configured=false;
|
||||
bool SmartCardAuth::pin_rejected=false;
|
||||
|
||||
void SmartCardAuth::initialize() {
|
||||
QSslSocketPrivate::ensureInitialized();
|
||||
|
||||
q_ENGINE_load_dynamic();
|
||||
e = q_ENGINE_by_id("dynamic");
|
||||
|
||||
//! @todo add library-name
|
||||
int r=q_ENGINE_ctrl_cmd_string(e, "SO_PATH", "...library-name...", 0);
|
||||
r=q_ENGINE_ctrl_cmd_string(e, "ID", "act", 0);
|
||||
r=q_ENGINE_ctrl_cmd_string(e, "LIST_ADD", "1", 0);
|
||||
r=q_ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0);
|
||||
|
||||
if(!r)
|
||||
{
|
||||
unsigned int err = 0;
|
||||
while((err = q_ERR_get_error()))
|
||||
{
|
||||
char *str = q_ERR_error_string(err, NULL);
|
||||
fprintf(stderr,"%s\n", str);
|
||||
}
|
||||
}
|
||||
|
||||
r=q_ENGINE_init(e);
|
||||
|
||||
}
|
||||
|
||||
void SmartCardAuth::deinitialize() {
|
||||
q_ENGINE_finish(e);
|
||||
q_ENGINE_cleanup();
|
||||
}
|
||||
|
||||
void SmartCardAuth::setPinDlgParent(QWidget* p) {
|
||||
parent=p;
|
||||
}
|
||||
|
||||
int SmartCardAuth::client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
|
||||
{
|
||||
// NB: Keep in mind that this function is called for EVERY SSL connection to be opened.
|
||||
|
||||
for(size_t i=certs_found->num_certs;i--;)
|
||||
{
|
||||
const char *id_p = certs_found->certificate[i].id;
|
||||
|
||||
if(id_p == NULL) continue;
|
||||
|
||||
// Name has the format "slot-x-name-SwissSign_digSig" for the certificate/key we're looking for
|
||||
std::string name(certs_found->certificate[i].name);
|
||||
std::string compare("-name-SwissSign_digSig");
|
||||
|
||||
// Compare the rightmost part of the retrieved name to locate the certificate/keypair
|
||||
size_t pos = name.length() - compare.length();
|
||||
if(name.substr(pos) != compare)
|
||||
continue;
|
||||
|
||||
// // Filter out the correct certificate depending on well-known sorting criteria
|
||||
// // Given example searches for a keyword in the certificate's subject, but since we've got
|
||||
// // the decoded certificate as an X509* structure we can check all the fields.
|
||||
// X509_NAME* subj_name = q_X509_get_subject_name(certs_found->certificate[i].cert);
|
||||
// int maxlen = 2048;
|
||||
// char buf[maxlen+1];
|
||||
// buf[maxlen]=0;
|
||||
// q_X509_NAME_oneline(subj_name, buf, maxlen);
|
||||
// std::string subject(buf);
|
||||
|
||||
// const char *compare="CN=Carsten Pluntke";
|
||||
// if(subject.find(compare) == std::string::npos)
|
||||
// continue;
|
||||
|
||||
// Here we found a suitable certificate.
|
||||
|
||||
// Now prepare the reference to the SmartCard's private key and a copy of the certificate
|
||||
// to pass back to the caller.
|
||||
*x509 = q_X509_dup(certs_found->certificate[i].cert);
|
||||
*pkey = NULL;
|
||||
|
||||
// If we don't have a PIN yet, pop up a dialog, ask for a PIN and pass it along to the engine
|
||||
// for usage.
|
||||
if(!pin_configured)
|
||||
{
|
||||
PinDialog dlg(parent);
|
||||
int ok=dlg.exec();
|
||||
if(ok!=1) return 0; // User cancelled
|
||||
QByteArray pinByteArray=dlg.pin().toAscii();
|
||||
char *pin_str = pinByteArray.data();
|
||||
|
||||
// The engine control command takes a copy and overwrites the source array
|
||||
if(q_ENGINE_ctrl_cmd_string(e, "PIN", pin_str, 0))
|
||||
pin_configured = true;
|
||||
else
|
||||
return 0; // Engine refuses to take the PIN
|
||||
|
||||
*pkey = q_ENGINE_load_private_key(e, id_p, NULL, NULL);
|
||||
|
||||
// We do a test authorization on loading of the private key. If the operation fails at all,
|
||||
// DON'T try again (see below) or we would instantly lock the card in a single session because
|
||||
// of the retries!
|
||||
if(!*pkey)
|
||||
pin_rejected = true;
|
||||
}
|
||||
|
||||
// Second to nth iteration: We skipped the PIN dialog here, now load the key if we don't have the
|
||||
// explicit information not to do it (because the PIN is wrong)
|
||||
if(!*pkey && !pin_rejected)
|
||||
*pkey = q_ENGINE_load_private_key(e, id_p, NULL, NULL);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if(!*x509) {
|
||||
qWarning("Unable to load certificate");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!*pkey) {
|
||||
qWarning("Unable to load key");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool SmartCardAuth::hookInitSslContext(SSL_CTX *ctx)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if(!certs_found)
|
||||
result = (q_ENGINE_ctrl_cmd(e, "ENUM_CERTS", 0, &certs_found, NULL, 0) != 0);
|
||||
else
|
||||
result = true;
|
||||
|
||||
#ifdef USE_CERTIFICATE_FILE
|
||||
// Load a specific intermediate certificate from a file
|
||||
//! @todo PEM-File
|
||||
BIO* cert_file= q_BIO_new_file("D:\\QtSmartCardAuth_TMI\\QtSslTest\\swsign_interm.pem", "r");
|
||||
X509* interm=q_PEM_read_bio_X509(cert_file,NULL,NULL, NULL);
|
||||
q_BIO_free(cert_file);
|
||||
|
||||
q_SSL_CTX_add_extra_chain_cert(ctx,interm);
|
||||
#else
|
||||
// Add all of the card's certificates without a private key as intermediate certs
|
||||
for(size_t i=certs_found->num_certs;i--;)
|
||||
{
|
||||
if(certs_found->certificate[i].id == NULL)
|
||||
q_SSL_CTX_add_extra_chain_cert(ctx, q_X509_dup(certs_found->certificate[i].cert));
|
||||
}
|
||||
#endif
|
||||
|
||||
q_SSL_CTX_set_client_cert_cb(ctx,client_cert_cb);
|
||||
return true;
|
||||
}
|
||||
|
Reference in New Issue
Block a user