Skip to content

Commit

Permalink
Merge pull request #285 from openpassport-org/fix/ecdsa-certificate-p…
Browse files Browse the repository at this point in the history
…arsing

Fix/ecdsa certificate parsing
  • Loading branch information
remicolin authored Jan 2, 2025
2 parents a1019e7 + 688c12a commit 55c5e2c
Show file tree
Hide file tree
Showing 31 changed files with 336 additions and 1,531 deletions.
14 changes: 7 additions & 7 deletions app/src/screens/ProveScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -43,9 +43,9 @@ const ProveScreen: React.FC<ProveScreenProps> = ({ setSheetRegisterIsOpen }) =>

const [socket, setSocket] = useState<Socket | null>(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<void> => {
return new Promise((resolve) => {
Expand Down Expand Up @@ -165,18 +165,18 @@ const ProveScreen: React.FC<ProveScreenProps> = ({ 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:
Expand All @@ -190,7 +190,7 @@ const ProveScreen: React.FC<ProveScreenProps> = ({ setSheetRegisterIsOpen }) =>
proof: proof.proof,
publicSignals: proof.publicSignals,
signatureAlgorithm: signatureAlgorithm,
hashFunction: hashFunction,
hashFunction: hashAlgorithm,
dsc: passportData.dsc,
});
break;
Expand Down
82 changes: 31 additions & 51 deletions app/src/utils/parsePassportData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -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',
Expand All @@ -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
};
}
4 changes: 1 addition & 3 deletions app/src/utils/qrCode.ts
Original file line number Diff line number Diff line change
@@ -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<string, string> => {
const [, queryString] = url.split('?');
const params = new Map<string, string>();
Expand Down
2 changes: 1 addition & 1 deletion circuits/tests/dsc.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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' },
Expand Down
3 changes: 1 addition & 2 deletions circuits/tests/prove.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@ 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' },
Expand Down
28 changes: 20 additions & 8 deletions common/src/utils/certificate_parsing/curves.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

export interface StandardCurve {
name: string;
p: string;
Expand Down Expand Up @@ -36,8 +35,7 @@ export const standardCurves: StandardCurve[] = [
G: "0400C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650",
n: "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409",
h: "01"
}
,
},
{
name: "brainpoolP224r1",
p: "d7c134aa264366862a18302575d1d787b09f075797da89f57ec8c0ff",
Expand Down Expand Up @@ -108,22 +106,36 @@ export function identifyCurve(params: any): string {

export function getECDSACurveBits(curveName: string): string {
const curveBits: { [key: string]: number } = {
'secp224r1': 224,
'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,

'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";
}
export function getCurveForElliptic(curveName: string): string {
const curves = {
secp224r1: 'p224',
secp256r1: 'p256',
secp384r1: 'p384',
secp521r1: 'p521',
brainpoolP224r1: 'brainpoolP224r1',
brainpoolP256r1: 'brainpoolP256r1',
brainpoolP384r1: 'brainpoolP384r1',
brainpoolP512r1: 'brainpoolP512r1',
};

if (!curves[curveName]) {
throw new Error('Invalid curve: ' + curveName);
}

return curves[curveName];
}
2 changes: 2 additions & 0 deletions common/src/utils/certificate_parsing/dataStructure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ export interface PublicKeyDetailsRSAPSS extends PublicKeyDetailsRSA {
}

export interface PublicKeyDetailsECDSA {
x: string;
y: string;
curve: string;
params: StandardCurve;
bits: string;
Expand Down
13 changes: 12 additions & 1 deletion common/src/utils/certificate_parsing/oids.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
1 change: 0 additions & 1 deletion common/src/utils/certificate_parsing/parseCertificate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
Loading

0 comments on commit 55c5e2c

Please sign in to comment.