From b62dd7c4749452c77856e693dbea7fc368f727df Mon Sep 17 00:00:00 2001 From: iaco Date: Tue, 24 Jun 2025 11:42:05 +0100 Subject: [PATCH 1/4] chore: remove tmp folder --- .gitignore | 1 + tmp/device-response.mdl | Bin 3562 -> 0 bytes tmp/ephemeral-reader-key | 1 - tmp/session-transcript | Bin 582 -> 0 bytes 4 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 tmp/device-response.mdl delete mode 100644 tmp/ephemeral-reader-key delete mode 100644 tmp/session-transcript diff --git a/.gitignore b/.gitignore index e1cfb91..e0b3772 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ /node_modules /.idea /lib +/tmp /coverage .DS_Store diff --git a/tmp/device-response.mdl b/tmp/device-response.mdl deleted file mode 100644 index add820209f5d34c1743a3b534e5b1863c3a868c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3562 zcmb7{2|SeB8^_<-OxBDUB@AP!ON`zb*(x%ItkDRKElo3nVa6~EBC?efE!tHsV=YQ_ zrBXL;*;=HMeMzZkL$2yl&3{JSmcM&H|Ih!-ndO|{d7tll&Uxo~o>LGK&E)Y}+z2|s z1Y|L|bRmZsA>bz$gh+mSZHZ(Gxx5e)7N2WEumlOFCT1oC6OO$bo5kk~nY{I^kO(G2 z6c$0_FxN-Y=uCco)SU4Bba7v5BW#!qM zUEhSgqL;rJxLbJzW7UX!>0`E(##E95dYR@O0nBq^@>dG+}Nc;k`zz~pFI z#av!EGd7aN+wyNf;_`n2BEJEbAeP!a-HF&xDpT)}GdYu3jd&2N8caMXzsWVtKPWeJ zE|B~8Mh8U*Ih&chpVpE^Aet^WGqQeKCM}42-yl=#|gFT%L(aV!BJ(WkhjxlUz z?zORQ6R^ZX6n5S@eG+~yF*K6P6Yyv(!A~e(xQe(-{0LBXS>wD0fIuL?KFJFZ_X1=9 zt*C@jQb42Tqf{~Ig;-Da;}WA<`l>{kCwzg%o2iYU~|1RP>05uO#0~j!fE&xSAU?_J zenN7Ms&wi<7b!;_CGG!-10kVw2sCjIpdjgnqF^XsHBeMLpxdKo*wm4IB|#B3Wjr(g z{l>V&$>)(r^zz$!hSv1YoUgNLMV>Kgk4q%>UhKzuc8s|icrXf+WD;g5AGXaL5(6)P zomi_A_$+KZqt(8qci_Z@3^@bK*Mn-vy>b1U+fid{FICDhJ1+TQ_{lF6o&66Gg`dMO z3+pk;F1rhrNj68V#ej$3)B{&nw*fj{e&UmA_SJ4p25Rzv+p^+{aIYhQ%AC6{%(Fft zK7iI0SW~NEf9{yp#QYnMeJ4x8?w=hsv&g@k=n>h!M+|Ie9GuyxzG%Bks&J2&XZpH> z5si^f>+ZnfThHz0Bp5ewOc#EP52*9F5XoaTG(Kv$AotW+Uq|oU@PT*GJfU~4*|Es( ztc!;hJA_kOD9si5Hl?F`R{4gS$65!_r;62&eX22>C+u|{*>ygxw)R?++UkMRbejxH zZ$iQ0J||C)%F?Sebw81aybLU}lZ)dJZJX5Y!n99~x#c`uhx5xbqzt-X*=aiGRBKqh znc0S^iK5?kYbaW^y*$-`NgM0URQi;)IICin{o!M8Ute`ddtPyZ@#L@Y<1Y=`%WV&6 zF=Csahv}Ctwm$^v3b|j|H*k6M_zB_C;a45~!}(k4>xVZT*t_3(jJc5#0NbBqaN>NQ zD0U`(BIeKOQp5htCvVGh67LM}JEC3D**CQD_3@}WwMLI348>J{WcWivOHF`Q%7&Bm zde)!oQY_z{>A+j5-`4c>DanoGc(xOo@-P(JOP?^g=Zh5^Mlx&v=#kY&jrK)N=EMa5 z=6K$I#IdjZ}$BGB5Hx>2SxS&(oS)( zk-aCvtUIh(Yg2m4hrBXYTl0za=Z79jM(ad1*tFN2$|M6(vhck}H0?<$HC#66b z%?xGH*~}oi#Mg&#B|ezWWiV-^A0oh4r*DY|CDrOjSN%o#+dKc8ExWn4Ebt%^Pc;2^ zTVF2Wk%WTKG;%&JU^wUL@qGgb?R4C*t9tJ_e>;QQA^D@5e({4tlAMaH0 zRER^<>2~wH738rOG1b%YJI5C#Z0I^_qhax&$m-9BJIyy*-n!<0up`qe-oKfTy|WAx zUXWZ0CKrKP5X?wA>EnP^YL2_mw0s{SUf`r&McV6i! zJXmauSb6nTD>}8lyku!x))n}zDkyH{ne8Xg#j7~#9SO;6$&c*72vKsx-UBaT} z*3(824+c%{*6w-x#=D=?oGeepRVTEW$1aP*ya-_L9xLPOi|n z$3m)-_tVNsETA_8Wq)N?Dg0U;U|wMU@{xKvhrx_y(V4EyEzS|a+cQCnDT6L$1rOXtm1z z;O~`OOQTEU0wV7n6*qcFr_`@ALnA2+`Jvi!mnlBGKBMHCq0P_~+1Bq_%GzMQfF=;~ Gf&T!oQLS76 diff --git a/tmp/ephemeral-reader-key b/tmp/ephemeral-reader-key deleted file mode 100644 index cce6899..0000000 --- a/tmp/ephemeral-reader-key +++ /dev/null @@ -1 +0,0 @@ -Þ;Kž_rÝ›X@jã 4ÚH¦ùý ˆü°•Ž,ëì”| \ No newline at end of file diff --git a/tmp/session-transcript b/tmp/session-transcript deleted file mode 100644 index fdd4947c528441cc13fd672ed38e5b7c02bec30f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 582 zcmca15y|A(d_y84Vi7~Kp`HO_6C;r0y@ZiTfl)C+A*$nI)1Iea^nOK7u{SoItJgKH z|5N8pyZ9w8+f+;p)Bh<&C~VB@`4MsVcqR+`uEZ;cEtIQz{(QcdwXEn*!qV_nMt{^|-LCB+yQ9^=^?zHh63bM{wL#Nmld{2s-k7nwK{lNlKe7+G>t@{^?$co-843UV@& z6H7Al^YqK|QuLB?N>fYn^Gh=Ha#Hp3^OFoXq&0-P%{4R_nPeDa#FSjb$Rx3ulm0kR!@#> Date: Tue, 24 Jun 2025 11:42:42 +0100 Subject: [PATCH 2/4] chore: npm audit fix --- package-lock.json | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index c70affb..e771a42 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3199,10 +3199,11 @@ ] }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -10545,9 +10546,9 @@ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "requires": { "balanced-match": "^1.0.0", From 471dd1fa2c3398821012b345fd862d14b2b690f1 Mon Sep 17 00:00:00 2001 From: iaco Date: Tue, 24 Jun 2025 12:28:31 +0100 Subject: [PATCH 3/4] feat: support inclusion of intermediate certificates at issuance time --- src/mdoc/model/Document.ts | 18 ++++++++++++------ src/mdoc/utils.ts | 18 +++++++++++++++--- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/mdoc/model/Document.ts b/src/mdoc/model/Document.ts index 27f9647..ed0a477 100644 --- a/src/mdoc/model/Document.ts +++ b/src/mdoc/model/Document.ts @@ -163,14 +163,14 @@ export class Document { * * @param {Object} params - The parameters object * @param {jose.JWK | Uint8Array} params.issuerPrivateKey - The issuer's private key either in JWK format or COSE_KEY format as buffer. - * @param {string | Uint8Array} params.issuerCertificate - The issuer's certificate in pem format or as a buffer. + * @param {string | Uint8Array | Array} params.issuerCertificate - The issuer's certificate in pem format, as a buffer, or an array. * @param {SupportedAlgs} params.alg - The algorhitm used for the MSO signature. * @param {string | Uint8Array} [params.kid] - The key id of the issuer's private key. default: issuerPrivateKey.kid * @returns {Promise} - The signed document */ async sign(params: { issuerPrivateKey: jose.JWK | Uint8Array, - issuerCertificate: string | Uint8Array, + issuerCertificate: string | Uint8Array | Array, alg: SupportedAlgs, kid?: string | Uint8Array, }): Promise { @@ -178,9 +178,15 @@ export class Document { throw new Error('No namespaces added'); } - const issuerPublicKeyBuffer = typeof params.issuerCertificate === 'string' ? - fromPEM(params.issuerCertificate) : - params.issuerCertificate; + let issuerCertificateChain: Uint8Array[]; + + if (Array.isArray(params.issuerCertificate)) { + issuerCertificateChain = params.issuerCertificate.flatMap((cert) => (typeof cert === 'string' ? fromPEM(cert) : [cert])); + } else if (typeof params.issuerCertificate === 'string') { + issuerCertificateChain = fromPEM(params.issuerCertificate); + } else { + issuerCertificateChain = [params.issuerCertificate]; + } const issuerPrivateKeyJWK = params.issuerPrivateKey instanceof Uint8Array ? COSEKeyToJWK(params.issuerPrivateKey) : @@ -210,7 +216,7 @@ export class Document { const protectedHeader: ProtectedHeaders = { alg: params.alg }; const unprotectedHeader: UnprotectedHeaders = { kid: params.kid ?? issuerPrivateKeyJWK.kid, - x5chain: [issuerPublicKeyBuffer], + x5chain: issuerCertificateChain, }; const issuerAuth = await IssuerAuth.sign( diff --git a/src/mdoc/utils.ts b/src/mdoc/utils.ts index cf395f0..440043c 100644 --- a/src/mdoc/utils.ts +++ b/src/mdoc/utils.ts @@ -120,7 +120,19 @@ export function getRandomBytes(len: number) { return webcrypto.getRandomValues(new Uint8Array(len)); } -export function fromPEM(pem: string): Uint8Array { - const base64 = pem.replace(/-{5}(BEGIN|END) .*-{5}/gm, '').replace(/\s/gm, ''); - return Buffer.from(base64, 'base64'); +export function fromPEM(pem: string): Uint8Array[] { + const certs = pem + .split(/-----END CERTIFICATE-----/) + .map((block) => block.trim()) + .filter((block) => block.length > 0) + .map((block) => { + const fullBlock = `${block}\n-----END CERTIFICATE-----`; + const base64 = fullBlock + .replace(/-----BEGIN CERTIFICATE-----/, '') + .replace(/-----END CERTIFICATE-----/, '') + .replace(/\s+/g, ''); + return Buffer.from(base64, 'base64'); + }); + + return certs; } From becd33d689af54fb39562c0253ac6e9bf657de1a Mon Sep 17 00:00:00 2001 From: iaco Date: Wed, 25 Jun 2025 09:14:01 +0100 Subject: [PATCH 4/4] fix: x5chain must be a CBOR byte string if a single certificate is specified --- src/mdoc/model/Document.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mdoc/model/Document.ts b/src/mdoc/model/Document.ts index ed0a477..4ad7d3d 100644 --- a/src/mdoc/model/Document.ts +++ b/src/mdoc/model/Document.ts @@ -216,7 +216,7 @@ export class Document { const protectedHeader: ProtectedHeaders = { alg: params.alg }; const unprotectedHeader: UnprotectedHeaders = { kid: params.kid ?? issuerPrivateKeyJWK.kid, - x5chain: issuerCertificateChain, + x5chain: issuerCertificateChain.length === 1 ? issuerCertificateChain[0] : issuerCertificateChain, }; const issuerAuth = await IssuerAuth.sign(