Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cdoc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ add_library(cdoc
Certificate.cpp Certificate.h
Crypto.cpp Crypto.h
Tar.cpp Tar.h
TLSKey.cpp TLSKey.h
ZStream.h
# Internal
Utils.cpp Utils.h
Expand Down
102 changes: 6 additions & 96 deletions cdoc/NetworkBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,9 @@
#include "Certificate.h"
#include "Crypto.h"
#include "CryptoBackend.h"
#include "TLSKey.h"
#include "Utils.h"

#define OPENSSL_SUPPRESS_DEPRECATED

#include <openssl/bio.h>
#include <openssl/http.h>
#include <openssl/ssl.h>
Expand All @@ -44,53 +43,14 @@

using namespace std::literals::chrono_literals;

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);

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);

struct Private {
libcdoc::Certificate x509;
EVP_PKEY *pkey = nullptr;

RSA_METHOD *rsamethod = nullptr;
EC_KEY_METHOD *ecmethod = nullptr;
libcdoc::unique_ptr_t<EVP_PKEY_free> key = libcdoc::make_unique_ptr<EVP_PKEY_free>(nullptr);

explicit Private(libcdoc::NetworkBackend *backend, const std::vector<uint8_t> &client_cert)
: x509(client_cert)
{
if (!x509) return;
pkey = X509_get_pubkey(x509.handle());
if (!pkey) return;
int id = EVP_PKEY_get_id(pkey);
if (id == EVP_PKEY_EC) {
ecmethod = EC_KEY_METHOD_new(EC_KEY_get_default_method());
EC_KEY_sign sign = nullptr;
EC_KEY_sign_setup sign_setup = nullptr;
EC_KEY_METHOD_get_sign(ecmethod, &sign, &sign_setup, nullptr);
EC_KEY_METHOD_set_sign(ecmethod, sign, sign_setup, ecdsa_do_sign);

auto *ec = (EC_KEY *) EVP_PKEY_get1_EC_KEY(pkey);
EC_KEY_set_method(ec, ecmethod);
EC_KEY_set_ex_data(ec, 0, backend);
EVP_PKEY_set1_EC_KEY(pkey, ec);
} else if (id == EVP_PKEY_RSA) {
rsamethod = RSA_meth_dup(RSA_get_default_method());
RSA_meth_set1_name(rsamethod, "libcdoc");
RSA_meth_set_sign(rsamethod, rsa_sign);

RSA *rsa = (RSA *) EVP_PKEY_get1_RSA(pkey);
RSA_set_method(rsa, rsamethod);
RSA_set_ex_data(rsa, 0, backend);
EVP_PKEY_set1_RSA(pkey, rsa);
}
}

~Private() {
if (pkey) EVP_PKEY_free(pkey);
if (rsamethod) RSA_meth_free(rsamethod);
if (ecmethod) EC_KEY_METHOD_free(ecmethod);
if (x509) key = libcdoc::createTLSKey(backend, x509.handle());
}
};

Expand Down Expand Up @@ -436,9 +396,10 @@ libcdoc::NetworkBackend::fetchKey (std::vector<uint8_t>& dst, const std::string&
result = getClientTLSCertificate(cert);
if (result != OK) return result;
std::unique_ptr<Private> d = std::make_unique<Private>(this, cert);
if (!cert.empty() && (!d->x509 || !d->pkey)) return CRYPTO_ERROR;
if (!cert.empty() && (!d->x509 || !d->key)) return CRYPTO_ERROR;

httplib::SSLClient cli(host, port, d->x509.handle(), d->pkey);
httplib::SSLClient cli(host, port, d->x509.handle(), d->key.get());
SSL_CTX_set_min_proto_version(cli.ssl_context(), TLS1_3_VERSION);
if (result = applySSLTimeout(cli, this); result != OK) return result;
result = setPeerCertificates(cli, this, buildURL(host, port));
if (result != OK) return result;
Expand Down Expand Up @@ -555,57 +516,6 @@ libcdoc::NetworkBackend::fetchShare(ShareInfo& share, const std::string& url, co
}
#endif

ECDSA_SIG *
ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM * /*inv*/, const BIGNUM * /*rp*/, EC_KEY *eckey)
{
auto *backend = (libcdoc::NetworkBackend *) EC_KEY_get_ex_data(eckey, 0);
std::vector<uint8_t> dst;
std::vector<uint8_t> digest(dgst, dgst + dgst_len);
int result = backend->signTLS(dst, libcdoc::CryptoBackend::SHA_512, digest);
if (result != libcdoc::OK) {
return nullptr;
}
int size_2 = (int) dst.size() / 2;
ECDSA_SIG *sig = ECDSA_SIG_new();
ECDSA_SIG_set0(sig,
BN_bin2bn(dst.data(), size_2, nullptr),
BN_bin2bn(dst.data() + size_2, size_2, nullptr));
return sig;
}

int
rsa_sign(int type, const unsigned char *m, unsigned int m_len, unsigned char *sigret, unsigned int *siglen, const RSA *rsa)
{
auto *backend = (libcdoc::NetworkBackend *) RSA_get_ex_data(rsa, 0);
auto algo = libcdoc::CryptoBackend::SHA_512;
switch (type) {
case NID_sha224:
algo = libcdoc::CryptoBackend::SHA_224;
break;
case NID_sha256:
algo = libcdoc::CryptoBackend::SHA_256;
break;
case NID_sha384:
algo = libcdoc::CryptoBackend::SHA_384;
break;
case NID_sha512:
break;
default:
return 0;
}
std::vector<uint8_t> dst;
std::vector<uint8_t> digest(m, m + m_len);
int result = backend->signTLS(dst, algo, digest);
if (result != libcdoc::OK) {
return 0;
}
if (sigret && (*siglen >= dst.size())) {
memcpy(sigret, dst.data(), dst.size());
}
*siglen = (unsigned int) dst.size();
return 1;
}

#ifdef HAS_KEYSHARES
libcdoc::result_t
libcdoc::NetworkBackend::showVerificationCode(unsigned int code)
Expand Down
3 changes: 3 additions & 0 deletions cdoc/NetworkBackend.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,9 @@ struct CDOC_EXPORT NetworkBackend {

/**
* @brief sign TLS digest with client's private key
*
* An ECDSA signature is returned as r || s, an RSA signature as is. RSA keys sign with RSASSA-PSS
* (salt as long as the digest, MGF1 with the same hash): the connection requires TLS 1.3, which allows only PSS.
* @param dst a destination container for signature
* @param algorithm signing algorithm
* @param digest data to be signed
Expand Down
38 changes: 11 additions & 27 deletions cdoc/PKCS11Backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -632,48 +632,32 @@ libcdoc::PKCS11Backend::sign(std::vector<uint8_t>& dst, HashAlgorithm algorithm,
CK_ATTRIBUTE attribute { CKA_KEY_TYPE, &keyType, sizeof(keyType) };
d->f->C_GetAttributeValue(d->session, d->key, &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 };
std::vector<uint8_t> data;
CK_RSA_PKCS_PSS_PARAMS pssParams {};
CK_MECHANISM mech { CKM_ECDSA, nullptr, 0 };
if(keyType == CKK_RSA) {
switch(algorithm) {
case libcdoc::CryptoBackend::HashAlgorithm::SHA_224:
data = libcdoc::fromHex("302d300d06096086480165030402040500041c");
pssParams = { CKM_SHA224, CKG_MGF1_SHA224, 24 };
break;
case libcdoc::CryptoBackend::HashAlgorithm::SHA_256:
data = libcdoc::fromHex("3031300d060960864801650304020105000420");
pssParams = { CKM_SHA256, CKG_MGF1_SHA256, 32 };
break;
case libcdoc::CryptoBackend::HashAlgorithm::SHA_384:
data = libcdoc::fromHex("3041300d060960864801650304020205000430");
pssParams = { CKM_SHA384, CKG_MGF1_SHA384, 48 };
break;
case libcdoc::CryptoBackend::HashAlgorithm::SHA_512:
data = libcdoc::fromHex("3051300d060960864801650304020305000440");
pssParams = { CKM_SHA512, CKG_MGF1_SHA512, 64 };
break;
case libcdoc::CryptoBackend::HashAlgorithm::SHA_224: pssParams = { CKM_SHA224, CKG_MGF1_SHA224, 24 }; break;
case libcdoc::CryptoBackend::HashAlgorithm::SHA_256: pssParams = { CKM_SHA256, CKG_MGF1_SHA256, 32 }; break;
case libcdoc::CryptoBackend::HashAlgorithm::SHA_384: pssParams = { CKM_SHA384, CKG_MGF1_SHA384, 48 }; break;
case libcdoc::CryptoBackend::HashAlgorithm::SHA_512: pssParams = { CKM_SHA512, CKG_MGF1_SHA512, 64 }; break;
default:
break;
}
if(usePSS(idx)) {
mech = { CKM_RSA_PKCS_PSS, &pssParams, sizeof(CK_RSA_PKCS_PSS_PARAMS) };
data.clear();
d->logout();
return INVALID_PARAMS;
}
mech = { CKM_RSA_PKCS_PSS, &pssParams, sizeof(pssParams) };
}
data.insert(data.end(), digest.begin(), digest.end());

if(d->f->C_SignInit(d->session, &mech, d->key) != CKR_OK) {
d->logout();
return PKCS11_ERROR;
}
CK_ULONG size = 0;
if(d->f->C_Sign(d->session, CK_BYTE_PTR(data.data()), CK_ULONG(data.size()), nullptr, &size) != CKR_OK) {
if(d->f->C_Sign(d->session, CK_BYTE_PTR(digest.data()), CK_ULONG(digest.size()), nullptr, &size) != CKR_OK) {
d->logout();
return PKCS11_ERROR;
}
dst.resize(int(size));
if(d->f->C_Sign(d->session, CK_BYTE_PTR(data.data()), CK_ULONG(data.size()), CK_BYTE_PTR(dst.data()), &size) != CKR_OK) {
if(d->f->C_Sign(d->session, CK_BYTE_PTR(digest.data()), CK_ULONG(digest.size()), CK_BYTE_PTR(dst.data()), &size) != CKR_OK) {
d->logout();
return PKCS11_ERROR;
}
Expand Down
8 changes: 0 additions & 8 deletions cdoc/PKCS11Backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,14 +146,6 @@ struct CDOC_EXPORT PKCS11Backend : public CryptoBackend {
* @return error code or OK
*/
virtual result_t connectToKey(int idx, bool priv) { return NOT_IMPLEMENTED; };
/**
* @brief whether to use PSS RSA padding
*
* A subclass should overwrite this to inform the backend about the correct padding.
* @param idx a lock idx
* @return true if PSS padding is used
*/
virtual result_t usePSS(int idx) {return true;}

virtual result_t deriveECDH1(std::vector<uint8_t>& dst, const std::vector<uint8_t> &public_key, unsigned int idx) override;
virtual result_t decryptRSA(std::vector<uint8_t>& dst, const std::vector<uint8_t> &data, bool oaep, unsigned int idxl) override;
Expand Down
Loading
Loading