From 2ddc12f441325ae1cad6183bea8be53b5a29ed76 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Wed, 1 Jan 2025 15:04:40 +0100 Subject: [PATCH 1/8] fix ecdsa certificate parsing for non explicits parameters certificates --- .../src/utils/certificate_parsing/curves.ts | 23 +++++++------------ .../parseCertificateSimple.ts | 16 ++++++++++++- common/src/utils/genMockPassportData.ts | 4 ++-- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/common/src/utils/certificate_parsing/curves.ts b/common/src/utils/certificate_parsing/curves.ts index f1cc0c75..de23402d 100644 --- a/common/src/utils/certificate_parsing/curves.ts +++ b/common/src/utils/certificate_parsing/curves.ts @@ -1,4 +1,3 @@ - export interface StandardCurve { name: string; p: string; @@ -11,7 +10,7 @@ export interface StandardCurve { export const standardCurves: StandardCurve[] = [ { - name: "secp256r1", + name: "ECDSA_P256", p: "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", a: "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", b: "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", @@ -20,7 +19,7 @@ export const standardCurves: StandardCurve[] = [ h: "01" }, { - name: "secp384r1", + name: "ECDSA_P384", p: "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF", a: "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC", b: "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF", @@ -29,15 +28,14 @@ export const standardCurves: StandardCurve[] = [ h: "01" }, { - name: "secp521r1", + name: "ECDSA_P521", p: "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", a: "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC", b: "0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", G: "0400C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650", n: "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", h: "01" - } - , + }, { name: "brainpoolP224r1", p: "d7c134aa264366862a18302575d1d787b09f075797da89f57ec8c0ff", @@ -108,22 +106,17 @@ export function identifyCurve(params: any): string { export function getECDSACurveBits(curveName: string): string { const curveBits: { [key: string]: number } = { - 'secp256r1': 256, - 'secp384r1': 384, - 'secp521r1': 521, + 'ECDSA_P256': 256, + 'ECDSA_P384': 384, + 'ECDSA_P521': 521, 'brainpoolP224r1': 224, 'brainpoolP256r1': 256, 'brainpoolP384r1': 384, - 'brainpoolP512r1': 512, - 'secp256r1 (NIST P-256)': 256, - 'secp384r1 (NIST P-384)': 384, - 'secp521r1 (NIST P-521)': 521, - + 'brainpoolP512r1': 512 }; if (curveName in curveBits) { return curveBits[curveName].toString(); } console.log('\x1b[31m%s\x1b[0m', `curve name ${curveName} not found in curveBits`); return "unknown"; - } \ No newline at end of file diff --git a/common/src/utils/certificate_parsing/parseCertificateSimple.ts b/common/src/utils/certificate_parsing/parseCertificateSimple.ts index d5cb40c7..f3b18442 100644 --- a/common/src/utils/certificate_parsing/parseCertificateSimple.ts +++ b/common/src/utils/certificate_parsing/parseCertificateSimple.ts @@ -176,6 +176,20 @@ export function getParamsECDSA(cert: Certificate): PublicKeyDetailsECDSA { return { curve: 'Unknown', params: {} as StandardCurve, bits: 'Unknown' }; } + // Add this check for named curves + if (algorithmParams instanceof asn1js.ObjectIdentifier) { + // Get the curve name from the OID + const curveOid = algorithmParams.valueBlock.toString(); + // You might want to add a mapping of OIDs to curve names + const curveName = getFriendlyName(curveOid) || 'secp256k1'; // Default to secp256k1 if unknown + return { + curve: curveName, + params: {} as StandardCurve, // Empty params since we're using a named curve + bits: getECDSACurveBits(curveName) + }; + } + + // Original code for explicit parameters const params = asn1js.fromBER(algorithmParams.valueBeforeDecodeView).result; const valueBlock: any = params.valueBlock; @@ -221,7 +235,7 @@ export function getParamsECDSA(cert: Certificate): PublicKeyDetailsECDSA { else { curveParams.h = '01'; } - + console.log(cert); const identifiedCurve = identifyCurve(curveParams); return { curve: identifiedCurve, params: curveParams, bits: getECDSACurveBits(identifiedCurve) }; } else { diff --git a/common/src/utils/genMockPassportData.ts b/common/src/utils/genMockPassportData.ts index 3089aff1..232b406b 100644 --- a/common/src/utils/genMockPassportData.ts +++ b/common/src/utils/genMockPassportData.ts @@ -165,10 +165,8 @@ export function genMockPassportData( dsc = mock_dsc_sha256_rsapss_65537_4096; break; } - console.log('dsc', dsc); const parsedDsc = parseCertificateSimple(dsc); const hashAlgorithm = parsedDsc.hashAlgorithm; - console.log('parsedDsc:', parsedDsc); const mrzHash = hash(hashAlgorithm, formatMrz(mrz)); @@ -227,6 +225,8 @@ function sign(privateKeyPem: string, dsc: string, eContent: number[]): number[] md.update(forge.util.binary.raw.encode(new Uint8Array(eContent))); const signature = keyPair.sign(md.digest().toHex(), 'hex'); const signatureBytes = Array.from(Buffer.from(signature.toDER(), 'hex')); + console.log('signatureBytes', signatureBytes); + console.log('signatureBytesLength', signatureBytes.length); return signatureBytes; } else { From ae3bc6884e1e380cadb319b154acde8fcbe7d258 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Wed, 1 Jan 2025 15:39:48 +0100 Subject: [PATCH 2/8] fix genMockPassportData for ecdsa --- .../src/utils/certificate_parsing/curves.ts | 16 ++++++++++++++ common/src/utils/genMockPassportData.ts | 22 +++++++++++++------ 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/common/src/utils/certificate_parsing/curves.ts b/common/src/utils/certificate_parsing/curves.ts index de23402d..44fe79a5 100644 --- a/common/src/utils/certificate_parsing/curves.ts +++ b/common/src/utils/certificate_parsing/curves.ts @@ -119,4 +119,20 @@ export function getECDSACurveBits(curveName: string): string { } console.log('\x1b[31m%s\x1b[0m', `curve name ${curveName} not found in curveBits`); return "unknown"; +} +export function getCurveForElliptic(curveName: string): string { + const curves = { + ECDSA_P256: 'p256', + ECDSA_P384: 'p384', + ECDSA_P521: 'p521', + brainpoolP224r1: 'brainpoolP224r1', + brainpoolP256r1: 'brainpoolP256r1', + brainpoolP384r1: 'brainpoolP384r1', + }; + + if (!curves[curveName]) { + throw new Error('Invalid curve: ' + curveName); + } + + return curves[curveName]; } \ No newline at end of file diff --git a/common/src/utils/genMockPassportData.ts b/common/src/utils/genMockPassportData.ts index 232b406b..336a8bec 100644 --- a/common/src/utils/genMockPassportData.ts +++ b/common/src/utils/genMockPassportData.ts @@ -41,6 +41,7 @@ import { countryCodes } from '../constants/constants'; import { parseCertificateSimple } from './certificate_parsing/parseCertificateSimple'; import { SignatureAlgorithm } from './types'; import { PublicKeyDetailsECDSA } from './certificate_parsing/dataStructure'; +import { getCurveForElliptic } from './certificate_parsing/curves'; export function genMockPassportData( signatureType: SignatureAlgorithm, nationality: keyof typeof countryCodes, @@ -196,6 +197,7 @@ export function genMockPassportData( function sign(privateKeyPem: string, dsc: string, eContent: number[]): number[] { const { signatureAlgorithm, hashAlgorithm, publicKeyDetails } = parseCertificateSimple(dsc); + const curve = (publicKeyDetails as PublicKeyDetailsECDSA).curve; if (signatureAlgorithm === 'rsapss') { const privateKey = forge.pki.privateKeyFromPem(privateKeyPem); @@ -209,7 +211,7 @@ function sign(privateKeyPem: string, dsc: string, eContent: number[]): number[] const signatureBytes = privateKey.sign(md, pss); return Array.from(signatureBytes, (c: string) => c.charCodeAt(0)); } else if (signatureAlgorithm === 'ecdsa') { - const curveForElliptic = (publicKeyDetails as PublicKeyDetailsECDSA).curve === 'secp256r1' ? 'p256' : 'p384'; + let curveForElliptic = getCurveForElliptic(curve); const ec = new elliptic.ec(curveForElliptic); const privateKeyDer = Buffer.from( @@ -218,22 +220,28 @@ function sign(privateKeyPem: string, dsc: string, eContent: number[]): number[] ); 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); - - const md = hashAlgorithm === 'sha1' ? forge.md.sha1.create() : forge.md.sha256.create(); + let md = forge.md[hashAlgorithm].create(); md.update(forge.util.binary.raw.encode(new Uint8Array(eContent))); + + 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 signatureBytes = Array.from(Buffer.from(signature.toDER(), 'hex')); - console.log('signatureBytes', signatureBytes); - console.log('signatureBytesLength', signatureBytes.length); + + console.log('sig', JSON.stringify(signatureBytes)); return signatureBytes; } else { const privKey = forge.pki.privateKeyFromPem(privateKeyPem); - const md = hashAlgorithm === 'sha1' ? forge.md.sha1.create() : forge.md.sha256.create(); + const md = forge.md[hashAlgorithm].create(); md.update(forge.util.binary.raw.encode(new Uint8Array(eContent))); const forgeSignature = privKey.sign(md); return Array.from(forgeSignature, (c: string) => c.charCodeAt(0)); } -} +} \ No newline at end of file From dd25996b576e9a4df1e3e4c3001ea198d7b81473 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Wed, 1 Jan 2025 16:49:49 +0100 Subject: [PATCH 3/8] clean certificate parsing library --- app/src/screens/ProveScreen.tsx | 14 +- app/src/utils/qrCode.ts | 4 +- circuits/tests/dsc.test.ts | 2 +- circuits/tests/prove.test.ts | 7 +- .../src/utils/certificate_parsing/curves.ts | 21 +- .../certificate_parsing/dataStructure.ts | 2 + common/src/utils/certificate_parsing/oids.ts | 13 +- .../certificate_parsing/parseCertificate.ts | 1 - .../parseCertificateSimple.ts | 204 ++++++++---- common/src/utils/certificates/certificates.ts | 111 ------- common/src/utils/certificates/curves.ts | 123 -------- .../src/utils/certificates/dataStructure.ts | 40 --- .../utils/certificates/handleCertificate.ts | 291 ------------------ .../utils/certificates/publicKeyDetails.ts | 252 --------------- common/src/utils/genMockPassportData.ts | 1 - common/src/utils/generateInputs.ts | 29 +- common/src/utils/openPassportAttestation.ts | 1 - common/src/utils/pubkeyTree.ts | 62 ++-- common/tests/genMockPassportData.test.ts | 44 ++- registry/src/buildMapJson.ts | 4 +- registry/src/parseData.ts | 4 +- registry/src/pushToDb.ts | 2 +- .../src/utils/certificateParsing/curves.ts | 129 -------- .../utils/certificateParsing/dataStructure.ts | 34 -- registry/src/utils/certificateParsing/oids.ts | 127 -------- .../certificateParsing/parseCertificate.ts | 202 ------------ .../src/utils/certificateParsing/utils.ts | 31 -- sdk/core/src/AttestationVerifier.ts | 8 +- sdk/core/utils/utils.ts | 2 +- 29 files changed, 279 insertions(+), 1486 deletions(-) delete mode 100644 common/src/utils/certificates/certificates.ts delete mode 100644 common/src/utils/certificates/curves.ts delete mode 100644 common/src/utils/certificates/dataStructure.ts delete mode 100644 common/src/utils/certificates/handleCertificate.ts delete mode 100644 common/src/utils/certificates/publicKeyDetails.ts delete mode 100644 registry/src/utils/certificateParsing/curves.ts delete mode 100644 registry/src/utils/certificateParsing/dataStructure.ts delete mode 100644 registry/src/utils/certificateParsing/oids.ts delete mode 100644 registry/src/utils/certificateParsing/parseCertificate.ts delete mode 100644 registry/src/utils/certificateParsing/utils.ts diff --git a/app/src/screens/ProveScreen.tsx b/app/src/screens/ProveScreen.tsx index 89f04eab..03963bcd 100644 --- a/app/src/screens/ProveScreen.tsx +++ b/app/src/screens/ProveScreen.tsx @@ -9,7 +9,7 @@ import { DisclosureOptions, OpenPassportApp } from '../../../common/src/utils/ap import CustomButton from '../components/CustomButton'; import { generateProof } from '../utils/prover'; import io, { Socket } from 'socket.io-client'; -import { getCircuitNameOld, parseCertificate } from '../../../common/src/utils/certificates/handleCertificate'; +import { getCircuitNameOld, parseCertificateSimple } from '../../../common/src/utils/certificate_parsing/parseCertificateSimple'; import { CircuitName } from '../utils/zkeyDownload'; import { generateCircuitInputsInApp } from '../utils/generateInputsInApp'; import { buildAttestation } from '../../../common/src/utils/openPassportAttestation'; @@ -43,9 +43,9 @@ const ProveScreen: React.FC = ({ setSheetRegisterIsOpen }) => const [socket, setSocket] = useState(null); const [isConnecting, setIsConnecting] = useState(false); - const { signatureAlgorithm, hashFunction, authorityKeyIdentifier } = parseCertificate(passportData.dsc); + const { signatureAlgorithm, hashAlgorithm, authorityKeyIdentifier } = parseCertificateSimple(passportData.dsc); const { secret, dscSecret } = useUserStore.getState(); - const circuitName = getCircuitNameOld(selectedApp.mode, signatureAlgorithm, hashFunction); + const circuitName = getCircuitNameOld(selectedApp.mode, signatureAlgorithm, hashAlgorithm); const waitForSocketConnection = (socket: Socket): Promise => { return new Promise((resolve) => { @@ -165,18 +165,18 @@ const ProveScreen: React.FC = ({ setSheetRegisterIsOpen }) => ) ]); const cscaPem = getCSCAFromSKI(authorityKeyIdentifier, DEVELOPMENT_MODE); - const { signatureAlgorithm: signatureAlgorithmDsc } = parseCertificate(cscaPem); + const { signatureAlgorithm: signatureAlgorithmDsc } = parseCertificateSimple(cscaPem); attestation = buildAttestation({ mode: selectedApp.mode, proof: proof.proof, publicSignals: proof.publicSignals, signatureAlgorithm: signatureAlgorithm, - hashFunction: hashFunction, + hashFunction: hashAlgorithm, userIdType: selectedApp.userIdType, dscProof: (dscProof as any).proof, dscPublicSignals: (dscProof as any).pub_signals, signatureAlgorithmDsc: signatureAlgorithmDsc, - hashFunctionDsc: hashFunction, + hashFunctionDsc: hashAlgorithm, }); break; default: @@ -190,7 +190,7 @@ const ProveScreen: React.FC = ({ setSheetRegisterIsOpen }) => proof: proof.proof, publicSignals: proof.publicSignals, signatureAlgorithm: signatureAlgorithm, - hashFunction: hashFunction, + hashFunction: hashAlgorithm, dsc: passportData.dsc, }); break; diff --git a/app/src/utils/qrCode.ts b/app/src/utils/qrCode.ts index 12d4fffa..df529771 100644 --- a/app/src/utils/qrCode.ts +++ b/app/src/utils/qrCode.ts @@ -1,14 +1,12 @@ import { NativeModules, Platform, Linking } from "react-native"; // import { AppType, reconstructAppType } from "../../../common/src/utils/appType"; import useNavigationStore from '../stores/navigationStore'; -import { getCircuitName, getCircuitNameOld, parseDSC } from "../../../common/src/utils/certificates/handleCertificate"; import useUserStore from "../stores/userStore"; import { downloadZkey } from "./zkeyDownload"; import msgpack from "msgpack-lite"; import pako from "pako"; import { Mode, OpenPassportApp } from "../../../common/src/utils/appType"; -import { parseCertificateSimple } from "../../../common/src/utils/certificate_parsing/parseCertificateSimple"; - +import { getCircuitNameOld, parseCertificateSimple } from "../../../common/src/utils/certificate_parsing/parseCertificateSimple"; const parseUrlParams = (url: string): Map => { const [, queryString] = url.split('?'); const params = new Map(); diff --git a/circuits/tests/dsc.test.ts b/circuits/tests/dsc.test.ts index e262bb7a..d84a8beb 100644 --- a/circuits/tests/dsc.test.ts +++ b/circuits/tests/dsc.test.ts @@ -11,7 +11,7 @@ import { mock_csca_sha256_rsapss_4096, } from '../../common/src/constants/mockCertificates'; import { max_cert_bytes } from '../../common/src/constants/constants'; -import { getCircuitName } from '../../common/src/utils/certificates/handleCertificate'; +import { getCircuitName } from '../../common/src/utils/certificate_parsing/parseCertificateSimple'; const sigAlgs = [ { sigAlg: 'rsa', hashFunction: 'sha256', domainParameter: '65537', keyLength: '4096' }, diff --git a/circuits/tests/prove.test.ts b/circuits/tests/prove.test.ts index 520c0a92..efbb02ed 100644 --- a/circuits/tests/prove.test.ts +++ b/circuits/tests/prove.test.ts @@ -4,16 +4,15 @@ import path from 'path'; import { wasm as wasm_tester } from 'circom_tester'; import { generateCircuitInputsProve } from '../../common/src/utils/generateInputs'; import { genMockPassportData } from '../../common/src/utils/genMockPassportData'; -import { getCircuitName } from '../../common/src/utils/certificates/handleCertificate'; import { SignatureAlgorithm } from '../../common/src/utils/types'; import crypto from 'crypto'; import { poseidon2 } from 'poseidon-lite'; import { SMT } from '@openpassport/zk-kit-smt'; import namejson from '../../common/ofacdata/outputs/nameSMT.json'; - +import { getCircuitName } from '../../common/src/utils/certificate_parsing/parseCertificateSimple'; const sigAlgs = [ - { sigAlg: 'rsapss', hashFunction: 'sha256', domainParameter: '3', keyLength: '3072' }, - { sigAlg: 'rsa', hashFunction: 'sha256', domainParameter: '65537', keyLength: '3072' }, + // { sigAlg: 'rsapss', hashFunction: 'sha256', domainParameter: '3', keyLength: '3072' }, + // { sigAlg: 'rsa', hashFunction: 'sha256', domainParameter: '65537', keyLength: '3072' }, { sigAlg: 'ecdsa', hashFunction: 'sha1', domainParameter: 'secp256r1', keyLength: '256' }, ]; diff --git a/common/src/utils/certificate_parsing/curves.ts b/common/src/utils/certificate_parsing/curves.ts index 44fe79a5..a1eec6eb 100644 --- a/common/src/utils/certificate_parsing/curves.ts +++ b/common/src/utils/certificate_parsing/curves.ts @@ -10,7 +10,7 @@ export interface StandardCurve { export const standardCurves: StandardCurve[] = [ { - name: "ECDSA_P256", + name: "secp256r1", p: "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", a: "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", b: "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", @@ -19,7 +19,7 @@ export const standardCurves: StandardCurve[] = [ h: "01" }, { - name: "ECDSA_P384", + name: "secp384r1", p: "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF", a: "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC", b: "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF", @@ -28,7 +28,7 @@ export const standardCurves: StandardCurve[] = [ h: "01" }, { - name: "ECDSA_P521", + name: "secp521r1", p: "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", a: "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC", b: "0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", @@ -106,9 +106,10 @@ export function identifyCurve(params: any): string { export function getECDSACurveBits(curveName: string): string { const curveBits: { [key: string]: number } = { - 'ECDSA_P256': 256, - 'ECDSA_P384': 384, - 'ECDSA_P521': 521, + 'secp224r1': 224, + 'secp256r1': 256, + 'secp384r1': 384, + 'secp521r1': 521, 'brainpoolP224r1': 224, 'brainpoolP256r1': 256, 'brainpoolP384r1': 384, @@ -122,12 +123,14 @@ export function getECDSACurveBits(curveName: string): string { } export function getCurveForElliptic(curveName: string): string { const curves = { - ECDSA_P256: 'p256', - ECDSA_P384: 'p384', - ECDSA_P521: 'p521', + secp224r1: 'p224', + secp256r1: 'p256', + secp384r1: 'p384', + secp521r1: 'p521', brainpoolP224r1: 'brainpoolP224r1', brainpoolP256r1: 'brainpoolP256r1', brainpoolP384r1: 'brainpoolP384r1', + brainpoolP512r1: 'brainpoolP512r1', }; if (!curves[curveName]) { diff --git a/common/src/utils/certificate_parsing/dataStructure.ts b/common/src/utils/certificate_parsing/dataStructure.ts index 6d1d8e87..7cad2c1b 100644 --- a/common/src/utils/certificate_parsing/dataStructure.ts +++ b/common/src/utils/certificate_parsing/dataStructure.ts @@ -29,6 +29,8 @@ export interface PublicKeyDetailsRSAPSS extends PublicKeyDetailsRSA { } export interface PublicKeyDetailsECDSA { + x: string; + y: string; curve: string; params: StandardCurve; bits: string; diff --git a/common/src/utils/certificate_parsing/oids.ts b/common/src/utils/certificate_parsing/oids.ts index 231b2b2b..a9bb58b5 100644 --- a/common/src/utils/certificate_parsing/oids.ts +++ b/common/src/utils/certificate_parsing/oids.ts @@ -104,8 +104,19 @@ export const oidMap: { [key: string]: string } = { "1.2.840.10045.3.1.6": "x962P239v3", }; +export const mapSecpCurves: { [key: string]: string } = { + "ECDSA_224": "secp224r1", + "ECDSA_P256": "secp256r1", + "ECDSA_P384": "secp384r1", + "ECDSA_P521": "secp521r1", +} + +function getFriendlyNameSecpCurves(friendlyName: string): string { + return mapSecpCurves[friendlyName] || friendlyName; +} + export function getFriendlyName(oid: string): string { - return oidMap[oid] || "Unknown Algorithm"; + return getFriendlyNameSecpCurves(oidMap[oid]) || "Unknown Algorithm"; } export function extractHashFunction(friendlyName: string): string { diff --git a/common/src/utils/certificate_parsing/parseCertificate.ts b/common/src/utils/certificate_parsing/parseCertificate.ts index 7f3c3e25..acad59f3 100644 --- a/common/src/utils/certificate_parsing/parseCertificate.ts +++ b/common/src/utils/certificate_parsing/parseCertificate.ts @@ -6,7 +6,6 @@ import { getECDSACurveBits, identifyCurve, StandardCurve } from "./curves"; import { getIssuerCountryCode, getSubjectKeyIdentifier } from "./utils"; import fs from 'fs'; import { execSync } from 'child_process'; -import { getAuthorityKeyIdentifier } from "../certificates/handleCertificate"; import { parseCertificateSimple } from "./parseCertificateSimple"; export function parseCertificate(pem: string, fileName: string): any { let certificateData: CertificateData = { diff --git a/common/src/utils/certificate_parsing/parseCertificateSimple.ts b/common/src/utils/certificate_parsing/parseCertificateSimple.ts index f3b18442..cee03516 100644 --- a/common/src/utils/certificate_parsing/parseCertificateSimple.ts +++ b/common/src/utils/certificate_parsing/parseCertificateSimple.ts @@ -2,9 +2,11 @@ import * as asn1js from "asn1js"; import { Certificate, RSAPublicKey, RSASSAPSSParams } from "pkijs"; import { extractHashFunction, getFriendlyName } from "./oids"; import { CertificateData, PublicKeyDetailsECDSA, PublicKeyDetailsRSA, PublicKeyDetailsRSAPSS } from "./dataStructure"; -import { getECDSACurveBits, identifyCurve, StandardCurve } from "./curves"; +import { getCurveForElliptic, getECDSACurveBits, identifyCurve, StandardCurve } from "./curves"; import { getIssuerCountryCode, getSubjectKeyIdentifier } from "./utils"; -import { getAuthorityKeyIdentifier } from "../certificates/handleCertificate"; +import elliptic from 'elliptic'; +import { circuitNameFromMode } from "../../constants/constants"; +import { Mode } from "../appType"; export function parseCertificateSimple(pem: string): CertificateData { @@ -170,84 +172,160 @@ function getParamsRSAPSS2(cert: Certificate): PublicKeyDetailsRSAPSS { export function getParamsECDSA(cert: Certificate): PublicKeyDetailsECDSA { try { + const algorithmParams = cert.subjectPublicKeyInfo.algorithm.algorithmParams; + if (!algorithmParams) { console.log('No algorithm params found'); - return { curve: 'Unknown', params: {} as StandardCurve, bits: 'Unknown' }; + return { curve: 'Unknown', params: {} as StandardCurve, bits: 'Unknown', x: 'Unknown', y: 'Unknown' }; } - // Add this check for named curves + let curveName, bits, x, y = 'Unknown'; + let curveParams: StandardCurve = {} as StandardCurve; + + // Try to get the curve name from the OID if (algorithmParams instanceof asn1js.ObjectIdentifier) { - // Get the curve name from the OID const curveOid = algorithmParams.valueBlock.toString(); - // You might want to add a mapping of OIDs to curve names - const curveName = getFriendlyName(curveOid) || 'secp256k1'; // Default to secp256k1 if unknown - return { - curve: curveName, - params: {} as StandardCurve, // Empty params since we're using a named curve - bits: getECDSACurveBits(curveName) - }; + curveName = getFriendlyName(curveOid) || 'Unknown'; + bits = getECDSACurveBits(curveName); } - // Original code for explicit parameters - const params = asn1js.fromBER(algorithmParams.valueBeforeDecodeView).result; - const valueBlock: any = params.valueBlock; - - if (valueBlock.value && valueBlock.value.length >= 5) { - const curveParams: StandardCurve = {} as StandardCurve; - // Field ID (index 1) - const fieldId = valueBlock.value[1]; - if (fieldId && fieldId.valueBlock && fieldId.valueBlock.value) { - const fieldType = fieldId.valueBlock.value[0]; - const prime = fieldId.valueBlock.value[1]; - //curveParams.fieldType = fieldType.valueBlock.toString(); - curveParams.p = Buffer.from(prime.valueBlock.valueHexView).toString('hex'); - } + // If the OID of the curve is not present, we try to get the curve parameters and identify the curve from them + else { + const params = asn1js.fromBER(algorithmParams.valueBeforeDecodeView).result; + const valueBlock: any = params.valueBlock; + if (valueBlock.value && valueBlock.value.length >= 5) { + const curveParams: StandardCurve = {} as StandardCurve; + // Field ID (index 1) + const fieldId = valueBlock.value[1]; + if (fieldId && fieldId.valueBlock && fieldId.valueBlock.value) { + const fieldType = fieldId.valueBlock.value[0]; + const prime = fieldId.valueBlock.value[1]; + //curveParams.fieldType = fieldType.valueBlock.toString(); + curveParams.p = Buffer.from(prime.valueBlock.valueHexView).toString('hex'); + } - // Curve Coefficients (index 2) - const curveCoefficients = valueBlock.value[2]; - if (curveCoefficients && curveCoefficients.valueBlock && curveCoefficients.valueBlock.value) { - const a = curveCoefficients.valueBlock.value[0]; - const b = curveCoefficients.valueBlock.value[1]; - curveParams.a = Buffer.from(a.valueBlock.valueHexView).toString('hex'); - curveParams.b = Buffer.from(b.valueBlock.valueHexView).toString('hex'); - } + // Curve Coefficients (index 2) + const curveCoefficients = valueBlock.value[2]; + if (curveCoefficients && curveCoefficients.valueBlock && curveCoefficients.valueBlock.value) { + const a = curveCoefficients.valueBlock.value[0]; + const b = curveCoefficients.valueBlock.value[1]; + curveParams.a = Buffer.from(a.valueBlock.valueHexView).toString('hex'); + curveParams.b = Buffer.from(b.valueBlock.valueHexView).toString('hex'); + } - // Base Point G (index 3) - const basePoint = valueBlock.value[3]; - if (basePoint && basePoint.valueBlock) { - curveParams.G = Buffer.from(basePoint.valueBlock.valueHexView).toString('hex'); - } + // Base Point G (index 3) + const basePoint = valueBlock.value[3]; + if (basePoint && basePoint.valueBlock) { + curveParams.G = Buffer.from(basePoint.valueBlock.valueHexView).toString('hex'); + } - // Order n (index 4) - const order = valueBlock.value[4]; - if (order && order.valueBlock) { - curveParams.n = Buffer.from(order.valueBlock.valueHexView).toString('hex'); - } + // Order n (index 4) + const order = valueBlock.value[4]; + if (order && order.valueBlock) { + curveParams.n = Buffer.from(order.valueBlock.valueHexView).toString('hex'); + } - if (valueBlock.value.length >= 6) { - // Cofactor h (index 5) - const cofactor = valueBlock.value[5]; - if (cofactor && cofactor.valueBlock) { - curveParams.h = Buffer.from(cofactor.valueBlock.valueHexView).toString('hex'); + if (valueBlock.value.length >= 6) { + // Cofactor h (index 5) + const cofactor = valueBlock.value[5]; + if (cofactor && cofactor.valueBlock) { + curveParams.h = Buffer.from(cofactor.valueBlock.valueHexView).toString('hex'); + } + } + else { + curveParams.h = '01'; + } + const identifiedCurve = identifyCurve(curveParams); + curveName = identifiedCurve; + bits = getECDSACurveBits(curveName); + } else { + if (valueBlock.value) { + console.log(valueBlock.value); + } + else { + console.log('No value block found'); } } - else { - curveParams.h = '01'; - } - console.log(cert); - const identifiedCurve = identifyCurve(curveParams); - return { curve: identifiedCurve, params: curveParams, bits: getECDSACurveBits(identifiedCurve) }; - } else { - if (valueBlock.value) { - console.log(valueBlock.value); - } - else { - console.log('No value block found'); - } } + + // Get the public key x and y parameters + const publicKeyBuffer = cert.subjectPublicKeyInfo.subjectPublicKey.valueBlock.valueHexView; + if (publicKeyBuffer && curveName !== 'Unknown') { + const ec = new elliptic.ec(getCurveForElliptic(curveName)); + const key = ec.keyFromPublic(publicKeyBuffer); + x = key.getPublic().getX().toString('hex'); + y = key.getPublic().getY().toString('hex'); + } + + return { curve: curveName, params: curveParams, bits: bits, x: x, y: y }; + + } catch (error) { console.error('Error parsing EC parameters:', error); - return { curve: 'Error', params: {} as StandardCurve, bits: 'Unknown' }; + return { curve: 'Error', params: {} as StandardCurve, bits: 'Unknown', x: 'Unknown', y: 'Unknown' }; + } +} + +export const getAuthorityKeyIdentifier = (cert: Certificate): string => { + const authorityKeyIdentifier = cert.extensions.find((ext) => ext.extnID === '2.5.29.35'); + if (authorityKeyIdentifier) { + let akiValue = Buffer.from(authorityKeyIdentifier.extnValue.valueBlock.valueHexView).toString( + 'hex' + ); + akiValue = akiValue.replace(/^(?:3016)?(?:0414)?/, ''); + // cur off the first 2 bytes + akiValue = akiValue.slice(4); + return akiValue; + } + return null; +}; + +export const getCircuitName = ( + circuitMode: "prove" | "dsc" | "vc_and_disclose", + signatureAlgorithm: string, + hashFunction: string, + domainParameter: string, + keyLength: string +) => { + const circuit = circuitNameFromMode[circuitMode]; + if (circuit == 'vc_and_disclose') { + return 'vc_and_disclose'; + } + if (circuit == 'dsc') { + return ( + circuit + + '_' + + signatureAlgorithm + + '_' + + hashFunction + + '_' + + domainParameter + + '_' + + keyLength + ); + } + return ( + circuit + + '_' + + signatureAlgorithm + + '_' + + hashFunction + + '_' + + domainParameter + + '_' + + keyLength + ); +}; +export const getCircuitNameOld = (circuitMode: Mode, signatureAlgorithm: string, hashFunction: string) => { + const circuit = circuitNameFromMode[circuitMode]; + if (circuit == 'vc_and_disclose') { + return 'vc_and_disclose'; + } + else if (signatureAlgorithm === 'ecdsa') { + return circuit + "_" + signatureAlgorithm + "_secp256r1_" + hashFunction; + } + else { + return circuit + "_" + signatureAlgorithm + "_65537_" + hashFunction; } } \ No newline at end of file diff --git a/common/src/utils/certificates/certificates.ts b/common/src/utils/certificates/certificates.ts deleted file mode 100644 index a62b4b91..00000000 --- a/common/src/utils/certificates/certificates.ts +++ /dev/null @@ -1,111 +0,0 @@ -import * as path from 'path'; -import jsrsasign from 'jsrsasign'; -import * as asn1 from 'asn1.js'; -import fs from 'fs'; - -export const RSAPublicKey = asn1.define('RSAPublicKey', function () { - this.seq().obj(this.key('n').int(), this.key('e').int()); -}); - -export function isRsaPublicKey(key) { - return key.type === 'RSA' || key.type === 'RSA-PSS'; -} - -export function getPublicKey(certificate) { - const publicKeyInfo = certificate.getPublicKeyHex(); - - try { - // Try to parse the public key as ASN.1 - const publicKeyAsn1 = asn1.define('PublicKey', function () { - this.seq().obj( - this.key('algorithm') - .seq() - .obj(this.key('algorithmId').objid(), this.key('parameters').optional().any()), - this.key('publicKey').bitstr() - ); - }); - - const parsed = publicKeyAsn1.decode(Buffer.from(publicKeyInfo, 'hex'), 'der'); - const publicKeyBuffer = parsed.publicKey.data; - - // Parse the RSA public key - const rsaPublicKey = RSAPublicKey.decode(publicKeyBuffer, 'der'); - - return { - n: new jsrsasign.BigInteger(rsaPublicKey.n.toString('hex'), 16), - e: new jsrsasign.BigInteger(rsaPublicKey.e.toString('hex'), 16), - type: 'RSA', - }; - } catch (e) { - console.error('Error parsing public key:', e); - } - - // If parsing fails, fall back to manual extraction - const modulus = extractModulus(publicKeyInfo); - if (modulus) { - return { n: new jsrsasign.BigInteger(modulus, 16), type: 'RSA' }; - } - - throw new Error('Unable to extract public key'); -} - -function extractModulus(publicKeyInfo: string): string | null { - // RSA OID - const rsaOid = '2a864886f70d010101'; - // RSA-PSS OID - const rsaPssOid = '2a864886f70d01010a'; - - let offset = publicKeyInfo.indexOf(rsaOid); - if (offset === -1) { - offset = publicKeyInfo.indexOf(rsaPssOid); - } - - if (offset === -1) { - return null; - } - - // Skip OID and move to the bit string - offset = publicKeyInfo.indexOf('03', offset); - if (offset === -1) { - return null; - } - - // Skip bit string tag and length - offset += 4; - - // Extract modulus - const modulusStart = publicKeyInfo.indexOf('02', offset) + 2; - const modulusLength = parseInt(publicKeyInfo.substr(modulusStart, 2), 16) * 2; - const modulus = publicKeyInfo.substr(modulusStart + 2, modulusLength); - - return modulus; -} - -export function readCertificate(filePath: string): jsrsasign.X509 { - const certPem = fs.readFileSync(filePath, 'utf8'); - const certificate = new jsrsasign.X509(); - certificate.readCertPEM(certPem); - return certificate; -} - -export function getTBSCertificate(certificate: jsrsasign.X509): Buffer { - // console.log("Certificate:", certificate); - - const certASN1 = certificate.getParam(); - // console.log("certASN1:", certASN1); - - if (!certASN1) { - console.error('Failed to get certificate parameters'); - throw new Error('Invalid certificate structure'); - } - - // Extract the TBS part directly from the certificate's hex representation - const certHex = certificate.hex; - const tbsStartIndex = certHex.indexOf('30') + 2; // Start after the first sequence tag - const tbsLength = parseInt(certHex.substr(tbsStartIndex, 2), 16) * 2 + 2; // Length in bytes * 2 for hex + 2 for length field - const tbsHex = certHex.substr(tbsStartIndex - 2, tbsLength); // Include the sequence tag - - // console.log("TBS Hex:", tbsHex); - - return Buffer.from(tbsHex, 'hex'); -} diff --git a/common/src/utils/certificates/curves.ts b/common/src/utils/certificates/curves.ts deleted file mode 100644 index a95192e7..00000000 --- a/common/src/utils/certificates/curves.ts +++ /dev/null @@ -1,123 +0,0 @@ -export interface StandardCurve { - name: string; - p: string; - a: string; - b: string; - G: string; - n: string; - h: string; -} - -export const standardCurves: StandardCurve[] = [ - { - name: 'secp256r1', - p: 'FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF', - a: 'FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC', - b: '5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B', - G: '046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5', - n: 'FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551', - h: '01', - }, - { - name: 'secp384r1', - p: 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF', - a: 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC', - b: 'B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF', - G: '04AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB73617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F', - n: 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973', - h: '01', - }, - { - name: 'secp521r1', - p: '01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF', - a: '01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC', - b: '0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00', - G: '0400C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650', - n: '01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409', - h: '01', - }, - { - name: 'brainpoolP256r1', - p: 'A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377', - a: '7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9', - b: '26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6', - G: '048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997', - n: 'A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7', - h: '01', - }, - { - name: 'brainpoolP384r1', - p: '8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53', - a: '7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826', - b: '04A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11', - G: '041D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315', - n: '8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565', - h: '01', - }, - { - name: 'brainpoolP512r1', - p: 'AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3', - a: '7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA', - b: '3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723', - G: '0481AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F8227DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892', - n: 'AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069', - h: '01', - }, -]; - -export function normalizeHex(hex: string): string { - return hex.toLowerCase().replace(/^0x/, '').replace(/^00/, ''); -} - -export function identifyCurve(params: any): string { - const normalizedParams = { - p: normalizeHex(params.p), - a: normalizeHex(params.a), - b: normalizeHex(params.b), - G: normalizeHex(params.G), - n: normalizeHex(params.n), - h: normalizeHex(params.h), - }; - - for (const curve of standardCurves) { - if ( - normalizedParams.p === normalizeHex(curve.p) && - normalizedParams.a === normalizeHex(curve.a) && - normalizedParams.b === normalizeHex(curve.b) && - normalizedParams.G === normalizeHex(curve.G) && - normalizedParams.n === normalizeHex(curve.n) && - normalizedParams.h === normalizeHex(curve.h) - ) { - return curve.name; - } - } - return 'Unknown curve'; -} - -export function getNamedCurve(oid: string): string { - const curves = { - '1.2.840.10045.3.1.7': 'secp256r1', - '1.3.132.0.34': 'secp384r1', - '1.3.132.0.35': 'secp521r1', - // Add more curve OIDs as needed - }; - return curves[oid] || `Unknown (${oid})`; -} -export function getECDSACurveBits(curveName: string): string { - const curveBits: { [key: string]: number } = { - secp256r1: 256, - secp384r1: 384, - secp521r1: 521, - brainpoolP256r1: 256, - brainpoolP384r1: 384, - brainpoolP512r1: 512, - 'secp256r1 (NIST P-256)': 256, - 'secp384r1 (NIST P-384)': 384, - 'secp521r1 (NIST P-521)': 521, - }; - if (curveName in curveBits) { - return curveBits[curveName].toString(); - } - console.log('\x1b[31m%s\x1b[0m', `curve name ${curveName} not found in curveBits`); - return 'unknown'; -} diff --git a/common/src/utils/certificates/dataStructure.ts b/common/src/utils/certificates/dataStructure.ts deleted file mode 100644 index 1862bef2..00000000 --- a/common/src/utils/certificates/dataStructure.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { StandardCurve } from './curves'; - -export interface CertificateData { - id: string; - issuer: string; - validity: { - notBefore: string; - notAfter: string; - }; - subjectKeyIdentifier: string; - signatureAlgorithm: string; - hashFunction: string; - publicKeyDetails: - | PublicKeyDetailsRSA - | PublicKeyDetailsECDSA - | PublicKeyDetailsRSAPSS - | undefined; - rawPem: string; - rawTxt: string; -} - -export interface PublicKeyDetailsRSA { - modulus: string; - exponent: string; - bits: string; -} - -export interface PublicKeyDetailsRSAPSS extends PublicKeyDetailsRSA { - hashFunction: string; - mgf: string; - saltLength: string; -} - -export interface PublicKeyDetailsECDSA { - curve: string; - params: StandardCurve; - bits: string; - x: string; - y: string; -} diff --git a/common/src/utils/certificates/handleCertificate.ts b/common/src/utils/certificates/handleCertificate.ts deleted file mode 100644 index aa90feb6..00000000 --- a/common/src/utils/certificates/handleCertificate.ts +++ /dev/null @@ -1,291 +0,0 @@ -import * as asn1 from 'asn1js'; -import { Certificate } from 'pkijs'; -import { getHashLen } from '../utils'; -import elliptic from 'elliptic'; -import { parseRsaPublicKey, parseRsaPssPublicKey, parseECParameters } from './publicKeyDetails'; -import { PublicKeyDetailsRSAPSS } from './dataStructure'; -import { getNamedCurve } from './curves'; -import { circuitNameFromMode } from '../../constants/constants'; -import { Mode } from '../appType'; - -if (typeof global.Buffer === 'undefined') { - global.Buffer = require('buffer').Buffer; -} - -export function parseCertificate(pem: string) { - const cert = getCertificateFromPem(pem); - let { signatureAlgorithm, hashFunction } = getSignatureAlgorithmDetails( - cert.signatureAlgorithm.algorithmId - ); - const subjectPublicKeyInfo = cert.subjectPublicKeyInfo; - const subjectKeyIdentifier = getSubjectKeyIdentifier(cert); - const authorityKeyIdentifier = getAuthorityKeyIdentifier(cert); - let publicKeyDetails: any; - switch (signatureAlgorithm) { - case 'rsa': - publicKeyDetails = parseRsaPublicKey(subjectPublicKeyInfo); - if (!publicKeyDetails) { - console.log('\x1b[33mRSA public key not found, probably ECDSA certificate\x1b[0m'); - } - break; - case 'rsapss': - const rsaPssParams = cert.signatureAlgorithm.algorithmParams; - publicKeyDetails = parseRsaPssPublicKey(subjectPublicKeyInfo, rsaPssParams); - if (publicKeyDetails) { - hashFunction = (publicKeyDetails as PublicKeyDetailsRSAPSS).hashFunction; - } - if (!publicKeyDetails) { - console.log('\x1b[33mRSA-PSS public key not found\x1b[0m'); - } - break; - case 'ecdsa': - publicKeyDetails = parseECParameters(subjectPublicKeyInfo); - if (!publicKeyDetails) { - console.log('\x1b[33mECDSA public key not found\x1b[0m'); - } - break; - default: - console.log('\x1b[33mUnknown signature algorithm: \x1b[0m', signatureAlgorithm); - } - const hashLen = getHashLen(hashFunction); - return { - signatureAlgorithm, - hashFunction, - hashLen, - subjectKeyIdentifier, - authorityKeyIdentifier, - ...publicKeyDetails, - }; -} - -export const getCircuitName = ( - circuitMode: "prove" | "dsc" | "vc_and_disclose", - signatureAlgorithm: string, - hashFunction: string, - domainParameter: string, - keyLength: string -) => { - const circuit = circuitNameFromMode[circuitMode]; - if (circuit == 'vc_and_disclose') { - return 'vc_and_disclose'; - } - if (circuit == 'dsc') { - return ( - circuit + - '_' + - signatureAlgorithm + - '_' + - hashFunction + - '_' + - domainParameter + - '_' + - keyLength - ); - } - return ( - circuit + - '_' + - signatureAlgorithm + - '_' + - hashFunction + - '_' + - domainParameter + - '_' + - keyLength - ); -}; -export const getCircuitNameOld = (circuitMode: Mode, signatureAlgorithm: string, hashFunction: string) => { - const circuit = circuitNameFromMode[circuitMode]; - if (circuit == 'vc_and_disclose') { - return 'vc_and_disclose'; - } - else if (signatureAlgorithm === 'ecdsa') { - return circuit + "_" + signatureAlgorithm + "_secp256r1_" + hashFunction; - } - else { - return circuit + "_" + signatureAlgorithm + "_65537_" + hashFunction; - } -} - - - -export function getSignatureAlgorithmDetails(oid: string): { - signatureAlgorithm: string; - hashFunction: string; -} { - const details = { - '1.2.840.113549.1.1.5': { - signatureAlgorithm: 'rsa', - hashFunction: 'sha1', - domainParameter: '65537', - keyLength: '2048', - }, - '1.2.840.113549.1.1.11': { - signatureAlgorithm: 'rsa', - hashFunction: 'sha256', - domainParameter: '65537', - keyLength: '2048', - }, - '1.2.840.113549.1.1.12': { - signatureAlgorithm: 'rsa', - hashFunction: 'sha384', - domainParameter: '65537', - keyLength: '2048', - }, - '1.2.840.113549.1.1.13': { - signatureAlgorithm: 'rsa', - hashFunction: 'sha512', - domainParameter: '65537', - keyLength: '2048', - }, - // rsapss - '1.2.840.113549.1.1.10': { - signatureAlgorithm: 'rsapss', - hashFunction: 'sha256', - domainParameter: '65537', - keyLength: '2048', - }, // TODO: detect which hash function is used (not always sha256) - // ecdsa - '1.2.840.10045.4.1': { - signatureAlgorithm: 'ecdsa', - hashFunction: 'sha1', - domainParameter: 'secp256r1', - keyLength: '256', - }, - '1.2.840.10045.4.3.1': { - signatureAlgorithm: 'ecdsa', - hashFunction: 'sha224', - domainParameter: 'secp256r1', - keyLength: '256', - }, - '1.2.840.10045.4.3.2': { - signatureAlgorithm: 'ecdsa', - hashFunction: 'sha256', - domainParameter: 'secp256r1', - keyLength: '256', - }, - '1.2.840.10045.4.3.3': { - signatureAlgorithm: 'ecdsa', - hashFunction: 'sha384', - domainParameter: 'secp384r1', - keyLength: '384', - }, - '1.2.840.10045.4.3.4': { - signatureAlgorithm: 'ecdsa', - hashFunction: 'sha512', - domainParameter: 'secp521r1', - keyLength: '521', - }, - }; - return details[oid] || { signatureAlgorithm: `Unknown (${oid})`, hashFunction: 'Unknown' }; -} - -export function gethashFunctionName(oid: string): string { - const hashFunctions = { - '1.3.14.3.2.26': 'sha1', - '2.16.840.1.101.3.4.2.1': 'sha256', - '2.16.840.1.101.3.4.2.2': 'sha384', - '2.16.840.1.101.3.4.2.3': 'sha512', - }; - return hashFunctions[oid] || `Unknown (${oid})`; -} - -export function getCertificateFromPem(pemContent: string): Certificate { - const certBuffer = Buffer.from( - pemContent.replace(/(-----(BEGIN|END) CERTIFICATE-----|\n)/g, ''), - 'base64' - ); - const asn1Data = asn1.fromBER(certBuffer); - return new Certificate({ schema: asn1Data.result }); -} - -export const getSubjectKeyIdentifier = (cert: Certificate): string => { - const subjectKeyIdentifier = cert.extensions.find( - (ext) => ext.extnID === '2.5.29.14' // OID for Subject Key Identifier - ); - if (subjectKeyIdentifier) { - let skiValue = Buffer.from(subjectKeyIdentifier.extnValue.valueBlock.valueHexView).toString( - 'hex' - ); - - skiValue = skiValue.replace(/^(?:3016)?(?:0414)?/, ''); - return skiValue; - } else { - return null; - } -}; - -export const getAuthorityKeyIdentifier = (cert: Certificate): string => { - const authorityKeyIdentifier = cert.extensions.find((ext) => ext.extnID === '2.5.29.35'); - if (authorityKeyIdentifier) { - let akiValue = Buffer.from(authorityKeyIdentifier.extnValue.valueBlock.valueHexView).toString( - 'hex' - ); - akiValue = akiValue.replace(/^(?:3016)?(?:0414)?/, ''); - // cur off the first 2 bytes - akiValue = akiValue.slice(4); - return akiValue; - } - return null; -}; - -export function getIssuerCountryCode(cert: Certificate): string { - const issuerRDN = cert.issuer.typesAndValues; - let issuerCountryCode = ''; - for (const rdn of issuerRDN) { - if (rdn.type === '2.5.4.6') { - // OID for Country Name - issuerCountryCode = rdn.value.valueBlock.value; - break; - } - } - return issuerCountryCode.toUpperCase(); -} - -export const parseDSC = (pemContent: string) => { - const certBuffer = Buffer.from( - pemContent.replace(/(-----(BEGIN|END) CERTIFICATE-----|\n)/g, ''), - 'base64' - ); - const asn1Data = asn1.fromBER(certBuffer); - const cert = new Certificate({ schema: asn1Data.result }); - const signatureAlgorithmOid = cert.signatureAlgorithm.algorithmId; - const { signatureAlgorithm, hashFunction } = getSignatureAlgorithmDetails(signatureAlgorithmOid); - const hashLen = getHashLen(hashFunction); - - let publicKeyDetails; - if (signatureAlgorithm === 'ecdsa') { - const subjectPublicKeyInfo = cert.subjectPublicKeyInfo; - const algorithmParams = subjectPublicKeyInfo.algorithm.algorithmParams; - const curveOid = asn1.fromBER(algorithmParams.valueBeforeDecode).result.valueBlock.toString(); - const curve = getNamedCurve(curveOid); - - const publicKeyBuffer = subjectPublicKeyInfo.subjectPublicKey.valueBlock.valueHexView; - const curveForElliptic = curve === 'secp256r1' ? 'p256' : 'p384'; - const ec = new elliptic.ec(curveForElliptic); - const key = ec.keyFromPublic(publicKeyBuffer); - const x = key.getPublic().getX().toString('hex'); - const y = key.getPublic().getY().toString('hex'); - - const fieldSizeMap: { [key: string]: number } = { - secp256r1: 256, - secp384r1: 384, - }; - const bits = fieldSizeMap[curve]; - - publicKeyDetails = { curve, x, y, bits }; - } else { - const publicKey = cert.subjectPublicKeyInfo.subjectPublicKey; - const asn1PublicKey = asn1.fromBER(publicKey.valueBlock.valueHexView); - const rsaPublicKey = asn1PublicKey.result.valueBlock; - const modulus = Buffer.from((rsaPublicKey as any).value[0].valueBlock.valueHexView).toString( - 'hex' - ); - const exponent = Buffer.from((rsaPublicKey as any).value[1].valueBlock.valueHexView).toString( - 'hex' - ); - const bits = Buffer.from(modulus, 'hex').length * 8; - publicKeyDetails = { modulus, exponent, bits }; - } - return { signatureAlgorithm, hashFunction, hashLen, ...publicKeyDetails }; -}; diff --git a/common/src/utils/certificates/publicKeyDetails.ts b/common/src/utils/certificates/publicKeyDetails.ts deleted file mode 100644 index 96d82c3a..00000000 --- a/common/src/utils/certificates/publicKeyDetails.ts +++ /dev/null @@ -1,252 +0,0 @@ -import { fromBER, BitString } from 'asn1js'; -import * as asn1 from 'asn1js'; -import * as forge from 'node-forge'; -import { - PublicKeyDetailsECDSA, - PublicKeyDetailsRSA, - PublicKeyDetailsRSAPSS, -} from './dataStructure'; -import { identifyCurve, StandardCurve, getNamedCurve, getECDSACurveBits } from './curves'; -import { gethashFunctionName } from './handleCertificate'; -import elliptic from 'elliptic'; - -export function parseRsaPublicKey(subjectPublicKeyInfo: any): PublicKeyDetailsRSA { - const publicKey = subjectPublicKeyInfo.subjectPublicKey; - const asn1PublicKey = fromBER(publicKey.valueBlock.valueHexView); - const rsaPublicKey = asn1PublicKey.result.valueBlock; - - if ( - rsaPublicKey && - (rsaPublicKey as any).value && - (rsaPublicKey as any).value[0] && - (rsaPublicKey as any).value[1] - ) { - const modulusAsn1 = (rsaPublicKey as any).value[0]; - const exponentAsn1 = (rsaPublicKey as any).value[1]; - const modulusHex = Buffer.from(modulusAsn1.valueBlock.valueHexView).toString('hex'); - const exponentHex = Buffer.from(exponentAsn1.valueBlock.valueHexView).toString('hex'); - - const publicKeyForge = forge.pki.rsa.setPublicKey( - new forge.jsbn.BigInteger(modulusHex, 16), - new forge.jsbn.BigInteger(exponentHex, 16) - ); - const publicKeyDetailsRSA: PublicKeyDetailsRSA = { - modulus: publicKeyForge.n.toString(16), - exponent: publicKeyForge.e.toString(10), - bits: publicKeyForge.n.bitLength().toString(), - }; - return publicKeyDetailsRSA; - } else { - return null; - } -} - -export function parseECParameters(publicKeyInfo: any): PublicKeyDetailsECDSA { - try { - const algorithmParams = publicKeyInfo.algorithm.algorithmParams; - if (!algorithmParams) { - console.error('\x1b[31mNo algorithm params found\x1b[0m'); - return null; - } - // get x and y; - const curveOid = asn1.fromBER(algorithmParams.valueBeforeDecode).result.valueBlock.toString(); - const curve = getNamedCurve(curveOid); - - const publicKeyBuffer = publicKeyInfo.subjectPublicKey.valueBlock.valueHexView; - const curveForElliptic = curve === 'secp256r1' ? 'p256' : 'p384'; - const ec = new elliptic.ec(curveForElliptic); - const key = ec.keyFromPublic(publicKeyBuffer); - const x = key.getPublic().getX().toString('hex'); - const y = key.getPublic().getY().toString('hex'); - const fieldSizeMap: { [key: string]: number } = { - secp256r1: 256, - secp384r1: 384, - }; - const bits = fieldSizeMap[curve]; - - const params = asn1.fromBER(algorithmParams.valueBeforeDecodeView).result; - const valueBlock: any = params.valueBlock; - let curveParams: StandardCurve = {} as StandardCurve; - - // if (valueBlock.value && valueBlock.value.length >= 6) { - // // Field ID (index 1) - // const curveParams = {} as StandardCurve; - // const fieldId = valueBlock.value[1]; - // if (fieldId && fieldId.valueBlock && fieldId.valueBlock.value) { - // const fieldType = fieldId.valueBlock.value[0]; - // const prime = fieldId.valueBlock.value[1]; - // //curveParams.fieldType = fieldType.valueBlock.toString(); - // curveParams.p = Buffer.from(prime.valueBlock.valueHexView).toString('hex'); - // } - - // // Curve Coefficients (index 2) - // const curveCoefficients = valueBlock.value[2]; - // if (curveCoefficients && curveCoefficients.valueBlock && curveCoefficients.valueBlock.value) { - // const a = curveCoefficients.valueBlock.value[0]; - // const b = curveCoefficients.valueBlock.value[1]; - // curveParams.a = Buffer.from(a.valueBlock.valueHexView).toString('hex'); - // curveParams.b = Buffer.from(b.valueBlock.valueHexView).toString('hex'); - // } - - // // Base Point G (index 3) - // const basePoint = valueBlock.value[3]; - // if (basePoint && basePoint.valueBlock) { - // curveParams.G = Buffer.from(basePoint.valueBlock.valueHexView).toString('hex'); - // } - - // // Order n (index 4) - // const order = valueBlock.value[4]; - // if (order && order.valueBlock) { - // curveParams.n = Buffer.from(order.valueBlock.valueHexView).toString('hex'); - // } - - // // Cofactor h (index 5) - // const cofactor = valueBlock.value[5]; - // if (cofactor && cofactor.valueBlock) { - // curveParams.h = Buffer.from(cofactor.valueBlock.valueHexView).toString('hex'); - // } - // if (curveParams.p && curveParams.a && curveParams.b && curveParams.G && curveParams.n && curveParams.h) { - // const identifiedCurve = identifyCurve(curveParams); - // } - // } else { - // if (valueBlock.value) { - - // if (algorithmParams.idBlock.tagNumber === 6) { - // console.log('\x1b[33malgorithmParams.idBlock.tagNumber === 6, looking for algorithmParams.valueBlock\x1b[0m'); - - // const curveOid = algorithmParams.valueBlock.toString(); - // const curveName = getNamedCurve(curveOid); - // // console.error('\x1b[33mCurve OID:', curveName, '\x1b[0m'); - // return { curve: curveName, params: {} as StandardCurve, bits: getECDSACurveBits(curveName) }; - // } - // else { - // console.log('\x1b[31malgorithmParams.idBlock.tagNumber !== 6\x1b[0m'); - // } - // } - // else { - // console.log('\x1b[31mvalue block is not defined\x1b[0m'); - // } - // } - const publicKeyDetailsECDSA: PublicKeyDetailsECDSA = { - curve: curve, - params: curveParams, - bits: bits.toString(), - x: x, - y: y, - }; - return publicKeyDetailsECDSA; - } catch (error) { - console.error('Error parsing EC parameters:', error); - } -} - -export function parseRsaPssParams(params: any): { - hashFunction: string; - mgf: string; - saltLength: string; -} { - try { - const algorithmParams = asn1.fromBER(params.valueBeforeDecodeView); - const sequence = algorithmParams.result; - - let hashFunction = 'Unknown'; - let mgf = 'Unknown'; - let saltLength = 'Unknown'; - - // Parse hash algorithm - if ((sequence.valueBlock as any).value && (sequence.valueBlock as any).value[0]) { - const hashFunctionSequence = (sequence.valueBlock as any).value[0].valueBlock.value[0]; - const hashFunctionOid = hashFunctionSequence.valueBlock.value[0].valueBlock.toString(); - hashFunction = gethashFunctionName(hashFunctionOid); - } - - // Parse MGF - if ((sequence.valueBlock as any).value && (sequence.valueBlock as any).value[1]) { - const mgfSequence = (sequence.valueBlock as any).value[1].valueBlock.value[0]; - const mgfOid = mgfSequence.valueBlock.value[0].valueBlock.toString(); - mgf = mgfOid === '1.2.840.113549.1.1.8' ? 'MGF1' : `Unknown (${mgfOid})`; - } - // console.log((sequence.valueBlock as any).value[0].valueBlock); - // console.log((sequence.valueBlock as any).value[1].valueBlock); - // console.log((sequence.valueBlock as any).value[2].valueBlock); - - // Parse salt length - if ((sequence.valueBlock as any).value && (sequence.valueBlock as any).value[2]) { - const saltLengthContainer = (sequence.valueBlock as any).value[2]; - - if (saltLengthContainer.valueBlock && saltLengthContainer.valueBlock.value) { - const rawSaltLength = saltLengthContainer.valueBlock.value[0]; - if (typeof rawSaltLength === 'number') { - saltLength = rawSaltLength.toString(); - } else if ( - rawSaltLength && - rawSaltLength.valueBlock && - rawSaltLength.valueBlock.valueHexView - ) { - const saltLengthValue = rawSaltLength.valueBlock.valueHexView[0]; - saltLength = saltLengthValue.toString(); - } else { - console.error('\x1b[31mUnable to parse salt length\x1b[0m'); - } - } else { - console.log('\x1b[31mSalt length not found\x1b[0m'); - } - } - - return { hashFunction, mgf, saltLength }; - } catch (error) { - console.error('Error parsing RSA-PSS parameters:', error); - return { hashFunction: 'Unknown', mgf: 'Unknown', saltLength: 'Unknown' }; - } -} - -export function parseRsaPssPublicKey( - subjectPublicKeyInfo: any, - rsaPssParams: any -): PublicKeyDetailsRSAPSS { - let hashFunction = 'Unknown'; - let mgf = 'Unknown'; - let saltLength = 'Unknown'; - - if (rsaPssParams) { - const parsedParams = parseRsaPssParams(rsaPssParams); - hashFunction = parsedParams.hashFunction; - mgf = parsedParams.mgf; - saltLength = parsedParams.saltLength; - } else { - console.log('\x1b[31mRSA-PSS parameters not found\x1b[0m'); - } - - // Add PublicKeyDetails for RSA-PSS - const publicKey = subjectPublicKeyInfo.subjectPublicKey; - const asn1PublicKey = fromBER(publicKey.valueBlock.valueHexView); - const rsaPublicKey = asn1PublicKey.result.valueBlock; - - if ( - rsaPublicKey && - (rsaPublicKey as any).value && - (rsaPublicKey as any).value[0] && - (rsaPublicKey as any).value[1] - ) { - const modulusAsn1 = (rsaPublicKey as any).value[0]; - const exponentAsn1 = (rsaPublicKey as any).value[1]; - const modulusHex = Buffer.from(modulusAsn1.valueBlock.valueHexView).toString('hex'); - const exponentHex = Buffer.from(exponentAsn1.valueBlock.valueHexView).toString('hex'); - - const publicKeyForge = forge.pki.rsa.setPublicKey( - new forge.jsbn.BigInteger(modulusHex, 16), - new forge.jsbn.BigInteger(exponentHex, 16) - ); - const PublicKeyDetailsRSAPSS: PublicKeyDetailsRSAPSS = { - modulus: publicKeyForge.n.toString(16), - exponent: publicKeyForge.e.toString(10), - bits: publicKeyForge.n.bitLength().toString(), - hashFunction, - mgf, - saltLength, - }; - return PublicKeyDetailsRSAPSS; - } else { - return null; - } -} diff --git a/common/src/utils/genMockPassportData.ts b/common/src/utils/genMockPassportData.ts index 336a8bec..6b02a123 100644 --- a/common/src/utils/genMockPassportData.ts +++ b/common/src/utils/genMockPassportData.ts @@ -37,7 +37,6 @@ import { } from '../constants/mockCertificates'; import { sampleDataHashes_small, sampleDataHashes_large } from '../constants/sampleDataHashes'; import { countryCodes } from '../constants/constants'; -// import { parseCertificate } from './certificates/handleCertificate'; import { parseCertificateSimple } from './certificate_parsing/parseCertificateSimple'; import { SignatureAlgorithm } from './types'; import { PublicKeyDetailsECDSA } from './certificate_parsing/dataStructure'; diff --git a/common/src/utils/generateInputs.ts b/common/src/utils/generateInputs.ts index 735fbcde..a05a3ebe 100644 --- a/common/src/utils/generateInputs.ts +++ b/common/src/utils/generateInputs.ts @@ -5,7 +5,7 @@ import { MAX_PADDED_SIGNED_ATTR_LEN, } from '../constants/constants'; import { assert, shaPad } from './shaPad'; -import { PassportData } from './types'; +import { PassportData, SignatureAlgorithm } from './types'; import { bytesToBigDecimal, formatMrz, @@ -30,7 +30,8 @@ import { LeanIMT } from '@openpassport/zk-kit-lean-imt'; import { getCountryLeaf, getNameLeaf, getNameDobLeaf, getPassportNumberLeaf } from './smtTree'; import { packBytes } from '../utils/utils'; import { SMT } from '@openpassport/zk-kit-smt'; -import { parseCertificate } from './certificates/handleCertificate'; +import { parseCertificateSimple } from './certificate_parsing/parseCertificateSimple'; +import { PublicKeyDetailsECDSA, PublicKeyDetailsRSA } from './certificate_parsing/dataStructure'; export function generateCircuitInputsDisclose( secret: string, @@ -181,16 +182,20 @@ export function generateCircuitInputsProve( user_identifier_type: 'uuid' | 'hex' | 'ascii' = DEFAULT_USER_ID_TYPE ) { const { mrz, eContent, signedAttr, encryptedDigest, dsc, dg2Hash } = passportData; - const { signatureAlgorithm, hashFunction, hashLen, x, y, modulus, curve, exponent, bits } = - parseCertificate(passportData.dsc); - - const signatureAlgorithmFullName = `${signatureAlgorithm}_${hashFunction}_${curve || exponent}_${bits}`; + const { signatureAlgorithm, hashAlgorithm, publicKeyDetails } = parseCertificateSimple(passportData.dsc); let pubKey: any; let signature: any; + let signatureAlgorithmFullName: string; + let n, k; + // const + - const { n, k } = getNAndK(`${signatureAlgorithm}_${hashFunction}_${curve || exponent}_${bits}` as any); + // const { n, k } = getNAndK(`${signatureAlgorithm}_${hashFunction}_${curve || exponent}_${bits}` as any); if (signatureAlgorithm === 'ecdsa') { + signatureAlgorithmFullName = `${signatureAlgorithm}_${hashAlgorithm}_${(publicKeyDetails as PublicKeyDetailsECDSA).curve}_${publicKeyDetails.bits}`; + ({ n, k } = getNAndK(signatureAlgorithmFullName as SignatureAlgorithm)); + const { x, y } = publicKeyDetails as PublicKeyDetailsECDSA; const { r, s } = extractRSFromSignature(encryptedDigest); const signature_r = splitToWords(BigInt(hexToDecimal(r)), n, k); const signature_s = splitToWords(BigInt(hexToDecimal(s)), n, k); @@ -199,18 +204,22 @@ export function generateCircuitInputsProve( const dsc_modulus_y = splitToWords(BigInt(hexToDecimal(y)), n, k); pubKey = [...dsc_modulus_x, ...dsc_modulus_y]; } else { + const modulus = (publicKeyDetails as PublicKeyDetailsRSA).modulus; + signatureAlgorithmFullName = `${signatureAlgorithm}_${hashAlgorithm}_${modulus}_${publicKeyDetails.bits}`; + ({ n, k } = getNAndK(signatureAlgorithmFullName as SignatureAlgorithm)); signature = splitToWords(BigInt(bytesToBigDecimal(encryptedDigest)), n, k); - pubKey = splitToWords(BigInt(hexToDecimal(modulus)), n, k); } + console.log('signatureAlgorithmFullName', signatureAlgorithmFullName); + const formattedMrz = formatMrz(mrz); - const dg1Hash = hash(hashFunction, formattedMrz); + const dg1Hash = hash(hashAlgorithm, formattedMrz); const dg1HashOffset = findSubarrayIndex(eContent, dg1Hash); console.log('\x1b[90m%s\x1b[0m', 'dg1HashOffset', dg1HashOffset); assert(dg1HashOffset !== -1, `DG1 hash ${dg1Hash} not found in eContent`); - const eContentHash = hash(hashFunction, eContent); + const eContentHash = hash(hashAlgorithm, eContent); const eContentHashOffset = findSubarrayIndex(signedAttr, eContentHash); console.log('\x1b[90m%s\x1b[0m', 'eContentHashOffset', eContentHashOffset); assert(eContentHashOffset !== -1, `eContent hash ${eContentHash} not found in signedAttr`); diff --git a/common/src/utils/openPassportAttestation.ts b/common/src/utils/openPassportAttestation.ts index 0097fb69..11487b80 100644 --- a/common/src/utils/openPassportAttestation.ts +++ b/common/src/utils/openPassportAttestation.ts @@ -1,5 +1,4 @@ import { ECDSA_K_LENGTH_FACTOR, k_dsc, k_dsc_ecdsa } from '../constants/constants'; -import { parseDSC } from './certificates/handleCertificate'; import { bigIntToHex, castToScope, diff --git a/common/src/utils/pubkeyTree.ts b/common/src/utils/pubkeyTree.ts index 24759cea..29b81d18 100644 --- a/common/src/utils/pubkeyTree.ts +++ b/common/src/utils/pubkeyTree.ts @@ -7,8 +7,10 @@ import { LeanIMT } from '@openpassport/zk-kit-lean-imt'; import axios from 'axios'; import { poseidon16, poseidon2, poseidon6, poseidon7 } from 'poseidon-lite'; import { formatDg2Hash, getNAndK, getNAndKCSCA, hexToDecimal, splitToWords } from './utils'; -import { parseCertificate } from './certificates/handleCertificate'; import { flexiblePoseidon } from './poseidon'; +import { parseCertificateSimple } from './certificate_parsing/parseCertificateSimple'; +import { PublicKeyDetailsECDSA, PublicKeyDetailsRSA } from './certificate_parsing/dataStructure'; +import { SignatureAlgorithm } from './types'; export function customHasher(pubKeyFormatted: string[]) { const rounds = Math.ceil(pubKeyFormatted.length / 16); @@ -28,45 +30,59 @@ export function customHasher(pubKeyFormatted: string[]) { } export function getLeaf(dsc: string): string { - const { signatureAlgorithm, hashFunction, modulus, x, y, bits, curve, exponent } = - parseCertificate(dsc); - const { n, k } = getNAndK(signatureAlgorithm); - console.log(`${signatureAlgorithm}_${hashFunction}_${curve || exponent}_${bits}`); - const sigAlgKey = `${signatureAlgorithm}_${hashFunction}_${curve || exponent}_${bits}`; - const sigAlgIndex = SignatureAlgorithmIndex[sigAlgKey]; + const { signatureAlgorithm, hashAlgorithm, publicKeyDetails } = parseCertificateSimple(dsc); + + - if (sigAlgIndex == undefined) { - console.error(`\x1b[31mInvalid signature algorithm: ${sigAlgKey}\x1b[0m`); - throw new Error(`Invalid signature algorithm: ${sigAlgKey}`); - } if (signatureAlgorithm === 'ecdsa') { + const { x, y, curve, bits } = publicKeyDetails as PublicKeyDetailsECDSA; + const sigAlgKey = `${signatureAlgorithm}_${hashAlgorithm}_${curve}_${bits}`; + const { n, k } = getNAndK(sigAlgKey as SignatureAlgorithm); + const sigAlgIndex = SignatureAlgorithmIndex[sigAlgKey]; + + if (sigAlgIndex == undefined) { + console.error(`\x1b[31mInvalid signature algorithm: ${sigAlgKey}\x1b[0m`); + throw new Error(`Invalid signature algorithm: ${sigAlgKey}`); + } let qx = splitToWords(BigInt(hexToDecimal(x)), n, k); let qy = splitToWords(BigInt(hexToDecimal(y)), n, k); return customHasher([sigAlgIndex, ...qx, ...qy]); } else { + const { modulus, bits } = publicKeyDetails as PublicKeyDetailsRSA; + const sigAlgKey = `${signatureAlgorithm}_${hashAlgorithm}_${modulus}_${bits}`; + const { n, k } = getNAndK(sigAlgKey as SignatureAlgorithm); const pubkeyChunked = splitToWords(BigInt(hexToDecimal(modulus)), n, k); + + const sigAlgIndex = SignatureAlgorithmIndex[sigAlgKey]; + if (sigAlgIndex == undefined) { + console.error(`\x1b[31mInvalid signature algorithm: ${sigAlgKey}\x1b[0m`); + throw new Error(`Invalid signature algorithm: ${sigAlgKey}`); + } return customHasher([sigAlgIndex, ...pubkeyChunked]); } } export function getLeafCSCA(dsc: string): string { - const { signatureAlgorithm, hashFunction, modulus, x, y, bits, curve, exponent } = - parseCertificate(dsc); - const { n, k } = getNAndKCSCA(signatureAlgorithm); - console.log(`${signatureAlgorithm}_${hashFunction}_${curve || exponent}_${bits}`); - const sigAlgKey = `${signatureAlgorithm}_${hashFunction}_${curve || exponent}_${bits}`; - console.log('sigAlgKey', sigAlgKey); - const sigAlgIndex = SignatureAlgorithmIndex[sigAlgKey]; - console.log('sigAlgIndex', sigAlgIndex); + const { signatureAlgorithm, hashAlgorithm, publicKeyDetails } = parseCertificateSimple(dsc); + const { n, k } = getNAndKCSCA(signatureAlgorithm as any); + - if (sigAlgIndex == undefined) { - console.error(`\x1b[31mInvalid signature algorithm: ${sigAlgKey}\x1b[0m`); - throw new Error(`Invalid signature algorithm: ${sigAlgKey}`); - } if (signatureAlgorithm === 'ecdsa') { + const { x, y, curve, bits } = publicKeyDetails as PublicKeyDetailsECDSA; + const sigAlgKey = `${signatureAlgorithm}_${hashAlgorithm}_${curve}_${bits}`; + const sigAlgIndex = SignatureAlgorithmIndex[sigAlgKey]; let qx = splitToWords(BigInt(hexToDecimal(x)), n, k); let qy = splitToWords(BigInt(hexToDecimal(y)), n, k); return customHasher([sigAlgIndex, ...qx, ...qy]); } else { + const { modulus, bits } = publicKeyDetails as PublicKeyDetailsRSA; + const sigAlgKey = `${signatureAlgorithm}_${hashAlgorithm}_${modulus}_${bits}`; + const sigAlgIndex = SignatureAlgorithmIndex[sigAlgKey]; + + if (sigAlgIndex == undefined) { + console.error(`\x1b[31mInvalid signature algorithm: ${sigAlgKey}\x1b[0m`); + throw new Error(`Invalid signature algorithm: ${sigAlgKey}`); + } + const pubkeyChunked = splitToWords(BigInt(hexToDecimal(modulus)), n, k); return customHasher([sigAlgIndex, ...pubkeyChunked]); } diff --git a/common/tests/genMockPassportData.test.ts b/common/tests/genMockPassportData.test.ts index 442c39a5..ab238c6c 100644 --- a/common/tests/genMockPassportData.test.ts +++ b/common/tests/genMockPassportData.test.ts @@ -4,10 +4,12 @@ import { genMockPassportData } from '../src/utils/genMockPassportData'; import * as forge from 'node-forge'; import { PassportData, SignatureAlgorithm } from '../src/utils/types'; import { formatMrz, hash, arraysAreEqual, findSubarrayIndex } from '../src/utils/utils'; -import { parseCertificate } from '../src/utils/certificates/handleCertificate'; import * as asn1 from 'asn1js'; import { Certificate } from 'pkijs'; import elliptic from 'elliptic'; +import { parseCertificateSimple } from '../src/utils/certificate_parsing/parseCertificateSimple'; +import { getCurveForElliptic } from '../src/utils/certificate_parsing/curves'; +import { PublicKeyDetailsECDSA, PublicKeyDetailsRSAPSS } from '../src/utils/certificate_parsing/dataStructure'; const sigAlgs: SignatureAlgorithm[] = [ 'rsa_sha1_65537_2048', @@ -32,26 +34,26 @@ describe('Mock Passport Data Generator', function () { function verify(passportData: PassportData): boolean { const { mrz, dsc, eContent, signedAttr, encryptedDigest } = passportData; - const { signatureAlgorithm, hashFunction, hashLen, curve } = parseCertificate(dsc); + const { signatureAlgorithm, hashAlgorithm, publicKeyDetails } = parseCertificateSimple(dsc); const formattedMrz = formatMrz(mrz); - const mrzHash = hash(hashFunction, formattedMrz); + const mrzHash = hash(hashAlgorithm, formattedMrz); const dg1HashOffset = findSubarrayIndex(eContent, mrzHash); assert(dg1HashOffset !== -1, 'MRZ hash index not found in eContent'); console.error( '\x1b[32m', 'signatureAlgorithm', signatureAlgorithm, - ' hashFunction', - hashFunction, + ' hashAlgorithm', + hashAlgorithm, 'eContent size', eContent.length, 'signedAttr size', signedAttr.length, '\x1b[0m' ); - const concatHash = hash(hashFunction, eContent); + const concatHash = hash(hashAlgorithm, eContent); assert( - arraysAreEqual(concatHash, signedAttr.slice(signedAttr.length - hashLen)), + arraysAreEqual(concatHash, signedAttr.slice(signedAttr.length - getHashLen(hashAlgorithm))), 'concatHash is not at the right place in signedAttr' ); @@ -64,11 +66,11 @@ function verify(passportData: PassportData): boolean { const cert = new Certificate({ schema: asn1Data.result }); const publicKeyInfo = cert.subjectPublicKeyInfo; const publicKeyBuffer = publicKeyInfo.subjectPublicKey.valueBlock.valueHexView; - const curveForElliptic = curve === 'secp256r1' ? 'p256' : 'p384'; + const curveForElliptic = getCurveForElliptic((publicKeyDetails as PublicKeyDetailsECDSA).curve); const ec = new elliptic.ec(curveForElliptic); const key = ec.keyFromPublic(publicKeyBuffer); - const md = hashFunction === 'sha1' ? forge.md.sha1.create() : forge.md.sha256.create(); + 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'); @@ -78,16 +80,17 @@ function verify(passportData: PassportData): boolean { const cert = forge.pki.certificateFromPem(dsc); const publicKey = cert.publicKey as forge.pki.rsa.PublicKey; - const md = forge.md[hashFunction].create(); + const md = forge.md[hashAlgorithm].create(); md.update(forge.util.binary.raw.encode(new Uint8Array(signedAttr))); const signature = Buffer.from(encryptedDigest).toString('binary'); if (signatureAlgorithm === 'rsapss') { + const saltLenght = (publicKeyDetails as PublicKeyDetailsRSAPSS).saltLength; const pss = forge.pss.create({ - md: forge.md[hashFunction].create(), - mgf: forge.mgf.mgf1.create(forge.md[hashFunction].create()), - saltLength: hashLen, + md: forge.md[hashAlgorithm].create(), + mgf: forge.mgf.mgf1.create(forge.md[hashAlgorithm].create()), + saltLength: saltLenght, }); return publicKey.verify(md.digest().bytes(), signature, pss); } else { @@ -95,3 +98,18 @@ function verify(passportData: PassportData): boolean { } } } + +function getHashLen(hashAlgorithm: string): number { + if (hashAlgorithm === 'sha1') { + return 20; + } else if (hashAlgorithm === 'sha256') { + return 32; + } else if (hashAlgorithm === 'sha384') { + return 48; + } else if (hashAlgorithm === 'sha512') { + return 64; + } else { + throw new Error('Unsupported hash algorithm'); + } +} + diff --git a/registry/src/buildMapJson.ts b/registry/src/buildMapJson.ts index 060a3a62..28947bc3 100644 --- a/registry/src/buildMapJson.ts +++ b/registry/src/buildMapJson.ts @@ -1,8 +1,8 @@ import * as fs from 'fs'; import * as path from 'path'; import { argv } from 'process'; -import { parseCertificate } from './utils/certificateParsing/parseCertificate'; -import { CertificateData } from './utils/certificateParsing/dataStructure'; +import { parseCertificate } from '../../common/src/utils/certificate_parsing/parseCertificate'; +import { CertificateData } from '../../common/src/utils/certificate_parsing/dataStructure'; let pemDirectory: string; diff --git a/registry/src/parseData.ts b/registry/src/parseData.ts index 5d53cbac..3770156c 100644 --- a/registry/src/parseData.ts +++ b/registry/src/parseData.ts @@ -1,9 +1,9 @@ -import { parseCertificate } from "./utils/certificateParsing/parseCertificate"; +import { parseCertificate } from "../../common/src/utils/certificate_parsing/parseCertificate"; import path from 'path'; import fs from 'fs'; const csca_pem_directory_path = path.join(__dirname, '..', 'outputs', 'csca', 'pem_masterlist copy'); const dsc_pem_directory_path = path.join(__dirname, '..', 'outputs', 'dsc', 'pem_masterlist'); -import { CertificateData } from './utils/certificateParsing/dataStructure'; +import { CertificateData } from "../../common/src/utils/certificate_parsing/dataStructure"; function main(arg: string) { diff --git a/registry/src/pushToDb.ts b/registry/src/pushToDb.ts index 09b927e2..93cfe7e2 100644 --- a/registry/src/pushToDb.ts +++ b/registry/src/pushToDb.ts @@ -2,7 +2,7 @@ import * as fs from 'fs'; import * as path from 'path'; import { argv } from 'process'; import { getPrismaClientFromEnv, prepareDataForInsertion } from './utils/prisma'; -import { parseCertificate } from './utils/certificateParsing/parseCertificate'; +import { parseCertificate } from '../../common/src/utils/certificate_parsing/parseCertificate'; let pemDirectory: string; let tableName: 'csca_masterlist' | 'dsc_masterlist'; diff --git a/registry/src/utils/certificateParsing/curves.ts b/registry/src/utils/certificateParsing/curves.ts deleted file mode 100644 index f1cc0c75..00000000 --- a/registry/src/utils/certificateParsing/curves.ts +++ /dev/null @@ -1,129 +0,0 @@ - -export interface StandardCurve { - name: string; - p: string; - a: string; - b: string; - G: string; - n: string; - h: string; -} - -export const standardCurves: StandardCurve[] = [ - { - name: "secp256r1", - p: "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", - a: "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", - b: "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", - G: "046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", - n: "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", - h: "01" - }, - { - name: "secp384r1", - p: "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF", - a: "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC", - b: "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF", - G: "04AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB73617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F", - n: "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973", - h: "01" - }, - { - name: "secp521r1", - p: "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", - a: "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC", - b: "0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", - G: "0400C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650", - n: "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", - h: "01" - } - , - { - name: "brainpoolP224r1", - p: "d7c134aa264366862a18302575d1d787b09f075797da89f57ec8c0ff", - a: "68a5e62ca9ce6c1c299803a6c1530b514e182ad8b0042a59cad29f43", - b: "2580f63ccfe44138870713b1a92369e33e2135d266dbb372386c400b", - G: "040d9029ad2c7e5cf4340823b2a87dc68c9e4ce3174c1e6efdee12c07d58aa56f772c0726f24c6b89e4ecdac24354b9e99caa3f6d3761402cd", - n: "d7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a7939f", - h: "01" - }, - { - name: "brainpoolP256r1", - p: "A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", - a: "7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9", - b: "26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6", - G: "048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997", - n: "A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", - h: "01" - }, - { - name: "brainpoolP384r1", - p: "8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53", - a: "7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826", - b: "04A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11", - G: "041D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315", - n: "8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565", - h: "01" - }, - { - name: "brainpoolP512r1", - p: "AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3", - a: "7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA", - b: "3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723", - G: "0481AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F8227DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892", - n: "AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069", - h: "01" - } -]; - -export function normalizeHex(hex: string): string { - return hex.toLowerCase().replace(/^0x/, '').replace(/^00/, ''); -} - -export function identifyCurve(params: any): string { - const normalizedParams = { - p: normalizeHex(params.p), - a: normalizeHex(params.a), - b: normalizeHex(params.b), - G: normalizeHex(params.G), - n: normalizeHex(params.n), - h: normalizeHex(params.h) - }; - - for (const curve of standardCurves) { - if ( - normalizedParams.p === normalizeHex(curve.p) && - normalizedParams.a === normalizeHex(curve.a) && - normalizedParams.b === normalizeHex(curve.b) && - normalizedParams.G === normalizeHex(curve.G) && - normalizedParams.n === normalizeHex(curve.n) && - normalizedParams.h === normalizeHex(curve.h) - ) { - return curve.name; - } - } - console.log("Unknown curve:", normalizedParams); - return "Unknown curve"; -} - -export function getECDSACurveBits(curveName: string): string { - const curveBits: { [key: string]: number } = { - 'secp256r1': 256, - 'secp384r1': 384, - 'secp521r1': 521, - 'brainpoolP224r1': 224, - 'brainpoolP256r1': 256, - 'brainpoolP384r1': 384, - 'brainpoolP512r1': 512, - 'secp256r1 (NIST P-256)': 256, - 'secp384r1 (NIST P-384)': 384, - 'secp521r1 (NIST P-521)': 521, - - }; - if (curveName in curveBits) { - return curveBits[curveName].toString(); - } - console.log('\x1b[31m%s\x1b[0m', `curve name ${curveName} not found in curveBits`); - return "unknown"; - -} \ No newline at end of file diff --git a/registry/src/utils/certificateParsing/dataStructure.ts b/registry/src/utils/certificateParsing/dataStructure.ts deleted file mode 100644 index fc4cf63c..00000000 --- a/registry/src/utils/certificateParsing/dataStructure.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { StandardCurve } from "./curves"; - -export interface CertificateData { - id: string; - issuer: string; - validity: { - notBefore: string; - notAfter: string; - }; - subjectKeyIdentifier: string; - signatureAlgorithm: string; - hashAlgorithm: string; - publicKeyDetails: PublicKeyDetailsRSA | PublicKeyDetailsECDSA | PublicKeyDetailsRSAPSS | undefined; - rawPem: string; - rawTxt: string; -} - -export interface PublicKeyDetailsRSA { - modulus: string; - exponent: string; - bits: string; -} - -export interface PublicKeyDetailsRSAPSS extends PublicKeyDetailsRSA { - hashAlgorithm: string; - mgf: string; - saltLength: string; -} - -export interface PublicKeyDetailsECDSA { - curve: string; - params: StandardCurve; - bits: string; -} \ No newline at end of file diff --git a/registry/src/utils/certificateParsing/oids.ts b/registry/src/utils/certificateParsing/oids.ts deleted file mode 100644 index 231b2b2b..00000000 --- a/registry/src/utils/certificateParsing/oids.ts +++ /dev/null @@ -1,127 +0,0 @@ -export const oidMap: { [key: string]: string } = { - "1.2.840.113549.3.7": "3des", - "2.16.840.1.101.3.4.1.2": "aes128", - "2.16.840.1.101.3.4.1.5": "aes128wrap", - "2.16.840.1.101.3.4.1.22": "aes192", - "2.16.840.1.101.3.4.1.25": "aes192wrap", - "2.16.840.1.101.3.4.1.42": "aes256", - "2.16.840.1.101.3.4.1.45": "aes256wrap", - "1.3.36.3.3.2.8.1.1.1": "brainpoolP160r1", - "1.3.36.3.3.2.8.1.1.2": "brainpoolP160t1", - "1.3.36.3.3.2.8.1.1.3": "brainpoolP192r1", - "1.3.36.3.3.2.8.1.1.4": "brainpoolP192t1", - "1.3.36.3.3.2.8.1.1.5": "brainpoolP224r1", - "1.3.36.3.3.2.8.1.1.6": "brainpoolP224t1", - "1.3.36.3.3.2.8.1.1.7": "brainpoolP256r1", - "1.3.36.3.3.2.8.1.1.8": "brainpoolP256t1", - "1.3.36.3.3.2.8.1.1.9": "brainpoolP320r1", - "1.3.36.3.3.2.8.1.1.10": "brainpoolP320t1", - "1.3.36.3.3.2.8.1.1.11": "brainpoolP384r1", - "1.3.36.3.3.2.8.1.1.12": "brainpoolP384t1", - "1.3.36.3.3.2.8.1.1.13": "brainpoolP512r1", - "1.3.36.3.3.2.8.1.1.14": "brainpoolP512t1", - "2.5.4.6": "C", - "1.2.840.113549.1.9.16.3.6": "CMS3DESwrap", - "1.2.840.113549.1.9.16.3.7": "CMSRC2wrap", - "2.5.4.3": "CN", - "1.3.6.1.5.5.7.2.1": "CPS", - "0.9.2342.19200300.100.1.25": "DC", - "1.3.14.3.2.7": "des", - "2.5.4.13": "Description", - "1.2.840.10046.2.1": "DH", - "2.5.4.46": "dnQualifier", - "1.2.840.10040.4.1": "DSA", - "1.3.14.3.2.27": "dsaSHA1", - "1.2.840.113549.1.9.1": "E", - "1.2.156.11235.1.1.2.1": "ec192wapi", - "1.2.840.10045.2.1": "ECC", - "1.3.133.16.840.63.0.2": "ECDH_STD_SHA1_KDF", - "1.3.132.1.11.1": "ECDH_STD_SHA256_KDF", - "1.3.132.1.11.2": "ECDH_STD_SHA384_KDF", - "1.2.840.10045.3.1.7": "ECDSA_P256", - "1.3.132.0.34": "ECDSA_P384", - "1.3.132.0.35": "ECDSA_P521", - "1.2.840.113549.1.9.16.3.5": "ESDH", - "2.5.4.42": "G", - "2.5.4.43": "I", - "2.5.4.7": "L", - "1.2.840.113549.2.2": "md2", - "1.2.840.113549.1.1.2": "md2RSA", - "1.2.840.113549.2.4": "md4", - "1.2.840.113549.1.1.3": "md4RSA", - "1.2.840.113549.2.5": "md5", - "1.2.840.113549.1.1.4": "md5RSA", - "1.2.840.113549.1.1.8": "mgf1", - "2.16.840.1.101.2.1.1.20": "mosaicKMandUpdSig", - "2.16.840.1.101.2.1.1.19": "mosaicUpdatedSig", - "1.2.840.10045.3.1.1": "nistP192", - "1.3.132.0.33": "nistP224", - "1.3.6.1.5.5.7.6.2": "NO_SIGN", - "2.5.4.10": "O", - "2.5.4.11": "OU", - "2.5.4.20": "Phone", - "2.5.4.18": "POBox", - "2.5.4.17": "PostalCode", - "1.2.840.113549.3.2": "rc2", - "1.2.840.113549.3.4": "rc4", - "1.2.840.113549.1.1.1": "RSA", - "1.2.840.113549.1.1.7": "RSAES_OAEP", - "1.2.840.113549.1.1.10": "RSASSA_PSS", - "2.5.4.8": "S", - "1.3.132.0.9": "secP160k1", - "1.3.132.0.8": "secP160r1", - "1.3.132.0.30": "secP160r2", - "1.3.132.0.31": "secP192k1", - "1.3.132.0.32": "secP224k1", - "1.3.132.0.10": "secP256k1", - "2.5.4.5": "SERIALNUMBER", - "1.3.14.3.2.26": "sha1", - "1.2.840.10040.4.3": "sha1DSA", - "1.2.840.10045.4.1": "sha1ECDSA", - "1.2.840.113549.1.1.5": "sha1RSA", - "2.16.840.1.101.3.4.2.1": "sha256", - "1.2.840.10045.4.3.2": "sha256ECDSA", - "1.2.840.113549.1.1.11": "sha256RSA", - "2.16.840.1.101.3.4.2.2": "sha384", - "1.2.840.10045.4.3.3": "sha384ECDSA", - "1.2.840.113549.1.1.12": "sha384RSA", - "2.16.840.1.101.3.4.2.3": "sha512", - "1.2.840.10045.4.3.4": "sha512ECDSA", - "1.2.840.113549.1.1.13": "sha512RSA", - "2.5.4.4": "SN", - "1.2.840.10045.4.3": "specifiedECDSA", - "2.5.4.9": "STREET", - "2.5.4.12": "T", - "2.23.133.2.1": "TPMManufacturer", - "2.23.133.2.2": "TPMModel", - "2.23.133.2.3": "TPMVersion", - "2.23.43.1.4.9": "wtls9", - "2.5.4.24": "X21Address", - "1.2.840.10045.3.1.2": "x962P192v2", - "1.2.840.10045.3.1.3": "x962P192v3", - "1.2.840.10045.3.1.4": "x962P239v1", - "1.2.840.10045.3.1.5": "x962P239v2", - "1.2.840.10045.3.1.6": "x962P239v3", -}; - -export function getFriendlyName(oid: string): string { - return oidMap[oid] || "Unknown Algorithm"; -} - -export function extractHashFunction(friendlyName: string): string { - if (friendlyName.toLowerCase().includes('sha1')) { - return 'sha1' - } - if (friendlyName.toLowerCase().includes('sha256')) { - return 'sha256' - } - if (friendlyName.toLowerCase().includes('sha384')) { - return 'sha384' - } - if (friendlyName.toLowerCase().includes('sha512')) { - return 'sha512' - } - throw new Error("hash function not found in: " + friendlyName); - - return 'unknown' -} \ No newline at end of file diff --git a/registry/src/utils/certificateParsing/parseCertificate.ts b/registry/src/utils/certificateParsing/parseCertificate.ts deleted file mode 100644 index 793377ff..00000000 --- a/registry/src/utils/certificateParsing/parseCertificate.ts +++ /dev/null @@ -1,202 +0,0 @@ -import * as asn1js from "asn1js"; -import { Certificate, RSAPublicKey, RSASSAPSSParams } from "pkijs"; -import { extractHashFunction, getFriendlyName } from "./oids"; -import { CertificateData, PublicKeyDetailsECDSA, PublicKeyDetailsRSA, PublicKeyDetailsRSAPSS } from "./dataStructure"; -import { getECDSACurveBits, identifyCurve, StandardCurve } from "./curves"; -import { getIssuerCountryCode, getSubjectKeyIdentifier } from "./utils"; -import fs from 'fs'; -import { execSync } from 'child_process'; - -export function parseCertificate(pem: string, fileName: string): any { - let certificateData: CertificateData = { - id: '', - issuer: '', - validity: { - notBefore: '', - notAfter: '' - }, - subjectKeyIdentifier: '', - signatureAlgorithm: '', - hashAlgorithm: '', - publicKeyDetails: undefined, - rawPem: '', - rawTxt: '' - }; - try { - const pemFormatted = pem.replace(/(-----(BEGIN|END) CERTIFICATE-----|\n|\r)/g, ""); - const binary = Buffer.from(pemFormatted, "base64"); - const arrayBuffer = new ArrayBuffer(binary.length); - const view = new Uint8Array(arrayBuffer); - for (let i = 0; i < binary.length; i++) { - view[i] = binary[i]; - } - - const asn1 = asn1js.fromBER(arrayBuffer); - if (asn1.offset === -1) { - throw new Error(`ASN.1 parsing error: ${asn1.result.error}`); - } - - const cert = new Certificate({ schema: asn1.result }); - const publicKeyAlgoOID = cert.subjectPublicKeyInfo.algorithm.algorithmId; - const publicKeyAlgoFN = getFriendlyName(publicKeyAlgoOID); - const signatureAlgoOID = cert.signatureAlgorithm.algorithmId; - const signatureAlgoFN = getFriendlyName(signatureAlgoOID); - - - let params; - if (publicKeyAlgoFN === 'RSA') { - if (signatureAlgoFN === 'RSASSA_PSS') { - certificateData.signatureAlgorithm = "rsapss"; - params = getParamsRSAPSS(cert); - certificateData.hashAlgorithm = (params as PublicKeyDetailsRSAPSS).hashAlgorithm; - } - else { - certificateData.hashAlgorithm = extractHashFunction(signatureAlgoFN); - certificateData.signatureAlgorithm = "rsa"; - params = getParamsRSA(cert); - } - - } - else if (publicKeyAlgoFN === 'ECC') { - certificateData.hashAlgorithm = extractHashFunction(signatureAlgoFN); - certificateData.signatureAlgorithm = "ecdsa"; - params = getParamsECDSA(cert); - } - else { - console.log(publicKeyAlgoFN); - } - certificateData.publicKeyDetails = params; - certificateData.issuer = getIssuerCountryCode(cert);; - certificateData.validity = { - notBefore: cert.notBefore.value.toString(), - notAfter: cert.notAfter.value.toString() - }; - const ski = getSubjectKeyIdentifier(cert); - certificateData.id = ski.slice(0, 12); - certificateData.subjectKeyIdentifier = ski; - - certificateData.rawPem = pem; - const tempCertPath = `/tmp/${fileName}.pem`; - fs.writeFileSync(tempCertPath, pem); - try { - const openSslOutput = execSync(`openssl x509 -in ${tempCertPath} -text -noout`).toString(); - certificateData.rawTxt = openSslOutput; - } catch (error) { - console.error(`Error executing OpenSSL command: ${error}`); - certificateData.rawTxt = 'Error: Unable to generate human-readable format'; - } finally { - fs.unlinkSync(tempCertPath); - } - - - return certificateData; - - } catch (error) { - console.error(`Error processing certificate ${fileName}:`, error); - throw error; - } -} - -function getParamsRSA(cert: Certificate): PublicKeyDetailsRSA { - const publicKeyValue = cert.subjectPublicKeyInfo.parsedKey as RSAPublicKey; - const modulusBigInt = publicKeyValue.modulus.toBigInt(); - const modulusHex = modulusBigInt < 0n ? (-modulusBigInt).toString(16) : modulusBigInt.toString(16); - const exponentBigInt = publicKeyValue.publicExponent.toBigInt(); - const exponentDecimal = exponentBigInt.toString(); - - const modulusBytes = publicKeyValue.modulus.valueBlock.valueHexView; - const actualBits = modulusBytes.length * 8; - - return { - modulus: modulusHex, - exponent: exponentDecimal, - bits: actualBits.toString() - }; -} - -function getParamsRSAPSS(cert: Certificate): PublicKeyDetailsRSAPSS { - const { modulus, exponent, bits } = getParamsRSA(cert); - const sigAlgParams = cert.signatureAlgorithm.algorithmParams; - const pssParams = new RSASSAPSSParams({ schema: sigAlgParams }); - const hashAlgorithm = getFriendlyName(pssParams.hashAlgorithm.algorithmId); - const mgf = getFriendlyName(pssParams.maskGenAlgorithm.algorithmId); - - return { - modulus: modulus, - exponent: exponent, - bits: bits, - hashAlgorithm: hashAlgorithm, - mgf: mgf, - saltLength: pssParams.saltLength.toString() - }; -} - -export function getParamsECDSA(cert: Certificate): PublicKeyDetailsECDSA { - try { - const algorithmParams = cert.subjectPublicKeyInfo.algorithm.algorithmParams; - if (!algorithmParams) { - console.log('No algorithm params found'); - return { curve: 'Unknown', params: {} as StandardCurve, bits: 'Unknown' }; - } - - const params = asn1js.fromBER(algorithmParams.valueBeforeDecodeView).result; - const valueBlock: any = params.valueBlock; - - if (valueBlock.value && valueBlock.value.length >= 5) { - const curveParams: StandardCurve = {} as StandardCurve; - // Field ID (index 1) - const fieldId = valueBlock.value[1]; - if (fieldId && fieldId.valueBlock && fieldId.valueBlock.value) { - const fieldType = fieldId.valueBlock.value[0]; - const prime = fieldId.valueBlock.value[1]; - //curveParams.fieldType = fieldType.valueBlock.toString(); - curveParams.p = Buffer.from(prime.valueBlock.valueHexView).toString('hex'); - } - - // Curve Coefficients (index 2) - const curveCoefficients = valueBlock.value[2]; - if (curveCoefficients && curveCoefficients.valueBlock && curveCoefficients.valueBlock.value) { - const a = curveCoefficients.valueBlock.value[0]; - const b = curveCoefficients.valueBlock.value[1]; - curveParams.a = Buffer.from(a.valueBlock.valueHexView).toString('hex'); - curveParams.b = Buffer.from(b.valueBlock.valueHexView).toString('hex'); - } - - // Base Point G (index 3) - const basePoint = valueBlock.value[3]; - if (basePoint && basePoint.valueBlock) { - curveParams.G = Buffer.from(basePoint.valueBlock.valueHexView).toString('hex'); - } - - // Order n (index 4) - const order = valueBlock.value[4]; - if (order && order.valueBlock) { - curveParams.n = Buffer.from(order.valueBlock.valueHexView).toString('hex'); - } - - if (valueBlock.value.length >= 6) { - // Cofactor h (index 5) - const cofactor = valueBlock.value[5]; - if (cofactor && cofactor.valueBlock) { - curveParams.h = Buffer.from(cofactor.valueBlock.valueHexView).toString('hex'); - } - } - else { - curveParams.h = '01'; - } - - const identifiedCurve = identifyCurve(curveParams); - return { curve: identifiedCurve, params: curveParams, bits: getECDSACurveBits(identifiedCurve) }; - } else { - if (valueBlock.value) { - console.log(valueBlock.value); - } - else { - console.log('No value block found'); - } - } - } catch (error) { - console.error('Error parsing EC parameters:', error); - return { curve: 'Error', params: {} as StandardCurve, bits: 'Unknown' }; - } -} \ No newline at end of file diff --git a/registry/src/utils/certificateParsing/utils.ts b/registry/src/utils/certificateParsing/utils.ts deleted file mode 100644 index 539ce5f7..00000000 --- a/registry/src/utils/certificateParsing/utils.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Certificate } from "pkijs"; - -export const getSubjectKeyIdentifier = (cert: Certificate): string => { - const subjectKeyIdentifier = cert.extensions.find( - (ext) => ext.extnID === '2.5.29.14' - ); - if (subjectKeyIdentifier) { - let skiValue = Buffer.from(subjectKeyIdentifier.extnValue.valueBlock.valueHexView).toString('hex'); - - skiValue = skiValue.replace(/^(?:3016)?(?:0414)?/, ''); - return skiValue - } else { - // do a sha1 of the certificate tbs - const crypto = require('crypto'); - const sha1 = crypto.createHash('sha1'); - sha1.update(cert.tbsView); - return sha1.digest('hex'); - } -} - -export function getIssuerCountryCode(cert: Certificate): string { - const issuerRDN = cert.issuer.typesAndValues; - let issuerCountryCode = ''; - for (const rdn of issuerRDN) { - if (rdn.type === '2.5.4.6') { // OID for Country Name - issuerCountryCode = rdn.value.valueBlock.value; - break; - } - } - return issuerCountryCode.toUpperCase(); -} \ No newline at end of file diff --git a/sdk/core/src/AttestationVerifier.ts b/sdk/core/src/AttestationVerifier.ts index e39e8acd..4f9d1b01 100644 --- a/sdk/core/src/AttestationVerifier.ts +++ b/sdk/core/src/AttestationVerifier.ts @@ -21,7 +21,6 @@ import { } from '../../../common/src/utils/openPassportAttestation'; import { Mode } from 'fs'; import forge from 'node-forge'; -import { parseCertificate } from '../../../common/src/utils/certificates/handleCertificate'; import { castToScope, formatForbiddenCountriesListFromCircuitOutput, @@ -33,6 +32,8 @@ import { unpackReveal } from '../../../common/src/utils/revealBitmap'; import { getCSCAModulusMerkleTree } from '../../../common/src/utils/csca'; import { OpenPassportVerifierReport } from './OpenPassportVerifierReport'; import { fetchTreeFromUrl } from '../../../common/src/utils/pubkeyTree'; +import { parseCertificateSimple } from '../../../common/src/utils/certificate_parsing/parseCertificateSimple'; +import { PublicKeyDetailsRSA } from '../../../common/src/utils/certificate_parsing/dataStructure'; export class AttestationVerifier { protected devMode: boolean; @@ -211,12 +212,13 @@ export class AttestationVerifier { console.log('\x1b[32m%s\x1b[0m', '- certificate verified'); } - const parsedDsc = parseCertificate(attestation.dsc.value); + const parsedDsc = parseCertificateSimple(attestation.dsc.value); const signatureAlgorithmDsc = parsedDsc.signatureAlgorithm; if (signatureAlgorithmDsc === 'ecdsa') { throw new Error('ECDSA not supported yet'); } else { - const dscModulus = parsedDsc.modulus; + const publicKeyDetails: PublicKeyDetailsRSA = parsedDsc.publicKeyDetails as PublicKeyDetailsRSA; + const dscModulus = publicKeyDetails.modulus; const dscModulusBigInt = BigInt(`0x${dscModulus}`); const dscModulusWords = splitToWords(dscModulusBigInt, n_dsc, k_dsc); const pubKeyFromProof = parsePublicSignalsProve( diff --git a/sdk/core/utils/utils.ts b/sdk/core/utils/utils.ts index 96a6d205..c76a7d44 100644 --- a/sdk/core/utils/utils.ts +++ b/sdk/core/utils/utils.ts @@ -18,8 +18,8 @@ import { vkey_dsc_rsapss_65537_sha256, vkey_vc_and_disclose, } from '../../../common/src/constants/vkey'; -import { getCircuitNameOld } from '../../../common/src/utils/certificates/handleCertificate'; import { Mode } from 'fs'; +import { getCircuitNameOld } from '../../../common/src/utils/certificate_parsing/parseCertificateSimple'; export function getCurrentDateFormatted() { return getCurrentDateYYMMDD().map((datePart) => BigInt(datePart).toString()); From d8a22d3127d8d5c861bfc870b8973cb69a449c84 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Wed, 1 Jan 2025 16:51:23 +0100 Subject: [PATCH 4/8] uncomment tests --- circuits/tests/prove.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/circuits/tests/prove.test.ts b/circuits/tests/prove.test.ts index efbb02ed..1900020a 100644 --- a/circuits/tests/prove.test.ts +++ b/circuits/tests/prove.test.ts @@ -11,8 +11,8 @@ import { SMT } from '@openpassport/zk-kit-smt'; import namejson from '../../common/ofacdata/outputs/nameSMT.json'; import { getCircuitName } from '../../common/src/utils/certificate_parsing/parseCertificateSimple'; const sigAlgs = [ - // { sigAlg: 'rsapss', hashFunction: 'sha256', domainParameter: '3', keyLength: '3072' }, - // { sigAlg: 'rsa', hashFunction: 'sha256', domainParameter: '65537', keyLength: '3072' }, + { sigAlg: 'rsapss', hashFunction: 'sha256', domainParameter: '3', keyLength: '3072' }, + { sigAlg: 'rsa', hashFunction: 'sha256', domainParameter: '65537', keyLength: '3072' }, { sigAlg: 'ecdsa', hashFunction: 'sha1', domainParameter: 'secp256r1', keyLength: '256' }, ]; From 7ee31e055712821fbbbd86485488fcfe4a67efd7 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Wed, 1 Jan 2025 16:59:01 +0100 Subject: [PATCH 5/8] fix getLeaf function --- common/src/utils/pubkeyTree.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common/src/utils/pubkeyTree.ts b/common/src/utils/pubkeyTree.ts index 29b81d18..f3decc54 100644 --- a/common/src/utils/pubkeyTree.ts +++ b/common/src/utils/pubkeyTree.ts @@ -48,8 +48,8 @@ export function getLeaf(dsc: string): string { let qy = splitToWords(BigInt(hexToDecimal(y)), n, k); return customHasher([sigAlgIndex, ...qx, ...qy]); } else { - const { modulus, bits } = publicKeyDetails as PublicKeyDetailsRSA; - const sigAlgKey = `${signatureAlgorithm}_${hashAlgorithm}_${modulus}_${bits}`; + const { modulus, bits, exponent } = publicKeyDetails as PublicKeyDetailsRSA; + const sigAlgKey = `${signatureAlgorithm}_${hashAlgorithm}_${exponent}_${bits}`; const { n, k } = getNAndK(sigAlgKey as SignatureAlgorithm); const pubkeyChunked = splitToWords(BigInt(hexToDecimal(modulus)), n, k); @@ -74,8 +74,8 @@ export function getLeafCSCA(dsc: string): string { let qy = splitToWords(BigInt(hexToDecimal(y)), n, k); return customHasher([sigAlgIndex, ...qx, ...qy]); } else { - const { modulus, bits } = publicKeyDetails as PublicKeyDetailsRSA; - const sigAlgKey = `${signatureAlgorithm}_${hashAlgorithm}_${modulus}_${bits}`; + const { modulus, bits, exponent } = publicKeyDetails as PublicKeyDetailsRSA; + const sigAlgKey = `${signatureAlgorithm}_${hashAlgorithm}_${exponent}_${bits}`; const sigAlgIndex = SignatureAlgorithmIndex[sigAlgKey]; if (sigAlgIndex == undefined) { From 7acf4b903243da765f6d1284b25b32ba95004829 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Wed, 1 Jan 2025 17:04:50 +0100 Subject: [PATCH 6/8] fix generate inputs prove --- common/src/utils/generateInputs.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/common/src/utils/generateInputs.ts b/common/src/utils/generateInputs.ts index a05a3ebe..980c4683 100644 --- a/common/src/utils/generateInputs.ts +++ b/common/src/utils/generateInputs.ts @@ -32,6 +32,7 @@ import { packBytes } from '../utils/utils'; import { SMT } from '@openpassport/zk-kit-smt'; import { parseCertificateSimple } from './certificate_parsing/parseCertificateSimple'; import { PublicKeyDetailsECDSA, PublicKeyDetailsRSA } from './certificate_parsing/dataStructure'; +import { cp } from 'fs'; export function generateCircuitInputsDisclose( secret: string, @@ -204,8 +205,8 @@ export function generateCircuitInputsProve( const dsc_modulus_y = splitToWords(BigInt(hexToDecimal(y)), n, k); pubKey = [...dsc_modulus_x, ...dsc_modulus_y]; } else { - const modulus = (publicKeyDetails as PublicKeyDetailsRSA).modulus; - signatureAlgorithmFullName = `${signatureAlgorithm}_${hashAlgorithm}_${modulus}_${publicKeyDetails.bits}`; + const { modulus, exponent } = (publicKeyDetails as PublicKeyDetailsRSA); + signatureAlgorithmFullName = `${signatureAlgorithm}_${hashAlgorithm}_${exponent}_${publicKeyDetails.bits}`; ({ n, k } = getNAndK(signatureAlgorithmFullName as SignatureAlgorithm)); signature = splitToWords(BigInt(bytesToBigDecimal(encryptedDigest)), n, k); pubKey = splitToWords(BigInt(hexToDecimal(modulus)), n, k); @@ -233,6 +234,7 @@ export function generateCircuitInputsProve( ); } + console.log('signatureAlgorithmFullName', signatureAlgorithmFullName); const [eContentPadded, eContentLen] = shaPad( new Uint8Array(eContent), MAX_PADDED_ECONTENT_LEN[signatureAlgorithmFullName] From 9973af2c647a96a440af5b64d91a23883ed7209a Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Thu, 2 Jan 2025 11:21:19 +0100 Subject: [PATCH 7/8] update parse passport data scripts --- app/src/utils/parsePassportData.ts | 82 +++++++------------ .../src/passport_data/parse_passport_data.ts | 1 - 2 files changed, 31 insertions(+), 52 deletions(-) diff --git a/app/src/utils/parsePassportData.ts b/app/src/utils/parsePassportData.ts index 613029c2..1c185113 100644 --- a/app/src/utils/parsePassportData.ts +++ b/app/src/utils/parsePassportData.ts @@ -88,12 +88,10 @@ export function getSimplePublicKeyDetails(certData: CertificateData): string { } export function parsePassportData(passportData: PassportData): PassportMetadata { - // Extract DG1 hash info const dg1HashInfo = passportData.mrz ? findDG1HashInEContent(passportData.mrz, passportData.eContent) : null; - // Use extracted DG1 hash if found, otherwise use provided dg1Hash const dg1Hash = dg1HashInfo?.hash || passportData.dg1Hash; const dg1HashFunction = dg1HashInfo?.hashFunction || 'unknown'; @@ -107,54 +105,36 @@ export function parsePassportData(passportData: PassportData): PassportMetadata const { hashFunction: eContentHashFunction, offset: eContentHashOffset } = findHashSizeOfEContent(passportData.eContent, passportData.signedAttr); - const parsedDsc: CertificateData | null = passportData.dsc ? - parseCertificateSimple(passportData.dsc) : - null; - - const dscHashFunction = parsedDsc ? - parsedDsc.hashAlgorithm : - 'unknown'; - - const dscSignature = parsedDsc ? - parsedDsc.signatureAlgorithm : - 'unknown'; - - const dscSignatureAlgorithmDetails = parsedDsc ? - getSimplePublicKeyDetails(parsedDsc) : - 'unknown'; - - const dscSignatureAlgorithmBits = parsedDsc ? - parsedDsc.publicKeyDetails?.bits : - 'unknown'; - - const dscAKI = parsedDsc ? - parsedDsc.authorityKeyIdentifier : - 'unknown'; - - let csca: string | null = null; - if (dscAKI) { - csca = getCSCAFromSKI(dscAKI, true); + let parsedDsc = null; + let parsedCsca = null; + let csca = null; + let dscHashFunction = 'unknown'; + 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); + dscHashFunction = parsedDsc.hashAlgorithm; + dscSignature = parsedDsc.signatureAlgorithm; + dscSignatureAlgorithmDetails = getSimplePublicKeyDetails(parsedDsc); + dscSignatureAlgorithmBits = parseInt(parsedDsc.publicKeyDetails?.bits || '0'); + + if (parsedDsc.authorityKeyIdentifier) { + 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'); + } + } } - const parsedCsca = csca ? - parseCertificateSimple(csca) : - null; - - const cscaHashFunction = parsedCsca ? - parsedCsca.hashAlgorithm : - 'unknown'; - - const cscaSignature = parsedCsca ? - parsedCsca.signatureAlgorithm : - 'unknown'; - - const cscaSignatureAlgorithmDetails = parsedCsca ? - getCurveOrExponent(parsedCsca) : - 'unknown'; - - const cscaSignatureAlgorithmBits = parsedCsca ? - parsedCsca.publicKeyDetails?.bits : - 'unknown'; - return { dataGroups: passportData.dgPresents?.toString().split(',').map(item => item.replace('DG', '')).join(',') || 'None', @@ -168,14 +148,14 @@ export function parsePassportData(passportData: PassportData): PassportMetadata signatureAlgorithm: dscSignature, signatureAlgorithmDetails: dscSignatureAlgorithmDetails, curveOrExponent: parsedDsc ? getCurveOrExponent(parsedDsc) : 'unknown', - signatureAlgorithmBits: dscSignatureAlgorithmBits ? parseInt(dscSignatureAlgorithmBits) : 0, + signatureAlgorithmBits: dscSignatureAlgorithmBits, countryCode: passportData.mrz ? getCountryCodeFromMrz(passportData.mrz) : 'unknown', cscaFound: !!csca, cscaHashFunction, cscaSignature, cscaSignatureAlgorithmDetails, cscaCurveOrExponent: parsedCsca ? getCurveOrExponent(parsedCsca) : 'unknown', - cscaSignatureAlgorithmBits: cscaSignatureAlgorithmBits ? parseInt(cscaSignatureAlgorithmBits) : 0, + cscaSignatureAlgorithmBits: cscaSignatureAlgorithmBits, dsc: passportData.dsc }; } diff --git a/registry/src/passport_data/parse_passport_data.ts b/registry/src/passport_data/parse_passport_data.ts index e8e4facb..e79a5598 100644 --- a/registry/src/passport_data/parse_passport_data.ts +++ b/registry/src/passport_data/parse_passport_data.ts @@ -32,7 +32,6 @@ function parsePassportFile(filePath: string) { console.log(`CSCA Signature Algorithm Details: ${passportMetaData.cscaSignatureAlgorithmDetails}`); console.log(`CSCA Curve or Exponent: ${passportMetaData.cscaCurveOrExponent}`); console.log(`CSCA Signature Algorithm Bits: ${passportMetaData.cscaSignatureAlgorithmBits}`); - console.log(`DSC: ${passportMetaData.dsc}`); } catch (error) { console.error(`Error processing file ${filePath}:`, error); From 688c12a1919fe2cc11bea308d65a3b38b39608b5 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Thu, 2 Jan 2025 11:58:49 +0100 Subject: [PATCH 8/8] fix genMockPassportData.test.ts --- common/tests/genMockPassportData.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/tests/genMockPassportData.test.ts b/common/tests/genMockPassportData.test.ts index ab238c6c..8d876676 100644 --- a/common/tests/genMockPassportData.test.ts +++ b/common/tests/genMockPassportData.test.ts @@ -86,16 +86,16 @@ function verify(passportData: PassportData): boolean { const signature = Buffer.from(encryptedDigest).toString('binary'); if (signatureAlgorithm === 'rsapss') { - const saltLenght = (publicKeyDetails as PublicKeyDetailsRSAPSS).saltLength; const pss = forge.pss.create({ md: forge.md[hashAlgorithm].create(), mgf: forge.mgf.mgf1.create(forge.md[hashAlgorithm].create()), - saltLength: saltLenght, + saltLength: parseInt((publicKeyDetails as PublicKeyDetailsRSAPSS).saltLength), }); return publicKey.verify(md.digest().bytes(), signature, pss); } else { return publicKey.verify(md.digest().bytes(), signature); } + } }