basic check of data group hashes
This commit is contained in:
parent
e864041b8d
commit
499ba26d7b
@ -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
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
@ -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;
|
||||||
|
@ -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',
|
||||||
|
Loading…
Reference in New Issue
Block a user