basic check of data group hashes

This commit is contained in:
nganhkhoa 2023-03-06 10:03:46 +07:00
parent e864041b8d
commit 499ba26d7b
3 changed files with 131 additions and 11 deletions

View File

@ -9,11 +9,17 @@
#include <android/log.h> #include <android/log.h>
#include <jni.h> #include <jni.h>
#include <openssl/sha.h>
#include <openssl/pkcs7.h>
#include <openssl/objects.h>
#include <openssl/asn1t.h>
#include <openssl/asn1.h>
#include <openssl/x509.h>
#include "api.h" #include "api.h"
#include "consts.h" #include "consts.h"
#include "utils.h" #include "utils.h"
#include "des.h" #include "des.h"
#include "sha1.h"
bytes Connector::finalizeAPDU(int cla, int ins, int p1, int p2, int ne, bytes& data) { bytes Connector::finalizeAPDU(int cla, int ins, int p1, int p2, int ne, bytes& data) {
int s = data.size(); int s = data.size();
@ -211,7 +217,6 @@ Connector::Response Connector::readBinaryExt(size_t offset, size_t ne) {
return sendICC(ISO7816_CLA::NO_SM, ISO7816_INS::READ_BINARY_EXT, 0, 0, ne, data); return sendICC(ISO7816_CLA::NO_SM, ISO7816_INS::READ_BINARY_EXT, 0, 0, ne, data);
} }
Connector::Response Connector::readBinaryNormal(size_t offset, size_t toRead) { Connector::Response Connector::readBinaryNormal(size_t offset, size_t toRead) {
LOGI("Read normal offset=%d len=%d");
bytes t; bytes t;
return sendICC(ISO7816_CLA::NO_SM, ISO7816_INS::READ_BINARY, offset >> 8, offset & 0xff, toRead, t); return sendICC(ISO7816_CLA::NO_SM, ISO7816_INS::READ_BINARY, offset >> 8, offset & 0xff, toRead, t);
} }
@ -234,10 +239,10 @@ void Connector::initBAC() {
// mrz.padRight(9, '<') + mrz_check_digit // mrz.padRight(9, '<') + mrz_check_digit
// + birth yymmdd + birth_check_digit // + birth yymmdd + birth_check_digit
// + expiry yymmdd + expiry_check_digit // + expiry yymmdd + expiry_check_digit
const char dbaKeys[] = "098002079798112232311229"; const unsigned char dbaKeys[] = "098002079798112232311229";
const int dbaKeysSize = 9 + 1 + 6 + 1 + 6 + 1; const int dbaKeysSize = 9 + 1 + 6 + 1 + 6 + 1;
bytes dbaKeysSeed(20); bytes dbaKeysSeed(20);
SHA1((char*)dbaKeysSeed.data(), dbaKeys, dbaKeysSize); SHA1(dbaKeys, dbaKeysSize, dbaKeysSeed.data());
dbaKeysSeed.resize(16); dbaKeysSeed.resize(16);
const bytes Kenc = deriveKeyDesEDE(dbaKeysSeed); const bytes Kenc = deriveKeyDesEDE(dbaKeysSeed);
@ -378,31 +383,143 @@ void Connector::readEFCOM() {
} }
void Connector::readEFDG1() { void Connector::readEFDG1() {
auto content = readFileBySFI(EFDG1_SFI); auto content = readFileBySFI(EFDG1_SFI);
bytes digest(256 / 8);
SHA256(content.data(), content.size(), digest.data());
LOGI("FILE DG1 size %d", content.size()); LOGI("FILE DG1 size %d", content.size());
logBytes("FILE DG1 %s", content); logBytes("FILE DG1 sha256 %s", digest);
calculatedDigests[1] = digest;
} }
void Connector::readEFDG2() { void Connector::readEFDG2() {
auto content = readFileBySFI(EFDG2_SFI); auto content = readFileBySFI(EFDG2_SFI);
bytes digest(256 / 8);
SHA256(content.data(), content.size(), digest.data());
LOGI("FILE DG2 size %d", content.size()); LOGI("FILE DG2 size %d", content.size());
logBytes("FILE DG2 %s", content); logBytes("FILE DG2 sha256 %s", digest);
calculatedDigests[2] = digest;
} }
void Connector::readEFDG13() { void Connector::readEFDG13() {
auto content = readFileBySFI(EFDG13_SFI); auto content = readFileBySFI(EFDG13_SFI);
bytes digest(256 / 8);
SHA256(content.data(), content.size(), digest.data());
LOGI("FILE DG13 size %d", content.size()); LOGI("FILE DG13 size %d", content.size());
logBytes("FILE DG13 %s", content); logBytes("FILE DG13 sha256 %s", digest);
calculatedDigests[13] = digest;
} }
void Connector::readEFDG14() { void Connector::readEFDG14() {
auto content = readFileBySFI(EFDG14_SFI); auto content = readFileBySFI(EFDG14_SFI);
bytes digest(256 / 8);
SHA256(content.data(), content.size(), digest.data());
LOGI("FILE DG14 size %d", content.size()); LOGI("FILE DG14 size %d", content.size());
logBytes("FILE DG14 %s", content); logBytes("FILE DG14 sha256 %s", digest);
calculatedDigests[14] = digest;
} }
void Connector::readEFDG15() { void Connector::readEFDG15() {
auto content = readFileBySFI(EFDG15_SFI); auto content = readFileBySFI(EFDG15_SFI);
bytes digest(256 / 8);
SHA256(content.data(), content.size(), digest.data());
LOGI("FILE DG15 size %d", content.size()); LOGI("FILE DG15 size %d", content.size());
logBytes("FILE DG15 %s", content); logBytes("FILE DG15 sha256 %s", digest);
calculatedDigests[15] = digest;
} }
typedef struct DigestItem {
ASN1_INTEGER* dg;
ASN1_OCTET_STRING* digest;
} DigestItem;
DECLARE_ASN1_FUNCTIONS(DigestItem)
ASN1_SEQUENCE(DigestItem) = {
ASN1_SIMPLE(DigestItem, dg, ASN1_INTEGER),
ASN1_SIMPLE(DigestItem, digest, ASN1_OCTET_STRING),
} ASN1_SEQUENCE_END(DigestItem)
IMPLEMENT_ASN1_FUNCTIONS(DigestItem)
typedef struct EncapsulatedContent {
ASN1_INTEGER* v; // some dummy value i don't know
X509_ALGOR* algo;
STACK_OF(DigestItem)* digests;
} EncapsulatedContent;
DECLARE_ASN1_FUNCTIONS(EncapsulatedContent)
ASN1_SEQUENCE(EncapsulatedContent) = {
ASN1_SIMPLE(EncapsulatedContent, v, ASN1_INTEGER),
ASN1_SIMPLE(EncapsulatedContent, algo, X509_ALGOR),
ASN1_SEQUENCE_OF(EncapsulatedContent, digests, DigestItem),
} ASN1_SEQUENCE_END(EncapsulatedContent)
IMPLEMENT_ASN1_FUNCTIONS(EncapsulatedContent)
void Connector::readEFSOD() { void Connector::readEFSOD() {
auto content = readFileBySFI(EFSOD_SFI); auto content = readFileBySFI(EFSOD_SFI);
bytes digest(256 / 8);
SHA256(content.data(), content.size(), digest.data());
LOGI("FILE SOD size %d", content.size()); LOGI("FILE SOD size %d", content.size());
logBytes("FILE SOD %s", content); logBytes("FILE SOD sha256 %s", digest);
// strip first 4 bytes, tag, extended-length-bit, length 2 bytes
content.erase(content.begin(), content.begin() + 4);
auto bio = BIO_new_mem_buf(content.data(), content.size());
auto pkcs7 = d2i_PKCS7_bio(bio, nullptr);
bytes encapsulatedBytes;
{
auto d = (pkcs7->d.sign->contents)->d.other->value.octet_string;
encapsulatedBytes.insert(encapsulatedBytes.end(), d->data, d->data + d->length);
}
logBytes("FILE SOD encapsulated content %s", encapsulatedBytes);
{ // check digest hash for each data group
auto p = encapsulatedBytes.data();
auto content = d2i_EncapsulatedContent(nullptr, (const unsigned char**)&p, encapsulatedBytes.size());
if (content == nullptr) {
LOGI("encapsulated content format is wrong");
return;
}
auto digests = (OPENSSL_STACK*)content->digests;
for (size_t i = 0; i < sk_num(digests); i++) {
auto item = (DigestItem*)sk_value(digests, i);
auto dg = ASN1_INTEGER_get(item->dg);
if (dg == 3) continue;
auto digest = bytes(item->digest->data, item->digest->data + item->digest->length);
// will throw if not found in calculatedDigests
if (calculatedDigests[dg] != digest) {
throw "Digest for data group is wrong";
}
LOGI("dg%d:", dg);
logBytes("%s", digest);
}
}
bytes encapsulatedDigest(256 / 8);
SHA256(encapsulatedBytes.data(), encapsulatedBytes.size(), encapsulatedDigest.data());
logBytes("FILE SOD encapsulated digest %s", encapsulatedDigest);
auto signer = (PKCS7_SIGNER_INFO*)sk_value((OPENSSL_STACK*)pkcs7->d.sign->signer_info, 0);
auto attrs = (OPENSSL_STACK*)(signer->auth_attr);
for (size_t i = 0; i < sk_num(attrs); i++) {
auto attr = (X509_ATTRIBUTE*)sk_value(attrs, i);
auto x = X509_ATTRIBUTE_get0_type(attr, 0);
// LOGI("%d", ASN1_TYPE_get(x));
if (ASN1_TYPE_get(x) == 4) {
auto p = x->value.octet_string;
auto pp = bytes(p->data, p->data + p->length);
logBytes("%s", pp);
if (pp != encapsulatedDigest) {
throw "Encapsulated digest check with attribute data wrong";
}
}
}
{ // now use openssl to verify with no CA
}
{ // extract certificate and check with CA pubkey
}
} }

View File

@ -7,6 +7,7 @@
#include <vector> #include <vector>
#include <stdint.h> #include <stdint.h>
#include <unordered_map>
#include "utils.h" #include "utils.h"
#include "des.h" #include "des.h"
@ -228,6 +229,8 @@ private:
bytes readFileBySFI(int sfi); bytes readFileBySFI(int sfi);
bytes readBinary(size_t offset, size_t length); bytes readBinary(size_t offset, size_t length);
std::unordered_map<int, bytes> calculatedDigests;
public: public:
transceive_type transceive; transceive_type transceive;
SecureMessaging* sm = nullptr; SecureMessaging* sm = nullptr;

View File

@ -34,7 +34,7 @@ inline bytes randomBytes(size_t length) {
return data; return data;
} }
inline void logBytes(char* msg, const bytes& data) { inline void logBytes(const char* msg, const bytes& data) {
unsigned char charmap[] = { unsigned char charmap[] = {
'0', '1', '2', '3', '0', '1', '2', '3',
'4', '5', '6', '7', '4', '5', '6', '7',