From c8cfe9bbdc6a9e882c997645b18390b1d4f43d61 Mon Sep 17 00:00:00 2001 From: Raul Metsma Date: Mon, 26 Jun 2023 14:55:39 +0300 Subject: [PATCH] Fix RSA padding selection (#536) IB-7756 Signed-off-by: Raul Metsma --- libdigidocpp.dox | 14 +++- src/crypto/Digest.cpp | 159 ++++++++++++------------------------ src/crypto/Digest.h | 17 ++-- src/crypto/PKCS11Signer.cpp | 24 +++--- src/crypto/Signer.cpp | 16 ++-- src/crypto/WinSigner.cpp | 61 +++++++------- src/digidoc-tool.1.cmake | 8 +- src/digidoc-tool.cpp | 27 +++--- test/libdigidocpp_boost.cpp | 8 +- 9 files changed, 144 insertions(+), 190 deletions(-) diff --git a/libdigidocpp.dox b/libdigidocpp.dox index bdf8d7ccf..9375cb6d5 100644 --- a/libdigidocpp.dox +++ b/libdigidocpp.dox @@ -1538,10 +1538,16 @@ Postal code of the place where the signature is created. Country of origin. ISO 3166-type 2-character country codes are used (e.g. EE) \-\-role= Optional Signer’s role(s). The option can occur multiple times. -\-\-sha(1,224,256,384,512) Optional -Used for testing purposes. Specifies the hash function that is used when calculating digest values, supported only in case of BDOC documents. If not specified then SHA-256 is used by default. -\-\-sigsha(1,224,256,384,512) Optional -Used for testing purposes. Specifies the hash function that is used for calculating the hash that is being signed, supported only in case of BDOC format. If not specified then SHA-256 is used by default. +\-\-sha(224,256,384,512) Optional +Used for testing purposes. Specifies the hash function that is used when calculating digest values. If not specified then SHA-256 is used by default. +\-\-sigsha(224,256,384,512) Optional +Used for testing purposes. Specifies the hash function that is used for calculating the hash that is being signed. If not specified then SHA-256 is used by default. +\-\-sigpsssha(224,256,384,512) Optional +Used for testing purposes. With RSA keys RSA-PSS padding is used. Specifies the hash function that is used for calculating the hash that is being signed. If not specified then SHA-256 is used by default. Same as \-\-sigsha* with \-\-rsapss +\-\-rsapkcs15 Optional +Option to change RSA Signature padding (RSA PKCS1.5). +\-\-rsapss Optional +Option to change RSA Signature padding (RSA PSS). \-\-tsurl Optional Option to change TS URL. \-\-dontValidate Optional diff --git a/src/crypto/Digest.cpp b/src/crypto/Digest.cpp index fdafe6f17..ec93e21c0 100644 --- a/src/crypto/Digest.cpp +++ b/src/crypto/Digest.cpp @@ -26,42 +26,31 @@ #include using namespace std; - -namespace digidoc -{ -class Digest::Private: public vector -{ -public: - EVP_MD_CTX *ctx {}; - int method = -1; -}; -} - using namespace digidoc; /** * Initializes OpenSSL digest calculator. * - * @param uri digest method URI (e.g. 'http://www.w3.org/2000/09/xmldsig#sha1' for SHA1). - * @throws IOException throws exception if the digest calculator initialization failed. + * @param uri digest method URI (e.g. 'http://www.w3.org/2001/04/xmlenc#sha256' for SHA256). + * @throws Exception throws exception if the digest calculator initialization failed. */ Digest::Digest(const string &uri) - : d(make_unique()) + : d(SCOPE_PTR(EVP_MD_CTX, EVP_MD_CTX_new())) { - reset(uri); + if(uri.empty() && Conf::instance()->digestUri() == URI_SHA1) + THROW("Unsupported digest method %s", uri.c_str()); + int method = toMethod(uri.empty() ? Conf::instance()->digestUri() : uri); + if(EVP_DigestInit(d.get(), EVP_get_digestbynid(method)) != 1) + THROW_OPENSSLEXCEPTION("Failed to initialize %s digest calculator", uri.c_str()); } /** * Destroys OpenSSL digest calculator. */ -Digest::~Digest() -{ - EVP_MD_CTX_free(d->ctx); -} +Digest::~Digest() = default; -vector Digest::addDigestInfo(const vector &digest, const string &uri) +vector Digest::addDigestInfo(vector digest, string_view uri) { - vector result = digest; vector oid; switch(toMethod(uri)) { @@ -73,8 +62,8 @@ vector Digest::addDigestInfo(const vector &digest, default: break; } if(!oid.empty()) - result.insert(result.begin(), oid.begin(), oid.end()); - return result; + digest.insert(digest.begin(), oid.begin(), oid.end()); + return digest; } vector Digest::digestInfoDigest(const std::vector &digest) @@ -83,7 +72,7 @@ vector Digest::digestInfoDigest(const std::vector SCOPE(X509_SIG, sig, d2i_X509_SIG(nullptr, &p, long(digest.size()))); if(!sig) return {}; - const ASN1_OCTET_STRING *value = nullptr; + const ASN1_OCTET_STRING *value {}; X509_SIG_get0(sig.get(), nullptr, &value); return { value->data, value->data + value->length }; } @@ -94,7 +83,7 @@ string Digest::digestInfoUri(const std::vector &digest) SCOPE(X509_SIG, sig, d2i_X509_SIG(nullptr, &p, long(digest.size()))); if(!sig) return {}; - const X509_ALGOR *algor = nullptr; + const X509_ALGOR *algor {}; X509_SIG_get0(sig.get(), &algor, nullptr); return toUri(OBJ_obj2nid(algor->algorithm)); } @@ -105,45 +94,24 @@ string Digest::digestInfoUri(const std::vector &digest) */ string Digest::uri() const { - return toUri(d->method); + return toUri(EVP_MD_CTX_type(d.get())); } -/** - * - */ -void Digest::reset(const string &uri) +bool Digest::isRsaPssUri(string_view uri) { - if(uri.empty() && Conf::instance()->digestUri() == URI_SHA1) - THROW("Unsupported digest method"); - - if(d->ctx) - EVP_MD_CTX_free(d->ctx); - d->ctx = EVP_MD_CTX_new(); - int result = -1; - switch(d->method = toMethod(uri.empty() ? Conf::instance()->digestUri() : uri)) - { - case NID_sha1: result = EVP_DigestInit(d->ctx, EVP_sha1()); break; - case NID_sha224: result = EVP_DigestInit(d->ctx, EVP_sha224()); break; - case NID_sha256: result = EVP_DigestInit(d->ctx, EVP_sha256()); break; - case NID_sha384: result = EVP_DigestInit(d->ctx, EVP_sha384()); break; - case NID_sha512: result = EVP_DigestInit(d->ctx, EVP_sha512()); break; + return + uri == URI_RSA_PSS_SHA224 || + uri == URI_RSA_PSS_SHA256 || + uri == URI_RSA_PSS_SHA384 || + uri == URI_RSA_PSS_SHA512 || #ifndef LIBRESSL_VERSION_NUMBER - case NID_sha3_224: result = EVP_DigestInit(d->ctx, EVP_sha3_224()); break; - case NID_sha3_256: result = EVP_DigestInit(d->ctx, EVP_sha3_256()); break; - case NID_sha3_384: result = EVP_DigestInit(d->ctx, EVP_sha3_384()); break; - case NID_sha3_512: result = EVP_DigestInit(d->ctx, EVP_sha3_512()); break; + uri == URI_RSA_PSS_SHA3_224 || + uri == URI_RSA_PSS_SHA3_256 || + uri == URI_RSA_PSS_SHA3_384 || + uri == URI_RSA_PSS_SHA3_512; +#else + false; #endif - default: break; - } - d->clear(); - if(result != 1) - THROW_OPENSSLEXCEPTION("Failed to initialize %s digest calculator", uri.c_str()); -} - -bool Digest::isRsaPssUri(const std::string &uri) -{ - return uri == URI_RSA_PSS_SHA224 || uri == URI_RSA_PSS_SHA256 || uri == URI_RSA_PSS_SHA384 || uri == URI_RSA_PSS_SHA512 || - uri == URI_RSA_PSS_SHA3_224 || uri == URI_RSA_PSS_SHA3_256 || uri == URI_RSA_PSS_SHA3_384 || uri == URI_RSA_PSS_SHA3_512; } /** @@ -152,14 +120,15 @@ bool Digest::isRsaPssUri(const std::string &uri) * For available method URIs see: *
  • *
      W3C XML Encryption Syntax and Processing (10 December 2005) http://www.w3.org/TR/xmlenc-core/
    - *
      RFC 4051 http://www.ietf.org/rfc/rfc4051.txt
    + *
      RFC 4051 https://www.ietf.org/rfc/rfc4051.txt
    + *
      RFC 6931 https://www.ietf.org/rfc/rfc6931.txt
    *
  • * * @param uri digest method URI (e.g. 'http://www.w3.org/2000/09/xmldsig#sha1' for SHA1). * @return returns digest OpenSSL method id. - * @throws IOException throws exception if digest method is not supported. + * @throws Exception throws exception if digest method is not supported. */ -int Digest::toMethod(const string &uri) +int Digest::toMethod(string_view uri) { if(uri == URI_SHA1 || uri == URI_RSA_SHA1 || uri == URI_ECDSA_SHA1) return NID_sha1; if(uri == URI_SHA224 || uri == URI_RSA_SHA224 || uri == URI_RSA_PSS_SHA224 || uri == URI_ECDSA_SHA224) return NID_sha224; @@ -172,11 +141,12 @@ int Digest::toMethod(const string &uri) if(uri == URI_SHA3_384 || uri == URI_RSA_PSS_SHA3_384) return NID_sha3_384; if(uri == URI_SHA3_512 || uri == URI_RSA_PSS_SHA3_512) return NID_sha3_512; #endif - THROW( "Digest method URI '%s' is not supported.", uri.c_str() ); + THROW("Digest method URI '%.*s' is not supported.", uri.size(), uri.data()); } string Digest::toRsaUri(const string &uri) { + DEBUG("method %s", uri.c_str()); if(uri == URI_SHA1) return URI_RSA_SHA1; if(uri == URI_SHA224) return URI_RSA_SHA224; if(uri == URI_SHA256) return URI_RSA_SHA256; @@ -186,33 +156,25 @@ string Digest::toRsaUri(const string &uri) uri == URI_RSA_SHA224 || uri == URI_RSA_SHA256 || uri == URI_RSA_SHA384 || - uri == URI_RSA_SHA512 || - uri == URI_RSA_PSS_SHA224 || - uri == URI_RSA_PSS_SHA256 || - uri == URI_RSA_PSS_SHA384 || - uri == URI_RSA_PSS_SHA512 || -#ifndef LIBRESSL_VERSION_NUMBER - uri == URI_RSA_PSS_SHA3_224 || - uri == URI_RSA_PSS_SHA3_256 || - uri == URI_RSA_PSS_SHA3_384 || - uri == URI_RSA_PSS_SHA3_512) -#else - 0) -#endif + uri == URI_RSA_SHA512) return uri; - return {}; + return toRsaPssUri(uri); } -string Digest::toRsaPssUri(const string &uri) +string Digest::toRsaPssUri(string uri) { if(uri == URI_SHA224) return URI_RSA_PSS_SHA224; if(uri == URI_SHA256) return URI_RSA_PSS_SHA256; if(uri == URI_SHA384) return URI_RSA_PSS_SHA384; if(uri == URI_SHA512) return URI_RSA_PSS_SHA512; +#ifndef LIBRESSL_VERSION_NUMBER if(uri == URI_SHA3_224) return URI_RSA_PSS_SHA3_224; if(uri == URI_SHA3_256) return URI_RSA_PSS_SHA3_256; if(uri == URI_SHA3_384) return URI_RSA_PSS_SHA3_384; if(uri == URI_SHA3_512) return URI_RSA_PSS_SHA3_512; +#endif + if(isRsaPssUri(uri)) + return uri; return {}; } @@ -252,61 +214,40 @@ std::string Digest::toUri(int nid) } /** - * Add data for digest calculation. - * - * @param data data to add for digest calculation. - * @throws IOException throws exception if SHA1 update failed. - * @see update(const unsigned char* data, unsigned long length) - */ -void Digest::update(const vector &data) -{ - update(data.data(), data.size()); -} - -/** - * Add data for digest calculation. After calling getDigest() SHA context + * Add data for digest calculation. After calling result() SHA context * is uninitialized and this method should not be called. * * @param data data to add for digest calculation. * @param length length of the data. - * @throws IOException throws exception if update failed. - * @see getDigest() + * @throws Exception throws exception if update failed. + * @see result() */ void Digest::update(const unsigned char *data, size_t length) { if(!data) THROW("Can not update digest value from NULL pointer."); - if(!d->empty()) - THROW("Digest is already finalized, can not update it."); - if(EVP_DigestUpdate(d->ctx, data, length) != 1) + if(EVP_DigestUpdate(d.get(), data, length) != 1) THROW_OPENSSLEXCEPTION("Failed to update %s digest value", uri().c_str()); } /** * Calculate message digest. SHA context will be invalid after this call. - * For calculating an other digest you must create new SHA1Digest class. + * For calculating an other digest you must create new Digest class. * * @return returns the calculated digest. - * @throws IOException throws exception if update failed. + * @throws Exception throws exception if update failed. */ vector Digest::result() const { - if(!d->empty()) - return *d; unsigned int size = 0; - d->resize(size_t(EVP_MD_CTX_size(d->ctx))); - if(EVP_DigestFinal(d->ctx, d->data(), &size) != 1) + vector result(size_t(EVP_MD_CTX_size(d.get())), 0); + if(EVP_DigestFinal_ex(d.get(), result.data(), &size) != 1) THROW_OPENSSLEXCEPTION("Failed to create %s digest", uri().c_str()); - return *d; + return result; } vector Digest::result(const vector &data) { - return result(data.data(), data.size()); -} - -vector Digest::result(const unsigned char *data, size_t length) -{ - update(data, length); + update(data.data(), data.size()); return result(); } diff --git a/src/crypto/Digest.h b/src/crypto/Digest.h index 5cea59f63..c0a289550 100644 --- a/src/crypto/Digest.h +++ b/src/crypto/Digest.h @@ -45,7 +45,6 @@ #define URI_RSA_PSS_SHA256 "http://www.w3.org/2007/05/xmldsig-more#sha256-rsa-MGF1" #define URI_RSA_PSS_SHA384 "http://www.w3.org/2007/05/xmldsig-more#sha384-rsa-MGF1" #define URI_RSA_PSS_SHA512 "http://www.w3.org/2007/05/xmldsig-more#sha512-rsa-MGF1" - #define URI_RSA_PSS_SHA3_224 "http://www.w3.org/2007/05/xmldsig-more#sha3-224-rsa-MGF1" #define URI_RSA_PSS_SHA3_256 "http://www.w3.org/2007/05/xmldsig-more#sha3-256-rsa-MGF1" #define URI_RSA_PSS_SHA3_384 "http://www.w3.org/2007/05/xmldsig-more#sha3-384-rsa-MGF1" @@ -57,6 +56,8 @@ #define URI_ECDSA_SHA384 "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384" #define URI_ECDSA_SHA512 "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512" +using EVP_MD_CTX = struct evp_md_ctx_st; + namespace digidoc { /** @@ -67,28 +68,24 @@ namespace digidoc public: Digest(const std::string &uri = {}); ~Digest(); - void reset(const std::string &uri = {}); - void update(const std::vector &data); void update(const unsigned char *data, size_t length); std::vector result(const std::vector &data); - std::vector result(const unsigned char *data, size_t length); std::vector result() const; std::string uri() const; - static bool isRsaPssUri(const std::string &uri); + static bool isRsaPssUri(std::string_view uri); static std::string toRsaUri(const std::string &uri); - static std::string toRsaPssUri(const std::string &uri); + static std::string toRsaPssUri(std::string uri); static std::string toEcUri(const std::string &uri); - static int toMethod(const std::string &uri); + static int toMethod(std::string_view uri); static std::string toUri(int nid); - static std::vector addDigestInfo(const std::vector &digest, const std::string &uri); + static std::vector addDigestInfo(std::vector digest, std::string_view uri); static std::vector digestInfoDigest(const std::vector &digest); static std::string digestInfoUri(const std::vector &digest); private: DISABLE_COPY(Digest); - class Private; - std::unique_ptr d; + std::unique_ptr d; }; } diff --git a/src/crypto/PKCS11Signer.cpp b/src/crypto/PKCS11Signer.cpp index c1ded1123..c7138943d 100644 --- a/src/crypto/PKCS11Signer.cpp +++ b/src/crypto/PKCS11Signer.cpp @@ -60,7 +60,7 @@ class PKCS11Signer::Private { return h ? (void*)GetProcAddress(h, symbol) : nullptr; } void unload() - { if(h) FreeLibrary(h); h = 0; } + { if(h) FreeLibrary(h); h = {}; } HINSTANCE h {}; #else @@ -71,7 +71,7 @@ class PKCS11Signer::Private { return h ? dlsym(h, symbol) : nullptr; } void unload() - { if(h) dlclose(h); h = nullptr; } + { if(h) dlclose(h); h = {}; } void *h {}; #endif @@ -222,7 +222,7 @@ X509Cert PKCS11Signer::cert() const if(d->findObject(session, CKO_PUBLIC_KEY, id).empty()) continue; certSlotMapping.push_back({x509, slot, id}); - certificates.push_back(move(x509)); + certificates.push_back(std::move(x509)); } } if(session) @@ -251,17 +251,19 @@ X509Cert PKCS11Signer::cert() const string PKCS11Signer::method() const { - if(!d->sign.certificate || !X509Crypto(d->sign.certificate).isRSAKey()) - return Signer::method(); + string parent = Signer::method(); + if(!d->sign.certificate || !X509Crypto(d->sign.certificate).isRSAKey() || + parent != CONF(signatureDigestUri)) + return parent; CK_ULONG count = 0; CK_RV rv = d->f->C_GetMechanismList(d->sign.slot, nullptr, &count); if(rv != CKR_OK) - return Signer::method(); + return parent; vector mech(count); rv = d->f->C_GetMechanismList(d->sign.slot, mech.data(), &count); if(find(mech.cbegin(), mech.cend(), CKM_RSA_PKCS_PSS) != mech.cend()) - return Digest::toRsaPssUri(Signer::method()); - return Signer::method(); + return Digest::toRsaPssUri(std::move(parent)); + return parent; } /** @@ -379,7 +381,7 @@ vector PKCS11Signer::sign(const string &method, const vectorf->C_GetAttributeValue(session, key[0], &attribute, 1); + d->f->C_GetAttributeValue(session, key.front(), &attribute, 1); CK_RSA_PKCS_PSS_PARAMS pssParams { CKM_SHA_1, CKG_MGF1_SHA1, 0 }; CK_MECHANISM mech { keyType == CKK_ECDSA ? CKM_ECDSA : CKM_RSA_PKCS, nullptr, 0 }; @@ -406,8 +408,8 @@ vector PKCS11Signer::sign(const string &method, const vectorf->C_SignInit(session, &mech, key[0]) != CKR_OK) + data = Digest::addDigestInfo(std::move(data), method); + if(d->f->C_SignInit(session, &mech, key.front()) != CKR_OK) THROW("Failed to sign digest"); CK_ULONG size = 0; diff --git a/src/crypto/Signer.cpp b/src/crypto/Signer.cpp index ea447a2d3..deb69d37f 100644 --- a/src/crypto/Signer.cpp +++ b/src/crypto/Signer.cpp @@ -22,13 +22,14 @@ #include "ASiC_E.h" #include "Conf.h" #include "crypto/Digest.h" -#include "crypto/OpenSSLHelpers.h" #include "crypto/X509Cert.h" +#include "util/log.h" #include #include #include +#include using namespace digidoc; using namespace std; @@ -36,7 +37,7 @@ using namespace std; class Signer::Private { public: - string method = CONF(signatureDigestUri); + optional method; string profile = "time-stamp"; bool ENProfile = false; string city, streetAddress, stateOrProvince, postalCode, countryName; @@ -210,7 +211,10 @@ vector Signer::signerRoles() const */ void Signer::setMethod(const string &method) { - d->method = method; + if(method.empty()) + d->method.reset(); + else + d->method = method; } /** @@ -226,10 +230,9 @@ void Signer::setENProfile(bool enable) */ string Signer::method() const { -#ifndef OPENSSL_NO_ECDSA X509Cert c = cert(); if(EVP_PKEY *key = X509_get0_pubkey(c.handle()); - key && EVP_PKEY_base_id(key) == EVP_PKEY_EC) + key && EVP_PKEY_base_id(key) == EVP_PKEY_EC && !d->method) { switch(EVP_PKEY_bits(key)) { case 224: return URI_SHA224; @@ -238,8 +241,7 @@ string Signer::method() const default: return URI_SHA512; } } -#endif - return d->method; + return d->method.value_or(CONF(signatureDigestUri)); } /** diff --git a/src/crypto/WinSigner.cpp b/src/crypto/WinSigner.cpp index 347ed7c91..a0d7eda0c 100644 --- a/src/crypto/WinSigner.cpp +++ b/src/crypto/WinSigner.cpp @@ -40,7 +40,7 @@ using namespace std; extern "C" { -typedef BOOL (WINAPI * PFNCCERTDISPLAYPROC)( +using PFNCCERTDISPLAYPROC = BOOL (WINAPI *)( __in PCCERT_CONTEXT pCertContext, __in HWND hWndSelCertDlg, __in void *pvCallbackData @@ -71,32 +71,27 @@ PCCERT_CONTEXT WINAPI CryptUIDlgSelectCertificateW( } // extern "C" -namespace digidoc -{ - class WinSigner::Private { public: static BOOL WINAPI CertFilter(PCCERT_CONTEXT cert_context, - BOOL *is_initial_selected_cert, void *callback_data); + PBOOL is_initial_selected_cert, PVOID callback_data); X509Cert cert; - HCRYPTPROV_OR_NCRYPT_KEY_HANDLE key = 0; - DWORD spec = 0; - BOOL freeKey = FALSE; + HCRYPTPROV_OR_NCRYPT_KEY_HANDLE key {}; + DWORD spec {}; + BOOL freeKey {}; string pin; vector thumbprint; - bool selectFirst = false; + bool selectFirst {}; }; -} - BOOL WinSigner::Private::CertFilter(PCCERT_CONTEXT cert_context, BOOL * /* is_initial_selected_cert */, void * /* callback_data */) { DWORD flags = CRYPT_ACQUIRE_PREFER_NCRYPT_KEY_FLAG|CRYPT_ACQUIRE_COMPARE_KEY_FLAG|CRYPT_ACQUIRE_SILENT_FLAG; - HCRYPTPROV_OR_NCRYPT_KEY_HANDLE key = 0; - DWORD spec = 0; - BOOL freeKey = FALSE; + HCRYPTPROV_OR_NCRYPT_KEY_HANDLE key {}; + DWORD spec {}; + BOOL freeKey {}; CryptAcquireCertificatePrivateKey(cert_context, flags, nullptr, &key, &spec, &freeKey); if(!key) return FALSE; @@ -158,14 +153,14 @@ WinSigner::~WinSigner() X509Cert WinSigner::cert() const { - if(!!d->cert) + if(d->cert) return d->cert; HCERTSTORE store = CertOpenSystemStore(0, L"MY"); if(!store) return d->cert; - PCCERT_CONTEXT cert_context = nullptr; + PCCERT_CONTEXT cert_context {}; if(!d->thumbprint.empty()) { CRYPT_HASH_BLOB hashBlob { DWORD(d->thumbprint.size()), PBYTE(d->thumbprint.data()) }; @@ -173,7 +168,7 @@ X509Cert WinSigner::cert() const } else if(d->selectFirst) { - PCCERT_CONTEXT find = nullptr; + PCCERT_CONTEXT find {}; while((find = CertFindCertificateInStore(store, X509_ASN_ENCODING|PKCS_7_ASN_ENCODING, 0, CERT_FIND_ANY, nullptr, find))) { if(d->CertFilter(find, nullptr, nullptr)) @@ -205,15 +200,17 @@ X509Cert WinSigner::cert() const string WinSigner::method() const { - if(!d->cert || !X509Crypto(d->cert).isRSAKey()) - return Signer::method(); + string parent = Signer::method(); + if(!d->cert || !X509Crypto(d->cert).isRSAKey() || + parent != CONF(signatureDigestUri)) + return parent; BCRYPT_PSS_PADDING_INFO rsaPSS { NCRYPT_SHA256_ALGORITHM, 32 }; - DWORD size = 0; + DWORD size {}; Digest dgst; vector digest = dgst.result({ 0 }); SECURITY_STATUS err = NCryptSignHash(d->key, &rsaPSS, PBYTE(digest.data()), DWORD(digest.size()), nullptr, 0, &size, BCRYPT_PAD_PSS); - return FAILED(err) ? Signer::method() : Digest::toRsaPssUri(Signer::method()); + return FAILED(err) ? parent : Digest::toRsaPssUri(std::move(parent)); } /** @@ -245,11 +242,11 @@ void WinSigner::setThumbprint(const vector &thumbprint) vector WinSigner::sign(const string &method, const vector &digest) const { - DEBUG("sign(method = %s, digest = length=%d)", method.c_str(), digest.size()); + DEBUG("sign(method = %s, digest = length=%zu)", method.c_str(), digest.size()); - BCRYPT_PKCS1_PADDING_INFO rsaPKCS1 { nullptr }; - BCRYPT_PSS_PADDING_INFO rsaPSS { nullptr, 0 }; - ALG_ID alg = 0; + BCRYPT_PKCS1_PADDING_INFO rsaPKCS1 {}; + BCRYPT_PSS_PADDING_INFO rsaPSS {}; + ALG_ID alg {}; if(method == URI_RSA_SHA1) { rsaPKCS1.pszAlgId = NCRYPT_SHA1_ALGORITHM; alg = CALG_SHA1;} else if(method == URI_RSA_SHA224) { rsaPKCS1.pszAlgId = L"SHA224";} else if(method == URI_RSA_SHA256) { rsaPKCS1.pszAlgId = NCRYPT_SHA256_ALGORITHM; alg = CALG_SHA_256;} @@ -265,7 +262,7 @@ vector WinSigner::sign(const string &method, const vector signature; switch(d->spec) { @@ -279,8 +276,8 @@ vector WinSigner::sign(const string &method, const vector WinSigner::sign(const string &method, const vectorkey, paddingInfo, PBYTE(digest.data()), DWORD(digest.size()), nullptr, 0, &size, padding); if(FAILED(err)) @@ -314,7 +311,7 @@ vector WinSigner::sign(const string &method, const vectorkey, alg, 0, 0, &hash)) THROW("Failed to sign"); @@ -323,7 +320,7 @@ vector WinSigner::sign(const string &method, const vectorspec, nullptr, 0, nullptr, &size)) { err = LONG(GetLastError()); CryptDestroyHash(hash); @@ -355,7 +352,7 @@ vector WinSigner::sign(const string &method, const vector siguri; // Params + optional rsaPss; string path, profile, pkcs11, pkcs12, pin, city, street, state, postalCode, country, cert; vector thumbprint; vector > files; @@ -361,13 +362,15 @@ static int printUsage(const char *executable) << " --pin= - default asks pin from prompt" << endl << " --sha(224,256,384,512) - set default digest method (default sha256)" << endl << " --sigsha(224,256,384,512) - set default digest method (default sha256)" << endl - << " --sigpsssha(224,256,384,512) - set default digest method using RSA PSS (default sha256)" << endl - << " --tsurl - option to change TS URL (default " << CONF(TSUrl) << ")" << endl - << " --dontValidate - Don't validate container on signature creation" << endl << endl + << " --sigpsssha(224,256,384,512) - set default digest method using RSA PSS (default sha256, same as --sigsha* with --rsapss)" << endl + << " --rsapkcs15 - Use RSA PKCS1.5 padding" << endl + << " --rsapss - Use RSA PSS padding" << endl + << " --tsurl - option to change TS URL (default " << CONF(TSUrl) << ")" << endl + << " --dontValidate - Don't validate container on signature creation" << endl << endl << " All commands:" << endl - << " --nocolor - Disable terminal colors" << endl + << " --nocolor - Disable terminal colors" << endl << " --loglevel=[0,1,2,3,4] - Log level 0 - none, 1 - error, 2 - warning, 3 - info, 4 - debug" << endl - << " --logfile= - File to log, empty to console" << endl; + << " --logfile= - File to log, empty to console" << endl; return EXIT_FAILURE; } @@ -423,10 +426,12 @@ ToolConfig::ToolConfig(int argc, char *argv[]) else if(arg == "--sigsha256") siguri = URI_SHA256; else if(arg == "--sigsha384") siguri = URI_SHA384; else if(arg == "--sigsha512") siguri = URI_SHA512; - else if(arg == "--sigpsssha224") siguri = URI_RSA_PSS_SHA224; - else if(arg == "--sigpsssha256") siguri = URI_RSA_PSS_SHA256; - else if(arg == "--sigpsssha384") siguri = URI_RSA_PSS_SHA384; - else if(arg == "--sigpsssha512") siguri = URI_RSA_PSS_SHA512; + else if(arg == "--sigpsssha224") { siguri = URI_SHA224; rsaPss = true; } + else if(arg == "--sigpsssha256") { siguri = URI_SHA256; rsaPss = true; } + else if(arg == "--sigpsssha384") { siguri = URI_SHA384; rsaPss = true; } + else if(arg == "--sigpsssha512") { siguri = URI_SHA512; rsaPss = true; } + else if(arg == "--rsapkcs15") rsaPss = false; + else if(arg == "--rsapss") rsaPss = true; else if(arg.find("--tsurl") == 0) tsurl = arg.substr(8); else if(arg.find("--tslurl=") == 0) tslurl = arg.substr(9); else if(arg.find("--tslcert=") == 0) tslcerts = vector{ X509Cert(arg.substr(10)) }; @@ -468,7 +473,7 @@ unique_ptr ToolConfig::getSigner(bool getwebsigner) const { unique_ptr win = make_unique(pin, selectFirst); win->setThumbprint(thumbprint); - signer = unique_ptr(win.release()); + signer = std::move(win); } #endif else if(!pkcs12.empty()) @@ -479,6 +484,8 @@ unique_ptr ToolConfig::getSigner(bool getwebsigner) const signer->setSignatureProductionPlaceV2(city, street, state, postalCode, country); signer->setSignerRoles(roles); signer->setProfile(profile); + if(rsaPss.has_value()) + signer->setMethod(rsaPss.value() ? Digest::toRsaPssUri(signatureDigestUri()) : Digest::toRsaUri(signatureDigestUri())); return signer; } diff --git a/test/libdigidocpp_boost.cpp b/test/libdigidocpp_boost.cpp index 2c5d5e33f..783728975 100644 --- a/test/libdigidocpp_boost.cpp +++ b/test/libdigidocpp_boost.cpp @@ -379,15 +379,15 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(signature, Doc, DocTypes) BOOST_CHECK_NO_THROW(d->save()); BOOST_CHECK_NO_THROW(s->validate()); + // RSA PSS tests d = Container::createPtr(Doc::EXT + ".tmp"); - signer1->setMethod(URI_RSA_PSS_SHA256); BOOST_CHECK_NO_THROW(d->addDataFile("test1.txt", "text/plain")); - BOOST_CHECK_NO_THROW(d->sign(signer1.get())); - s = d->signatures().back(); + signer1->setMethod(URI_RSA_PSS_SHA256); + BOOST_CHECK_NO_THROW(s = d->sign(signer1.get())); BOOST_CHECK_NO_THROW(s->validate()); BOOST_CHECK_EQUAL(s->signatureMethod(), signer1->method()); auto signer4 = make_unique("signerEC384.p12", "signerEC"); - signer4->setProfile("BES"); + signer4->setProfile("BES"); // Not signed with same Issuer d = Container::createPtr(Doc::EXT + ".tmp"); BOOST_CHECK_NO_THROW(d->addDataFile("test1.txt", "text/plain")); Signature *s4 = nullptr;