add active authentication (challenge/response)

This commit is contained in:
nganhkhoa 2023-03-06 17:14:02 +07:00
parent 3b93c9ea30
commit 490ce44ccb
3 changed files with 104 additions and 2 deletions

View File

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

View File

@ -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<int, bytes> 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

View File

@ -29,7 +29,10 @@ Java_com_bshield_cccc_MainActivity_initNFCScan(
connector->readEFDG13();
connector->readEFDG14();
connector->readEFDG15();
connector->readEFSOD();
connector->activeAuthentication();
return 1;
}