void KeyAddDialog::addFile() { QString file = QFileDialog::getOpenFileName( this, windowTitle(), QDesktopServices::storageLocation( QDesktopServices::DocumentsLocation ), tr("Certificates (*.pem *.cer *.crt)") ); if( file.isEmpty() ) return; QFile f( file ); if( !f.open( QIODevice::ReadOnly ) ) { QMessageBox::warning( this, windowTitle(), tr("Failed to open certifiacte") ); return; } CKey k( QSslCertificate( &f, QSsl::Pem ) ); if( k.cert.isNull() ) { f.reset(); k.setCert( QSslCertificate( &f, QSsl::Der ) ); } if( k.cert.isNull() ) { QMessageBox::warning( this, windowTitle(), tr("Failed to read certificate") ); } else if( !SslCertificate( k.cert ).keyUsage().contains( SslCertificate::DataEncipherment ) ) { QMessageBox::warning( this, windowTitle(), tr("This certificate is not usable for crypting") ); } else addKeys( QList<CKey>() << k ); f.close(); }
void KeyModel::load( const QList<CKey> &result ) { skKeys.clear(); Q_FOREACH( const CKey &k, result ) if( SslCertificate( k.cert ).keyUsage().contains( SslCertificate::DataEncipherment ) ) skKeys << k; reset(); }
void SettingsDialog::updateCert() { QSslCertificate c = AccessCert::cert(); if( !c.isNull() ) d->p12Error->setText( tr("Issued to: %1<br />Valid to: %2 %3") .arg( SslCertificate(c).subjectInfo( QSslCertificate::CommonName ) ) .arg( c.expiryDate().toString("dd.MM.yyyy") ) .arg( !c.isValid() ? "<font color='red'>(" + tr("expired") + ")</font>" : "" ) ); else d->p12Error->setText( "<b>" + tr("Server access certificate is not installed.") + "</b>" ); d->showP12Cert->setEnabled( !c.isNull() ); d->showP12Cert->setProperty( "cert", QVariant::fromValue( c ) ); }
QPKCS11::PinStatus QPKCS11::login( const TokenData &_t ) { CK_TOKEN_INFO token; if( !d->pslot || (d->err = d->f->C_GetTokenInfo( *(d->pslot), &token )) != CKR_OK ) return PinUnknown; if( !(token.flags & CKF_LOGIN_REQUIRED) ) return PinOK; TokenData t = _t; if( token.flags & CKF_SO_PIN_COUNT_LOW || token.flags & CKF_USER_PIN_COUNT_LOW ) t.setFlag( TokenData::PinCountLow ); if( token.flags & CKF_SO_PIN_FINAL_TRY || token.flags & CKF_USER_PIN_FINAL_TRY ) t.setFlag( TokenData::PinFinalTry ); if( token.flags & CKF_SO_PIN_LOCKED || token.flags & CKF_USER_PIN_LOCKED ) t.setFlag( TokenData::PinLocked ); if( d->session ) d->err = d->f->C_CloseSession( d->session ); d->session = 0; if( (d->err = d->f->C_OpenSession( *(d->pslot), CKF_SERIAL_SESSION, 0, 0, &d->session )) != CKR_OK ) return PinUnknown; bool pin2 = SslCertificate( t.cert() ).keyUsage().keys().contains( SslCertificate::NonRepudiation ); if( token.flags & CKF_PROTECTED_AUTHENTICATION_PATH ) { PinDialog p( pin2 ? PinDialog::Pin2PinpadType : PinDialog::Pin1PinpadType, t, qApp->activeWindow() ); QPKCS11Thread t( d ); connect( &t, SIGNAL(started()), &p, SIGNAL(startTimer()) ); p.open(); d->err = t.waitForDone(); } else { PinDialog p( pin2 ? PinDialog::Pin2Type : PinDialog::Pin1Type, t, qApp->activeWindow() ); if( !p.exec() ) return PinCanceled; QByteArray pin = p.text().toUtf8(); d->err = d->f->C_Login( d->session, CKU_USER, (unsigned char*)pin.constData(), pin.size() ); } switch( d->err ) { case CKR_OK: return PinOK; case CKR_CANCEL: case CKR_FUNCTION_CANCELED: return PinCanceled; case CKR_PIN_INCORRECT: return PinIncorrect; case CKR_PIN_LOCKED: return PinLocked; default: return PinUnknown; } }
QVariant KeyModel::data( const QModelIndex &index, int role ) const { if( !index.isValid() && index.row() >= skKeys.count() ) return QVariant(); CKey k = skKeys[index.row()]; switch( role ) { case Qt::DisplayRole: switch( index.column() ) { case 0: return k.recipient; case 1: return k.cert.issuerInfo( QSslCertificate::CommonName ); case 2: return k.cert.expiryDate().toLocalTime().toString( "dd.MM.yyyy" ); default: break; } case Qt::UserRole: return SslCertificate( k.cert ).isTempel(); default: break; } return QVariant(); }
void KeyAddDialog::on_add_clicked() { if( !skView->selectionModel()->hasSelection() ) return; QList<CKey> keys; Q_FOREACH( const QModelIndex &index, skView->selectionModel()->selectedRows() ) { const CKey k = keyModel->key( index ); keys << k; if( usedView->findItems( k.recipient, Qt::MatchExactly ).isEmpty() ) { QTreeWidgetItem *i = new QTreeWidgetItem( usedView ); i->setText( 0, k.recipient ); i->setText( 1, k.cert.issuerInfo( "CN" ) ); i->setText( 2, k.cert.expiryDate().toLocalTime().toString( "dd.MM.yyyy" ) ); i->setData( 0, Qt::UserRole, SslCertificate( k.cert ).isTempel() ); usedView->addTopLevelItem( i ); } } addKeys( keys ); saveHistory(); }
bool AccessCert::download( bool noCard ) { if( noCard ) { QDesktopServices::openUrl( QUrl( tr("http://www.id.ee/kehtivuskinnitus") ) ); return false; } QMessageBox d( QMessageBox::Information, tr("Server access certificate"), tr("Hereby I agree to terms and conditions of validity confirmation service and " "will use the service in extent of 10 signatures per month. If you going to " "exceed the limit of 10 signatures per month or/and will use the service for " "commercial purposes, please refer to IT support of your company. Additional " "information is available from <a href=\"%1\">%1</a> or phone 1777") .arg( tr("http://www.id.ee/kehtivuskinnitus") ), QMessageBox::Help, m_parent ); d.addButton( tr("Agree"), QMessageBox::AcceptRole ); if( QLabel *label = d.findChild<QLabel*>() ) label->setOpenExternalLinks( true ); if( d.exec() == QMessageBox::Help ) { QDesktopServices::openUrl( QUrl( tr("http://www.id.ee/kehtivuskinnitus") ) ); return false; } QSigner *s = qApp->signer(); QPKCS11 *p = s->handle(); s->lock(); TokenData token; bool retry = false; do { retry = false; token = p->selectSlot( s->token().card(), SslCertificate::DataEncipherment ); QPKCS11::PinStatus status = p->login( token ); switch( status ) { case QPKCS11::PinOK: break; case QPKCS11::PinCanceled: s->unlock(); return false; case QPKCS11::PinIncorrect: showWarning( QPKCS11::errorString( status ) ); retry = true; break; default: showWarning( tr("Error downloading server access certificate!") + "\n" + QPKCS11::errorString( status ) ); s->unlock(); return false; } } while( retry ); QScopedPointer<SSLConnect> ssl( new SSLConnect ); ssl->setToken( token.cert(), p->key() ); QByteArray result = ssl->getUrl( SSLConnect::AccessCert ); if( !ssl->errorString().isEmpty() ) { showWarning( tr("Error downloading server access certificate!") + "\n" + ssl->errorString() ); return false; } s->unlock(); if( result.isEmpty() ) { showWarning( tr("Empty result!") ); return false; } QString status, cert, pass, message; QXmlStreamReader xml( result ); while( xml.readNext() != QXmlStreamReader::Invalid ) { if( !xml.isStartElement() ) continue; if( xml.name() == "StatusCode" ) status = xml.readElementText(); else if( xml.name() == "MessageToDisplay" ) message = xml.readElementText(); else if( xml.name() == "TokenData" ) cert = xml.readElementText(); else if( xml.name() == "TokenPassword" ) pass = xml.readElementText(); } if( status.isEmpty() ) { showWarning( tr("Error parsing server access certificate result!") ); return false; } switch( status.toInt() ) { case 1: //need to order cert manually from SK web QDesktopServices::openUrl( QUrl( tr("http://www.id.ee/kehtivuskinnitus") ) ); return false; case 2: //got error, show message from MessageToDisplay element showWarning( tr("Error downloading server access certificate!\n%1").arg( message ) ); return false; default: break; //ok } if ( cert.isEmpty() ) { showWarning( tr("Error reading server access certificate - empty content!") ); return false; } QString path = QDesktopServices::storageLocation( QDesktopServices::DataLocation ); if ( !QDir( path ).exists() ) QDir().mkpath( path ); QFile f( QString( "%1/%2.p12" ).arg( path, SslCertificate( qApp->signer()->token().cert() ).subjectInfo( "serialNumber" ) ) ); if ( !f.open( QIODevice::WriteOnly|QIODevice::Truncate ) ) { showWarning( tr("Failed to save server access certificate file to %1!\n%2") .arg( f.fileName() ) .arg( f.errorString() ) ); return false; } f.write( QByteArray::fromBase64( cert.toLatin1() ) ); Application::setConfValue( Application::PKCS12Cert, m_cert = QDir::toNativeSeparators( f.fileName() ) ); Application::setConfValue( Application::PKCS12Pass, m_pass = pass ); return true; }
bool AccessCert::download( bool noCard ) { if( noCard ) { QDesktopServices::openUrl( QUrl( tr("http://www.sk.ee/toend/") ) ); return false; } SslCertificate tempel( qApp->signer()->tokensign().cert() ); if( tempel.type() & SslCertificate::TempelType ) { setIcon( Information ); setText( tr("For getting server access certificate to Tempel contact <a href=\"mailto:[email protected]\">[email protected]</a>") ); return false; } setIcon( Information ); setText( tr("Hereby I agree to terms and conditions of validity confirmation service and " "will use the service in extent of 10 signatures per month. If you going to " "exceed the limit of 10 signatures per month or/and will use the service for " "commercial purposes, please refer to IT support of your company. Additional " "information is available from <a href=\"%1\">%1</a> or phone 1777") .arg( tr("http://www.id.ee/kehtivuskinnitus") ) ); setStandardButtons( Help ); QPushButton *agree = addButton( tr("Agree"), AcceptRole ); if( exec() == Help ) { QDesktopServices::openUrl( QUrl( tr("http://www.id.ee/kehtivuskinnitus") ) ); return false; } removeButton( agree ); QSigner *s = qApp->signer(); QPKCS11 *p = qobject_cast<QPKCS11*>(reinterpret_cast<QObject*>(s->handle())); #ifdef Q_OS_WIN QCNG *c = qobject_cast<QCNG*>(reinterpret_cast<QObject*>(s->handle())); if( !p && !c ) return false; #endif s->lock(); Qt::HANDLE key = 0; TokenData token; if( p ) { bool retry = false; do { retry = false; token.setCard( s->tokensign().card() ); Q_FOREACH( const TokenData &t, p->tokens() ) if( token.card() == t.card() && SslCertificate( t.cert() ).enhancedKeyUsage().contains( SslCertificate::ClientAuth ) ) token.setCert( t.cert() ); QPKCS11::PinStatus status = p->login( token ); switch( status ) { case QPKCS11::PinOK: break; case QPKCS11::PinCanceled: s->unlock(); return false; case QPKCS11::PinIncorrect: showWarning( QPKCS11::errorString( status ) ); retry = true; break; default: showWarning( tr("Error downloading server access certificate!") + "\n" + QPKCS11::errorString( status ) ); s->unlock(); return false; } } while( retry ); key = p->key(); } else {
SignatureDialog::SignatureDialog( const DigiDocSignature &signature, QWidget *parent ) : QDialog( parent ) , s( signature ) , d( new SignatureDialogPrivate ) { d->setupUi( this ); d->error->hide(); setAttribute( Qt::WA_DeleteOnClose ); const SslCertificate c = s.cert(); #define addCertButton(cert, button) if(!cert.isNull()) \ d->buttonBox->addButton(button, QDialogButtonBox::ActionRole)->setProperty("cert", QVariant::fromValue(cert)); addCertButton(s.cert(), tr("Show signer's certificate")); addCertButton(s.ocspCert(), tr("Show OCSP certificate")); addCertButton(s.tsaCert(), tr("Show TSA certificate")); addCertButton(qApp->confValue( Application::TSLCert ).value<QSslCertificate>(), tr("Show TSL certificate")); QString status; switch( s.validate() ) { case DigiDocSignature::Valid: status = tr("Signature is valid"); break; case DigiDocSignature::Warning: status = QString("%1 (%2)").arg( tr("Signature is valid"), tr("Warnings") ); if( !s.lastError().isEmpty() ) d->error->setPlainText( s.lastError() ); if( s.warning() & DigiDocSignature::WrongNameSpace ) { d->info->setText( tr( "This Digidoc document has not been created according to specification, " "but the digital signature is legally valid. Please inform the document creator " "of this issue. <a href='http://www.id.ee/?id=36511'>Additional information</a>.") ); } if( s.warning() & DigiDocSignature::DigestWeak ) { d->info->setText( tr( "The current BDOC container uses weaker encryption method than officialy accepted in Estonia.") ); } break; case DigiDocSignature::Test: status = QString("%1 (%2)").arg( tr("Signature is valid"), tr("Test signature") ); if( !s.lastError().isEmpty() ) d->error->setPlainText( s.lastError() ); d->info->setText( tr( "Test signature is signed with test certificates that are similar to the " "certificates of real tokens, but digital signatures with legal force cannot " "be given with them as there is no actual owner of the card. " "<a href='http://www.id.ee/index.php?id=30494'>Additional information</a>.") ); break; case DigiDocSignature::Invalid: status = tr("Signature is not valid"); d->error->setPlainText( s.lastError().isEmpty() ? tr("Unknown error") : s.lastError() ); d->info->setText( tr( "This is an invalid signature or malformed digitally signed file. The signature is not valid.") ); break; case DigiDocSignature::Unknown: status = tr("Signature status unknown"); d->error->setPlainText( s.lastError().isEmpty() ? tr("Unknown error") : s.lastError() ); d->info->setText( tr( "Signature status is displayed unknown if you don't have all validity confirmation service " "certificates and/or certificate authority certificates installed into your computer. " "<a href='http://www.id.ee/index.php?id=35941'>Additional information</a>.") ); break; } if( d->error->toPlainText().isEmpty() && d->info->text().isEmpty() ) d->tabWidget->removeTab( 0 ); else d->buttonBox->addButton( QDialogButtonBox::Help ); d->title->setText( c.toString( c.showCN() ? "CN serialNumber" : "GN SN serialNumber" ) + "\n" + status ); setWindowTitle( c.toString( c.showCN() ? "CN serialNumber" : "GN SN serialNumber" ) + " - " + status ); const QStringList l = s.locations(); d->signerCity->setText( l.value( 0 ) ); d->signerState->setText( l.value( 1 ) ); d->signerZip->setText( l.value( 2 ) ); d->signerCountry->setText( l.value( 3 ) ); Q_FOREACH( const QString &role, s.roles() ) { QLineEdit *line = new QLineEdit( role, d->signerRoleGroup ); line->setReadOnly( true ); d->signerRoleGroupLayout->addRow( line ); } // Certificate info QTreeWidget *t = d->signatureView; t->header()->setResizeMode( 0, QHeaderView::ResizeToContents ); addItem( t, tr("TSL URL"), qApp->confValue( Application::TSLUrl ).toString() ); addItem( t, tr("Signer's computer time (UTC)"), DateTime( s.signTime() ).toStringZ( "dd.MM.yyyy hh:mm:ss" ) ); addItem( t, tr("Signature method"), s.signatureMethod() ); addItem( t, tr("Container format"), s.parent()->mediaType() ); if( s.type() != DigiDocSignature::DDocType ) addItem( t, tr("Signature format"), s.profile() ); if( !s.policy().isEmpty() ) { #define toVer(X) (X)->toUInt() - 1 QStringList ver = s.policy().split( "." ); if( ver.size() >= 3 ) addItem( t, tr("Signature policy"), QString("%1.%2.%3").arg( toVer(ver.end()-3) ).arg( toVer(ver.end()-2) ).arg( toVer(ver.end()-1) ) ); else addItem( t, tr("Signature policy"), s.policy() ); } addItem( t, tr("Signed file count"), QString::number( s.parent()->documentModel()->rowCount() ) ); addItem( t, tr("Signer Certificate issuer"), c.issuerInfo( QSslCertificate::CommonName ) ); if( !s.spuri().isEmpty() ) addItem( t, "SPUri", s.spuri() ); // OCSP info switch( s.type() ) { case DigiDocSignature::TSType: { addItem( t, tr("Signature Timestamp"), DateTime( s.tsaTime().toLocalTime() ).toStringZ( "dd.MM.yyyy hh:mm:ss" )); addItem( t, tr("Signature Timestamp") + " (UTC)", DateTime( s.tsaTime() ).toStringZ( "dd.MM.yyyy hh:mm:ss" ) ); addItem( t, tr("TSA Certificate issuer"), SslCertificate(s.tsaCert()).issuerInfo( QSslCertificate::CommonName ) ); } //Fall through to OCSP info case DigiDocSignature::DDocType: case DigiDocSignature::TMType: { SslCertificate ocsp = s.ocspCert(); addItem( t, tr("OCSP Certificate issuer"), ocsp.issuerInfo( QSslCertificate::CommonName ) ); addItem( t, tr("OCSP time"), DateTime( s.ocspTime().toLocalTime() ).toStringZ( "dd.MM.yyyy hh:mm:ss" ) ); addItem( t, tr("OCSP time") + " (UTC)", DateTime( s.ocspTime() ).toStringZ( "dd.MM.yyyy hh:mm:ss" ) ); addItem( t, tr("Hash value of signature"), SslCertificate::toHex( s.ocspNonce() ) ); break; } default: break; } }
bool AccessCert::download( bool noCard ) { if( noCard ) { QDesktopServices::openUrl( QUrl( "http://www.sk.ee/toend/" ) ); return false; } QMessageBox d( QMessageBox::Information, tr("Server access certificate"), tr("Hereby I agree to terms and conditions of validity confirmation service and " "will use the service in extent of 10 signatures per month. If you going to " "exceed the limit of 10 signatures per month or/and will use the service for " "commercial purposes, please refer to IT support of your company. Additional " "information is available from <a href=\"http://www.sk.ee/kehtivuskinnitus\">" "http://www.sk.ee/kehtivuskinnitus</a> or phone 1777"), QMessageBox::Help, m_parent ); d.addButton( tr("Agree"), QMessageBox::AcceptRole ); if( QLabel *label = d.findChild<QLabel*>() ) label->setOpenExternalLinks( true ); if( d.exec() == QMessageBox::Help ) { QDesktopServices::openUrl( QUrl( "http://www.sk.ee/kehtivuskinnitus" ) ); return false; } qApp->signer()->lock(); QScopedPointer<SSLConnect> ssl( new SSLConnect() ); ssl->setPKCS11( Application::confValue( Application::PKCS11Module ), false ); ssl->setCard( qApp->signer()->token().card() ); bool retry = false; do { retry = false; if( ssl->flags() & TokenData::PinLocked ) { showWarning( tr("Error downloading server access certificate!\nPIN1 is blocked" ) ); qApp->signer()->unlock(); return false; } ssl->waitForFinished( SSLConnect::AccessCert ); switch( ssl->error() ) { case SSLConnect::PinCanceledError: qApp->signer()->unlock(); return false; case SSLConnect::PinInvalidError: showWarning( ssl->errorString() ); retry = true; break; default: if( !ssl->errorString().isEmpty() ) { showWarning( tr("Error downloading server access certificate!\n%1").arg( ssl->errorString() ) ); qApp->signer()->unlock(); return false; } break; } } while( retry ); QByteArray result = ssl->result(); qApp->signer()->unlock(); if( result.isEmpty() ) { showWarning( tr("Empty result!") ); return false; } QDomDocument domDoc; if( !domDoc.setContent( QString::fromUtf8( result ) ) ) { showWarning( tr("Error parsing server access certificate result!") ); return false; } QDomElement e = domDoc.documentElement(); QDomNodeList status = e.elementsByTagName( "StatusCode" ); if( status.isEmpty() ) { showWarning( tr("Error parsing server access certificate result!") ); return false; } switch( status.item(0).toElement().text().toInt() ) { case 1: //need to order cert manually from SK web QDesktopServices::openUrl( QUrl( "http://www.sk.ee/toend/" ) ); return false; case 2: //got error, show message from MessageToDisplay element showWarning( tr("Error downloading server access certificate!\n%1") .arg( e.elementsByTagName( "MessageToDisplay" ).item(0).toElement().text() ) ); return false; default: break; //ok } QString cert = e.elementsByTagName( "TokenData" ).item(0).toElement().text(); if ( cert.isEmpty() ) { showWarning( tr("Error reading server access certificate - empty content!") ); return false; } QString path = QDesktopServices::storageLocation( QDesktopServices::DataLocation ); if ( !QDir( path ).exists() ) QDir().mkpath( path ); QFile f( QString( "%1/%2.p12" ).arg( path, SslCertificate( qApp->signer()->token().cert() ).subjectInfo( "serialNumber" ) ) ); if ( !f.open( QIODevice::WriteOnly|QIODevice::Truncate ) ) { showWarning( tr("Failed to save server access certificate file to %1!\n%2") .arg( f.fileName() ) .arg( f.errorString() ) ); return false; } f.write( QByteArray::fromBase64( cert.toLatin1() ) ); Application::setConfValue( Application::PKCS12Cert, m_cert = f.fileName() ); Application::setConfValue( Application::PKCS12Pass, m_pass = e.elementsByTagName( "TokenPassword" ).item(0).toElement().text() ); return true; }
void CKey::setCert( const QSslCertificate &c ) { cert = c; recipient = SslCertificate(c).friendlyName(); }