fix: working tests

This commit is contained in:
ayman
2025-01-07 16:50:52 +05:30
parent 6a8cd77740
commit 17240f5d9f
36 changed files with 422 additions and 283 deletions

View File

@@ -40,19 +40,21 @@ export const DEFAULT_MAJORITY = '18';
// rsa_sha256_65537_3072: 384,
// rsa_sha256_3_2048: 384,
// };
export const hashAlgos = ['sha1', 'sha256', 'sha384', 'sha512'] as const;
export const hashAlgos = ['sha1', 'sha224', 'sha256', 'sha384', 'sha512'] as const;
export const MAX_PADDED_ECONTENT_LEN: Record<(typeof hashAlgos)[number], number> = {
sha1: 320,
sha224: 384,
sha256: 448,
sha384: 576,
sha512: 704,
sha384: 640,
sha512: 768,
};
export const MAX_PADDED_SIGNED_ATTR_LEN: Partial<Record<(typeof hashAlgos)[number], number>> = {
export const MAX_PADDED_SIGNED_ATTR_LEN: Record<(typeof hashAlgos)[number], number> = {
sha1: 128,
sha224: 128,
sha256: 128,
sha384: 128,
sha512: 192,
sha384: 256,
sha512: 256,
};
export const MAX_CERT_BYTES: Partial<Record<keyof typeof SignatureAlgorithmIndex, number>> = {
@@ -104,6 +106,7 @@ export enum SignatureAlgorithmIndex {
ecdsa_sha1_brainpoolP224r1_224 = 27,
ecdsa_sha256_brainpoolP224r1_224 = 28,
ecdsa_sha512_brainpoolP512r1_512 = 29,
ecdsa_sha224_brainpoolP224r1_224 = 30,
}
export const attributeToPosition = {

View File

@@ -1265,6 +1265,25 @@ jnD0AhwDAIPS8xytmOiI0MuVj3kwdnzTLdsGslSkmj8l
-----END CERTIFICATE-----
`;
export const mock_dsc_key_sha224_braipoolP224r1 = `-----BEGIN EC PRIVATE KEY-----
MGwCAQEEHD8zMUlakQzf4dhsIN/RlRKZqRRPX+y2LJj/6OWgCwYJKyQDAwIIAQEF
oTwDOgAEVhYeSwufAC+rdeIw8skbC2bwM3g7giuR+5vl0brGHgiEIaUr33msAPHz
epGlvTkSRQz+nOWMogI=
-----END EC PRIVATE KEY-----`;
export const mock_dsc_sha224_brainpoolP224r1 = `-----BEGIN CERTIFICATE-----
MIIB0DCCAX6gAwIBAgIUKS+C9XWWr12MLB1+rcVEaYGW53UwCgYIKoZIzj0EAwEw
RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNTAxMDcwNzUxMDJaFw0yNjAxMDcw
NzUxMDJaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYD
VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwUjAUBgcqhkjOPQIBBgkrJAMD
AggBAQUDOgAEVhYeSwufAC+rdeIw8skbC2bwM3g7giuR+5vl0brGHgiEIaUr33ms
APHzepGlvTkSRQz+nOWMogKjUzBRMB0GA1UdDgQWBBS7hFp/MRDFZ//5GxYHnpM+
N8mqKTAfBgNVHSMEGDAWgBS7hFp/MRDFZ//5GxYHnpM+N8mqKTAPBgNVHRMBAf8E
BTADAQH/MAoGCCqGSM49BAMBA0AAMD0CHQCT+jX3mCRjmvdXO2HKlb9faeYgKfiX
frIJV5mBAhwEqIQRW2USNItxRt1iTO69eBj/20q67UOhDgK2
-----END CERTIFICATE-----`;
export const mock_dsc_key_sha256_brainpoolP224r1 = `-----BEGIN EC PRIVATE KEY-----
MGwCAQEEHEtm6OSi3EClphbb0ovVMLNX6SCQ/ZpYsFTjlnqgCwYJKyQDAwIIAQEF
oTwDOgAEb8kcLsVLjpC1RWAjA/lRTHP2HVdW1ntmtfo1g2R6E6NkgLetsRXxc8Sn

View File

@@ -56,12 +56,15 @@ import {
mock_dsc_sha256_brainpoolP224r1,
mock_dsc_key_sha512_brainpoolP512r1,
mock_dsc_sha512_brainpoolP512r1,
mock_dsc_key_sha224_braipoolP224r1,
mock_dsc_sha224_brainpoolP224r1,
} from '../constants/mockCertificates';
import { countryCodes } from '../constants/constants';
import { parseCertificateSimple } from './certificate_parsing/parseCertificateSimple';
import { SignatureAlgorithm } from './types';
import { PublicKeyDetailsECDSA, PublicKeyDetailsRSAPSS } from './certificate_parsing/dataStructure';
import { getCurveForElliptic } from './certificate_parsing/curves';
import { createHash } from 'crypto';
function generateRandomBytes(length: number): number[] {
// Generate numbers between -128 and 127 to match the existing signed byte format
@@ -219,6 +222,10 @@ export function genMockPassportData(
privateKeyPem = mock_dsc_key_sha1_brainpoolP224r1;
dsc = mock_dsc_sha1_brainpoolP224r1;
break;
case 'ecdsa_sha224_brainpoolP224r1_224':
privateKeyPem = mock_dsc_key_sha224_braipoolP224r1;
dsc = mock_dsc_sha224_brainpoolP224r1;
break;
case 'ecdsa_sha256_brainpoolP224r1_224':
privateKeyPem = mock_dsc_key_sha256_brainpoolP224r1;
dsc = mock_dsc_sha256_brainpoolP224r1;
@@ -284,22 +291,16 @@ function sign(
);
const asn1Data = asn1.fromBER(privateKeyDer);
const privateKeyBuffer = (asn1Data.result.valueBlock as any).value[1].valueBlock.valueHexView;
// console.log('sig deets');
// console.log('pk', privateKeyBuffer);
// console.log('hashFUnction', hashAlgorithm);
// console.log('message', Buffer.from(eContent).toString('hex'));
const keyPair = ec.keyFromPrivate(privateKeyBuffer);
let md = forge.md[hashAlgorithm].create();
md.update(forge.util.binary.raw.encode(new Uint8Array(eContent)));
// let md = forge.md[hashAlgorithm].create();
// md.update(forge.util.binary.raw.encode(new Uint8Array(eContent)));
const hasher = createHash(hashAlgorithm);
const msgHash = hasher.update(new Uint8Array(eContent)).digest('hex');
// console.log('message to sign', md.digest().toHex());
const signature = keyPair.sign(md.digest().toHex(), 'hex');
// console.log(Buffer.from(signature.toDER(), 'hex').toString('hex'));
const signature = keyPair.sign(msgHash, 'hex');
const signatureBytes = Array.from(Buffer.from(signature.toDER(), 'hex'));
// console.log('sig', JSON.stringify(signatureBytes));
return signatureBytes;
} else {
const privKey = forge.pki.privateKeyFromPem(privateKeyPem);

View File

@@ -221,11 +221,12 @@ export function generateCircuitInputsProve(
);
}
// const paddingFunction =
// hashFunction == 'sha1' || hashFunction == 'sha256' ? shaPad : sha384_512Pad;
const dg1PaddingFunction =
MAX_PADDED_ECONTENT_LEN[passportMetadata.dg1HashFunction] <= 256 ? shaPad : sha384_512Pad;
passportMetadata.dg1HashFunction === 'sha1' ||
passportMetadata.dg1HashFunction === 'sha224' ||
passportMetadata.dg1HashFunction === 'sha256'
? shaPad
: sha384_512Pad;
const [eContentPadded, eContentLen] = dg1PaddingFunction(
new Uint8Array(eContent),
@@ -233,7 +234,11 @@ export function generateCircuitInputsProve(
);
const eContentPaddingFunction =
MAX_PADDED_ECONTENT_LEN[passportMetadata.eContentHashFunction] <= 256 ? shaPad : sha384_512Pad;
passportMetadata.eContentHashFunction === 'sha1' ||
passportMetadata.eContentHashFunction === 'sha224' ||
passportMetadata.eContentHashFunction === 'sha256'
? shaPad
: sha384_512Pad;
const [signedAttrPadded, signedAttrPaddedLen] = eContentPaddingFunction(
new Uint8Array(signedAttr),
MAX_PADDED_SIGNED_ATTR_LEN[passportMetadata.eContentHashFunction]

View File

@@ -2,10 +2,10 @@ import { PassportData } from '../../../common/src/utils/types';
import { findSubarrayIndex, formatMrz, hash } from './utils';
import { parseCertificateSimple } from './certificate_parsing/parseCertificateSimple';
import {
CertificateData,
PublicKeyDetailsECDSA,
PublicKeyDetailsRSA,
PublicKeyDetailsRSAPSS,
CertificateData,
PublicKeyDetailsECDSA,
PublicKeyDetailsRSA,
PublicKeyDetailsRSAPSS,
} from './certificate_parsing/dataStructure';
import { getCSCAFromSKI } from './csca';
import { hashAlgos } from '../constants/constants';
@@ -14,225 +14,227 @@ import forge from 'node-forge';
import * as asn1js from 'asn1js';
import { initElliptic } from './elliptic';
import { getCurveForElliptic } from './certificate_parsing/curves';
import { createHash } from 'crypto';
export interface PassportMetadata {
dataGroups: string;
dg1HashFunction: string;
dg1HashOffset: number;
eContentSize: number;
eContentHashFunction: string;
eContentHashOffset: number;
signedAttrSize: number;
signedAttrHashFunction: string;
signatureAlgorithm: string;
signatureAlgorithmDetails: string;
curveOrExponent: string;
signatureAlgorithmBits: number;
countryCode: string;
cscaFound: boolean;
cscaHashFunction: string;
cscaSignature: string;
cscaSignatureAlgorithmDetails: string;
cscaCurveOrExponent: string;
cscaSignatureAlgorithmBits: number;
dsc: string;
dataGroups: string;
dg1HashFunction: string;
dg1HashOffset: number;
eContentSize: number;
eContentHashFunction: string;
eContentHashOffset: number;
signedAttrSize: number;
signedAttrHashFunction: string;
signatureAlgorithm: string;
signatureAlgorithmDetails: string;
curveOrExponent: string;
signatureAlgorithmBits: number;
countryCode: string;
cscaFound: boolean;
cscaHashFunction: string;
cscaSignature: string;
cscaSignatureAlgorithmDetails: string;
cscaCurveOrExponent: string;
cscaSignatureAlgorithmBits: number;
dsc: string;
}
export function findHashSizeOfEContent(eContent: number[], signedAttr: number[]) {
for (const hashFunction of hashAlgos) {
const hashValue = hash(hashFunction, eContent);
const hashOffset = findSubarrayIndex(signedAttr, hashValue);
if (hashOffset !== -1) {
return { hashFunction, offset: hashOffset };
}
for (const hashFunction of hashAlgos) {
const hashValue = hash(hashFunction, eContent);
const hashOffset = findSubarrayIndex(signedAttr, hashValue);
if (hashOffset !== -1) {
return { hashFunction, offset: hashOffset };
}
return { hashFunction: 'unknown', offset: -1 };
}
return { hashFunction: 'unknown', offset: -1 };
}
export function findDG1HashInEContent(
mrz: string,
eContent: number[]
mrz: string,
eContent: number[]
): { hash: number[]; hashFunction: string; offset: number } | null {
const formattedMrz = formatMrz(mrz);
const formattedMrz = formatMrz(mrz);
for (const hashFunction of hashAlgos) {
const hashValue = hash(hashFunction, formattedMrz);
const normalizedHash = hashValue.map((byte) => (byte > 127 ? byte - 256 : byte));
const hashOffset = findSubarrayIndex(eContent, normalizedHash);
for (const hashFunction of hashAlgos) {
const hashValue = hash(hashFunction, formattedMrz);
const normalizedHash = hashValue.map((byte) => (byte > 127 ? byte - 256 : byte));
const hashOffset = findSubarrayIndex(eContent, normalizedHash);
if (hashOffset !== -1) {
return { hash: hashValue, hashFunction, offset: hashOffset };
}
if (hashOffset !== -1) {
return { hash: hashValue, hashFunction, offset: hashOffset };
}
return null;
}
return null;
}
export function getCountryCodeFromMrz(mrz: string): string {
return mrz.substring(2, 5);
return mrz.substring(2, 5);
}
export function getCurveOrExponent(certData: CertificateData): string {
if (certData.signatureAlgorithm === 'rsapss' || certData.signatureAlgorithm === 'rsa') {
return (certData.publicKeyDetails as PublicKeyDetailsRSA).exponent;
}
return (certData.publicKeyDetails as PublicKeyDetailsECDSA).curve;
if (certData.signatureAlgorithm === 'rsapss' || certData.signatureAlgorithm === 'rsa') {
return (certData.publicKeyDetails as PublicKeyDetailsRSA).exponent;
}
return (certData.publicKeyDetails as PublicKeyDetailsECDSA).curve;
}
export function getSimplePublicKeyDetails(certData: CertificateData): string {
interface SimplePublicKeyDetails {
exponent?: string;
curve?: string;
hashAlgorithm?: string;
saltLength?: string;
interface SimplePublicKeyDetails {
exponent?: string;
curve?: string;
hashAlgorithm?: string;
saltLength?: string;
}
const simplePublicKeyDetails: SimplePublicKeyDetails = {};
if (certData.signatureAlgorithm === 'rsapss' || certData.signatureAlgorithm === 'rsa') {
simplePublicKeyDetails.exponent = (certData.publicKeyDetails as PublicKeyDetailsRSA).exponent;
if (certData.signatureAlgorithm === 'rsapss') {
simplePublicKeyDetails.hashAlgorithm = (
certData.publicKeyDetails as PublicKeyDetailsRSAPSS
).hashAlgorithm;
simplePublicKeyDetails.saltLength = (
certData.publicKeyDetails as PublicKeyDetailsRSAPSS
).saltLength;
}
const simplePublicKeyDetails: SimplePublicKeyDetails = {};
if (certData.signatureAlgorithm === 'rsapss' || certData.signatureAlgorithm === 'rsa') {
simplePublicKeyDetails.exponent = (certData.publicKeyDetails as PublicKeyDetailsRSA).exponent;
if (certData.signatureAlgorithm === 'rsapss') {
simplePublicKeyDetails.hashAlgorithm = (
certData.publicKeyDetails as PublicKeyDetailsRSAPSS
).hashAlgorithm;
simplePublicKeyDetails.saltLength = (
certData.publicKeyDetails as PublicKeyDetailsRSAPSS
).saltLength;
}
} else if (certData.signatureAlgorithm === 'ecdsa') {
simplePublicKeyDetails.curve = (certData.publicKeyDetails as PublicKeyDetailsECDSA).curve;
}
return JSON.stringify(simplePublicKeyDetails);
} else if (certData.signatureAlgorithm === 'ecdsa') {
simplePublicKeyDetails.curve = (certData.publicKeyDetails as PublicKeyDetailsECDSA).curve;
}
return JSON.stringify(simplePublicKeyDetails);
}
export function verifySignature(passportData: PassportData, hashAlgorithm: string): boolean {
const elliptic = initElliptic();
const { dsc, signedAttr, encryptedDigest } = passportData;
const { signatureAlgorithm, publicKeyDetails } = parseCertificateSimple(dsc);
const elliptic = initElliptic();
const { dsc, signedAttr, encryptedDigest } = passportData;
const { signatureAlgorithm, publicKeyDetails } = parseCertificateSimple(dsc);
if (signatureAlgorithm === 'ecdsa') {
const certBuffer = Buffer.from(
dsc.replace(/(-----(BEGIN|END) CERTIFICATE-----|\n)/g, ''),
'base64'
);
const asn1Data = asn1js.fromBER(certBuffer);
const cert = new Certificate({ schema: asn1Data.result });
const publicKeyInfo = cert.subjectPublicKeyInfo;
const publicKeyBuffer = publicKeyInfo.subjectPublicKey.valueBlock.valueHexView;
const curveForElliptic = getCurveForElliptic((publicKeyDetails as PublicKeyDetailsECDSA).curve);
const ec = new elliptic.ec(curveForElliptic);
if (signatureAlgorithm === 'ecdsa') {
const certBuffer = Buffer.from(
dsc.replace(/(-----(BEGIN|END) CERTIFICATE-----|\n)/g, ''),
'base64'
);
const asn1Data = asn1js.fromBER(certBuffer);
const cert = new Certificate({ schema: asn1Data.result });
const publicKeyInfo = cert.subjectPublicKeyInfo;
const publicKeyBuffer = publicKeyInfo.subjectPublicKey.valueBlock.valueHexView;
const curveForElliptic = getCurveForElliptic((publicKeyDetails as PublicKeyDetailsECDSA).curve);
const ec = new elliptic.ec(curveForElliptic);
const key = ec.keyFromPublic(publicKeyBuffer);
const md = forge.md[hashAlgorithm].create();
md.update(forge.util.binary.raw.encode(new Uint8Array(signedAttr)));
const msgHash = md.digest().toHex();
const signature_crypto = Buffer.from(encryptedDigest).toString('hex');
const key = ec.keyFromPublic(publicKeyBuffer);
const hasher = createHash(hashAlgorithm);
const msgHash = hasher.update(new Uint8Array(signedAttr)).digest('hex');
const signature_crypto = Buffer.from(encryptedDigest).toString('hex');
return key.verify(msgHash, signature_crypto);
} else {
const cert = forge.pki.certificateFromPem(dsc);
const publicKey = cert.publicKey as forge.pki.rsa.PublicKey;
return key.verify(msgHash, signature_crypto);
} else {
const cert = forge.pki.certificateFromPem(dsc);
const publicKey = cert.publicKey as forge.pki.rsa.PublicKey;
try {
const md = forge.md[hashAlgorithm].create();
md.update(forge.util.binary.raw.encode(new Uint8Array(signedAttr)));
const md = forge.md[hashAlgorithm].create();
md.update(forge.util.binary.raw.encode(new Uint8Array(signedAttr)));
const signature = Buffer.from(encryptedDigest).toString('binary');
const signature = Buffer.from(encryptedDigest).toString('binary');
if (signatureAlgorithm === 'rsapss') {
try {
const pss = forge.pss.create({
md: forge.md[hashAlgorithm].create(),
mgf: forge.mgf.mgf1.create(forge.md[hashAlgorithm].create()),
saltLength: parseInt((publicKeyDetails as PublicKeyDetailsRSAPSS).saltLength),
});
return publicKey.verify(md.digest().bytes(), signature, pss);
} catch (error) {
return false;
}
} else {
return publicKey.verify(md.digest().bytes(), signature);
if (signatureAlgorithm === 'rsapss') {
try {
const pss = forge.pss.create({
md: forge.md[hashAlgorithm].create(),
mgf: forge.mgf.mgf1.create(forge.md[hashAlgorithm].create()),
saltLength: parseInt((publicKeyDetails as PublicKeyDetailsRSAPSS).saltLength),
});
return publicKey.verify(md.digest().bytes(), signature, pss);
} catch (error) {
return false;
}
} else {
return publicKey.verify(md.digest().bytes(), signature);
}
} catch (err) {
return false;
}
}
}
export function brutforceHashAlgorithm(passportData: PassportData): any {
for (const hashFunction of hashAlgos) {
if (verifySignature(passportData, hashFunction)) {
return hashFunction;
}
for (const hashFunction of hashAlgos) {
if (verifySignature(passportData, hashFunction)) {
return hashFunction;
}
return null;
}
return null;
}
export function parsePassportData(passportData: PassportData): PassportMetadata {
const dg1HashInfo = passportData.mrz
? findDG1HashInEContent(passportData.mrz, passportData.eContent)
: null;
const dg1HashInfo = passportData.mrz
? findDG1HashInEContent(passportData.mrz, passportData.eContent)
: null;
const dg1HashFunction = dg1HashInfo?.hashFunction || 'unknown';
const dg1HashOffset = dg1HashInfo?.offset || 0;
const dg1HashFunction = dg1HashInfo?.hashFunction || 'unknown';
const dg1HashOffset = dg1HashInfo?.offset || 0;
const { hashFunction: eContentHashFunction, offset: eContentHashOffset } = findHashSizeOfEContent(
passportData.eContent,
passportData.signedAttr
);
const { hashFunction: eContentHashFunction, offset: eContentHashOffset } = findHashSizeOfEContent(
passportData.eContent,
passportData.signedAttr
);
const signatureHashAlgo = brutforceHashAlgorithm(passportData);
const signatureHashAlgo = brutforceHashAlgorithm(passportData);
let parsedDsc = null;
let parsedCsca = null;
let csca = null;
let dscSignature = 'unknown';
let dscSignatureAlgorithmDetails = 'unknown';
let dscSignatureAlgorithmBits = 0;
let cscaHashFunction = 'unknown';
let cscaSignature = 'unknown';
let cscaSignatureAlgorithmDetails = 'unknown';
let cscaSignatureAlgorithmBits = 0;
let parsedDsc = null;
let parsedCsca = null;
let csca = null;
let dscSignature = 'unknown';
let dscSignatureAlgorithmDetails = 'unknown';
let dscSignatureAlgorithmBits = 0;
let cscaHashFunction = 'unknown';
let cscaSignature = 'unknown';
let cscaSignatureAlgorithmDetails = 'unknown';
let cscaSignatureAlgorithmBits = 0;
if (passportData.dsc) {
parsedDsc = parseCertificateSimple(passportData.dsc);
dscSignature = parsedDsc.signatureAlgorithm;
dscSignatureAlgorithmDetails = getSimplePublicKeyDetails(parsedDsc);
dscSignatureAlgorithmBits = parseInt(parsedDsc.publicKeyDetails?.bits || '0');
if (passportData.dsc) {
parsedDsc = parseCertificateSimple(passportData.dsc);
dscSignature = parsedDsc.signatureAlgorithm;
dscSignatureAlgorithmDetails = getSimplePublicKeyDetails(parsedDsc);
dscSignatureAlgorithmBits = parseInt(parsedDsc.publicKeyDetails?.bits || '0');
if (parsedDsc.authorityKeyIdentifier) {
try {
csca = getCSCAFromSKI(parsedDsc.authorityKeyIdentifier, true);
if (csca) {
parsedCsca = parseCertificateSimple(csca);
cscaHashFunction = parsedCsca.hashAlgorithm;
cscaSignature = parsedCsca.signatureAlgorithm;
cscaSignatureAlgorithmDetails = getSimplePublicKeyDetails(parsedCsca);
cscaSignatureAlgorithmBits = parseInt(parsedCsca.publicKeyDetails?.bits || '0');
}
} catch (error) {
}
if (parsedDsc.authorityKeyIdentifier) {
try {
csca = getCSCAFromSKI(parsedDsc.authorityKeyIdentifier, true);
if (csca) {
parsedCsca = parseCertificateSimple(csca);
cscaHashFunction = parsedCsca.hashAlgorithm;
cscaSignature = parsedCsca.signatureAlgorithm;
cscaSignatureAlgorithmDetails = getSimplePublicKeyDetails(parsedCsca);
cscaSignatureAlgorithmBits = parseInt(parsedCsca.publicKeyDetails?.bits || '0');
}
} catch (error) {}
}
}
return {
dataGroups:
passportData.dgPresents
?.toString()
.split(',')
.map((item) => item.replace('DG', ''))
.join(',') || 'None',
dg1HashFunction,
dg1HashOffset,
eContentSize: passportData.eContent?.length || 0,
eContentHashFunction,
eContentHashOffset,
signedAttrSize: passportData.signedAttr?.length || 0,
signedAttrHashFunction: signatureHashAlgo,
signatureAlgorithm: dscSignature,
signatureAlgorithmDetails: dscSignatureAlgorithmDetails,
curveOrExponent: parsedDsc ? getCurveOrExponent(parsedDsc) : 'unknown',
signatureAlgorithmBits: dscSignatureAlgorithmBits,
countryCode: passportData.mrz ? getCountryCodeFromMrz(passportData.mrz) : 'unknown',
cscaFound: !!csca,
cscaHashFunction,
cscaSignature,
cscaSignatureAlgorithmDetails,
cscaCurveOrExponent: parsedCsca ? getCurveOrExponent(parsedCsca) : 'unknown',
cscaSignatureAlgorithmBits: cscaSignatureAlgorithmBits,
dsc: passportData.dsc,
};
return {
dataGroups:
passportData.dgPresents
?.toString()
.split(',')
.map((item) => item.replace('DG', ''))
.join(',') || 'None',
dg1HashFunction,
dg1HashOffset,
eContentSize: passportData.eContent?.length || 0,
eContentHashFunction,
eContentHashOffset,
signedAttrSize: passportData.signedAttr?.length || 0,
signedAttrHashFunction: signatureHashAlgo,
signatureAlgorithm: dscSignature,
signatureAlgorithmDetails: dscSignatureAlgorithmDetails,
curveOrExponent: parsedDsc ? getCurveOrExponent(parsedDsc) : 'unknown',
signatureAlgorithmBits: dscSignatureAlgorithmBits,
countryCode: passportData.mrz ? getCountryCodeFromMrz(passportData.mrz) : 'unknown',
cscaFound: !!csca,
cscaHashFunction,
cscaSignature,
cscaSignatureAlgorithmDetails,
cscaCurveOrExponent: parsedCsca ? getCurveOrExponent(parsedCsca) : 'unknown',
cscaSignatureAlgorithmBits: cscaSignatureAlgorithmBits,
dsc: passportData.dsc,
};
}

View File

@@ -35,6 +35,7 @@ export type SignatureAlgorithm =
| 'ecdsa_sha384_brainpoolP384r1_384'
| 'ecdsa_sha512_brainpoolP384r1_384'
| 'ecdsa_sha1_brainpoolP224r1_224'
| 'ecdsa_sha224_brainpoolP224r1_224'
| 'ecdsa_sha256_brainpoolP224r1_224'
| 'ecdsa_sha512_brainpoolP512r1_512'
| 'rsapss_sha256_65537_4096';

View File

@@ -1,5 +1,5 @@
import { LeanIMT } from '@openpassport/zk-kit-lean-imt';
import { sha256 } from 'js-sha256';
import { sha224, sha256 } from 'js-sha256';
import { sha1 } from 'js-sha1';
import { sha384, sha512 } from 'js-sha512';
import { SMT } from '@openpassport/zk-kit-smt';
@@ -248,6 +248,9 @@ export function hash(hashFunction: string, bytesArray: number[]): number[] {
case 'sha1':
hashResult = sha1(unsignedBytesArray);
break;
case 'sha224':
hashResult = sha224(unsignedBytesArray);
break;
case 'sha256':
hashResult = sha256(unsignedBytesArray);
break;
@@ -323,6 +326,8 @@ export function getHashLen(hashFunction: string) {
switch (hashFunction) {
case 'sha1':
return 20;
case 'sha224':
return 28;
case 'sha256':
return 32;
case 'sha384':