#include "smartcardauth.h" #include "pindialog.h" #include #include "engine_sct.h" #include #include 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(); ENGINE_load_dynamic(); e = ENGINE_by_id("dynamic"); Q_ASSERT(e); int r=ENGINE_ctrl_cmd_string(e, "SO_PATH", "../openssl-act-engine/src/.libs/libengine_act.so", 0); Q_ASSERT(r); r=ENGINE_ctrl_cmd_string(e, "ID", "act", 0); Q_ASSERT(r); r=ENGINE_ctrl_cmd_string(e, "LIST_ADD", "1", 0); Q_ASSERT(r); r=ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0); Q_ASSERT(r); 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=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); qDebug()<<"Certificate:"<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("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; }