From 490ce44ccb0b7b72077126971bf46862ab713800 Mon Sep 17 00:00:00 2001 From: nganhkhoa Date: Mon, 6 Mar 2023 17:14:02 +0700 Subject: [PATCH] add active authentication (challenge/response) --- app/src/main/cpp/api.cpp | 98 ++++++++++++++++++++++++++++++++- app/src/main/cpp/api.h | 5 ++ app/src/main/cpp/native-lib.cpp | 3 + 3 files changed, 104 insertions(+), 2 deletions(-) diff --git a/app/src/main/cpp/api.cpp b/app/src/main/cpp/api.cpp index 6c06861..31a92fc 100644 --- a/app/src/main/cpp/api.cpp +++ b/app/src/main/cpp/api.cpp @@ -198,6 +198,13 @@ Connector::Response Connector::externalAuthenticate(bytes& eifd, uint64_t mifd) return sendICC(ISO7816_CLA::NO_SM, ISO7816_INS::EXTERNAL_AUTHENTICATE, 0x00, 0x00, data.size(), data); } +Connector::Response Connector::internalAuthenticate(bytes data, size_t sigLength) { + if (data.size() != 8) { + throw "Internal Authentication accepts challenge with size 8 bytes only"; + } + return sendICC(ISO7816_CLA::NO_SM, ISO7816_INS::INTERNAL_AUTHENTICATE, 0x00, 0x00, sigLength, data); +} + Connector::Response Connector::readBinaryBySFI(int sfi, int offset) { bytes t; sfi |= 0x80; @@ -549,11 +556,11 @@ void Connector::readEFSOD() { X509_get0_signature(&psig, &palg, cert); bytes signature(psig->data, psig->data + psig->length); - logBytes("signature raw %s", signature); + logBytes("certificate signature raw %s", signature); const unsigned char* sig = signature.data(); ECDSA_SIG* cert_sig; - d2i_ECDSA_SIG(&cert_sig, &sig, signature.size()); + cert_sig = d2i_ECDSA_SIG(nullptr, &sig, signature.size()); if (!cert_sig) { throw "cannot get certificate signature"; @@ -595,4 +602,91 @@ void Connector::readEFSOD() { throw "verification with CA returns false"; } } +} + +void Connector::activeAuthentication() { + const unsigned char* dg15ptr = dg15.data(); + auto pubkey = d2i_RSA_PUBKEY(nullptr, &dg15ptr, dg15.size()); + + if (!pubkey) { + throw "Cannot read pubkey"; + } + + bytes m2 = randomBytes(8); + + // 256 is hardcoded + // MRTD returns signature of size [sigLength] or of arbitrarily size if [sigLength] is 256. + auto response = internalAuthenticate(m2, 256); + auto message = response.data; + + BIGNUM* msg_number = BN_bin2bn(message.data(), message.size(), nullptr); + const BIGNUM* n = RSA_get0_n(pubkey); + const BIGNUM* e = RSA_get0_e(pubkey); + + auto ctx = BN_CTX_new(); + BIGNUM* raw_msg_number = BN_new(); + BN_mod_exp(raw_msg_number, msg_number, e, n, ctx); + BN_CTX_free(ctx); + + LOGI("pubkey n %s", BN_bn2hex(n)); + LOGI("extracted raw message %s", BN_bn2hex(raw_msg_number)); + + bytes raw_msg(BN_num_bytes(raw_msg_number)); + BN_bn2bin(raw_msg_number, raw_msg.data()); + logBytes("active signature %s", raw_msg); + + const uint8_t t = (raw_msg[raw_msg.size() - 1] == 0xbc) ? 1 : 2; + int hashlen; + if (t == 1) { + hashlen = 160; + } else { + switch (raw_msg[raw_msg.size() - 2]) { + case 0x34: + hashlen = 256; + break; + case 0x35: + hashlen = 512; + break; + case 0x36: + hashlen = 384; + break; + case 0x38: + hashlen = 224; + break; + default: + hashlen = 0; + break; + } + } + + const int k = BN_num_bits(n); + const int m1_len = ((k - hashlen - 8 * t - 4) - 4); + + // bits 01 default bit + // bit 1 partial recovery + // bit 1 end of padding + // k - hash_len - m1_len - 8t - 4 bits padding + const int pad = (2 + 1 + 1 + k - hashlen - m1_len - 8 * t - 4); + + const int m1_len_bytes = m1_len / 8; + const int pad_bytes = pad / 8; + const int hash_len_bytes = hashlen / 8; + + const int message_end = pad_bytes + m1_len_bytes; + const int hash_end = message_end + hash_len_bytes; + + const auto m1 = bytes(raw_msg.begin() + pad_bytes, raw_msg.begin() + message_end); + const auto hash = bytes(raw_msg.begin() + message_end, raw_msg.begin() + hash_end); + + bytes m1_m2; + m1_m2.insert(m1_m2.end(), m1.begin(), m1.end()); + m1_m2.insert(m1_m2.end(), m2.begin(), m2.end()); + + bytes check_hash(160 / 8); + SHA1(m1_m2.data(), m1_m2.size(), check_hash.data()); + bool verified = std::equal(hash.begin(), hash.end(), check_hash.begin()); + + logBytes("hash %s", hash); + logBytes("check hash %s", check_hash); + LOGI("active authentication verified %d", verified); } \ No newline at end of file diff --git a/app/src/main/cpp/api.h b/app/src/main/cpp/api.h index b3bd3a3..1c5d420 100644 --- a/app/src/main/cpp/api.h +++ b/app/src/main/cpp/api.h @@ -221,6 +221,7 @@ private: Connector::Response getChallenge(int challengeLen); Connector::Response externalAuthenticate(bytes& eifd, uint64_t mifd); + Connector::Response internalAuthenticate(bytes data, size_t sigLength); Connector::Response readBinaryBySFI(int sfi, int offset); Connector::Response readBinaryExt(size_t offset, size_t ne); @@ -229,8 +230,11 @@ private: bytes readFileBySFI(int sfi); bytes readBinary(size_t offset, size_t length); + std::unordered_map calculatedDigests; + bytes dg15; + public: transceive_type transceive; SecureMessaging* sm = nullptr; @@ -249,6 +253,7 @@ public: void readEFDG15(); void readEFSOD(); + void activeAuthentication(); }; #endif //CCCC_API_H diff --git a/app/src/main/cpp/native-lib.cpp b/app/src/main/cpp/native-lib.cpp index 2d89d39..599d43c 100644 --- a/app/src/main/cpp/native-lib.cpp +++ b/app/src/main/cpp/native-lib.cpp @@ -29,7 +29,10 @@ Java_com_bshield_cccc_MainActivity_initNFCScan( connector->readEFDG13(); connector->readEFDG14(); connector->readEFDG15(); + connector->readEFSOD(); + connector->activeAuthentication(); + return 1; }