Skip to content

Commit

Permalink
Derive sign and auth algorithms from certificate and add additional B…
Browse files Browse the repository at this point in the history
…elEID ATR-s

WE2-808

Signed-off-by: Raul Metsma <[email protected]>
  • Loading branch information
metsma authored and mrts committed May 31, 2024
1 parent 47d4602 commit 2d2ab20
Show file tree
Hide file tree
Showing 9 changed files with 167 additions and 194 deletions.
3 changes: 1 addition & 2 deletions include/electronic-id/electronic-id.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ class ElectronicID
LatEID,
LitEID,
HrvEID,
BelEIDV1_7,
BelEIDV1_8,
BelEID,
CzeEID,
#ifdef _WIN32
MsCryptoApiEID,
Expand Down
24 changes: 15 additions & 9 deletions src/electronic-id.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ constexpr auto constructor(const Reader& reader)
return std::make_unique<T>(reader.connectToCard());
}

template <Pkcs11ElectronicIDType value>
template <ElectronicID::Type value>
constexpr auto constructor(const Reader& /*reader*/)
{
return std::make_unique<Pkcs11ElectronicID>(value);
Expand Down Expand Up @@ -84,26 +84,32 @@ const std::map<byte_vector, ElectronicIDConstructor> SUPPORTED_ATRS {
// LitEID
{{0x3B, 0x9D, 0x18, 0x81, 0x31, 0xFC, 0x35, 0x80, 0x31, 0xC0, 0x69,
0x4D, 0x54, 0x43, 0x4F, 0x53, 0x73, 0x02, 0x05, 0x05, 0xD3},
constructor<Pkcs11ElectronicIDType::LitEIDv3>},
constructor<ElectronicID::Type::LitEID>},
// LitEID v2.0
{{0x3B, 0x9D, 0x18, 0x81, 0x31, 0xFC, 0x35, 0x80, 0x31, 0xC0, 0x69,
0x4D, 0x54, 0x43, 0x4F, 0x53, 0x73, 0x02, 0x06, 0x04, 0xD1},
constructor<Pkcs11ElectronicIDType::LitEIDv3>},
constructor<ElectronicID::Type::LitEID>},
// HrvEID
{{0x3b, 0xff, 0x13, 0x00, 0x00, 0x81, 0x31, 0xfe, 0x45, 0x00, 0x31, 0xb9, 0x64,
0x04, 0x44, 0xec, 0xc1, 0x73, 0x94, 0x01, 0x80, 0x82, 0x90, 0x00, 0x12},
constructor<Pkcs11ElectronicIDType::HrvEID>},
// BelEIDV1_7
constructor<ElectronicID::Type::HrvEID>},
// BelEID
{{0x3b, 0x98, 0x13, 0x40, 0x0a, 0xa5, 0x03, 0x01, 0x01, 0x01, 0xad, 0x13, 0x11},
constructor<Pkcs11ElectronicIDType::BelEIDV1_7>},
// BelEIDV1_8
constructor<ElectronicID::Type::BelEID>},
// BelEID
{{0x3B, 0x98, 0x94, 0x40, 0x0A, 0xA5, 0x03, 0x01, 0x01, 0x01, 0xAD, 0x13, 0x10},
constructor<ElectronicID::Type::BelEID>},
// BelEID
{{0x3B, 0x98, 0x94, 0x40, 0xFF, 0xA5, 0x03, 0x01, 0x01, 0x01, 0xAD, 0x13, 0x10},
constructor<ElectronicID::Type::BelEID>},
// BelEID - https://github.com/Fedict/eid-mw/wiki/Applet-1.8
{{0x3b, 0x7f, 0x96, 0x00, 0x00, 0x80, 0x31, 0x80, 0x65, 0xb0,
0x85, 0x04, 0x01, 0x20, 0x12, 0x0f, 0xff, 0x82, 0x90, 0x00},
constructor<Pkcs11ElectronicIDType::BelEIDV1_8>},
constructor<ElectronicID::Type::BelEID>},
// CzeEID
{{0x3b, 0x7e, 0x94, 0x00, 0x00, 0x80, 0x25, 0xd2, 0x03, 0x10, 0x01, 0x00, 0x56, 0x00, 0x00,
0x00, 0x02, 0x02, 0x00},
constructor<Pkcs11ElectronicIDType::CzeEID>},
constructor<ElectronicID::Type::CzeEID>},
};

inline std::string byteVectorToHexString(const byte_vector& bytes)
Expand Down
115 changes: 41 additions & 74 deletions src/electronic-ids/ms-cryptoapi/MsCryptoApiElectronicID.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,49 +21,60 @@
*/

#include "MsCryptoApiElectronicID.hpp"
#include "../scope.hpp"

#include <openssl/x509v3.h>
#include <openssl/err.h>
#include "../x509.hpp"

using namespace pcsc_cpp;

namespace
namespace electronic_id
{

using namespace electronic_id;
JsonWebSignatureAlgorithm MsCryptoApiElectronicID::authSignatureAlgorithm() const
{
// TODO: PS256
return getAuthAlgorithmFromCert(certData);
}

JsonWebSignatureAlgorithm getESAlgorithmFromCert(const byte_vector& cert)
byte_vector MsCryptoApiElectronicID::signWithAuthKey(const byte_vector& /* pin */,
const byte_vector& hash) const
{
const unsigned char* certPtr = cert.data();
auto x509 = SCOPE_GUARD(X509, d2i_X509(nullptr, &certPtr, long(cert.size())));
if (!x509) {
THROW(MsCryptoApiError, "Failed to create X509 object from certificate");
if (certType != CertificateType::AUTHENTICATION) {
THROW(WrongCertificateTypeError,
"This electronic ID does not support signing with the authentication key. "
"It contains a "
+ std::string(certType) + " certificate.");
}

EVP_PKEY* key = X509_get0_pubkey(x509.get());
if (EVP_PKEY_base_id(key) != EVP_PKEY_EC) {
THROW(MsCryptoApiError, "EVP_PKEY_base_id() reports non-EC key where EC key expected");
}
validateAuthHashLength(authSignatureAlgorithm(), name(), hash);

auto keyBitLength = EVP_PKEY_bits(key);
switch (keyBitLength) {
case 256:
return JsonWebSignatureAlgorithm::ES256;
case 384:
return JsonWebSignatureAlgorithm::ES384;
case 512:
case 521: // secp521r1
return JsonWebSignatureAlgorithm::ES512;
default:
THROW(MsCryptoApiError,
"EVP_PKEY_bits() returned an unsupported key size: " + std::to_string(keyBitLength));
auto signature = sign(hash, authSignatureAlgorithm().hashAlgorithm());
return std::move(signature.first);
}

const std::set<SignatureAlgorithm>& MsCryptoApiElectronicID::supportedSigningAlgorithms() const
{
return getSignAlgorithmFromCert(certData);
}

ElectronicID::Signature
MsCryptoApiElectronicID::signWithSigningKey(const byte_vector& /* pin */, const byte_vector& hash,
const HashAlgorithm hashAlgo) const
{
if (certType != CertificateType::SIGNING) {
THROW(WrongCertificateTypeError,
"This electronic ID does not support signing with the digital signature key. "
"It contains a "
+ std::string(certType) + " certificate.");
}

validateSigningHash(*this, hashAlgo, hash);

return sign(hash, hashAlgo);
}

ElectronicID::Signature sign(const byte_vector& hash, HashAlgorithm hashAlgo,
const HCRYPTPROV_OR_NCRYPT_KEY_HANDLE key, const bool isRSA)
ElectronicID::Signature MsCryptoApiElectronicID::sign(const byte_vector& hash,
HashAlgorithm hashAlgo) const
{
bool isRSA = signatureAlgo != SignatureAlgorithm::ES;
BCRYPT_PKCS1_PADDING_INFO padInfo {};
switch (hashAlgo) {
case HashAlgorithm::SHA224:
Expand Down Expand Up @@ -114,51 +125,7 @@ ElectronicID::Signature sign(const byte_vector& hash, HashAlgorithm hashAlgo,
THROW(MsCryptoApiError, "Signing failed with error: " + std::to_string(err));
}

return {signature,
SignatureAlgorithm {isRSA ? SignatureAlgorithm::RS : SignatureAlgorithm::ES, hashAlgo}};
}

} // namespace

namespace electronic_id
{

JsonWebSignatureAlgorithm MsCryptoApiElectronicID::authSignatureAlgorithm() const
{
// TODO: PS256
return isRSA() ? JsonWebSignatureAlgorithm::RS256 : getESAlgorithmFromCert(certData);
}

byte_vector MsCryptoApiElectronicID::signWithAuthKey(const byte_vector& /* pin */,
const byte_vector& hash) const
{
if (certType != CertificateType::AUTHENTICATION) {
THROW(WrongCertificateTypeError,
"This electronic ID does not support sigining with the authentication key. "
"It contains a "
+ std::string(certType) + " certificate.");
}

validateAuthHashLength(authSignatureAlgorithm(), name(), hash);

const auto signature = sign(hash, authSignatureAlgorithm().hashAlgorithm(), key, isRSA());
return signature.first;
}

ElectronicID::Signature
MsCryptoApiElectronicID::signWithSigningKey(const byte_vector& /* pin */, const byte_vector& hash,
const HashAlgorithm hashAlgo) const
{
if (certType != CertificateType::SIGNING) {
THROW(WrongCertificateTypeError,
"This electronic ID does not support sigining with the digital signature key. "
"It contains a "
+ std::string(certType) + " certificate.");
}

validateSigningHash(*this, hashAlgo, hash);

return sign(hash, hashAlgo, key, isRSA());
return {signature, {signatureAlgo, hashAlgo}};
}

} // namespace electronic_id
23 changes: 8 additions & 15 deletions src/electronic-ids/ms-cryptoapi/MsCryptoApiElectronicID.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@

#include "electronic-id/electronic-id.hpp"
#include "pcsc-cpp/pcsc-cpp-utils.hpp"
#include "../common.hpp"

#include <windows.h>
#include <wincrypt.h>
Expand All @@ -35,9 +34,8 @@ namespace electronic_id
class MsCryptoApiElectronicID : public ElectronicID
{
public:
MsCryptoApiElectronicID(PCCERT_CONTEXT certCtx, pcsc_cpp::byte_vector&& cert,
CertificateType cType, bool isRsa, HCRYPTPROV_OR_NCRYPT_KEY_HANDLE k,
bool freeK) :
MsCryptoApiElectronicID(PCCERT_CONTEXT certCtx, byte_vector&& cert, CertificateType cType,
bool isRsa, HCRYPTPROV_OR_NCRYPT_KEY_HANDLE k, bool freeK) :
ElectronicID {std::make_unique<pcsc_cpp::SmartCard>()}, certContext {certCtx},
certData {cert}, certType {cType},
// TODO: SignatureAlgorithm::PS?
Expand Down Expand Up @@ -65,7 +63,7 @@ class MsCryptoApiElectronicID : public ElectronicID
// Use the external dialog provided by the CryptoAPI cryptographic service provider.
bool providesExternalPinDialog() const override { return true; }

pcsc_cpp::byte_vector getCertificate(const CertificateType typ) const override
byte_vector getCertificate(const CertificateType typ) const override
{
if (typ != certType) {
THROW(WrongCertificateTypeError,
Expand All @@ -86,13 +84,9 @@ class MsCryptoApiElectronicID : public ElectronicID
return {uint8_t(PIN_RETRY_COUNT_PLACEHOLDER), PIN_RETRY_COUNT_PLACEHOLDER};
}

pcsc_cpp::byte_vector signWithAuthKey(const pcsc_cpp::byte_vector& pin,
const pcsc_cpp::byte_vector& hash) const override;
byte_vector signWithAuthKey(const byte_vector& pin, const byte_vector& hash) const override;

const std::set<SignatureAlgorithm>& supportedSigningAlgorithms() const override
{
return isRSA() ? RSA_SIGNATURE_ALGOS() : ELLIPTIC_CURVE_SIGNATURE_ALGOS();
}
const std::set<SignatureAlgorithm>& supportedSigningAlgorithms() const override;

PinMinMaxLength signingPinMinMaxLength() const override
{
Expand All @@ -104,8 +98,7 @@ class MsCryptoApiElectronicID : public ElectronicID
return {uint8_t(PIN_RETRY_COUNT_PLACEHOLDER), PIN_RETRY_COUNT_PLACEHOLDER};
}

Signature signWithSigningKey(const pcsc_cpp::byte_vector& pin,
const pcsc_cpp::byte_vector& hash,
Signature signWithSigningKey(const byte_vector& pin, const byte_vector& hash,
const HashAlgorithm hashAlgo) const override;

std::string name() const override
Expand All @@ -115,10 +108,10 @@ class MsCryptoApiElectronicID : public ElectronicID
}
Type type() const override { return Type::MsCryptoApiEID; }

bool isRSA() const { return signatureAlgo != SignatureAlgorithm::ES; }
ElectronicID::Signature sign(const byte_vector& hash, HashAlgorithm hashAlgo) const;

PCCERT_CONTEXT certContext;
const pcsc_cpp::byte_vector certData;
const byte_vector certData;
const CertificateType certType;
const SignatureAlgorithm signatureAlgo;
const HCRYPTPROV_OR_NCRYPT_KEY_HANDLE key;
Expand Down
10 changes: 1 addition & 9 deletions src/electronic-ids/pkcs11/PKCS11CardManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,8 @@

#include "electronic-id/electronic-id.hpp"

#include "../common.hpp"
#include "../scope.hpp"
#include "../x509.hpp"

#include <cstring>
#include <string>
#include <vector>
#include <unordered_map>
#include <algorithm>
#include <filesystem>
Expand All @@ -51,11 +46,8 @@

#define C(API, ...) Call(__func__, __FILE__, __LINE__, "C_" #API, fl->C_##API, __VA_ARGS__)

// HANDLE is captured by copy into the lambda, so the auto* function argument is unused,
// it is only required for satisfying std::unique_ptr constructor requirements.
#define SCOPE_GUARD_SESSION(HANDLE, CLOSE) \
std::unique_ptr<decltype(HANDLE), std::function<void(decltype(HANDLE)*)>>( \
&HANDLE, [HANDLE, this](auto*) { C(CLOSE, HANDLE); })
make_unique_ptr(&(HANDLE), [this](auto* h) { C(CLOSE, *h); });

namespace electronic_id
{
Expand Down
Loading

0 comments on commit 2d2ab20

Please sign in to comment.