clean certificate parsing library

This commit is contained in:
turnoffthiscomputer
2025-01-01 16:49:49 +01:00
parent ae3bc6884e
commit dd25996b57
29 changed files with 279 additions and 1486 deletions

View File

@@ -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]) {

View File

@@ -29,6 +29,8 @@ export interface PublicKeyDetailsRSAPSS extends PublicKeyDetailsRSA {
}
export interface PublicKeyDetailsECDSA {
x: string;
y: string;
curve: string;
params: StandardCurve;
bits: string;

View File

@@ -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 {

View File

@@ -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 = {

View File

@@ -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 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');
}
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;
}
}

View File

@@ -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');
}

View File

@@ -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';
}

View File

@@ -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;
}

View File

@@ -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 };
};

View File

@@ -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;
}
}

View File

@@ -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';

View File

@@ -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`);

View File

@@ -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,

View File

@@ -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]);
}