diff --git a/client/Application.cpp b/client/Application.cpp index e164686e8..333bef813 100644 --- a/client/Application.cpp +++ b/client/Application.cpp @@ -305,6 +305,10 @@ class Application::Private #ifdef Q_OS_WIN QStringList tempFiles; #endif // Q_OS_WIN + + ~Private() { + delete signer; + } }; Application::Application( int &argc, char **argv ) @@ -429,6 +433,7 @@ Application::Application( int &argc, char **argv ) // Clear obsolete registriy settings #ifndef Q_OS_DARWIN Settings::DEFAULT_DIR.clear(); + Settings::CDOC2_NOTIFICATION.clear(); #endif // Actions diff --git a/client/CDocSupport.cpp b/client/CDocSupport.cpp index 47a4419d1..ec07b781f 100644 --- a/client/CDocSupport.cpp +++ b/client/CDocSupport.cpp @@ -93,11 +93,11 @@ CDocSupport::getCDocFileList(const QString &filename) } static libcdoc::result_t -getDecryptStatus(const std::vector& result, QCryptoBackend::PinStatus pin_status) +getDecryptStatus(QCryptoBackend::Status pin_status) { switch (pin_status) { case QCryptoBackend::PinOK: - return (result.empty()) ? DDCryptoBackend::BACKEND_ERROR : libcdoc::OK; + return libcdoc::OK; case QCryptoBackend::PinCanceled: return DDCryptoBackend::PIN_CANCELED; case QCryptoBackend::PinIncorrect: @@ -109,44 +109,62 @@ getDecryptStatus(const std::vector& result, QCryptoBackend::PinStatus p } } +static libcdoc::result_t +getDecryptResultStatus(const std::vector &result, std::unique_ptr backend) +{ + if (!result.empty()) + return libcdoc::OK; + libcdoc::result_t mapped = getDecryptStatus(backend->status); + return mapped == libcdoc::OK ? DDCryptoBackend::BACKEND_ERROR : mapped; +} + libcdoc::result_t -DDCryptoBackend::decryptRSA(std::vector& result, const std::vector &data, bool oaep, unsigned int idx) +DDCryptoBackend::decryptRSA(std::vector& dst, const std::vector &data, bool oaep, unsigned int idx) { - QCryptoBackend::PinStatus pin_status; - QByteArray qkek = qApp->signer()->decrypt([qdata = toByteArray(data), &oaep](QCryptoBackend *backend) { - return backend->decrypt(qdata, oaep); - }, pin_status); - result.assign(qkek.cbegin(), qkek.cend()); - return getDecryptStatus(result, pin_status); + if (!backend) { + auto val = QCryptoBackend::getBackend(qApp->signer()->tokenauth()); + if (!val) + return getDecryptStatus(val.error()); + backend.reset(val.value()); + } + QByteArray decryptedKey = backend->decrypt(toByteArray(data), oaep); + dst.assign(decryptedKey.cbegin(), decryptedKey.cend()); + return getDecryptResultStatus(dst, std::move(backend)); } libcdoc::result_t DDCryptoBackend::deriveConcatKDF(std::vector& dst, const std::vector &publicKey, const std::string &digest, const std::vector &algorithmID, const std::vector &partyUInfo, const std::vector &partyVInfo, unsigned int idx) { - QCryptoBackend::PinStatus pin_status; - QByteArray decryptedKey = qApp->signer()->decrypt([&publicKey, &digest, &algorithmID, &partyUInfo, &partyVInfo](QCryptoBackend *backend) { - static const QHash SHA_MTH{ - {"http://www.w3.org/2001/04/xmlenc#sha256", QCryptographicHash::Sha256}, - {"http://www.w3.org/2001/04/xmlenc#sha384", QCryptographicHash::Sha384}, - {"http://www.w3.org/2001/04/xmlenc#sha512", QCryptographicHash::Sha512} - }; - return backend->deriveConcatKDF(toByteArray(publicKey), SHA_MTH.value(digest), - toByteArray(algorithmID), toByteArray(partyUInfo), toByteArray(partyVInfo)); - }, pin_status); + static const QHash SHA_MTH{ + {"http://www.w3.org/2001/04/xmlenc#sha256", QCryptographicHash::Sha256}, + {"http://www.w3.org/2001/04/xmlenc#sha384", QCryptographicHash::Sha384}, + {"http://www.w3.org/2001/04/xmlenc#sha512", QCryptographicHash::Sha512} + }; + if (!backend) { + auto val = QCryptoBackend::getBackend(qApp->signer()->tokenauth()); + if (!val) + return getDecryptStatus(val.error()); + backend.reset(val.value()); + } + QByteArray decryptedKey = backend->deriveConcatKDF(toByteArray(publicKey), SHA_MTH.value(digest), + toByteArray(algorithmID), toByteArray(partyUInfo), toByteArray(partyVInfo)); dst.assign(decryptedKey.cbegin(), decryptedKey.cend()); - return getDecryptStatus(dst, pin_status); + return getDecryptResultStatus(dst, std::move(backend)); } libcdoc::result_t DDCryptoBackend::deriveHMACExtract(std::vector& dst, const std::vector &key_material, const std::vector &salt, unsigned int idx) { - QCryptoBackend::PinStatus pin_status; - QByteArray qkekpm = qApp->signer()->decrypt([qkey_material = toByteArray(key_material), qsalt = toByteArray(salt)](QCryptoBackend *backend) { - return backend->deriveHMACExtract(qkey_material, qsalt, ECC_KEY_LEN); - }, pin_status); - dst = std::vector(qkekpm.cbegin(), qkekpm.cend()); - return getDecryptStatus(dst, pin_status); + if (!backend) { + auto val = QCryptoBackend::getBackend(qApp->signer()->tokenauth()); + if (!val) + return getDecryptStatus(val.error()); + backend.reset(val.value()); + } + QByteArray decryptedKey = backend->deriveHMACExtract(toByteArray(key_material), toByteArray(salt), ECC_KEY_LEN); + dst.assign(decryptedKey.cbegin(), decryptedKey.cend()); + return getDecryptResultStatus(dst, std::move(backend)); } libcdoc::result_t @@ -281,22 +299,25 @@ libcdoc::result_t DDNetworkBackend::sendKey( }; libcdoc::result_t -DDNetworkBackend::fetchKey(std::vector &result, - const std::string &url, - const std::string &transaction_id) { +DDNetworkBackend::fetchKey(std::vector &result, const std::string &url, const std::string &transaction_id) +{ QNetworkRequest req(QStringLiteral("%1/key-capsules/%2").arg(QString::fromStdString(url), QLatin1String(transaction_id.c_str()))); req.setHeader(QNetworkRequest::ContentTypeHeader, QStringLiteral("application/json")); if(!checkConnection()) { last_error = "No connection"; return BACKEND_ERROR; } - QCryptoBackend::PinStatus pin_status; - auto authKey = dispatchToMain([&] { - return qApp->signer()->key(pin_status); - }); + + TokenData auth = qApp->signer()->tokenauth(); + auto val = QCryptoBackend::getBackend(qApp->signer()->tokenauth()); + if (!val.value()) + return getDecryptStatus(val.error()); + std::unique_ptr backend(val.value()); + + auto authKey = backend->getKey(); if (!authKey.handle()) { - last_error = qApp->signer()->getLastErrorStr().toStdString(); - return getDecryptStatus(result, pin_status); + last_error = "Cannot create authentication key"; + return BACKEND_ERROR; } QScopedPointer nam( CheckConnection::setupNAM(req, qApp->signer()->tokenauth().cert(), authKey, Settings::CDOC2_GET_CERT)); @@ -304,9 +325,6 @@ DDNetworkBackend::fetchKey(std::vector &result, QNetworkReply *reply = nam->get(req); connect(reply, &QNetworkReply::finished, &e, &QEventLoop::quit); e.exec(); - if(authKey.handle()) { - qApp->signer()->logout(); - } if(reply->error() != QNetworkReply::NoError && reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() != 201) { last_error = reply->errorString().toStdString(); @@ -315,6 +333,9 @@ DDNetworkBackend::fetchKey(std::vector &result, QJsonObject json = QJsonDocument::fromJson(reply->readAll()).object(); QByteArray key_material = QByteArray::fromBase64(json.value(QLatin1String("ephemeral_key_material")).toString().toLatin1()); result.assign(key_material.cbegin(), key_material.cend()); + + crypto.setBackend(std::move(backend)); + return libcdoc::OK; } diff --git a/client/CDocSupport.h b/client/CDocSupport.h index b3c87bd90..42f6efc12 100644 --- a/client/CDocSupport.h +++ b/client/CDocSupport.h @@ -19,6 +19,8 @@ #pragma once +#include "QCryptoBackend.h" + #include #include #include @@ -76,9 +78,14 @@ struct DDCryptoBackend final : public libcdoc::CryptoBackend { unsigned int idx) final; std::string getLastErrorStr(libcdoc::result_t code) const final; + std::unique_ptr backend; std::vector secret; explicit DDCryptoBackend() = default; + + void setBackend(std::unique_ptr &&backend) { + this->backend = std::move(backend); + } }; // @@ -110,8 +117,9 @@ struct DDNetworkBackend final : public libcdoc::NetworkBackend, private QObject return libcdoc::NOT_IMPLEMENTED; } - explicit DDNetworkBackend() = default; + explicit DDNetworkBackend(DDCryptoBackend &_crypto) : crypto(_crypto) {} + DDCryptoBackend &crypto; std::string last_error; }; diff --git a/client/CryptoDoc.cpp b/client/CryptoDoc.cpp index 81af61290..babdfebfa 100644 --- a/client/CryptoDoc.cpp +++ b/client/CryptoDoc.cpp @@ -84,6 +84,7 @@ struct CryptoDoc::Private std::vector files; std::vector keys; + explicit Private() : network(crypto) {} bool isEncryptedWarning(const QString &title) const; bool isEncrypted() const { @@ -340,28 +341,6 @@ bool CryptoDoc::decrypt(const libcdoc::Lock *lock, const QByteArray& secret) return false; } - if (d->reader->version == 2 && - (lock->type == libcdoc::Lock::Type::SERVER) && - !Settings::CDOC2_NOTIFICATION.isSet()) { - auto *dlg = WarningDialog::create() - ->withTitle(tr("You must enter your PIN code twice in order to decrypt the CDOC2 container")) - ->withText(tr( - "The first PIN entry is required for authentication to the key server referenced in the CDOC2 container. " - "Second PIN entry is required to decrypt the CDOC2 container.")) - ->setCancelText(WarningDialog::Cancel) - ->addButton(WarningDialog::OK, QMessageBox::Ok) - ->addButton(tr("Don't show again"), QMessageBox::Ignore); - switch (dlg->exec()) - { - case QMessageBox::Ok: break; - case QMessageBox::Ignore: - Settings::CDOC2_NOTIFICATION = true; - break; - default: - return false; - } - } - d->crypto.secret.assign(secret.cbegin(), secret.cend()); TempListConsumer cons; @@ -394,13 +373,13 @@ bool CryptoDoc::decrypt(const libcdoc::Lock *lock, const QByteArray& secret) str = tr("Cannot read file."); break; case DDCryptoBackend::PIN_CANCELED: - str = tr("PIN entry canceled"); + str = QCryptoBackend::errorString(QCryptoBackend::Status::PinCanceled); break; case DDCryptoBackend::PIN_INCORRECT: - str = tr("PIN incorrect"); + str = QCryptoBackend::errorString(QCryptoBackend::Status::PinIncorrect); break; case DDCryptoBackend::PIN_LOCKED: - str = tr("PIN locked"); + QCryptoBackend::errorString(QCryptoBackend::Status::PinLocked); break; default: str = tr("Please check your internet connection and network settings."); diff --git a/client/QCNG.cpp b/client/QCNG.cpp index 7107299e5..51f9abf76 100644 --- a/client/QCNG.cpp +++ b/client/QCNG.cpp @@ -41,21 +41,30 @@ struct SCOPE constexpr T* operator&() noexcept { return &d; } }; -class QCNG::Private +struct QCNG::Private { -public: - TokenData token; - QCNG::PinStatus err = QCNG::PinOK; + SCOPE prov; + SCOPE key; + bool pss; }; -QCNG::QCNG( QObject *parent ) - : QCryptoBackend(parent) - , d(new Private) -{} +QCNG::QCNG() noexcept = default; + +QCNG::~QCNG() noexcept = default; -QCNG::~QCNG() +QCNG::Status QCNG::login(const TokenData &token) { - delete d; + std::unique_ptr p = std::make_unique(); + if(FAILED(NCryptOpenStorageProvider(&p->prov, LPCWSTR(token.data(u"provider"_s).toString().utf16()), 0))) + return DeviceError; + if(FAILED(NCryptOpenKey(p->prov, &p->key, LPWSTR(token.data(u"key"_s).toString().utf16()), + token.data(u"spec"_s).value(), 0))) + return DeviceError; + // https://docs.microsoft.com/en-us/archive/blogs/alejacma/smart-cards-pin-gets-cached + NCryptSetProperty(p->key, NCRYPT_PIN_PROPERTY, nullptr, 0, 0); + p->pss = token.data(u"PSS"_s).toBool(); + d = std::move(p); + return PinOK; } QByteArray QCNG::decrypt(const QByteArray &data, bool oaep) const @@ -155,33 +164,24 @@ QByteArray QCNG::deriveHMACExtract(const QByteArray &publicKey, const QByteArray template QByteArray QCNG::exec(F &&func) const { - d->err = UnknownError; - SCOPE prov; - if(FAILED(NCryptOpenStorageProvider(&prov, LPCWSTR(d->token.data(u"provider"_s).toString().utf16()), 0))) - return {}; - SCOPE key; - if(FAILED(NCryptOpenKey(prov, &key, LPWSTR(d->token.data(u"key"_s).toString().utf16()), - d->token.data(u"spec"_s).value(), 0))) + if (!d) return {}; - // https://docs.microsoft.com/en-us/archive/blogs/alejacma/smart-cards-pin-gets-cached - NCryptSetProperty(key, NCRYPT_PIN_PROPERTY, nullptr, 0, 0); + status = UnknownError; QByteArray result; - switch(func(prov, key, result)) + switch(func(d->prov, d->key, result)) { case ERROR_SUCCESS: - d->err = PinOK; + status = PinOK; return result; case SCARD_W_CANCELLED_BY_USER: case ERROR_CANCELLED: - d->err = PinCanceled; + status = PinCanceled; default: return {}; } } -QCNG::PinStatus QCNG::lastError() const { return d->err; } - -QList QCNG::tokens() const +QList QCNG::tokens() { QList result; auto prop = [](NCRYPT_HANDLE handle, LPCWSTR param) -> QByteArray { @@ -275,12 +275,6 @@ QList QCNG::tokens() const return result; } -QCNG::PinStatus QCNG::login(const TokenData &token) -{ - d->token = token; - return d->err = QCNG::PinOK; -} - QByteArray QCNG::sign(QCryptographicHash::Algorithm type, const QByteArray &digest) const { return exec([&](NCRYPT_PROV_HANDLE prov, NCRYPT_KEY_HANDLE key, QByteArray &result) { @@ -301,7 +295,7 @@ QByteArray QCNG::sign(QCryptographicHash::Algorithm type, const QByteArray &dige bool isRSA = algo == QLatin1String("RSA"); DWORD padding {}; PVOID paddingInfo {}; - if(isRSA && d->token.data(u"PSS"_s).toBool()) + if(isRSA && d->pss) { padding = BCRYPT_PAD_PSS; paddingInfo = &rsaPSS; diff --git a/client/QCNG.h b/client/QCNG.h index 279860ab5..7b060e9e7 100644 --- a/client/QCNG.h +++ b/client/QCNG.h @@ -20,33 +20,32 @@ #pragma once #include "QCryptoBackend.h" +#include "TokenData.h" #include #include class QCNG final: public QCryptoBackend { - Q_OBJECT public: - explicit QCNG(QObject *parent = nullptr); - ~QCNG() final; + explicit QCNG() noexcept; + ~QCNG() noexcept final; + + Status login(const TokenData &token) final; - QList tokens() const final; QByteArray decrypt(const QByteArray &data, bool oaep) const final; QByteArray deriveConcatKDF(const QByteArray &publicKey, QCryptographicHash::Algorithm digest, const QByteArray &algorithmID, const QByteArray &partyUInfo, const QByteArray &partyVInfo) const final; QByteArray deriveHMACExtract(const QByteArray &publicKey, const QByteArray &salt, int keySize) const final; - PinStatus lastError() const final; - PinStatus login(const TokenData &token) final; - void logout() final {} QByteArray sign(QCryptographicHash::Algorithm type, const QByteArray &digest) const final; + static QList tokens(); private: template QByteArray derive(const QByteArray &publicKey, F &&func) const; template QByteArray exec(F &&func) const; - class Private; - Private *d; + struct Private; + std::unique_ptr d; }; diff --git a/client/QCryptoBackend.cpp b/client/QCryptoBackend.cpp index 254ebe201..dd523d2f9 100644 --- a/client/QCryptoBackend.cpp +++ b/client/QCryptoBackend.cpp @@ -19,16 +19,157 @@ #include "QCryptoBackend.h" -QString QCryptoBackend::errorString(PinStatus error) +#include "TokenData.h" +#ifdef Q_OS_WIN +#include "QCNG.h" +#endif +#include "QPKCS11.h" + +#include +#include + +// TODO: Port everything to the new OpenSSL API +#define OPENSSL_SUPPRESS_DEPRECATED + +#include +#include +#include + +std::expected +QCryptoBackend::getBackend(const TokenData& token) { +#ifdef Q_OS_WIN + auto backend = std::make_unique(); +#else + auto backend = std::make_unique(); +#endif + backend->cert = token.cert(); + Status status; + do { + status = backend->login(token); + } while (status == PinIncorrect); + if (status != PinOK) return std::unexpected(status); + return backend.release(); +} + +QList +QCryptoBackend::getTokens() +{ +#ifdef Q_OS_WIN + return QCNG::tokens(); +#else + return QPKCS11::tokens(); +#endif +} + +QString QCryptoBackend::errorString(Status error) { switch( error ) { case PinOK: return QString(); - case PinCanceled: return tr("PIN Canceled"); - case PinLocked: return tr("PIN locked"); - case PinIncorrect: return tr("PIN Incorrect"); - case GeneralError: return tr("PKCS11 general error"); - case DeviceError: return tr("PKCS11 device error"); - default: return tr("Unknown error"); + case PinCanceled: return QCoreApplication::translate("QCryptoBackend", "PIN entry canceled"); + case PinLocked: return QCoreApplication::translate("QCryptoBackend", "PIN locked"); + case PinIncorrect: return QCoreApplication::translate("QCryptoBackend", "PIN incorrect"); + case GeneralError: return QCoreApplication::translate("QCryptoBackend", "PKCS11 general error"); + case DeviceError: return QCoreApplication::translate("QCryptoBackend", "PKCS11 device error"); + default: return QCoreApplication::translate("QCryptoBackend", "Unknown error"); } } + +static int rsa_sign(int type, const unsigned char *m, unsigned int m_len, unsigned char *sigret, unsigned int *siglen, const RSA *rsa) +{ + auto *backend = (QCryptoBackend*) RSA_get_ex_data(rsa, 0); + QCryptographicHash::Algorithm algo = QCryptographicHash::Sha256; + switch(type) + { + case NID_sha224: algo = QCryptographicHash::Sha224; break; + case NID_sha256: algo = QCryptographicHash::Sha256; break; + case NID_sha384: algo = QCryptographicHash::Sha384; break; + case NID_sha512: algo = QCryptographicHash::Sha512; break; + } + QByteArray result = backend->sign(algo, QByteArray::fromRawData((const char*)m, int(m_len))); + if(result.isEmpty()) + return 0; + *siglen = (unsigned int)result.size(); + memcpy(sigret, result.constData(), size_t(result.size())); + return 1; +} + +static ECDSA_SIG* +ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM * /*inv*/, const BIGNUM * /*rp*/, EC_KEY *eckey) +{ + auto *backend = (QCryptoBackend*)EC_KEY_get_ex_data(eckey, 0); + QByteArray result = backend->sign(QCryptographicHash::Sha512, QByteArray::fromRawData((const char*)dgst, dgst_len)); + if(result.isEmpty()) + return nullptr; + QByteArray r = result.left(result.size()/2); + QByteArray s = result.right(result.size()/2); + ECDSA_SIG *sig = ECDSA_SIG_new(); + ECDSA_SIG_set0(sig, + BN_bin2bn((const unsigned char*)r.data(), int(r.size()), nullptr), + BN_bin2bn((const unsigned char*)s.data(), int(s.size()), nullptr)); + return sig; +} + +static RSA_METHOD *get_rsa_method(bool release = false) +{ + static RSA_METHOD *method = nullptr; + if (!method && !release) { + method = RSA_meth_dup(RSA_get_default_method()); + RSA_meth_set1_name(method, "QSmartCard"); + RSA_meth_set_sign(method, rsa_sign); + } else if (method && release) { + RSA_meth_free(method); + method = nullptr; + } + return method; +} + +static EC_KEY_METHOD *get_ec_method(bool release = false) +{ + static EC_KEY_METHOD *method = nullptr; + if(!method && !release) { + method = EC_KEY_METHOD_new(EC_KEY_get_default_method()); + using EC_KEY_sign = int (*)(int type, const unsigned char *dgst, int dlen, unsigned char *sig, + unsigned int *siglen, const BIGNUM *kinv, const BIGNUM *r, EC_KEY *eckey); + using EC_KEY_sign_setup = int (*)(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp); + EC_KEY_sign sign = nullptr; + EC_KEY_sign_setup sign_setup = nullptr; + EC_KEY_METHOD_get_sign(method, &sign, &sign_setup, nullptr); + EC_KEY_METHOD_set_sign(method, sign, sign_setup, ecdsa_do_sign); + } else if (method && release) { + EC_KEY_METHOD_free(method); + method = nullptr; + } + return method; +} + +QSslKey +QCryptoBackend::getKey() const +{ + QSslKey key = cert.publicKey(); + if(!key.handle()) { + status = GeneralError; + return {}; + } + if(key.algorithm() == QSsl::Ec) + { + auto *ec = (EC_KEY*)key.handle(); + EC_KEY_set_method(ec, get_ec_method()); + EC_KEY_set_ex_data(ec, 0, (void *) this); + } + else + { + RSA *rsa = (RSA*)key.handle(); + RSA_set_method(rsa, get_rsa_method()); + RSA_set_ex_data(rsa, 0, (void *) this); + } + return key; +} + +void +QCryptoBackend::shutDown() +{ + get_rsa_method(true); + get_ec_method(true); +} + diff --git a/client/QCryptoBackend.h b/client/QCryptoBackend.h index 210826b96..9f60ce469 100644 --- a/client/QCryptoBackend.h +++ b/client/QCryptoBackend.h @@ -19,16 +19,17 @@ #pragma once -#include -#include +#include + +#include class TokenData; +class QSslKey; -class QCryptoBackend: public QObject +class QCryptoBackend { - Q_OBJECT public: - enum PinStatus : quint8 + enum Status : quint8 { PinOK, PinCanceled, @@ -39,17 +40,49 @@ class QCryptoBackend: public QObject UnknownError }; - using QObject::QObject; + virtual ~QCryptoBackend() {}; - virtual QList tokens() const = 0; virtual QByteArray decrypt(const QByteArray &data, bool oaep) const = 0; virtual QByteArray deriveConcatKDF(const QByteArray &publicKey, QCryptographicHash::Algorithm digest, const QByteArray &algorithmID, const QByteArray &partyUInfo, const QByteArray &partyVInfo) const = 0; virtual QByteArray deriveHMACExtract(const QByteArray &publicKey, const QByteArray &salt, int keySize) const = 0; - virtual PinStatus lastError() const { return PinOK; } - virtual PinStatus login(const TokenData &cert) = 0; - virtual void logout() = 0; virtual QByteArray sign(QCryptographicHash::Algorithm method, const QByteArray &digest) const = 0; - static QString errorString( PinStatus error ); + /** + * @brief Get the SSL key for the certificate + * + * @return the Qt SSL key + */ + QSslKey getKey() const; + /** + * @brief Get a new Backend object and log in with the given token + * + * @param token the token to use + * @return the new backend object or an error code + */ + static std::expected getBackend(const TokenData& token); + /** + * @brief Shut down all backends + * + * This should be called when the application is about to exit. It releases all static data held by backend(s) (e.g. PKCS11 library) + */ + static void shutDown(); + + /** + * @brief The status of the last operation + */ + mutable Status status = PinOK; + + /** + * @brief Get a list of all available tokens + * + * @return list of all available tokens + */ + static QList getTokens(); + + static QString errorString(Status error); +protected: + virtual Status login(const TokenData &cert) = 0; + + QSslCertificate cert; }; diff --git a/client/QPKCS11.cpp b/client/QPKCS11.cpp index 296bd84f2..4adf9c0ea 100644 --- a/client/QPKCS11.cpp +++ b/client/QPKCS11.cpp @@ -17,7 +17,8 @@ * */ -#include "QPKCS11_p.h" +#include "QPKCS11.h" +#include "pkcs11.h" #include "Application.h" #include "CryptoDoc.h" @@ -29,6 +30,7 @@ #include #include +#include #include @@ -37,6 +39,7 @@ #include #include +#include template static QString toQString(const Container &c) @@ -44,7 +47,138 @@ static QString toQString(const Container &c) return QString::fromLatin1((const char*)std::data(c), std::size(c)); } -QByteArray QPKCS11::Private::attribute(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE obj, CK_ATTRIBUTE_TYPE type) const +struct QPKCS11Library +{ + explicit QPKCS11Library(const QString &driver); + ~QPKCS11Library(); + + QByteArray attribute(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE obj, CK_ATTRIBUTE_TYPE type) const; + std::vector findObject(CK_SESSION_HANDLE session, CK_OBJECT_CLASS cls, const QByteArray &id = {}) const; + static std::shared_ptr current(); + + QLibrary lib; + CK_FUNCTION_LIST_PTR f {}; + bool isFinDriver = false; +}; + +QPKCS11Library::QPKCS11Library(const QString &driver) + : lib(driver) +{ + qWarning() << "Loading:" << driver; + if(auto l = CK_C_GetFunctionList(lib.resolve("C_GetFunctionList")); + !l || l(&f) != CKR_OK) + { + qWarning() << "Failed to resolve symbols" << lib.errorString(); + return; + } + + CK_C_INITIALIZE_ARGS init_args { nullptr, nullptr, nullptr, nullptr, CKF_OS_LOCKING_OK, nullptr }; + CK_RV err = f->C_Initialize(&init_args); + if(err != CKR_OK && err != CKR_CRYPTOKI_ALREADY_INITIALIZED) + { + qWarning() << "Failed to initalize"; + f = nullptr; + return; + } + + CK_INFO info{}; + f->C_GetInfo(&info); + qWarning() + << QStringLiteral("%1 (%2.%3)").arg(toQString(info.manufacturerID)) + .arg(info.cryptokiVersion.major).arg(info.cryptokiVersion.minor) << '\n' + << QStringLiteral("%1 (%2.%3)").arg(toQString(info.libraryDescription)) + .arg(info.libraryVersion.major).arg(info.libraryVersion.minor) << '\n' + << "Flags:" << info.flags; + isFinDriver = toQString(info.libraryDescription).contains(QLatin1String("MPOLLUX"), Qt::CaseInsensitive); +} + +QPKCS11Library::~QPKCS11Library() +{ + if(f) + f->C_Finalize(nullptr); +} + +static std::shared_ptr loadLibrary(const QString &driver) +{ + static std::mutex loadedMutex; + static std::shared_ptr loaded; + std::lock_guard lock(loadedMutex); + if(loaded && loaded->lib.fileName() == driver) + return loaded; + + auto lib = std::make_shared(driver); + if(!lib->f) + return {}; + loaded = lib; + return lib; +} + +std::shared_ptr QPKCS11Library::current() +{ + static const QMultiHash drivers { +#ifdef Q_OS_MAC + { QApplication::applicationDirPath() + "/opensc-pkcs11.so", {} }, + { "/Library/latvia-eid/lib/eidlv-pkcs11.bundle/Contents/MacOS/eidlv-pkcs11", "3BDB960080B1FE451F830012428F536549440F900020" }, // LV-G2 + { "/Library/latvia-eid/lib/eidlv-pkcs11.bundle/Contents/MacOS/eidlv-pkcs11", "3BDC960080B1FE451F830012428F54654944320F900012" }, // LV-G2.1 + { "/Library/mCard/lib/mcard-pkcs11.so", "3B9D188131FC358031C0694D54434F5373020604D1" }, // LT MaskTech 2.6.4 + { "/Library/mCard/lib/mcard-pkcs11.so", "3B9D188131FC358031C0694D54434F5373020605D0" }, // LT MaskTech 2.6.5 + { "/Library/Atostek ID/Atostek-ID-PKCS11.dylib", "3B7F9600008031B865B08504021B1200F6829000" }, // FI-G3.1 + { "/Library/Atostek ID/Atostek-ID-PKCS11.dylib", "3B7F9600008031B865B085050011122460829000" }, // FI-G4 + { "/Library/Atostek ID/Atostek-ID-PKCS11.dylib", "3B7F9600008031B865B085051024122460829000" }, // FI-G4.1 + { "/Library/mPolluxDigiSign/libcryptoki.dylib", "3B7F9600008031B865B08504021B1200F6829000" }, // FI-G3.1 + { "/Library/mPolluxDigiSign/libcryptoki.dylib", "3B7F9600008031B865B085050011122460829000" }, // FI-G4 + { "/Library/mPolluxDigiSign/libcryptoki.dylib", "3B7F9600008031B865B085051024122460829000" }, // FI-G4.1 + { "/Library/Frameworks/eToken.framework/Versions/Current/libeToken.dylib", "3BD5180081313A7D8073C8211030" }, + { "/Library/Frameworks/eToken.framework/Versions/Current/libeToken.dylib", "3BD518008131FE7D8073C82110F4" }, + { "/Library/Frameworks/eToken.framework/Versions/Current/libeToken.dylib", "3BFF9600008131FE4380318065B0846566FB12017882900085" }, + { "/Library/Frameworks/eToken.framework/Versions/Current/libIDPrimePKCS11.dylib", "3BFF9600008131804380318065B0850300EF120FFE82900066" }, + { "/Library/Frameworks/eToken.framework/Versions/Current/libIDPrimePKCS11.dylib", "3BFF9600008131FE4380318065B0855956FB120FFE82900000" }, +#elif defined(Q_OS_WIN) + { "opensc-pkcs11.dll", {} }, +#else + { "opensc-pkcs11.so", {} }, +#if defined(Q_OS_LINUX) + { "/opt/latvia-eid/lib/eidlv-pkcs11.so", "3BDB960080B1FE451F830012428F536549440F900020" }, // LV-G2 + { "/opt/latvia-eid/lib/eidlv-pkcs11.so", "3BDC960080B1FE451F830012428F54654944320F900012" }, // LV-G2.1 + { "mcard-pkcs11.so", "3B9D188131FC358031C0694D54434F5373020604D1" }, // LT MaskTech 2.6.4 + { "mcard-pkcs11.so", "3B9D188131FC358031C0694D54434F5373020605D0" }, // LT MaskTech 2.6.5 +#if Q_PROCESSOR_WORDSIZE == 8 + { "/usr/lib/Atostek-ID-PKCS11.so", "3B7F9600008031B865B08504021B1200F6829000" }, // FI-G3.1 + { "/usr/lib/Atostek-ID-PKCS11.so", "3B7F9600008031B865B085050011122460829000" }, // FI-G4 + { "/usr/lib/Atostek-ID-PKCS11.so", "3B7F9600008031B865B085051024122460829000" }, // FI-G4.1 + { "/usr/lib64/libcryptoki.so", "3B7F9600008031B865B08504021B1200F6829000" }, // FI-G3.1 + { "/usr/lib64/libcryptoki.so", "3B7F9600008031B865B085050011122460829000" }, // FI-G4 + { "/usr/lib64/libcryptoki.so", "3B7F9600008031B865B085051024122460829000" }, // FI-G4.1 +#else + { "libcryptoki.so", "3B7F9600008031B865B08504021B1200F6829000" }, // FI-G3.1 + { "libcryptoki.so", "3B7F9600008031B865B085050011122460829000" }, // FI-G4 + { "libcryptoki.so", "3B7F9600008031B865B085051024122460829000" }, // FI-G4.1 +#endif + { "/usr/lib/libeTPkcs11.so", "3BD5180081313A7D8073C8211030" }, + { "/usr/lib/libeTPkcs11.so", "3BD518008131FE7D8073C82110F4" }, + { "/usr/lib/libeTPkcs11.so", "3BFF9600008131FE4380318065B0846566FB12017882900085" }, + { "/usr/lib/libIDPrimePKCS11.so", "3BFF9600008131804380318065B0850300EF120FFE82900066" }, + { "/usr/lib/libIDPrimePKCS11.so", "3BFF9600008131FE4380318065B0855956FB120FFE82900000" }, +#endif +#endif + }; + for(const QString &reader: QPCSC::instance().readers()) + { + QPCSCReader r(reader, &QPCSC::instance()); + if(!r.isPresent()) + continue; + QByteArray atr = r.atr(); + for(auto i = drivers.cbegin(); i != drivers.cend(); ++i) { + if(i.value() == atr) { + if(auto lib = loadLibrary(i.key())) + return lib; + } + } + } + return loadLibrary(drivers.key({})); +} + +QByteArray QPKCS11Library::attribute(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE obj, CK_ATTRIBUTE_TYPE type) const { QByteArray data; CK_ATTRIBUTE attr { type, nullptr, 0 }; @@ -57,7 +191,7 @@ QByteArray QPKCS11::Private::attribute(CK_SESSION_HANDLE session, CK_OBJECT_HAND return data; } -std::vector QPKCS11::Private::findObject(CK_SESSION_HANDLE session, CK_OBJECT_CLASS cls, const QByteArray &id) const +std::vector QPKCS11Library::findObject(CK_SESSION_HANDLE session, CK_OBJECT_CLASS cls, const QByteArray &id) const { std::vector result; if(!f) @@ -83,47 +217,73 @@ std::vector QPKCS11::Private::findObject(CK_SESSION_HANDLE ses } +struct QPKCS11::Private +{ + void closeSession() + { + id.clear(); + if(l && l->f && session) { + l->f->C_Logout(session); + l->f->C_CloseSession(session); + } + session = 0; + } + + std::shared_ptr l; + CK_SESSION_HANDLE session = 0; + QByteArray id; + bool isPSS = false; +}; -QPKCS11::QPKCS11( QObject *parent ) - : QCryptoBackend(parent) - , d(new Private) +QPKCS11::QPKCS11() + : QCryptoBackend() + , d(std::make_unique()) { } -QPKCS11::~QPKCS11() +QPKCS11::~QPKCS11() noexcept { - unload(); - delete d; + d->closeSession(); } QByteArray QPKCS11::decrypt(const QByteArray &data, bool oaep) const { - std::vector key = d->findObject(d->session, CKO_PRIVATE_KEY, d->id); - if(key.size() != 1) + auto key = d->l->findObject(d->session, CKO_PRIVATE_KEY, d->id); + if(key.size() != 1){ + status = GeneralError; return {}; + } CK_RSA_PKCS_OAEP_PARAMS params { CKM_SHA256, CKG_MGF1_SHA256, 0, nullptr, 0 }; auto mech = oaep ? CK_MECHANISM{ CKM_RSA_PKCS_OAEP, ¶ms, sizeof(params) } : CK_MECHANISM{ CKM_RSA_PKCS, nullptr, 0 }; - if(d->f->C_DecryptInit(d->session, &mech, key.front()) != CKR_OK) + if(d->l->f->C_DecryptInit(d->session, &mech, key.front()) != CKR_OK) { + status = GeneralError; return {}; + } CK_ULONG size = 0; - if(d->f->C_Decrypt(d->session, CK_BYTE_PTR(data.constData()), CK_ULONG(data.size()), nullptr, &size) != CKR_OK) + if(d->l->f->C_Decrypt(d->session, CK_BYTE_PTR(data.constData()), CK_ULONG(data.size()), nullptr, &size) != CKR_OK) { + status = GeneralError; return {}; - + } QByteArray result(int(size), 0); - if(d->f->C_Decrypt(d->session, CK_BYTE_PTR(data.constData()), CK_ULONG(data.size()), CK_BYTE_PTR(result.data()), &size) != CKR_OK) + if(d->l->f->C_Decrypt(d->session, CK_BYTE_PTR(data.constData()), CK_ULONG(data.size()), CK_BYTE_PTR(result.data()), &size) != CKR_OK) { + status = GeneralError; return {}; + } + return result; } QByteArray QPKCS11::derive(const QByteArray &publicKey) const { - std::vector key = d->findObject(d->session, CKO_PRIVATE_KEY, d->id); - if(key.size() != 1) + std::vector key = d->l->findObject(d->session, CKO_PRIVATE_KEY, d->id); + if(key.size() != 1) { + status = GeneralError; return {}; + } CK_ECDH1_DERIVE_PARAMS ecdh_parms { CKD_NULL, 0, nullptr, CK_ULONG(publicKey.size()), CK_BYTE_PTR(publicKey.data()) }; CK_MECHANISM mech { CKM_ECDH1_DERIVE, &ecdh_parms, sizeof(CK_ECDH1_DERIVE_PARAMS) }; @@ -141,10 +301,12 @@ QByteArray QPKCS11::derive(const QByteArray &publicKey) const {CKA_VALUE_LEN, &value_len, sizeof(value_len)}, }); CK_OBJECT_HANDLE newkey = CK_INVALID_HANDLE; - if(d->f->C_DeriveKey(d->session, &mech, key.front(), newkey_template.data(), CK_ULONG(newkey_template.size()), &newkey) != CKR_OK) + if(d->l->f->C_DeriveKey(d->session, &mech, key.front(), newkey_template.data(), CK_ULONG(newkey_template.size()), &newkey) != CKR_OK) { + status = GeneralError; return {}; + } - return d->attribute(d->session, newkey, CKA_VALUE); + return d->l->attribute(d->session, newkey, CKA_VALUE); } QByteArray QPKCS11::deriveConcatKDF(const QByteArray &publicKey, QCryptographicHash::Algorithm digest, @@ -179,12 +341,13 @@ QByteArray QPKCS11::deriveHMACExtract(const QByteArray &publicKey, const QByteAr auto ctx = libcdoc::make_unique_ptr(EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr)); QByteArray out(keySize, 0); auto outlen = size_t(out.length()); - auto isError = [](int err) { + auto isError = [this](int err) { if(err < 1) { unsigned long errorCode = 0; while((errorCode = ERR_get_error())) qCWarning(CRYPTO) << ERR_error_string(errorCode, nullptr); + status = GeneralError; } return err < 1; }; @@ -199,64 +362,30 @@ QByteArray QPKCS11::deriveHMACExtract(const QByteArray &publicKey, const QByteAr return out; } -bool QPKCS11::isLoaded() const -{ - return d->f != nullptr; -} - -bool QPKCS11::load( const QString &driver ) +QPKCS11::Status QPKCS11::login(const TokenData &t) { - if(d->lib.fileName() == driver && isLoaded()) - return true; - qWarning() << "Loading:" << driver; - unload(); - d->lib.setFileName( driver ); - if(auto l = CK_C_GetFunctionList(d->lib.resolve("C_GetFunctionList")); - !l || l(&d->f) != CKR_OK) - { - qWarning() << "Failed to resolve symbols" << d->lib.errorString(); - return false; + if(!d->l) { + d->l = QPKCS11Library::current(); } + if(!d->l || !d->l->f) + return UnknownError; - CK_C_INITIALIZE_ARGS init_args { nullptr, nullptr, nullptr, nullptr, CKF_OS_LOCKING_OK, nullptr }; - CK_RV err = d->f->C_Initialize( &init_args ); - if( err != CKR_OK && err != CKR_CRYPTOKI_ALREADY_INITIALIZED ) - { - qWarning() << "Failed to initalize"; - return false; - } - - CK_INFO info{}; - d->f->C_GetInfo( &info ); - qWarning() - << QStringLiteral("%1 (%2.%3)").arg(toQString(info.manufacturerID)) - .arg(info.cryptokiVersion.major).arg(info.cryptokiVersion.minor) << '\n' - << QStringLiteral("%1 (%2.%3)").arg(toQString(info.libraryDescription)) - .arg(info.libraryVersion.major).arg(info.libraryVersion.minor) << '\n' - << "Flags:" << info.flags; - d->isFinDriver = toQString(info.libraryDescription).contains(QLatin1String("MPOLLUX"), Qt::CaseInsensitive); - return true; -} - -QPKCS11::PinStatus QPKCS11::login(const TokenData &t) -{ - logout(); - + d->closeSession(); auto currentSlot = t.data(QStringLiteral("slot")).value(); d->id = t.data(QStringLiteral("id")).toByteArray(); d->isPSS = t.data(QStringLiteral("PSS")).toBool(); CK_TOKEN_INFO token; - if(d->f->C_GetTokenInfo(currentSlot, &token) != CKR_OK || - d->f->C_OpenSession(currentSlot, CKF_SERIAL_SESSION, nullptr, nullptr, &d->session) != CKR_OK) + if(d->l->f->C_GetTokenInfo(currentSlot, &token) != CKR_OK || + d->l->f->C_OpenSession(currentSlot, CKF_SERIAL_SESSION, nullptr, nullptr, &d->session) != CKR_OK) return UnknownError; - std::vector list = d->findObject(d->session, CKO_CERTIFICATE, d->id); - if(list.size() != 1 || QSslCertificate(d->attribute(d->session, list.front(), CKA_VALUE), QSsl::Der) != t.cert()) + std::vector list = d->l->findObject(d->session, CKO_CERTIFICATE, d->id); + if(list.size() != 1 || QSslCertificate(d->l->attribute(d->session, list.front(), CKA_VALUE), QSsl::Der) != t.cert()) return UnknownError; // Hack: Workaround broken FIN pkcs11 drivers not providing CKF_LOGIN_REQUIRED info - if(!d->isFinDriver && !(token.flags & CKF_LOGIN_REQUIRED)) + if(!d->l->isFinDriver && !(token.flags & CKF_LOGIN_REQUIRED)) return PinOK; SslCertificate cert(t.cert()); @@ -271,48 +400,44 @@ QPKCS11::PinStatus QPKCS11::login(const TokenData &t) PinPopup p(isSign ? QSmartCardData::Pin2Type : QSmartCardData::Pin1Type, f, cert, Application::mainWindow()); p.open(); p.startTimer(); - return waitFor(d->f->C_Login, d->session, CKU_USER, nullptr, 0); + return waitFor(d->l->f->C_Login, d->session, CKU_USER, nullptr, 0); } else { PinPopup p(isSign ? QSmartCardData::Pin2Type : QSmartCardData::Pin1Type, f, cert, Application::mainWindow()); p.setPinLen(token.ulMinPinLen, token.ulMaxPinLen < 12 ? 12 : token.ulMaxPinLen); if(!p.exec()) return CKR_FUNCTION_CANCELED; QByteArray pin = p.pin().toUtf8(); - return d->f->C_Login(d->session, CKU_USER, CK_UTF8CHAR_PTR(pin.constData()), CK_ULONG(pin.size())); + return d->l->f->C_Login(d->session, CKU_USER, CK_UTF8CHAR_PTR(pin.constData()), CK_ULONG(pin.size())); } }); - switch( err ) + switch(err) { case CKR_OK: - case CKR_USER_ALREADY_LOGGED_IN: return PinOK; + case CKR_USER_ALREADY_LOGGED_IN: + return PinOK; case CKR_CANCEL: - case CKR_FUNCTION_CANCELED: return PinCanceled; + case CKR_FUNCTION_CANCELED: + return PinCanceled; case CKR_PIN_INCORRECT: - d->f->C_GetTokenInfo(currentSlot, &token); + d->l->f->C_GetTokenInfo(currentSlot, &token); return (token.flags & CKF_USER_PIN_LOCKED) ? PinLocked : PinIncorrect; - case CKR_PIN_LOCKED: return PinLocked; - case CKR_DEVICE_ERROR: return DeviceError; - case CKR_GENERAL_ERROR: return GeneralError; - default: return UnknownError; - } -} - -void QPKCS11::logout() -{ - d->id.clear(); - if( d->f && d->session ) - { - d->f->C_Logout( d->session ); - d->f->C_CloseSession( d->session ); + case CKR_PIN_LOCKED: + return PinLocked; + case CKR_DEVICE_ERROR: + return DeviceError; + case CKR_GENERAL_ERROR: + return GeneralError; + default: + return UnknownError; } - d->session = 0; } -QList QPKCS11::tokens() const +QList QPKCS11::tokens() { QList list; - if(!d->f) + auto d = QPKCS11Library::current(); + if(!d || !d->f) return list; size_t size = 0; if(d->f->C_GetSlotList(CK_TRUE, nullptr, CK_ULONG_PTR(&size)) != CKR_OK) @@ -367,78 +492,17 @@ QList QPKCS11::tokens() const return list; } -bool QPKCS11::reload() -{ - static const QMultiHash drivers { -#ifdef Q_OS_MAC - { QApplication::applicationDirPath() + "/opensc-pkcs11.so", {} }, - { "/Library/latvia-eid/lib/eidlv-pkcs11.bundle/Contents/MacOS/eidlv-pkcs11", "3BDB960080B1FE451F830012428F536549440F900020" }, // LV-G2 - { "/Library/latvia-eid/lib/eidlv-pkcs11.bundle/Contents/MacOS/eidlv-pkcs11", "3BDC960080B1FE451F830012428F54654944320F900012" }, // LV-G2.1 - { "/Library/mCard/lib/mcard-pkcs11.so", "3B9D188131FC358031C0694D54434F5373020604D1" }, // LT MaskTech 2.6.4 - { "/Library/mCard/lib/mcard-pkcs11.so", "3B9D188131FC358031C0694D54434F5373020605D0" }, // LT MaskTech 2.6.5 - { "/Library/Atostek ID/Atostek-ID-PKCS11.dylib", "3B7F9600008031B865B08504021B1200F6829000" }, // FI-G3.1 - { "/Library/Atostek ID/Atostek-ID-PKCS11.dylib", "3B7F9600008031B865B085050011122460829000" }, // FI-G4 - { "/Library/Atostek ID/Atostek-ID-PKCS11.dylib", "3B7F9600008031B865B085051024122460829000" }, // FI-G4.1 - { "/Library/mPolluxDigiSign/libcryptoki.dylib", "3B7F9600008031B865B08504021B1200F6829000" }, // FI-G3.1 - { "/Library/mPolluxDigiSign/libcryptoki.dylib", "3B7F9600008031B865B085050011122460829000" }, // FI-G4 - { "/Library/mPolluxDigiSign/libcryptoki.dylib", "3B7F9600008031B865B085051024122460829000" }, // FI-G4.1 - { "/Library/Frameworks/eToken.framework/Versions/Current/libeToken.dylib", "3BD5180081313A7D8073C8211030" }, - { "/Library/Frameworks/eToken.framework/Versions/Current/libeToken.dylib", "3BD518008131FE7D8073C82110F4" }, - { "/Library/Frameworks/eToken.framework/Versions/Current/libeToken.dylib", "3BFF9600008131FE4380318065B0846566FB12017882900085" }, - { "/Library/Frameworks/eToken.framework/Versions/Current/libIDPrimePKCS11.dylib", "3BFF9600008131804380318065B0850300EF120FFE82900066" }, - { "/Library/Frameworks/eToken.framework/Versions/Current/libIDPrimePKCS11.dylib", "3BFF9600008131FE4380318065B0855956FB120FFE82900000" }, -#elif defined(Q_OS_WIN) - { "opensc-pkcs11.dll", {} }, -#else - { "opensc-pkcs11.so", {} }, -#if defined(Q_OS_LINUX) - { "/opt/latvia-eid/lib/eidlv-pkcs11.so", "3BDB960080B1FE451F830012428F536549440F900020" }, // LV-G2 - { "/opt/latvia-eid/lib/eidlv-pkcs11.so", "3BDC960080B1FE451F830012428F54654944320F900012" }, // LV-G2.1 - { "mcard-pkcs11.so", "3B9D188131FC358031C0694D54434F5373020604D1" }, // LT MaskTech 2.6.4 - { "mcard-pkcs11.so", "3B9D188131FC358031C0694D54434F5373020605D0" }, // LT MaskTech 2.6.5 -#if Q_PROCESSOR_WORDSIZE == 8 - { "/usr/lib/Atostek-ID-PKCS11.so", "3B7F9600008031B865B08504021B1200F6829000" }, // FI-G3.1 - { "/usr/lib/Atostek-ID-PKCS11.so", "3B7F9600008031B865B085050011122460829000" }, // FI-G4 - { "/usr/lib/Atostek-ID-PKCS11.so", "3B7F9600008031B865B085051024122460829000" }, // FI-G4.1 - { "/usr/lib64/libcryptoki.so", "3B7F9600008031B865B08504021B1200F6829000" }, // FI-G3.1 - { "/usr/lib64/libcryptoki.so", "3B7F9600008031B865B085050011122460829000" }, // FI-G4 - { "/usr/lib64/libcryptoki.so", "3B7F9600008031B865B085051024122460829000" }, // FI-G4.1 -#else - { "libcryptoki.so", "3B7F9600008031B865B08504021B1200F6829000" }, // FI-G3.1 - { "libcryptoki.so", "3B7F9600008031B865B085050011122460829000" }, // FI-G4 - { "libcryptoki.so", "3B7F9600008031B865B085051024122460829000" }, // FI-G4.1 -#endif - { "/usr/lib/libeTPkcs11.so", "3BD5180081313A7D8073C8211030" }, - { "/usr/lib/libeTPkcs11.so", "3BD518008131FE7D8073C82110F4" }, - { "/usr/lib/libeTPkcs11.so", "3BFF9600008131FE4380318065B0846566FB12017882900085" }, - { "/usr/lib/libIDPrimePKCS11.so", "3BFF9600008131804380318065B0850300EF120FFE82900066" }, - { "/usr/lib/libIDPrimePKCS11.so", "3BFF9600008131FE4380318065B0855956FB120FFE82900000" }, -#endif -#endif - }; - for(const QString &reader: QPCSC::instance().readers()) - { - QPCSCReader r(reader, &QPCSC::instance()); - if(!r.isPresent()) - continue; - QByteArray atr = r.atr(); - for(auto i = drivers.cbegin(); i != drivers.cend(); ++i) { - if(i.value() == atr && load(i.key())) - return true; - } - } - return load(drivers.key({})); -} - QByteArray QPKCS11::sign(QCryptographicHash::Algorithm type, const QByteArray &digest) const { - std::vector key = d->findObject(d->session, CKO_PRIVATE_KEY, d->id); - if(key.size() != 1) + std::vector key = d->l->findObject(d->session, CKO_PRIVATE_KEY, d->id); + if(key.size() != 1) { + status = GeneralError; return {}; + } CK_KEY_TYPE keyType = CKK_RSA; CK_ATTRIBUTE attribute { CKA_KEY_TYPE, &keyType, sizeof(keyType) }; - d->f->C_GetAttributeValue(d->session, key.front(), &attribute, 1); + d->l->f->C_GetAttributeValue(d->session, key.front(), &attribute, 1); CK_RSA_PKCS_PSS_PARAMS pssParams { CKM_SHA256, CKG_MGF1_SHA256, 32 }; CK_MECHANISM mech { keyType == CKK_ECDSA ? CKM_ECDSA : CKM_RSA_PKCS, nullptr, 0 }; @@ -473,22 +537,19 @@ QByteArray QPKCS11::sign(QCryptographicHash::Algorithm type, const QByteArray &d } data.append(digest); - if(d->f->C_SignInit(d->session, &mech, key.front()) != CKR_OK) + if(d->l->f->C_SignInit(d->session, &mech, key.front()) != CKR_OK) { + status = GeneralError; return {}; + } CK_ULONG size = 0; - if(d->f->C_Sign(d->session, CK_BYTE_PTR(data.constData()), CK_ULONG(data.size()), nullptr, &size) != CKR_OK) + if(d->l->f->C_Sign(d->session, CK_BYTE_PTR(data.constData()), CK_ULONG(data.size()), nullptr, &size) != CKR_OK) { + status = GeneralError; return {}; + } QByteArray sig(int(size), 0); - if(d->f->C_Sign(d->session, CK_BYTE_PTR(data.constData()), CK_ULONG(data.size()), CK_BYTE_PTR(sig.data()), &size) != CKR_OK) + if(d->l->f->C_Sign(d->session, CK_BYTE_PTR(data.constData()), CK_ULONG(data.size()), CK_BYTE_PTR(sig.data()), &size) != CKR_OK) { + status = GeneralError; return {}; + } return sig; } - -void QPKCS11::unload() -{ - logout(); - if(d->f) - d->f->C_Finalize(nullptr); - d->f = nullptr; - d->lib.unload(); -} diff --git a/client/QPKCS11.h b/client/QPKCS11.h index f9310f3bd..c01994018 100644 --- a/client/QPKCS11.h +++ b/client/QPKCS11.h @@ -21,27 +21,26 @@ #include "QCryptoBackend.h" +#include + class QPKCS11 final: public QCryptoBackend { - Q_OBJECT public: - explicit QPKCS11(QObject *parent = nullptr); - ~QPKCS11() final; + explicit QPKCS11(); + ~QPKCS11() noexcept final; QByteArray decrypt(const QByteArray &data, bool oaep) const final; QByteArray derive(const QByteArray &publicKey) const; QByteArray deriveConcatKDF(const QByteArray &publicKey, QCryptographicHash::Algorithm digest, const QByteArray &algorithmID, const QByteArray &partyUInfo, const QByteArray &partyVInfo) const final; QByteArray deriveHMACExtract(const QByteArray &publicKey, const QByteArray &salt, int keySize) const final; - bool isLoaded() const; - bool load( const QString &driver ); - void unload(); - PinStatus login(const TokenData &t) final; - void logout() final; - bool reload(); QByteArray sign(QCryptographicHash::Algorithm type, const QByteArray &digest) const final; - QList tokens() const final; + + Status login(const TokenData &t) final; + + static QList tokens(); + private: struct Private; - Private *d; + std::unique_ptr d; }; diff --git a/client/QPKCS11_p.h b/client/QPKCS11_p.h deleted file mode 100644 index f95870c94..000000000 --- a/client/QPKCS11_p.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * QDigiDoc4 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#pragma once - -#include "QPKCS11.h" - -#include "pkcs11.h" - -#include - -#include - -struct QPKCS11::Private -{ - QByteArray attribute( CK_SESSION_HANDLE session, CK_OBJECT_HANDLE obj, CK_ATTRIBUTE_TYPE type ) const; - std::vector findObject(CK_SESSION_HANDLE session, CK_OBJECT_CLASS cls, const QByteArray &id = {}) const; - - QLibrary lib; - CK_FUNCTION_LIST_PTR f = nullptr; - bool isFinDriver = false; - CK_SESSION_HANDLE session = 0; - QByteArray id; - bool isPSS = false; -}; diff --git a/client/QSigner.cpp b/client/QSigner.cpp index e8328e74a..ee960d727 100644 --- a/client/QSigner.cpp +++ b/client/QSigner.cpp @@ -49,77 +49,20 @@ static Q_LOGGING_CATEGORY(SLog, "qdigidoc4.QSigner") class QSigner::Private final { public: - QCryptoBackend *backend {}; QSmartCard *smartcard {}; TokenData auth, sign; QList cache; QReadWriteLock lock; QMutex sleepMutex; QWaitCondition sleepCond; - - static ECDSA_SIG* ecdsa_do_sign(const unsigned char *dgst, int dgst_len, - const BIGNUM *inv, const BIGNUM *rp, EC_KEY *eckey); - static int rsa_sign(int type, const unsigned char *m, unsigned int m_len, - unsigned char *sigret, unsigned int *siglen, const RSA *rsa); - - RSA_METHOD *rsamethod = RSA_meth_dup(RSA_get_default_method()); - EC_KEY_METHOD *ecmethod = EC_KEY_METHOD_new(EC_KEY_get_default_method()); }; -ECDSA_SIG* QSigner::Private::ecdsa_do_sign(const unsigned char *dgst, int dgst_len, - const BIGNUM * /*inv*/, const BIGNUM * /*rp*/, EC_KEY *eckey) -{ - auto *backend = (QCryptoBackend*)EC_KEY_get_ex_data(eckey, 0); - QByteArray result = backend->sign(QCryptographicHash::Sha512, QByteArray::fromRawData((const char*)dgst, dgst_len)); - if(result.isEmpty()) - return nullptr; - QByteArray r = result.left(result.size()/2); - QByteArray s = result.right(result.size()/2); - ECDSA_SIG *sig = ECDSA_SIG_new(); - ECDSA_SIG_set0(sig, - BN_bin2bn((const unsigned char*)r.data(), int(r.size()), nullptr), - BN_bin2bn((const unsigned char*)s.data(), int(s.size()), nullptr)); - return sig; -} - -int QSigner::Private::rsa_sign(int type, const unsigned char *m, unsigned int m_len, - unsigned char *sigret, unsigned int *siglen, const RSA *rsa) -{ - auto *backend = (QCryptoBackend*)RSA_get_ex_data(rsa, 0); - QCryptographicHash::Algorithm algo = QCryptographicHash::Sha256; - switch(type) - { - case NID_sha224: algo = QCryptographicHash::Sha224; break; - case NID_sha256: algo = QCryptographicHash::Sha256; break; - case NID_sha384: algo = QCryptographicHash::Sha384; break; - case NID_sha512: algo = QCryptographicHash::Sha512; break; - } - QByteArray result = backend->sign(algo, QByteArray::fromRawData((const char*)m, int(m_len))); - if(result.isEmpty()) - return 0; - *siglen = (unsigned int)result.size(); - memcpy(sigret, result.constData(), size_t(result.size())); - return 1; -} - - - using namespace digidoc; QSigner::QSigner(QObject *parent) : QThread(parent) , d(new Private) { - RSA_meth_set1_name(d->rsamethod, "QSmartCard"); - RSA_meth_set_sign(d->rsamethod, Private::rsa_sign); - using EC_KEY_sign = int (*)(int type, const unsigned char *dgst, int dlen, unsigned char *sig, - unsigned int *siglen, const BIGNUM *kinv, const BIGNUM *r, EC_KEY *eckey); - using EC_KEY_sign_setup = int (*)(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp); - EC_KEY_sign sign = nullptr; - EC_KEY_sign_setup sign_setup = nullptr; - EC_KEY_METHOD_get_sign(d->ecmethod, &sign, &sign_setup, nullptr); - EC_KEY_METHOD_set_sign(d->ecmethod, sign, sign_setup, Private::ecdsa_do_sign); - d->smartcard = new QSmartCard(parent); connect(this, &QSigner::error, this, [](const QString &title, const QString &msg) { WarningDialog::create() @@ -156,8 +99,6 @@ QSigner::~QSigner() d->sleepCond.wakeAll(); wait(); delete d->smartcard; - RSA_meth_free(d->rsamethod); - EC_KEY_METHOD_free(d->ecmethod); delete d; } @@ -171,113 +112,6 @@ X509Cert QSigner::cert() const return X509Cert((const unsigned char*)der.constData(), size_t(der.size()), X509Cert::Der); } -QByteArray QSigner::decrypt(std::function &&func, QCryptoBackend::PinStatus& pin_status) -{ - if(!d->lock.tryLockForWrite(10 * 1000)) - { - Q_EMIT error(tr("Failed to decrypt document"), tr("Signing/decrypting is already in progress another window.")); - pin_status = QCryptoBackend::GeneralError; - return {}; - } - - if( d->auth.cert().isNull() ) - { - Q_EMIT error(tr("Failed to decrypt document"), tr("Authentication certificate is not selected.")); - d->lock.unlock(); - pin_status = QCryptoBackend::GeneralError; - return {}; - } - - switch(pin_status = QCryptoBackend::PinStatus(login(d->auth))) - { - case QCryptoBackend::PinOK: break; - case QCryptoBackend::PinCanceled: return {}; - case QCryptoBackend::PinLocked: - Q_EMIT error(tr("Failed to decrypt document"), QCryptoBackend::errorString(pin_status)); - return {}; - default: - Q_EMIT error(tr("Failed to decrypt document"), tr("Failed to login token") + ' ' + QCryptoBackend::errorString(pin_status)); - return {}; - } - QByteArray result = waitFor(func, d->backend); - logout(); - if(d->backend->lastError() == QCryptoBackend::PinCanceled) { - pin_status = QCryptoBackend::PinCanceled; - return {}; - } - - if(result.isEmpty()) - Q_EMIT error(tr("Failed to decrypt document"), {}); - return result; -} - -QSslKey QSigner::key(QCryptoBackend::PinStatus& pin_status) -{ - QSslKey key = d->auth.cert().publicKey(); - if(!key.handle()) { - pin_status = QCryptoBackend::GeneralError; - return {}; - } - if(!d->lock.tryLockForWrite(10 * 1000)) { - Q_EMIT error(tr("Failed to decrypt document"), tr("Signing/decrypting is already in progress another window.")); - pin_status = QCryptoBackend::GeneralError; - return {}; - } - switch(pin_status = QCryptoBackend::PinStatus(login(d->auth))) - { - case QCryptoBackend::PinOK: break; - case QCryptoBackend::PinCanceled: return {}; - case QCryptoBackend::PinLocked: - Q_EMIT error(tr("Failed to decrypt document"), QCryptoBackend::errorString(pin_status)); - return {}; - default: - Q_EMIT error(tr("Failed to decrypt document"), tr("Failed to login token") + ' ' + QCryptoBackend::errorString(pin_status)); - return {}; - } - if(key.algorithm() == QSsl::Ec) - { - auto *ec = (EC_KEY*)key.handle(); - EC_KEY_set_method(ec, d->ecmethod); - EC_KEY_set_ex_data(ec, 0, d->backend); - } - else - { - RSA *rsa = (RSA*)key.handle(); - RSA_set_method(rsa, d->rsamethod); - RSA_set_ex_data(rsa, 0, d->backend); - } - return key; -} - -quint8 QSigner::login(const TokenData &token) const -{ - switch(auto status = d->backend->login(token)) - { - case QCryptoBackend::PinOK: return status; - case QCryptoBackend::PinIncorrect: - dispatchToMain([&]{ - WarningDialog::create() - ->withTitle(SslCertificate(token.cert()).keyUsage().contains(SslCertificate::NonRepudiation) ? tr("Failed to sign document") : tr("Failed to decrypt document")) - ->withText(QCryptoBackend::errorString(status)) - ->exec(); - }); - return login(token); - default: - d->lock.unlock(); - // QSmartCard should also know that PIN is blocked. - d->smartcard->reloadCard(d->smartcard->tokenData(), true); - return status; - } -} - -void QSigner::logout() const -{ - d->backend->logout(); - d->lock.unlock(); - // QSmartCard should also know that PIN1 info is updated - d->smartcard->reloadCard(d->smartcard->tokenData(), true); -} - QCryptographicHash::Algorithm QSigner::methodToNID(const std::string &method) { if(method == "http://www.w3.org/2001/04/xmldsig-more#sha224" || @@ -303,25 +137,11 @@ void QSigner::run() { d->auth.clear(); d->sign.clear(); -#ifdef Q_OS_WIN - d->backend = new QCNG(this); -#else - d->backend = new QPKCS11(this); -#endif - - while(!isInterruptionRequested()) - { - if(d->lock.tryLockForRead()) - { - auto *pkcs11 = qobject_cast(d->backend); - if(pkcs11 && !pkcs11->reload()) - { - Q_EMIT error(tr("Failed to load PKCS#11 module"), {}); - return; - } + while(!isInterruptionRequested()) { + if(d->lock.tryLockForRead()) { QList acards, scards; - QList cache = d->backend->tokens(); + QList cache = QCryptoBackend::getTokens(); if(cache != d->cache) { d->cache = std::move(cache); @@ -374,6 +194,7 @@ void QSigner::run() break; d->sleepCond.wait(&d->sleepMutex, 5000); } + QCryptoBackend::shutDown(); } void QSigner::selectCard(const TokenData &token) @@ -415,24 +236,38 @@ std::vector QSigner::sign(const std::string &method, const std::v throwException(tr("Signing certificate is not selected."), Exception::General) } - switch(auto status = QCryptoBackend::PinStatus(login(d->sign))) - { - case QCryptoBackend::PinOK: break; - case QCryptoBackend::PinCanceled: - throwException((tr("Failed to login token") + ' ' + QCryptoBackend::errorString(status)), Exception::PINCanceled); - case QCryptoBackend::PinLocked: - throwException((tr("Failed to login token") + ' ' + QCryptoBackend::errorString(status)), Exception::PINLocked); - default: - throwException((tr("Failed to login token") + ' ' + QCryptoBackend::errorString(status)), Exception::PINFailed); + auto unlock = qScopeGuard([this] { + d->lock.unlock(); + // QSmartCard should also know that PIN2 info is updated + d->smartcard->reloadCard(d->smartcard->tokenData(), true); + }); + + auto val = QCryptoBackend::getBackend(d->sign); + if (!val) { + switch(val.error()) { + case QCryptoBackend::PinCanceled: + throwException((tr("Failed to login token") + ' ' + QCryptoBackend::errorString(val.error())), Exception::PINCanceled); + case QCryptoBackend::PinLocked: + throwException((tr("Failed to login token") + ' ' + QCryptoBackend::errorString(val.error())), Exception::PINLocked); + default: + throwException((tr("Failed to login token") + ' ' + QCryptoBackend::errorString(val.error())), Exception::PINFailed); + } } - QByteArray sig = waitFor(&QCryptoBackend::sign, d->backend, - methodToNID(method), QByteArray::fromRawData((const char*)digest.data(), int(digest.size()))); - logout(); - if(d->backend->lastError() == QCryptoBackend::PinCanceled) - throwException(tr("Failed to login token"), Exception::PINCanceled) + std::unique_ptr backend(val.value()); - if( sig.isEmpty() ) + QByteArray sig = waitFor(&QCryptoBackend::sign, backend.get(), + methodToNID(method), QByteArray::fromRawData((const char*)digest.data(), int(digest.size()))); + if (sig.isEmpty()) { + switch(backend->status) { + case QCryptoBackend::PinCanceled: + throwException((tr("Failed to login token") + ' ' + QCryptoBackend::errorString(backend->status)), Exception::PINCanceled); + case QCryptoBackend::PinLocked: + throwException((tr("Failed to login token") + ' ' + QCryptoBackend::errorString(backend->status)), Exception::PINLocked) + default: + break; + } throwException(tr("Failed to sign document"), Exception::General) + } return {sig.constBegin(), sig.constEnd()}; } @@ -443,6 +278,5 @@ TokenData QSigner::tokensign() const { return d->sign; } QString QSigner::getLastErrorStr() const { - QCryptoBackend::PinStatus status = d->backend->lastError(); - return d->backend->errorString(status); + return "Backend error"; } diff --git a/client/QSigner.h b/client/QSigner.h index 286320631..8a08150ea 100644 --- a/client/QSigner.h +++ b/client/QSigner.h @@ -41,9 +41,6 @@ class QSigner final: public QThread, public digidoc::Signer QList cache() const; digidoc::X509Cert cert() const final; - QByteArray decrypt(std::function &&func, QCryptoBackend::PinStatus& pin_status); - QSslKey key(QCryptoBackend::PinStatus& pin_status); - void logout() const; void selectCard(const TokenData &token); std::vector sign( const std::string &method, const std::vector &digest) const final; @@ -59,7 +56,6 @@ class QSigner final: public QThread, public digidoc::Signer void error(const QString &title, const QString &text); private: - quint8 login(const TokenData &token) const; static QCryptographicHash::Algorithm methodToNID(const std::string &method); void run() final; diff --git a/client/Settings.cpp b/client/Settings.cpp index f0ed78eef..7952cd169 100644 --- a/client/Settings.cpp +++ b/client/Settings.cpp @@ -30,6 +30,7 @@ using Option = Settings::Option; const Option Settings::CDOC2_DEFAULT { QStringLiteral("CDOC2-DEFAULT"), [] { return Application::confValue(QLatin1String("CDOC2-DEFAULT")).toBool(false); }}; +// TODO: Remove this after 2 releases const Option Settings::CDOC2_NOTIFICATION { QStringLiteral("CDOC2-NOTIFICATION"), false }; const Option Settings::CDOC2_USE_KEYSERVER { QStringLiteral("CDOC2-USE-KEYSERVER"), [] { return Application::confValue(QLatin1String("CDOC2-USE-KEYSERVER")).toBool(true); diff --git a/client/Settings.h b/client/Settings.h index d55a03695..b5d0af5dc 100644 --- a/client/Settings.h +++ b/client/Settings.h @@ -75,6 +75,7 @@ struct Settings }; static const Option CDOC2_DEFAULT; + // TODO: Remove this after 2 releases static const Option CDOC2_NOTIFICATION; static const Option CDOC2_USE_KEYSERVER; static const Option CDOC2_DEFAULT_KEYSERVER; diff --git a/client/translations/en.ts b/client/translations/en.ts index db28da8f2..2ca78bfd5 100644 --- a/client/translations/en.ts +++ b/client/translations/en.ts @@ -489,14 +489,6 @@ Decrypting Decrypting - - You are about to delete the last file in the container - You are about to delete the last file in the container - - - It is removed along with the container. - It is removed along with the container. - In order to view Validity Confirmation Sheet there has to be at least one printer installed! In order to view Validity Confirmation Sheet there has to be at least one printer installed! @@ -576,14 +568,6 @@ Failed to add key Failed to add key - - You must enter your PIN code twice in order to decrypt the CDOC2 container - You must enter your PIN code twice in order to decrypt the CDOC2 container - - - The first PIN entry is required for authentication to the key server referenced in the CDOC2 container. Second PIN entry is required to decrypt the CDOC2 container. - The first PIN entry is required for authentication to the key server referenced in the CDOC2 container. Second PIN entry is required to decrypt the CDOC2 container. - Please check your internet connection and network settings. Please check your internet connection and network settings. @@ -600,10 +584,6 @@ Failed to open document Failed to open document - - Don't show again - Don't show again - Wrong password. Wrong password. @@ -2120,18 +2100,10 @@ ID-Card QCryptoBackend - - PIN Canceled - PIN Canceled - PIN locked PIN locked - - PIN Incorrect - PIN Incorrect - PKCS11 general error PKCS11 general error @@ -2144,6 +2116,14 @@ ID-Card Unknown error Unknown error + + PIN incorrect + PIN Incorrect + + + PIN entry canceled + PIN entry canceled + QFileDialog @@ -2154,10 +2134,6 @@ ID-Card QSigner - - Failed to load PKCS#11 module - Failed to load PKCS#11 module - Signing certificate is not selected. Signing certificate is not selected. @@ -2178,10 +2154,6 @@ ID-Card Signing/decrypting is already in progress another window. Signing/decrypting is already in progress another window. - - Authentication certificate is not selected. - Authentication certificate is not selected. - Failed to decrypt document Failed to decrypt document @@ -3047,6 +3019,14 @@ Additional licenses and components Remove Remove + + You are about to delete the last file in the container + You are about to delete the last file in the container + + + It is removed along with the container. + It is removed along with the container. + WarningItem diff --git a/client/translations/et.ts b/client/translations/et.ts index 1e9b3e11d..fc84c46e2 100644 --- a/client/translations/et.ts +++ b/client/translations/et.ts @@ -489,14 +489,6 @@ Decrypting Dekrüpteerin - - You are about to delete the last file in the container - Oled kustutamas viimast faili ümbrikus - - - It is removed along with the container. - Koos sellega eemaldatakse ka ümbrik. - In order to view Validity Confirmation Sheet there has to be at least one printer installed! Digitaalallkirjade kinnituslehe kuvamiseks peab olema arvutis vähemalt üks printer seadistatud! @@ -576,14 +568,6 @@ Failed to add key Võtme lisamine ebaõnnestus - - You must enter your PIN code twice in order to decrypt the CDOC2 container - CDOC2 ümbriku dekrüpteerimiseks tuleb sisestada PIN-koodi kaks korda - - - The first PIN entry is required for authentication to the key server referenced in the CDOC2 container. Second PIN entry is required to decrypt the CDOC2 container. - Esimene PIN-koodi sisestamine on vajalik autentimiseks CDOC2 ümbrikus viidatud võtmeedastusserverisse. Teine PIN-koodi sisestamine on vajalik CDOC2 ümbriku dekrüpteerimiseks. - Please check your internet connection and network settings. Palun kontrolli internetiühendust ja võrgu sätteid. @@ -600,10 +584,6 @@ Failed to open document Dokumendi avamine ebaõnnestus - - Don't show again - Ära rohkem näita - Wrong password. Vale parool. @@ -2120,18 +2100,10 @@ ID-kaardiga QCryptoBackend - - PIN Canceled - PIN katkestatud - PIN locked PIN on lukus - - PIN Incorrect - Vale PIN - PKCS11 general error PKCS11 üldine viga @@ -2144,6 +2116,14 @@ ID-kaardiga Unknown error Tundmatu viga + + PIN incorrect + Vale PIN + + + PIN entry canceled + PIN sisestus katkestatus + QFileDialog @@ -2154,10 +2134,6 @@ ID-kaardiga QSigner - - Failed to load PKCS#11 module - PKCS#11 mooduli laadimine ebaõnnestus - Signing certificate is not selected. Allkirjastamise sertifikaat ei ole valitud. @@ -2178,10 +2154,6 @@ ID-kaardiga Signing/decrypting is already in progress another window. Allkirjastamine/dekrüpteerimine on juba käimas teises aknas. - - Authentication certificate is not selected. - Isikutuvastamise sertifikaat ei ole valitud. - Failed to decrypt document Dokumendi dekrüpteerimine ebaõnnestus @@ -3047,6 +3019,14 @@ Täiendavad litsentsid ja komponendid Remove Eemalda + + You are about to delete the last file in the container + Oled kustutamas viimast faili ümbrikus + + + It is removed along with the container. + Koos sellega eemaldatakse ka ümbrik. + WarningItem diff --git a/client/translations/ru.ts b/client/translations/ru.ts new file mode 100644 index 000000000..0d330f261 --- /dev/null +++ b/client/translations/ru.ts @@ -0,0 +1,3143 @@ + + + + + Accordion + + PIN/PUK codes and certificates + PIN/PUK и сертификаты + + + + AddRecipients + + Failed to read certificate + Не удалось прочитать сертификат + + + This certificate cannot be used for encryption + Данным сертификатом нельзя зашифровать + + + Failed to add certificate + Не удалось добавить сертификат + + + An expired certificate cannot be used for encryption. + Сертификат с истекшим сроком действия нельзя использовать для шифрования. + + + Personal code is not valid! + Личный код недействителен! + + + Person or company does not own a valid certificate + У человека или предприятия отсутствует действующий сертификат + + + It is necessary to have a valid certificate for encryption.<br /><a href='https://www.id.ee/en/article/encryption-and-decryption-of-documents/'>Read more about it</a>. + Для шифрования нужен действующий сертификат.<br /><a href='https://www.id.ee/ru/artikkel/shifrovanie-i-deshifrovka-dokumentov/'>Точнее можно прочитать</a>. + + + Certificates (*.cer *.crt *.pem) + Сертификаты (*.cer *.crt *.pem) + + + Are you sure that you want use certificate for encrypting, which expired on %1?<br />When decrypter has updated certificates then decrypting is impossible. + Вы уверены, что хотите использовать для зашифровки сертификат, который просрочился %1?<br /><br />В случае, когда расшифровщик обновит сертификат, расшифровка будет невозможна. + + + Recipient’s certification chain contains certificates that are not trusted. Continue with encryption? + Цепочка сертификатов получателя содержит ненадежные сертификаты. Продолжить шифрование? + + + Certificate from card + Сертификат с карты + + + Certificate from file + Сертификат из файла + + + Latest used certificate + Последний сертификат + + + Cancel + Отмена + + + Confirm + Подтвердить + + + The name you were looking for gave too many results, please refine your search. + Согласно Вашему запросу выдается много ответов, пожалуйста уточните запрос. + + + + AddressItem + + (Yourself) + (Вы сами) + + + digi-ID + digi-ID + + + ID-card + ID-карта + + + mobile-ID + mobiil-ID + + + Expires on + Истекает + + + Added + Добавлен + + + Decrypt + Расшифровать + + + Add + Добавить + + + Remove + Удалить + + + Certificate for Encryption + Сертификат шифрования + + + e-Seal + э-Печать + + + Authentication certificate + Сертификат идентификации + + + Expired on + Истекший + + + Unsupported cryptographic algorithm or recipient type + Неподдерживаемый криптографический алгоритм или тип получателя + + + pw + Пароль + + + Decryption is possible until: + Расшифровка возможна до: + + + Decryption has expired + Срок расшифровки истек + + + ID-CARD + ID-КАРТА + + + + Application + + Failed to initalize. + Запуск не удался. + + + Caught exception! + Перехвачена системная ошибка! + + + Loading TSL lists + Загружаем список TSL + + + Added file(s) exceeds the maximum size limit of the container(120MB). + Вложенные файл(ы) превышают размер контейнера безопасности (~120 МБ). + + + The renewal of Trust Service status List has failed + Не удалось обновить список доверенных сертификатов + + + Trust Service status List is used for digital signature validation. Please check your internet connection and make sure you have the latest ID-software version installed. An expired Trust Service List (TSL) will be used for signature validation. <a href="https://www.id.ee/en/article/digidoc4-message-updating-the-list-of-trusted-certificates-was-unsuccessful/">Additional information</a> + Список доверенных сертификатов используется для проверки действительности цифровых подписей. Пожалуйста, проверьте ваше интернет-соединение и убедитесь в том, что на компьютере установлена последняя версия программного обеспечения ID-карты. Для верификации подписей будет использован устаревший список доверенных сертификатов. <a href="https://www.id.ee/ru/artikkel/uvedomlenie-digidoc4-obnovlenie-spiska-doveriya-sertifikatov-ne-udalos/">Дополнительная информация</a> + + + Ignore forever + Не устанавливать + + + Remind later + Напомнить позже + + + DigiDoc4 Client Help + DigiDoc4 клиент помощь + + + This version of ID-software on your computer is unsupported + Программное обеспечение ID на вашем компьютере не поддерживается + + + DigiDoc4 Client cannot be used until you update ID-software. Install new ID-software from <a href="https://www.id.ee/en/article/install-id-software/">www.id.ee</a>. macOS users can download the latest ID-software version from the <a href="https://itunes.apple.com/ee/developer/ria/id556524921?mt=12">Mac App Store</a>. + Чтобы использовать программу DigiDoc4 клиент, вам необходимо обновить программное обеспечение ID. Установите новое программное обеспечение ID с веб-сайта <a href="https://www.id.ee/ru/artikkel/ustanovite-id-programmu/">www.id.ee</a>. Пользователи macOS могут скачать последнюю версию программного обеспечения ID-карты в магазине <a href="https://itunes.apple.com/ee/developer/ria/id556524921?mt=12">Mac App Store</a>. + + + Your ID-software has expired + Вам необходимо обновить программное обеспечение ID-карты + + + To download the latest software version, go to the <a href="https://www.id.ee/en/article/install-id-software/">id.ee</a> website. macOS users can download the latest ID-software version from the <a href="https://itunes.apple.com/ee/developer/ria/id556524921?mt=12">Mac App Store</a>. + Чтобы скачать последнюю версию программы, перейдите на сайт <a href="https://www.id.ee/ru/artikkel/ustanovite-id-programmu/">id.ee</a>. Пользователи macOS могут скачать последнюю версию программного обеспечения ID-карты в магазине <a href="https://itunes.apple.com/ee/developer/ria/id556524921?mt=12">Mac App Store</a>. + + + An ID-software update has been found + Выпущено обновление для программного обеспечения ID-карты + + + To download the update, go to the <a href="https://www.id.ee/en/article/install-id-software/">id.ee</a> website. macOS users can download the update from the <a href="https://itunes.apple.com/ee/developer/ria/id556524921?mt=12">Mac App Store</a>. + Чтобы скачать обновление, перейдите на сайт <a href="https://www.id.ee/ru/artikkel/ustanovite-id-programmu/">id.ee</a>. Пользователи macOS могут скачать обновление в магазине <a href="https://itunes.apple.com/ee/developer/ria/id556524921?mt=12">Mac App Store</a>. + + + Close Window + Закрыть окно + + + New Window + Новое окно + + + In order to authenticate and sign in e-services with an ID-card you need to install the web browser components. + Для аутентификации и подписания в э-услугах с помощью ID-карты необходимо установить компоненты интернет-браузера. + + + Install + Установить + + + https://www.id.ee/en/article/install-id-software/ + https://www.id.ee/ru/artikkel/ustanovite-id-programmu/ + + + https://www.id.ee/en/id-help/ + https://www.id.ee/ru/id-pomoshh/ + + + Start downloading + Начать установку + + + + CDocumentModel + + Added file(s) exceeds the maximum size limit of the container (∼120MB). <a href='https://www.id.ee/en/article/encrypting-large-120-mb-files/'>Read more about it</a> + Добаленные файл/ы превышают максимальный размер контейнера. <a href='https://www.id.ee/ru/artikkel/kriptovanie-fajlov-s-bolshim-obemom-120-mb/'>Точнее можно прочитать</a> + + + + CardWidget + + ID-card + ID-kарта + + + Digi-ID + digi-ID + + + e-Seal + э-Печать + + + Certificate for Encryption + сертификат шифрования + + + Authentication certificate + сертификат идентификации + + + %1 is selected + Выбранный %1 + + + %1 in reader + В считывателе %1 + + + + CertificateDetails + + Certificate information + Информация о сертификате + + + Certificate details + Сведения о сертификате + + + This certificate is intended for following purpose(s): + Этот сертификат предназначен для следующих целей: + + + Issued to: + Выдан: + + + Issued by: + Выдано: + + + Valid: + Действителен: + + + From + От + + + To + До + + + Field + Поле + + + Value + Значение + + + Version + Версия + + + Serial number + Серийный номер + + + Signature algorithm + Алгоритм подписи + + + Issuer + Выдавший + + + Valid from + Действительно с + + + Valid to + Действительно до + + + Subject + Субъект + + + Public key + Открытый ключ + + + Enhanced key usage + Дополнительное использование ключа + + + Certificate policies + Правила сертификатов + + + Authority key identifier + Идентификатор личного ключа + + + Subject key identifier + Идентификатор ключа заглавия + + + Key usage + Использование ключа + + + Certificates (*.cer *.crt *.pem) + Сертификаты (*.cer *.crt *.pem) + + + Save certificate + Сохранить сертификат + + + Close + Закрыть + + + Save + Сохранить + + + + CertificateHistory + + Owner + Владелец + + + Type + Тип + + + Issuer + Выдавший + + + Expiry date + Дата окончания + + + ID-card + ID-карта + + + Digi-ID + Digi-ID + + + Other + Неопределен + + + Used certificates + Использованные сертификаты + + + Close + Закрыть + + + Remove + Удалить + + + Certificate for Encryption + Сертификат шифрования + + + Last used certificates + Последний сертификат + + + Add + Добавить + + + + CheckConnection + + Check proxy settings + Проверте настройки прокси + + + Check proxy username and password + Проверьте имя пользователя и пароль прокси + + + Cannot connect to certificate status service! + Услуга подтверждения действительности не доступна! + + + + Configuration + + The configuration file located on the server cannot be validated. + Находящийся на сервере конфигурационный файл не валидируется. + + + Your computer's configuration file is later than the server has. + Находящийся на Вашем компьютере конфигурационный файл новее файла на сервере. + + + + ContainerPage + + Container: + Kонтейнер: + + + The document has already been signed by you + Вы уже подписали этот документ + + + DigiDoc4 Client + DigiDoc4 клиент + + + Decrypting + Расшифровка + + + In order to view Validity Confirmation Sheet there has to be at least one printer installed! + Для отображения листа подтверждения действительности цифровой подписи на компьютере должен быть установлен как минимум один принтер! + + + Change + Поменять + + + Cancel + Отмена + + + Encrypt + Зашифровать + + + Save as + Cохранить + + + Send with e-mail + Отправить с е-пoчтoй + + + Print summary + Подтверждающий лист + + + Save without signing + Сохранить без подписи + + + Start + В начало + + + Sign + Подписать + + + Continue signing + Подписать + + + Cannot alter container %1. Save different location? + Сохранение контейнера %1 не удалось. Сохранить в другой каталог? + + + Encrypting + Зашифровывание + + + + CryptoDoc + + Container is encrypted + Контейнер зашифрован + + + Container is not open + Контейнер не открыт + + + Unsupported file format + Неподдерживаемый формат файла + + + Key already exists + Адресат уже добавлен + + + You do not have the key to decrypt this document + У вас отсутствует ключ для расшифровки документа + + + No keys specified + Не выбрано ни одного получателя + + + Failed to add key + Не удалось добавить ключ + + + Please check your internet connection and network settings. + Пожалуйста, проверьте подключение к Интернету и настройки сети. + + + Failed to encrypt document + Не удалось зашифровать документ + + + Failed to remove key + Не удалось удалить ключ + + + Failed to open document + Не удалось открыть документ + + + Wrong password. + Неверный пароль. + + + Wrong key. + Неверный ключ. + + + Corrupted or tampered file. + Файл повреждён или был изменён. + + + Cannot read file. + Не удаётся прочитать файл. + + + + Diagnostics + + Arguments: + Аргументация: + + + Library paths: + Поиск библиотеки: + + + Central Configuration + Центральная конфигурация + + + Smart Card service status: + Статус Smart Card сервиса: + + + Running + Работает + + + Not running + Не работает + + + Smart Card readers + Считыватели карт + + + Smart Card reader drivers + Драйвера считывателей + + + Locale: + Языковые настройки: + + + Base version: + Базовая версия: + + + Application version: + Версия приложения: + + + OS: + Оп. система: + + + CPU: + CPU: + + + Kernel: + Ядро: + + + Libraries + Библиотеки + + + Browsers: + Браузеры: + + + USB info: + Информация об USB: + + + Unknown - error %1 + Неизвестная - ошибка %1 + + + User + Пользователь + + + Administrator + Администратор + + + User rights: + Права пользователя: + + + Not found + Не найдено + + + Certificate Propagation service status: + Статус Certificate Propagation сервиса: + + + is set manually + назначено вручную + + + is set by default + назначено по умолчанию + + + TSL signing certs + Сертификаты подписывания TSL + + + TSL cache + TSL-буфер + + + + DigiDoc + + Container is not open + Контейнер не открыт + + + Cannot add files to signed container + Нельзя добавлять файлы в подписанный контейнер + + + Missing signature + Подпись отсутствует + + + Check your Time-Stamping service access settings. + Проверьте настройки доступа к меткам времени. + + + Please check your internet connection. + Пожалуйста проверьте подключение к интернету. + + + Cannot add signature to empty container + Нельзя добавить подпись в пустой контейнер + + + PIN Incorrect + Неверный PIN + + + PIN Login failed + Введенный PIN неверен + + + Certificate status revoked + Сертификат недействителен + + + Certificate status unknown + Статус сертификата неизвестен + + + PIN Locked. Unblock to reuse PIN. + PIN заблокирован. Разблокируйте его для повторного использования PIN. + + + An error occurred while opening the document + Во время открытия конверта возникла ошибка + + + Connecting to SiVa server failed! + Ошибка при подключении с SiVa сервером! + + + Please check your internet connection and network settings. + Пожалуйста, проверьте подключение к Интернету и настройки сети. + + + Send document to SiVa + Отправить документ в SiVa + + + Failed add file to container + Не удается добавить файл в контейнер + + + Failed remove signature from container + Не удается удалить подпись из контейнера + + + Failed to save container + Не удается сохранить контейнер + + + Signing service URL is incorrect. + Службы URL-адрес подписи неверены. + + + You have not granted IP-based access. Check your validity confirmation service access settings. + Отсутствует доступ по IP-адресу. Проверьте настройки доступа к услуге подтверждения действительности. + + + The limit for digital signatures per month has been reached for this IP address. <a href="https://www.id.ee/en/article/for-organisations-that-sign-large-quantities-of-documents-using-digidoc4-client/">Additional information</a> + Предел для цифровых подписей в месяц был достигнут для этого IP-адреса. <a href="https://www.id.ee/ru/artikkel/dlya-uchrezhdenij-v-kotoryh-v-bolshom-obeme-podpisyvayutsya-dokumenty-s-pomoshhyu-digidoc4-klienta/">Дополнительная информация</a> + + + Please check your computer time. <a href='https://www.id.ee/en/article/digidoc4-client-error-please-check-your-computer-time-2/'>Additional information</a> + Пожалуйста проверьте время Вашего компьютера. <a href='https://www.id.ee/ru/artikkel/oshibka-klienta-digidoc4-pozhalujsta-proverte-chasy-na-vashem-kompyutere-2/'>Дополнительная информация</a> + + + The timestamp added to the signature must be taken before validity confirmation. + Добавленная к подписи метка времени должна быть более ранней по времени, чем подтверждение действительности. + + + This type of signed document will be transmitted to the Digital Signature Validation Service SiVa to verify the validity of the digital signature. Read more information about transmitted data to Digital Signature Validation service from <a href="https://www.id.ee/en/article/data-protection-conditions-for-the-id-software-of-the-national-information-system-authority/">here</a>.<br />Do you want to continue? + Данный тип подписанного документа передается в службу валидации SiVa для проверки действительности цифровых подписей. Подробнее о данных, переданных для проверки действительности электронно-цифровых подписей, можно прочитать <a href="https://www.id.ee/ru/artikkel/usloviya-zashhity-dannyh-programmnogo-obespecheniya-id-karty-departamenta-gosudarstvennoj-infosistemy/">здесь</a>.<br />Желаете продолжить? + + + Opening + Открывается + + + Failed to sign container + Не удалось подписать контейнер + + + + DocumentModel + + Cannot add container to same container + Невозможно добавить контейнер в тот же контейнер + + + File is already in container + Файл уже в контейнере + + + Failed to open file + Не удалось открыть файл + + + A file with this extension cannot be opened in the DigiDoc4 Client. Download the file to view it. + Файл с таким расширением не может быть открыт в клиенте DigiDoc4. Загрузите файл, чтобы просмотреть его. + + + Failed remove document from container + Не удается удалить файл из контейнера + + + Internal error + Внутренняя ошибка + + + Cannot add file with name 'mimetype' to the envelope. + Файл с названием "mimetype" нельзя добавить в контейнер. + + + Cannot add empty file to the container + Пустой файл нельзя добавить в контейнер + + + Failed to add file + Не удалось добавить файл + + + + FileDialog + + You don't have sufficient privileges to write this file into folder %1 + У Вас недостаточно прав для записи файла в каталог %1 + + + Choose + Выбрать + + + signature container + контейнер подписи + + + crypto container + криптоконтейнер + + + Create %1 + Создайте %1 + + + Failed to save files + Не удалось сохранить файлы + + + Documents (%1) + Документы (%1) + + + Save file + Сохранить файл + + + Move file + Переместить файл + + + Failed to save file + Не удалось сохранить файл + + + + FileItem + + Remove file + accessible + Удалить файл + + + Download file + accessible + Скачать файл + + + + FileList + + Add files + Добавить файлы + + + Select folder where files will be stored + Выберите папку для сохранения файлов + + + %1 already exists.<br />Do you want replace it? + %1 уже существует.<br />Заменить? + + + Save with other name + Сохранить под другим именем + + + Replace all + Заменить все + + + + FirstRun + + Welcome to the Estonian eID application DigiDoc! + Добро пожаловать в Эстонское приложение eID DigiDoc! + + + DigiDoc is created for managing Estonian eIDs and is the official digital signing and encryption application. + DigiDoc создан для управления эстонскими eID и является официальным приложением для цифровой подписи и шифрования. + + + Skip introductions + Пропустить введение → + + + The DigiDoc application allows you to: + DigiDoc приложение позволяет Вам: + + + Sign documents + Подписывать документы + + + Encrypt documents + Шифровать документы + + + Manage your eID-s + Управлять своими eID + + + DigiDoc Client can be used to sign digitally with ID-card, mobile-ID and Smart-ID, check the validity of digital signatures and open and save documents inside the signature container. + DigiDoc приложение используется для цифро­вой подписи с помощью ID-карты, mobiil-ID и Smart-ID, проверки подлинности подписей, открытия и сохранения документов. + + + DigiDoc Client can also be used to encrypt data and decrypt the previously encrypted data. For encryption the program uses the authentication certificate of the ID-card. + DigiDoc приложение может использоваться для шифрования и расшифровки данных. Для шифрования программа использует сертификат идентификации ID-карты. + + + Manage your ID-card’s PIN/PUK codes and check personal data. + Управлять PIN/PUK-кодами Вашей ID-карты и проверяйте личные данные. + + + How to sign document digitally? + Как подписывать документ в цифровом виде? + + + Select file + Выберите файл + + + Choose the signing method + Выберите метод подписи + + + Enter PIN2 + Введите PIN2 + + + To sign the file, drag it from your computer to the DigiDoc application or click the "... or load a file from disk" button. You can drag or select multiple files at a time. + Чтобы подписать файл, перетащите его из компьютера в прило­жение DigiDoc или нажмите кнопку «... или загрузите файл с диска». Вы можете одновременно пере­таскивать или выбирать несколько файлов. + + + Once the files have been selected, check them and choose whether you want to sign with ID-card, mobile-ID or Smart-ID. You can also save the container without signing. + После того, как файлы были выбраны, проверьте их и решите, хотите ли вы подписывать их ID-картой, mobiil-ID или Smart-ID. Вы также можете сохранить файлы в контейнере не подписывая его. + + + By entering the PIN2 code, you will have signed the document with digital signature that by law is equal to the signature signed by hand. + Введя PIN2-код, вы подписываете документ цифровой подписью, которая по закону равносильна подписи «от руки». + + + How to encrypt documents? + Как зашифровать документы? + + + Add recipients + Добавьте получателей + + + Encrypt + Зашифровать + + + A recipient must be selected in order to encrypt data. Drag the file to be encrypted from your computer to the DigiDoc application or select a file from the disk. You can drag or select multiple files at a time. + Для шифрования данных выберите получа­теля. Перетащите файл, который нужно зашифровать, с вашего компьютера в приложение или выберите файл с диска. Одновременно можно выбирать несколько файлов. + + + Select people who can open the container. + Выберите людей, которые смогут открыть контейнер. + + + Click the "Encrypt" button and the file is now encrypted. You now have the option to open the location of the container or forward the file by e-mail. + Нажмите кнопку «Зашифровать», и контейнер с файлами будет зашифрован. Теперь у вас есть возможность открыть папку с контейнером или переслать его по электронной почте. + + + How to manage your electronic identities? + Как управлять своими eID? + + + Manage PIN and PUK codes + Управление PIN- и PUK-кодами + + + Check personal data + Проверка личных данных + + + Under "My eID", you will find the option to modify your PIN1, PIN2 and PUK, and the details of the certificates. Here you can also unlock the PUK code of your blocked PIN. + В «Мой eID» можно изменить свои PIN1, PIN2 и PUK, и увидеть данные сертификатов. Также можно разблокировать PUK-кодом заблокированный PIN-код. + + + Continue + Продолжить + + + View introduction + Посмотреть введение + + + View next intro + Посмотреть следующий + + + Enter the application + Войти в программу + + + Go to signing intro + Перейти к информации о проставлении подписи + + + Go to EID intro + Перейти к информации об eID + + + Go to encryption intro + Перейти к информации о шифровании + + + "My eID" also provides a good overview of the status and contact information of the ID card inserted in the card reader. + "Мой eID" даёт хороший обзор о статусе вставленой в считыватель ID-карты и контактных данных. + + + + InfoStack + + You're using digital identity card + Вы используете дигитальное удостоверение личности + + + Name + Имя + + + Organization + Организация + + + Serial + Серийный номер + + + Country + Страна + + + Given names + Имена + + + Surname + Фамилия + + + Personal code + Личный код + + + Citizenship + Гражданство + + + Expiry date + Дата окончания + + + Document + Документ + + + + ItemList + + Enter the personal code, institution or registry code + Введите личный код, учреждение или код реестра + + + Container is not signed + Подписи контейнера отсутствуют + + + Container files + Файлы контейнера + + + Container signatures + Подписи контейнера + + + Container timestamps + Временные штампы контейнерa + + + Recipients + Получатели + + + Encrypted files + Зашифрованные файлы + + + RECIPIENT_MESSAGE + <p align="left">Кто является получателем?</p> +<p align="left">Получатель - физическое или юридическое лицо, для которого документ может быть зашифрован. Если документ зашифрован, только указанный получатель может видеть его содержимое.</p> + + + Add recipients + Добавьте получателей + + + Added recipients + Добавлен получатель + + + Search + Найти + + + Download all files + Скачайте все файлы + + + + Add more files + + Добавить файлы + + + + Add recipient + + Добавить получателей + + + Add all + Добавить все + + + + KeyDialog + + Encrypt for + Зашифровать получателю + + + Attribute + Атрибут + + + Value + Значение + + + ConcatKDF digest method + Метод подсчета ConcatKDF + + + Issuer + Выдавший + + + Close + Закрыть + + + Show certificate + Показать сертификат + + + Recipient + Получател + + + Lock type + Тип блокировки + + + Expiry date + Дата окончания + + + Key server ID + Идентификатор сервера + + + Transaction ID + Идентификатор транзакции + + + + LabelItem + + The container must be decrypted in order to see the contents of an encrypted container. + Контейнер должен быть расшифрован, чтобы увидеть его зашифрованное содержимое. + + + + LdapSearch + + Failed to init ldap + Инициализация LDAP неудалась + + + Failed to init ldap search + Инициализация поиска LDAP неуспешна + + + Failed to get result + Получение ответа неуспешно + + + Check your internet connection! +LDAP server is unavailable. + Проверьте подключение к Интернету! +LDAP сервер недоступен. + + + Error Code: %1 (%2) + Код ошибки:%1 (%2) + + + Failed to set ldap version + Не удалось настроить версию LDAP + + + Failed to start ssl + Не удалось запустить SSL + + + + MacMenuBar + + &File + &Файл + + + &Help + &Помощь + + + + MainAction + + Token selection + accessible + Выбрать средство + + + Sign with +Mobile-ID + Подписать с +Mobiil-ID + + + Sign with +Smart-ID + Подписать с +Smart-ID + + + Sign with +E-Seal + Подписать с +Э-печатью + + + Encrypt + Зашифровать + + + Decrypt + Расшифровать + + + Decrypt with +ID-Card + Расшифровать +с ID-картой + + + Encrypt +long-term + Зашифровать +долгосрочно + + + Sign with +ID-Card + Подписать с +ID-картой + + + + MainWindow + + Help + Помощь + + + Settings + Настройки + + + Drag file here for signing ... + Перетащите файл сюда для подписи или проверки ... + + + ... or load file from disk + ... или загрузите файл с диска + + + Drag file here for encryption ... + Перетащите файл сюда для (рас/за)шифровывания ... + + + Decryption succeeded! + Расшифровывание прошло успешно! + + + Encryption succeeded! + Зашифровывание выполнено успешно! + + + Select documents + Добавить файлы + + + DigiDoc4 Client + DigiDoc4 клиент + + + Cannot alter container %1. Save different location? + Сохранение контейнера %1 не удалось. Сохранить в другой каталог? + + + The container has been successfully signed! + Контейнер успешно подписан! + + + Ver. + Вер. + + + You've added file(s) to container, but these are not signed yet. Keep the unsigned container or remove it? + Вы добавили файл(ы) в контейнер, но они еще не подписаны. Сохранить неподписанный контейнер или удалить? + + + You've changed the open container but have not saved any changes. Save the changes or close without saving? + Вы изменили открытый контейнер, но не сохранили никаких изменений. Сохранить контейнер или закрыть без изменений? + + + Converted to signed document! + Переделан в контейнер для подписания! + + + Converted to crypto container! + Переделан в контейнер для зашифровывания! + + + Cannot alter container + Сохранение контейнера не удалось + + + Removing signature + Удаление подписи + + + Connect the card reader to your computer and insert your ID card into the reader + Подключите устройство чтения карт к компьютеру и вставьте ID-карту в устройство чтения + + + Signing + Подписывание + + + Check internet connection + Проверьте подключение к Интернету + + + Load file from disk for signing or verifying + accessible + Загрузить файл с диска для подписания или проверки + + + Load file from disk for encryption or decryption + accessible + Загрузить файл с диска для шифрования или расшифровки + + + Select signature page + accessible + Выбрать раздел Подпись + + + Select crypto page + accessible + Выбрать раздел Крипто + + + Select my EID page + accessible + Выбрать раздел Мой eID + + + The card in the card reader is not an Estonian ID-card + Карта в считывателе не является эстонской ID-картой + + + My eID + Мой eID + + + Signature + Подпись + + + Crypto + Крипто + + + Do not save + Не сохраняй + + + Keep + Оставить + + + Save + Сохранить + + + Files can not be added to the signed container + Файлы не могут быть добавлены в подписанный контейнер + + + Files can not be added to the cryptocontainer + Файлы не могут быть добавлены в криптоконтейнер + + + The system will create a new container which shall contain the signed document and the files you wish to add. + Система создаст новый контейнер, в который будет добавлен подписанный документ и выбранные вами файлы. + + + The system will create a new container which shall contain the cypto-document and the files you wish to add. + Система создаст новый контейнер, в который будет добавлен зашифрованный документ и выбранные вами файлы. + + + Continue + Продолжить + + + + MobileDialog + + Enter your phone number to sign with mobile-ID + <b>Введите свой номер телефона для<br/>подписи с mobiil-ID </b> + + + Remember me + Запомнить меня + + + Personal code is not valid + Личный код недействителен + + + Phone number is not entered + Номер телефона не указан + + + Cancel + Отмена + + + Sign + Подписать + + + Country code and phone number + Код страны и телефонный номер + + + Personal code + Личный код + + + Invalid country code + Неверный код страны + + + Mobile-ID + Mobiil-ID + + + + MobileProgress + + Signing in process + Подписывание + + + Phone is not in coverage area + Телефон вне сети интернет + + + Request sending error + Ошибка запроса + + + SIM error + Ошибка SIM карты + + + User is not a mobile-ID client + Пользователь не является клиентом mobiil-ID + + + Make sure control code matches with one in phone screen and enter mobile-ID PIN2-code. + Убедитесь в правильности контрольного кодaи введите PIN2-код для mobiil-ID. + + + Control code: + Kонтрольный код: + + + SSL handshake failed. Check the proxy settings of your computer or software upgrades. + Не удалось создать SSL канал передачи данных. Проверьте настройки буферного сервера компьютера или обновления программного обеспечения. + + + %v sec + %v сек + + + Cancel + Отмена + + + %1 service has encountered technical errors. Please try again later. + Технический сбой услуги %1. Пожалуйста, попробуйте позже. + + + Invalid content type header + Неправильный заголовок типа содержимого + + + Failed to parse JSON content + Не удалось считать содержимое файла JSON + + + Failed to parse certificate: + Не удалось считать содержимое сертификата: + + + Service result: + Ответ/результат услуги: + + + Account not found + Учетная запись не найдена + + + Session not found + Сессия не найден + + + mobile-ID + mobiil-ID + + + Your Smart-ID transaction has expired or user account not found. + Срок действия вашей операции Smart-ID истек или учетная запись не найдена. + + + Smart-ID + Smart-ID + + + Check your %1 service access settings. <a href="https://www.id.ee/en/article/for-organisations-that-sign-large-quantities-of-documents-using-digidoc4-client/">Additional information</a> + Проверьте настройки доступа услуги %1 <a href="https://www.id.ee/ru/artikkel/dlya-uchrezhdenij-v-kotoryh-v-bolshom-obeme-podpisyvayutsya-dokumenty-s-pomoshhyu-digidoc4-klienta/">Дополнительная информация</a> + + + You need to update your Smart-ID application to sign documents in DigiDoc4 Client. + Для подписания с помощью Smart-ID в программе DigiDoc4 клиент нужно обновить приложение Smart-ID. + + + Service result: + Ответ/результат услуги: + + + Make sure control code matches with one in phone screen and enter Smart-ID PIN2-code. + Убедитесь в правильности контрольного кодa и введите PIN2-код для Smart-ID. + + + Your Smart-ID certificate level must be qualified to sign documents in DigiDoc4 Client. + Для подписания в DigiDoc4 клиенте Ваш Smart-ID должен соответствовать более высокому уровню. + + + Your signing software needs an upgrade. Please update your ID software, which you can get from <a href="https://www.id.ee/en/">www.id.ee</a>. Additional info is available ID-helpline (+372) 666 8888. + Обновите программу подписывания. Для этого установите программное обеспечение ID-карты, скачав его с сайта <a href="https://www.id.ee/ru/">www.id.ee</a>. Дополнительная информация: телефон линии помощи ID-карты (+372) 666 8888. + + + Open the Smart-ID application on your smart device and confirm device for signing. + Откройте приложение Smart-ID на смарт-устройстве и подтвердите это устройство для подписывания. + + + The limit for %1 digital signatures per month has been reached. <a href="https://www.id.ee/en/article/for-organisations-that-sign-large-quantities-of-documents-using-digidoc4-client/">Additional information</a> + Ваш месячный лимит бесплатных подписей для %1 превышен. <a href="https://www.id.ee/ru/artikkel/dlya-uchrezhdenij-v-kotoryh-v-bolshom-obeme-podpisyvayutsya-dokumenty-s-pomoshhyu-digidoc4-klienta/">Подробнее читайте здесь</a> + + + Please include correct country code. + Номер телефона должен содержать код страны. + + + Error: an incorrect control code was chosen + Ошибка: выбран неправильный контрольный код + + + Sign document + Подписать документ + + + Your mobile-ID transaction has failed. Please contact your mobile network operator. + Не удалось выполнить операцию mobiil-ID. Пожалуйста, свяжитесь со своим мобильным оператором. + + + User denied or cancelled + Пользователю отказано + + + Your mobile-ID transaction has expired. Please try again. + Срок действия вашей транзакции mobiil-ID истек. Пожалуйста, попробуйте еще раз. + + + Failed to connect with service server. Please check your network settings or try again later. + Не удалось связаться с сервером услуги. Пожалуйста, проверьте настройки сети или повторите попытку позже. + + + Failed to send request. Check your %1 service access settings. + Не удалось отправить запрос. Проверьте настройки доступа услуги %1. + + + Your Smart-ID transaction has failed. Please check your Smart-ID application or contact Smart-ID customer support. + Не удалось выполнить операцию Smart-ID. Пожалуйста, проверьте приложение Smart-ID или свяжитесь со службой поддержки Smart-ID. + + + Mobile-ID + mobiil-ID + + + Failed to send request. %1 service has encountered technical errors. Please try again later. + Не удалось отправить запрос. Технический сбой услуги %1. Пожалуйста, попробуйте позже. + + + Failed to send request. The number of unsuccesful request from this IP address has been exceeded. Please try again later. + Не удалось отправить запрос. Превышено количество неудачных запросов с этого IP-адреса. Пожалуйста, попробуйте позже. + + + Failed to send request. A valid session is associated with this personal code. It is not possible to start a new signing before the current session expires. Please try again later. + Не удалось отправить запрос. С данным персональным номером связана действующая сессия. До истечения действующей сессии невозможно начать новое подписание. Пожалуйста, попробуйте позже. + + + ENG + RUS + + + + NoCardInfo + + No card in reader + В считывателе нет карты; проверьте, введена ли карточка правильно + + + No readers found + Считывающее устройство не обнаружено + + + Loading data + Данные считываются + + + The PCSC service, required for using the ID-card, is not working. Check your computer settings. + Необходимая для использования ID-карты услуга PCSC не работает. Проверьте настройки компьютера. + + + + PasswordDialog + + Encrypt with password + Зашифровать с паролем + + + Key label (recipient name or id) + Метка ключа (имя или идентификатор получателя) + + + Be sure to save the password in a secure place +- without the password, you won’t be able to open the file again. + Обязательно сохраните пароль в надёжном месте +- без пароля вы не сможете открыть файл снова. + + + • Length: 20–64 characters +• Contains at least one number (0–9) +• Contains at least one uppercase letter +• Contains at least one lowercase letter + • Длина: 20–64 символа +• Содержит хотя бы одну цифру (0–9) +• Содержит хотя бы одну заглавную букву +• Содержит хотя бы одну строчную букву + + + Repeat password + Повторите пароль + + + Cancel + Отмена + + + Encrypt + Зашифровать + + + Decrypt with password + Расшифровать с паролем + + + Enter password to decrypt the document + Введите пароль для расшифровки документа + + + Decrypt + Расшифровать + + + Password is empty + Пароль пустой + + + Password does not meet complexity requirements + Пароль не соответствует требованиям сложности + + + Passwords do not match + Пароли не совпадают + + + Enter a password to encrypt the document + Введите пароль для шифрования документа + + + + PinPopup + + For using sign certificate enter PIN2 at the reader + Для использования сертификата цифровой подписи введите PIN2<br/>с клавиатуры считывателя + + + For using sign certificate enter PIN2 + Для использования сертификата цифровой подписи введите PIN2 + + + Selected action requires sign certificate. + Данная операция требует наличия сертификата цифровой подписи. + + + For using authentication certificate enter PIN1 at the reader + Для использования сертификата идентификации введите PIN1<br/>с клавиатуры считывателя + + + For using authentication certificate enter PIN1 + Для использования сертификата идентификации введите PIN1 + + + %1 will be locked next failed attempt + %1 будет заблокирован при следующей неудачной попытке + + + %1 has been entered incorrectly at least once + По меньшей мере один раз был введен неправильный %1 + + + Selected action requires authentication certificate. + Данная операция требует сертификат идентификации. + + + Cancel + Отмена + + + You need to use a personal identification certificate for the selected activity. + Для выбранного действия необходима идентификация личности. + + + Enter PIN1 to use the certificate + Для использования сертификата идентификации введите PIN1 + + + + PinUnblock + + PIN2 code is used to digitally sign documents. + PIN2-код используется для дигитальной подписи. + + + PIN1 code is used for confirming the identity of a person. + PIN1-код используется для идентификации личности. + + + %1 unblocking + %1 разблокирование + + + %1 code change + Замена %1-кода + + + PUK remaining attempts: %1 + PUK оставшиеся попытки: %1 + + + Remaining attempts: %1 + Оставшиеся попытки: %1 + + + New %1 code can't be increasing sequence + Новый %1 не может увеличиваться + + + New %1 code can't be decreasing sequence + Новый %1 не может уменьшаться + + + New %1 code can't be sequence of same numbers + Новый %1 не может быть рядом одинаковых номеров + + + New %1 code can't be part of your personal code + Новый %1 не может быть частью вашего личного кода + + + New %1 code can't be your date of birth + Новый %1 не может быть вашей датой рождения + + + Current %1 code and new %1 code must be different + Новый %1 должен отличаться от старого %1 + + + Cancel + Отмена + + + Unblock + Разблокировать + + + PUK code is used for unblocking the certificates, when PIN1 or PIN2 has been entered 3 times incorrectly. + PUK-код - это код, разблокирующий заблокированные сертификаты, если код PIN1 или PIN2 был введён неверно 3 раза подряд. + + + If you forget the PUK code or the certificates remain blocked, you have to visit the <a href="https://www.politsei.ee/en/">service center</a> to obtain new codes. + Если PUK-код забыт и сетрификат блокируется из-за неверно введённых PIN1 или PIN2, то единственной возможностью восстановить работоспособность ID-карты, это обратиться в <a href="https://www.politsei.ee/ru/">бюро обслуживания</a>. + + + To unblock the certificate you have to enter the PUK code. + Для разблокировки сертификата введите PUK-код. + + + You can find your PUK code inside the ID-card codes envelope. + PUK-код находится в конверте с кодами, который выдаётся при получении ID-карты или смене сертификатов. + + + If you have forgotten the PUK code for your ID card, please visit <a href="https://www.politsei.ee/en/">the Police and Border Guard Board service center</a> to obtain new PIN codes. + Если вы забыли PUK-код своей ID-карты, посетите <a href="https://www.politsei.ee/ru/">бюро</a> <a href="https://www.politsei.ee/ru/">обслуживания Департамента полиции и пограничной</a> <a href="https://www.politsei.ee/ru/">охраны</a>, где вы сможете получить конверт с кодами. + + + If you have forgotten the PUK code of your ID-card then you can view it from the Police and Border Guard Board portal. <a href="https://www.id.ee/en/article/my-pin-is-blocked-locked/">Additional information</a> + На ID-карте, находящейся в считывателе, невозможно изменить PUK-код. Если вы забыли PUK-код своей ID-карты, вы можете посмотреть его в самообслуживании Департамента полиции и погранохраны. <a href="https://www.id.ee/ru/artikkel/moj-pin-kod-zablokirovan/">Дополнительная информация</a> + + + PUK code is written in the envelope, that is given with the ID-card. + Ваш PUK-код находится в конверте с кодами. + + + If %1 is inserted incorrectly 3 times the %2 certificate will be blocked and it will be impossible to use ID-card to %3, until it is unblocked via the PUK code. + Если %1 введён 3 раза неверно, тогда блокируется %2 и использовать ID-карту для %3 невозможно, пока блокировка не снята PUK-кодом. + + + signing + сертификат цифровой подписи + + + identification + идентификационный сертификат + + + digital signing + цифровой подписи + + + verify identification + идентификации личности + + + New %1 codes doesn't match + Новые %1-коды не сходятся + + + If you have forgotten PIN%1, but know PUK, then here you can enter new PIN%1. + Если вы забыли PIN%1-код, но знаете PUK-код, тогда здесь вы можете ввести новый PIN%1-код. + + + %1 length has to be between %2 and 12 + Длина %1 должна быть %2-12 номера + + + Valid %1 code + Действующий %1-код + + + New %1 code + Новый %1-код + + + Repeat new %1 code + Новый %1-код заново + + + Current PUK code + Действующий PUK-код + + + Change + Поменять + + + + PrintSheet + + SIGNED FILES + ПОДПИСАННЫЕ ФАЙЛЫ + + + FILE NAME + ИМЯ ФАЙЛА + + + FILE SIZE + РАЗМЕР ФАЙЛА + + + SIGNERS + ПОДПИСАВШИЙСЯ + + + NAME + ИМЯ + + + PERSONAL CODE + ЛИЧНЫЙ КОД + + + TIME + ВРЕМЯ + + + NOTES + ЗАМЕЧАНИЯ + + + VALIDITY CONFIRMATION SHEET + ЛИСТ ПОДТВЕРЖДЕНИЯ ДИГИТАЛЬНЫХ ПОДПИСЕЙ + + + NO. + №. + + + VALIDITY OF SIGNATURE + ДЕЙСТВИТЕЛЬНОСТЬ ПОДПИСИ + + + ROLE / RESOLUTION + РОЛЬ / ЗАЯВЛЕНИЕ + + + PLACE OF CONFIRMATION (CITY, STATE, ZIP, COUNTRY) + МЕСТОПОЛОЖЕНИЕ ПОДПИСАВШЕГО (город, уезд, индекс, страна) + + + ISSUER OF CERTIFICATE + ИМЯ ВЫДАВШЕГО СЕРТИФИКАТ + + + The print out of files listed in the section <b>"Signed Files"</b> are inseparable part of this Validity Confirmation Sheet. + Неотъемлемой частью этого листа подтверждения подписей является распечатка файлов на бумаге из раздела <b>"Подписанные файлы"</b>. + + + COMPANY + УЧЕРЕЖДЕНИЕ + + + REGISTER CODE + КОД РЕГИСТРА + + + UNKNOWN + НЕИЗВЕСТНО + + + SERIAL NUMBER OF SIGNER CERTIFICATE + СЕРИЙНЫЙ НОМЕР СЕРТИФИКАТА + + + SIGNATURE IS VALID + ПОДПИСЬ ДЕЙСТВИТЕЛЬНА + + + SIGNATURE IS NOT VALID + ПОДПИСЬ НЕДЕЙСТВИТЕЛЬНА + + + HASH VALUE OF SIGNATURE + ХЭШ ЗНАЧАНИЕ ПОДТВЕРЖДЕНИЯ ПОДЛИННОСТИ ПОДПИСИ + + + AUTHORITY KEY IDENTIFIER + ИДЕНТИФИКАТОР ЛИЧНОГО КЛЮЧА + + + NB! WARNINGS + NB! ПРЕДУПРЕЖДЕНИЯ + + + NB! RESTRICTIONS + NB! ОГРАНИЧЕНИЯ + + + Presented print summary is informative to confirm existence of signed file with given hash value. The print summary itself does not have independent verification value. Declaration of signers’ signature can be verified only through digitally signed file. + Этот лист подтверждения является информативным, информация в котором только подтверждает, что файл, подписанный этим хешем, существует. Лист подтверждения не имеет независимого значения проверки. Только файл с цифровой подписью может подтвердить действительность заявления о намерениях сторон. + + + + QCryptoBackend + + PIN locked + PIN заблокирован + + + PKCS11 general error + Ошибка PKCS11 + + + PKCS11 device error + Ошибка PKCS11 устройства + + + Unknown error + Неизвестная ошибка + + + PIN incorrect + Неверный PIN + + + PIN entry canceled + PIN-код отменен + + + + QFileDialog + + All Files (*) + Все файлы (*) + + + + QSigner + + Signing certificate is not selected. + Сертификат подписи не выбран. + + + Failed to login token + PIN-код не подтвежден + + + Failed to sign document + Не удалось подписать документ + + + Sign certificate is not selected + Сертификат подписи не выбран + + + Signing/decrypting is already in progress another window. + Операция подписи/расшифровки уже выполняется в другом окне. + + + Failed to decrypt document + Не удалось расшифровать документ + + + + QSmartCard + + To change %1 on a PinPad reader the old %1 code has to be entered first and then the new %1 code twice. + Для замены %1-кода Вам необходимо ввести один раз<br>действующий %1-код и два раза новый %1-код с помощью PinPad. + + + To change %1 code with the PUK code on a PinPad reader the PUK code has to be entered first and then the %1 code twice. + Для изменения %1-кода с помощью PUK-кода Вам необходимо<br>ввести один раз PUK-код и два раза новый %1-код с помощью PinPad. + + + To unblock the %1 code on a PinPad reader the PUK code has to be entered first and then the %1 code twice. + Для разблокировки %1-кода Вам необходимо ввести один раз<br>PUK-код и два раза новый %1-код с помощью PinPad. + + + Changing %1 failed + Смена %1-кода прошла неудачно + + + %1 changed! + %1-код изменён! + + + %1 has been changed and the certificate has been unblocked! + %1-код изменён и сертификат разблокирован! + + + %1 blocked + %1 заблокирован + + + Wrong %1 code. You can try %n more time(s). + + Неверный %1-код. Попыток ещё: %n. + Неверный %1-код. Попыток ещё: %n. + Неверный %1-код. Попыток ещё: %n. + + + + %1 timeout + Время запроса %1-кода истекло + + + New %1 codes doesn't match + Новые %1-коды не сходятся + + + %1 length has to be between %2 and 12 + Длина %1 должна быть %2-12 номера + + + Old and new %1 has to be different! + Старый и новый %1 должны отличаться! + + + + RoleAddressDialog + + Enter your role and address info + Введите свою роль и адрес + + + Role / resolution + Роль / pезолюция + + + City + Город + + + State + Уезд + + + Country + Страна + + + Zip + Индекс + + + Sign + Подписать + + + Cancel + Отмена + + + + SettingsDialog + + Settings + Настройки + + + Language + Язык + + + Show print summary + Показать подтверждающий лист + + + Ask role and address info on signing + Спросить роль и адрес при каждом подписании + + + Access to Time-Stamping service + Доступ к услугам отметки времени + + + https://www.id.ee/en/article/for-organisations-that-sign-large-quantities-of-documents-using-digidoc4-client/ + https://www.id.ee/ru/artikkel/dlya-uchrezhdenij-v-kotoryh-v-bolshom-obeme-podpisyvayutsya-dokumenty-s-pomoshhyu-digidoc4-klienta/ + + + No proxy + Прокси не используется + + + Use system proxy settings + Использовать системные настройки прокси + + + Manual proxy configuration + Настроить прокси вручную + + + Host + Хост + + + Port + Порт + + + Username + Имя пользователя + + + Password + Пароль + + + The connection to certificate status service is successful! + Настройки Интернета верны, услуга подтверждения действительности доступна! + + + Checking updates has failed. + Ошибка проверки обновлений. + + + Restart DigiDoc4 Client to activate logging + Перезапустите клиент DigiDoc4, чтобы активировать ведение журнала + + + Read more <a href="https://www.id.ee/en/article/log-file-generation-in-digidoc4-client/">here</a>. + Подробнее читайте <a href="https://www.id.ee/ru/artikkel/generirovanie-log-fajla-v-kliente-digidoc4/">здесь</a>. + + + Read more <a href="https://www.id.ee/en/article/log-file-generation-in-digidoc4-client/">here</a>. Restart now? + Подробнее читайте <a href="https://www.id.ee/ru/artikkel/generirovanie-log-fajla-v-kliente-digidoc4/">здесь</a>. Перезапустить приложение? + + + Please try again. + Пожалуйста, попробуйте еще раз. + + + Issued to: %1<br />Valid to: %2 %3 + Выдан: %1<br />Действительно до: %2 %3 + + + expired + истекший + + + <p>Estonian ID-software is released by Information Systems's Authority<br /> +In case of questions please contact our support via <a href="https://www.id.ee/en/id-help/">id.ee</a>.</p> +Additional licenses and components + <p>Разработчиком программного обеспечения ID-карты является Riigi Infosüsteemi Amet.<br /> +Если у вас возникнут вопросы, пожалуйста, обратитесь на <a href="https://www.id.ee/ru/id-pomoshh/">id.ee</a>.</p> +Дополнительные лицензии и компоненты + + + Save as + Cохранить + + + Text files (*.txt) + Текстовые файлы (*.txt) + + + Failed write to file! + Не удалось записать файл! + + + General + accessible + Основные + + + Proxy + Прокси + + + Diagnostics + Диагностика + + + Info + Инфо + + + First run + Первый запуск + + + Refresh configuration + Проверьте обновления + + + Check connection + Проверьте настройки интернета + + + Save diagnostics report + Сохранить диагностику + + + Remove old certificates + Удалить старые сертификаты + + + Use default settings + Использовать настройки по умолчанию + + + Close + Закрыть + + + Redundant certificates have been successfully removed. + Лишние сертификаты успешно удалены. + + + Help + Помощь + + + Access to mobile-ID and Smart-ID service + Доступ к услуге mobiil-ID и Smart-ID + + + DigiDoc4 Client configuration update was successful. + Обновление конфигурации программы DigiDoc4 удачно завершено. + + + DigiDoc4 version %1, released %2 + DigiDoc4 версия %1, выпущенный %2 + + + Use default access + Использовать доступ, назначенный по умолчанию + + + Use manually configured access + Использовать доступ, назначенный вручную + + + Enable one-time log generation + Активировать одноразовое создание лог-файла + + + Save log + Сохранить лог-файл + + + The project is supported by the European Regional Development Fund + Проект поддерживается Европейским фондом регионального развития + + + Signing services + Услуги подписания + + + Validation services + Услуги валидации + + + Access to Digital Signature Validation Service SiVa + Доступ к услуге валидации SiVa + + + https://www.id.ee/en/article/configuring-the-siva-validation-service-in-the-digidoc4-client/ + https://www.id.ee/ru/artikkel/nastrojka-sluzhby-validaczii-siva-v-digidoc4-klient-2/ + + + Digital Signature Validation Service SiVa SSL certificate + Сертификат услуги валидации SiVa SSL + + + Select SiVa server certificate + Выберите сертификат сервера валидации + + + Select Time-Stamping server certificate + Выберите сертификат сервера отметки времени + + + Time-Stamping service SSL certificate + SSL сертификат службы отметок времени + + + Encryption settings + Настройки шифрования + + + Add certificate + Добавить сертификат + + + Show certificate + Показать сертификат + + + Use CDOC1 file format for encryption + Для шифрования используйте формат файла CDOC1 + + + Use CDOC2 file format for encryption + Для шифрования используйте формат файла CDOC2 + + + Use a manually specified key transfer server for encryption + Используйте вручную указанный сервер передачи ключей для шифрования + + + Key transfer server SSL certificate + SSL-сертификат сервера передачи ключей + + + Select a key transfer server certificate + Выберите сертификат сервера передачи ключей + + + Use a key transfer server for encryption + Используйте сервер передачи ключей для шифрования + + + Name + Имя + + + Fetch URL + URL для получения данных + + + Post URL + URL для отправки данных + + + + SignatureDialog + + Warnings + Предупреждение + + + Role / resolution + Роль / резолюция + + + Signer + Подписавшаяся сторона + + + Technical information + Техническая информация + + + Role and address + Роль и адрес + + + City + Город + + + Country + Страна + + + State + Уезд + + + Zip + Индекс + + + Signature + Подпись + + + Attribute + Атрибут + + + Value + Значение + + + This e-Signature is not equivalent with handwritten signature and therefore can be used only in transactions where Qualified e-Signature is not required. + Эта электронная подпись не эквивалентна рукописной подписи и поэтому может использоваться только в тех случаях, когда не требуется квалифицированная электронная подпись. + + + The signature is valid, but the container has a specific feature. Usually, this feature has arisen accidentally when containers were created. However, as it is not possible to edit a container without invalidating the signature, <a href='https://www.id.ee/en/article/digital-signing-and-electronic-signatures/'>a warning</a> is displayed. + Подпись действительна, но у контейнера имеется какая-то особенность. Чаще всего, такая особенность возникает при изготовлении контейнеров случайно. Однако поскольку контейнер невозможно изменить без потери действительности подписи, то отображается <a href='https://www.id.ee/ru/artikkel/czifrovoe-podpisanie-i-elektronnye-podpisi/'>предупреждение</a>. + + + Unknown error + Неизвестная ошибка + + + This is an invalid signature or malformed digitally signed file. The signature is not valid. + Повреждена подпись или подписанный файл. Данная подпись недействительна. + + + 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='https://www.id.ee/en/article/digidoc4-client-error-ocsp-responder-is-not-trusted-no-certificate-for-this-responder-in-local-certstore/'>additional information</a>). + Статус подписи отображается как "неизвестный", если на компьютере не установлены необходимые для проверки подписи сертификаты сертифицирующей организации и/или услуги подтверждения действительности (<a href='https://www.id.ee/ru/artikkel/digidoc4-klient-oshibka-ocsp-responder-is-not-trusted-no-certificate-for-this-responder-in-local-certstore/'>дополнительная информация</a>). + + + Signer's Certificate issuer + Организация, выдавшая сертификат подписавшего + + + Signer's Certificate + Сертификат пользователя + + + Signature method + Метод подписи + + + Container format + Формат контейнера + + + Signature format + Формат подписи + + + Signature policy + Политика цифровой подписи + + + Signed file count + Количество подписанных файлов + + + Archive Timestamp + Временной штамп архива + + + Archive TS Certificate issuer + Издатель сертификата временного штампа архива + + + Archive TS Certificate + Издатель сертификата временного штампа архива + + + Signature Timestamp + Временной штамп подписи + + + TS Certificate issuer + Издатель сертификата временного штампа + + + TS Certificate + Сертификат временного штампа + + + OCSP Certificate issuer + Организация, выдавшая сертификат OCSP + + + OCSP Certificate + Сертификат OCSP + + + Hash value of signature + Хэш значение подтверждения подлинности подписи + + + OCSP time + Время подтверждения подлинности подписи + + + Claimed signing time (UTC) + Заявленное время подписания (UTC) + + + Close + Закрыть + + + Signing time (UTC) + Время подписания (UTC) + + + The signature is technically correct, but it is based on the currently weak hash algorithm SHA-1, therefore it is not protected against forgery or alteration. + Подпись технически верна, но так как она основана на слабом на данный момент алгоритме хеширования SHA-1, то не защищена от подделки или изменения. + + + + SignatureItem + + Warnings + Предупреждения + + + Restrictions + Ограничения + + + Signature is valid + Подпись действительна + + + Timestamp is valid + Временной штамп действителен + + + Signature is not valid + Подпись недействительна + + + Timestamp is not valid + Временной штамп недействителен + + + Signature is unknown + Подпись неизвестная + + + Timestamp is unknown + Временной штамп неизвестный + + + Signed on + Подписано + + + time + время + + + Remove signature + accessible + Удалить подпись + + + To view signature details press enter or space + accessible + Для просмотра деталей подписи нажмите пробел или enter + + + + SmartIDDialog + + Personal code + Личный код + + + Enter your personal code to sign with Smart-ID + Введите свой личный код для подписи с Smart-ID + + + Remember me + Запомнить меня + + + Personal code is not valid + Личный код недействителен + + + Country + Страна + + + Estonia + Эстония + + + Lithuania + Литва + + + Latvia + Латвия + + + Cancel + Отмена + + + Sign + Подписать + + + + SslCertificate + + All application policies + Все полисы приложений + + + Proves your identity to a remote computer + Подтверждает Вашу личность на отдалённом компьютере + + + Protects email messages + Защищает сообщения электронной почты + + + OCSP signing + OCSP подписывание + + + Digital signature + Дигитальная подпись + + + Non repudiation + Невозможность отказа + + + Key encipherment + Зашифровка ключа + + + Data encipherment + Зашифровка данных + + + Key agreement + Подтверждение ключа + + + Key certificate sign + Подпись ключа сертификата + + + CRL sign + CRL подпись + + + Encipher only + Только зашифровка + + + Decipher only + Только разшифровка + + + Unknown + Неизвестно + + + Time Stamping + Штамп времени + + + Ensures the identity of a remote computer + Обеспечивается идентификация сервера + + + + VerifyCert + + Certificate has expired! + Срок действия сертификата истек! + + + Authentication certificate + Сертификат идентификации + + + Unblock + Разблокировать + + + Change PIN%1 + Изменить PIN%1 + + + The PUK code cannot be changed on the ID-card in the reader.<br />If you have forgotten the PUK code of your ID-card then you can view it from the Police and Border Guard Board portal.<br /><a href="https://www.id.ee/en/article/pin-and-puk-codes-security-recommendations/">Additional information</a>. + На ID-карте, находящейся в считывателе, невозможно изменить PUK-код.<br />Если вы забыли PUK-код своей ID-карты, вы можете посмотреть его в самообслуживании Департамента полиции и погранохраны.<br /><a href="https://www.id.ee/ru/artikkel/pin-i-puk-kody-rekomendaczii-po-obespecheniyu-bezopasnosti/">Дополнительная информация</a>. + + + PUK code is blocked because the PUK code has been entered 3 times incorrectly.<br/>You can not unblock the PUK code yourself.<br/>As long as the PUK code is blocked, all eID options can be used, except PUK-code.<br/> + PUK заблокирован, потому что PUK введен неверно 3 раза.<br/>PUK невозможно разблокировать самому.<br/>Пока PUK-код заблокирован, можно использовать все возможности eID, кроме тех которые требуют PUK.<br/> + + + Please visit the service center to obtain new codes.<br/><a href="https://www.politsei.ee/en/instructions/applying-for-an-id-card-for-an-adult/reminders-for-id-card-holders/">Additional information</a>. + Для получения нового PUK-кода для своей ID-карты, посетите центр обслуживания, где вы сможете получить конверт с кодами.<br/><a href="https://www.politsei.ee/ru/instruktsii/hodataystvo-o-vydache-id-karty-vzroslomu/pamyatka-dlya-polzovatelya-id-karti/">Дополнительная информация</a>. + + + A new document must be requested to receive the new PUK code.<br/><a href="https://www.politsei.ee/en/instructions/applying-for-an-id-card-for-an-adult">Additional information</a>. + Для получения нового PUK-кода необходимо оформить новую ID-карту.<br/><a href="https://www.politsei.ee/ru/instruktsii/hodataystvo-o-vydache-id-karty-vzroslomu">Дополнительная информация</a>. + + + Signing certificate + Сертификат подписи + + + Certificate is valid until %1 + Сертификат действителен до %1 + + + Change with PUK code + Изменить с помощью PUK-кода + + + PIN%1 code must be changed in order to authenticate + Чтобы аутентифицироваться, необходимо изменить PIN%1 + + + PIN%1 code must be changed in order to sign + Чтобы подписывать, необходимо изменить PIN%1 + + + Check the details of the certificate + Проверьте сведения о сертификате + + + PUK code + PUK-код + + + The PUK code is located in your envelope + PUK-код находится в конверте + + + Change PUK + Изменить PUK + + + PIN can be changed only using eToken utility + PIN-код можно сменить только при помощи программного обеспечения e-Tempel + + + Certificate for Encryption + Сертификат шифрования + + + Certificate is valid + Сертификат действителен + + + Your ID-card signing certificate is valid + Сертификат подписи в вашей ID-карте действителен + + + Your ID-card authentication certificate is valid + Сертификат идентификации личности в вашей ID-карте действителен + + + Certificate is not valid + Сертификат недействителен + + + A valid certificate is required for electronic use. + Для электронного использования необходим действующий сертификат. + + + Your ID-card signing certificate is not valid + Сертификат подписи вашей ID-карты недействителен + + + You need valid certificates to use your ID-card electronically. + Для электронного использования ID-карты требуются действующие сертификаты. + + + Your ID-card authentication certificate is not valid + Сертификат идентификации личности в вашей ID-карте недействителен + + + Certificate status is unknown + Статус сертификата неизвестен + + + Your ID-card signing certificate status is unknown + Статус сертификата подписи вашей ID-карты неизвестен + + + Your ID-card authentication certificate status is unknown + Статус сертификата идентификации вашей ID-карты неизвестен + + + Certificate status check failed + Проверка статуса сертификата не удалась + + + Please check your internet connection. + Пожалуйста проверьте подключение к интернету. + + + The ID-card must be activated in order to authenticate + Для аутентификации ID карту необходимо активировать + + + The ID-card must be activated in order to sign + Для подписания документов ID карту необходимо активировать + + + PIN%1 has been blocked because PIN%1 code has been entered incorrectly 3 times. + PIN%1 заблокирован, потому что PIN%1-код был введен неверно 3 раза. + + + Unblock to reuse PIN%1. + Разблокируйте его для повторного использования PIN%1. + + + Check certificate status + Проверить статус сертификата + + + Read more <a href="https://www.id.ee/en/article/validity-of-id-card-certificates/">here</a>. + Подробнее читайте <a href="https://www.id.ee/ru/artikkel/dejstvitelnost-sertifikatov-id-karty/">здесь</a>. + + + PIN%1 can not be used because the certificate has expired. + PIN%1 не может быть использован, так как срок действия сертификата истек. + + + + WarningDialog + + Details + Детали + + + No + Нет + + + Cancel + Отмена + + + Yes + Да + + + Remove + Удалить + + + You are about to delete the last file in the container + Вы собираетесь удалить последний файл в контейнере + + + It is removed along with the container. + Он удаляется вместе с контейнером. + + + + WarningItem + + Signing with an ID-card isn't possible yet. PIN%1 code must be changed in order to sign. + Подписание с помощью ID-карты ещё невозможно. Чтобы подписывать, необходимо изменить PIN%1. + + + %n signatures are not valid! + + %n подпись недействительна! + %n подписи недействительны! + %n подписи недействительны! + + + + %n timestamps are not valid! + + %n временной штамп недействителен! + %n временных штампов недействительны! + %n временных штампов недействительны! + + + + %n signatures are unknown! + + %n подпись неизвестная! + %n подписи неизвестны! + %n подписи неизвестны! + + + + %n timestamps are unknown! + + %n временной штамп неизвестен! + %n временных штампов неизвестны! + %n временных штампов неизвестны! + + + + https://www.id.ee/en/article/digital-signing-and-electronic-signatures/ + https://www.id.ee/ru/artikkel/czifrovoe-podpisanie-i-elektronnye-podpisi/ + + + More information + Дополнительная информация + + + https://www.id.ee/en/article/digidoc-container-format-life-cycle-2/ + https://www.id.ee/en/article/digidoc-container-format-life-cycle-2/ + + + The current file is a DigiDoc container that is not supported officially any longer. You are not allowed to add or remove signatures to this container. + DigiDoc контейнер имеет старый формат. К данному контейнеру нельзя добавить или удалить из него подпись. + + + An empty file is attached to the container. Remove the empty file from the container to sign. + В контейнер добавлен пустой файл. Для подписания удалите из контейнера пустой файл. + + + Certificates have expired! + Срок действия сертификатов истек! + + + https://www.politsei.ee/en/instructions/applying-for-an-id-card-for-an-adult/ + https://www.politsei.ee/ru/instruktsii/hodataystvo-o-vydache-id-karty-vzroslomu/ + + + Certificates expire soon! + Срок действия сертификатов скоро истекает! + + + Additional information + Дополнительная информация + + + https://www.id.ee/en/article/changing-id-card-pin-codes-and-puk-code/ + https://www.id.ee/ru/artikkel/poryadok-izmeneniya-pin-kodov-i-puk-koda-id-karty/ + + + Authentication and signing with the ID-card isn't possible yet. ID-card must be activated in the Police and Border Guard Board’s self-service portal in order to use it. + Идентификация и подписание документов с помощью ID карты пока невозможны. Для использования удостоверения личности его необходимо активировать в системе самообслуживания Управления полиции и пограничной охраны. + + + Activate ID-card + Активировать ID карту + + + https://www.politsei.ee/en/self-service-portal/ + https://www.politsei.ee/ru/samoobsluzhivanie/ + + + This ASiC-S container contains XAdES signature. You are not allowed to add or remove signatures to this container. + Речь идет о конверте ASiC-S, содержащемся в подписи XAdES. К данному контейнеру нельзя добавить или удалить из него подпись. + + + This container contains CAdES signature. You are not allowed to add or remove signatures to this container. + Этот контейнер содержит подпись CAdES. К данному контейнеру нельзя добавить или удалить из него подпись. + + + The encrypted container contains a cryptographic algorithm or recipient type that is not supported in this DigiDoc4 application version. Please make sure that you are using the latest DigiDoc4 application version. + Зашифрованный конверт содержит криптографический алгоритм или тип получателя, не поддерживаемый в текущей версии приложения DigiDoc4. Пожалуйста, убедитесь, что вы используете последнюю версию приложения DigiDoc4. + + + https://www.id.ee/en/article/install-id-software/ + https://www.id.ee/ru/artikkel/ustanovite-id-programmu/ + + + diff --git a/client/widgets/ContainerPage.cpp b/client/widgets/ContainerPage.cpp index 289eb2a6d..d5bbb4fa8 100644 --- a/client/widgets/ContainerPage.cpp +++ b/client/widgets/ContainerPage.cpp @@ -232,7 +232,7 @@ void ContainerPage::deleteConfirm(C *c, int index) if (dlg->exec() != QMessageBox::Ok) return; window()->setWindowFilePath({}); - window()->setWindowTitle(tr("DigiDoc4 Client")); + window()->setWindowTitle(QCoreApplication::translate("MainWindow", "DigiDoc4 Client")); if(QFile::exists(c->fileName())) QFile::remove(c->fileName()); emit action(ContainerClose);