@openeudi/openid4vp 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -124,6 +124,7 @@ class MyCustomParser implements ICredentialParser {
124
124
  | --------------------- | -------------- | ------------------------------------ |
125
125
  | `trustedCertificates` | `Uint8Array[]` | Issuer certificates to trust |
126
126
  | `nonce` | `string` | Expected nonce for replay protection |
127
+ | `skipTrustCheck` | `boolean?` | Explicit opt-in to skip the trust check. When omitted or `false`, `trustedCertificates` must be non-empty — otherwise parsing throws `MalformedCredentialError`. Use `true` for demo/mock environments. |
127
128
 
128
129
  ### PresentationResult
129
130
 
@@ -157,6 +158,31 @@ try {
157
158
  }
158
159
  ```
159
160
 
161
+ ## Scope and limitations
162
+
163
+ This library implements the **verifier side** of OpenID4VP for SD-JWT VC and mDOC credentials.
164
+
165
+ **What is implemented (v0.2.x):**
166
+
167
+ - SD-JWT VC: full cryptographic verification (issuer JWT signature via x5c, disclosure hashes, key binding JWT signature + sd_hash, nonce check)
168
+ - mDOC / ISO 18013-5 *mso_mdoc* format: CBOR decoding and claim extraction
169
+ - Algorithm allowlist (ES256/384/512 — ECDSA only per EUDI policy)
170
+ - Authorization request builder
171
+ - Certificate trust check via byte-equality against a caller-supplied trusted set
172
+
173
+ **What is NOT yet implemented** (planned for follow-up releases — do not assume compliance in production until present):
174
+
175
+ - mDOC / COSE_Sign1 cryptographic signature verification (design ready, implementation pending)
176
+ - X.509 certificate chain building and validation beyond leaf-byte-equality
177
+ - EU List of Trusted Lists (LOTL) / ETSI TL resolution
178
+ - Certificate revocation (CRL, OCSP)
179
+ - DCQL query / credential matching — see [@openeudi/dcql](https://www.npmjs.com/package/@openeudi/dcql)
180
+ - OpenID4VP HAIP (High Assurance Interoperability Profile) constraint validation
181
+ - OpenID Foundation conformance test suite integration
182
+ - SIOPv2 (Self-Issued OpenID Provider) identity flows
183
+
184
+ EUDI Architecture Reference Framework (ARF) alignment: tracks OpenID4VP 1.0 final. HAIP and ARF 1.4+ profile compliance will be added before a stable 1.0.
185
+
160
186
  ## Related packages
161
187
 
162
188
  - **[@openeudi/core](https://www.npmjs.com/package/@openeudi/core)** -- Framework-agnostic EUDI Wallet verification protocol engine with session management and QR code generation.
package/dist/index.cjs CHANGED
@@ -183,7 +183,13 @@ var SdJwtParser = class {
183
183
  certificate: issuerCertBytes,
184
184
  country: extractCountryHint(issuerString)
185
185
  };
186
- if (options.trustedCertificates.length > 0) {
186
+ if (options.trustedCertificates.length === 0) {
187
+ if (options.skipTrustCheck !== true) {
188
+ throw new MalformedCredentialError(
189
+ "trustedCertificates must not be empty unless skipTrustCheck is true"
190
+ );
191
+ }
192
+ } else {
187
193
  const isTrusted = options.trustedCertificates.some((trusted) => bytesEqual(trusted, issuerCertBytes));
188
194
  if (!isTrusted) {
189
195
  return invalidResult("Issuer certificate is not trusted");
@@ -399,13 +405,17 @@ var MdocParser = class {
399
405
  certificate: issuerCertBytes,
400
406
  country: ""
401
407
  };
402
- if (options.trustedCertificates.length > 0) {
408
+ if (options.trustedCertificates.length === 0) {
409
+ if (options.skipTrustCheck !== true) {
410
+ throw new MalformedCredentialError(
411
+ "trustedCertificates must not be empty unless skipTrustCheck is true"
412
+ );
413
+ }
414
+ } else {
403
415
  const isTrusted = options.trustedCertificates.some((trusted) => bytesEqual2(trusted, issuerCertBytes));
404
416
  if (!isTrusted) {
405
417
  return invalidResult("Issuer certificate is not trusted");
406
418
  }
407
- } else if (issuerCertBytes.length === 0) {
408
- return invalidResult("No issuer certificate found and no trusted certificates configured");
409
419
  }
410
420
  const { validUntil } = extractValidityPeriod(issuerAuth);
411
421
  if (validUntil) {
@@ -486,7 +496,7 @@ async function parsePresentation(vpToken, options) {
486
496
  }
487
497
 
488
498
  // src/index.ts
489
- var VERSION = "0.2.0";
499
+ var VERSION = "0.2.1";
490
500
 
491
501
  exports.ExpiredCredentialError = ExpiredCredentialError;
492
502
  exports.InvalidSignatureError = InvalidSignatureError;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/parsers/sd-jwt.parser.ts","../src/parsers/mdoc.parser.ts","../src/authorization.ts","../src/presentation.ts","../src/index.ts"],"names":["splitSdJwt","decodeProtectedHeader","importX509","jwtVerify","importJWK","decodeSdJwt","getClaims","bytesEqual","decode","mapToCredentialClaims","uuidv4"],"mappings":"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","file":"index.cjs","sourcesContent":["export class InvalidSignatureError extends Error {\n constructor(message = 'Credential signature validation failed') {\n super(message);\n this.name = 'InvalidSignatureError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class ExpiredCredentialError extends Error {\n constructor(message = 'Credential has expired') {\n super(message);\n this.name = 'ExpiredCredentialError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class UnsupportedFormatError extends Error {\n constructor(format: string) {\n super(`Unsupported credential format: ${format}`);\n this.name = 'UnsupportedFormatError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class MalformedCredentialError extends Error {\n constructor(message = 'Credential structure is malformed') {\n super(message);\n this.name = 'MalformedCredentialError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class NonceValidationError extends Error {\n constructor(message = 'Nonce does not match expected value') {\n super(message);\n this.name = 'NonceValidationError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n","import { splitSdJwt, decodeSdJwt, getClaims } from '@sd-jwt/decode';\nimport { decodeProtectedHeader, jwtVerify, importX509, importJWK } from 'jose';\n\nimport { MalformedCredentialError } from '../errors.js';\nimport type { IssuerInfo } from '../types/issuer.js';\nimport type { CredentialFormat, CredentialClaims, PresentationResult } from '../types/presentation.js';\n\nimport type { ICredentialParser, ParseOptions } from './parser.interface.js';\n\n/**\n * Hasher function signature expected by @sd-jwt/decode.\n * Inlined here to avoid a direct dependency on @sd-jwt/types.\n */\ntype SdJwtHasher = (data: string | ArrayBuffer, alg: string) => Promise<Uint8Array>;\n\nconst DEFAULT_ALLOWED_ALGORITHMS = ['ES256', 'ES384', 'ES512'];\n\n/**\n * SHA-256 hasher implementation using the Web Crypto API.\n * Compatible with the @sd-jwt/decode Hasher signature.\n */\nconst sha256Hasher: SdJwtHasher = async (data: string | ArrayBuffer, _alg: string): Promise<Uint8Array> => {\n const encoder = new TextEncoder();\n const input = typeof data === 'string' ? encoder.encode(data) : data;\n const hashBuffer = await crypto.subtle.digest('SHA-256', input);\n return new Uint8Array(hashBuffer);\n};\n\n// Standard base64 alphabet for decoding x5c certificate entries\nconst BASE64_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n/**\n * Decodes a standard base64-encoded string into raw bytes.\n * Does not depend on Node.js Buffer or browser atob.\n */\nfunction base64ToBytes(base64: string): Uint8Array<ArrayBuffer> {\n const cleaned = base64.replace(/=+$/, '');\n const byteLength = Math.floor((cleaned.length * 3) / 4);\n const buffer = new ArrayBuffer(byteLength);\n const bytes = new Uint8Array(buffer);\n\n let byteIndex = 0;\n for (let i = 0; i < cleaned.length; i += 4) {\n const a = BASE64_CHARS.indexOf(cleaned[i]);\n const b = i + 1 < cleaned.length ? BASE64_CHARS.indexOf(cleaned[i + 1]) : 0;\n const c = i + 2 < cleaned.length ? BASE64_CHARS.indexOf(cleaned[i + 2]) : 0;\n const d = i + 3 < cleaned.length ? BASE64_CHARS.indexOf(cleaned[i + 3]) : 0;\n\n bytes[byteIndex++] = (a << 2) | (b >> 4);\n if (byteIndex < byteLength) bytes[byteIndex++] = ((b & 0x0f) << 4) | (c >> 2);\n if (byteIndex < byteLength) bytes[byteIndex++] = ((c & 0x03) << 6) | d;\n }\n\n return bytes;\n}\n\n/**\n * Checks whether two Uint8Array instances contain identical bytes.\n */\nfunction bytesEqual(a: Uint8Array, b: Uint8Array): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false;\n }\n return true;\n}\n\n/**\n * Converts a base64-encoded DER certificate to PEM format for jose.importX509.\n */\nfunction derToPem(base64Der: string): string {\n const lines = base64Der.match(/.{1,64}/g) || [];\n return `-----BEGIN CERTIFICATE-----\\n${lines.join('\\n')}\\n-----END CERTIFICATE-----`;\n}\n\n/**\n * Encodes a Uint8Array to base64url (no padding).\n * Used by disclosure hash verification (Task 5) and KB-JWT verification (Task 6).\n */\nfunction bytesToBase64url(bytes: Uint8Array): string {\n let binary = '';\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n return globalThis.btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\n/**\n * Maps raw decoded claims to the CredentialClaims structure,\n * picking known age/residency fields and preserving any extra keys.\n */\nfunction mapToCredentialClaims(raw: Record<string, unknown>): CredentialClaims {\n const claims: CredentialClaims = {};\n\n if (typeof raw['age_over_18'] === 'boolean') {\n claims.age_over_18 = raw['age_over_18'];\n }\n if (typeof raw['age_over_21'] === 'boolean') {\n claims.age_over_21 = raw['age_over_21'];\n }\n if (typeof raw['resident_country'] === 'string') {\n claims.resident_country = raw['resident_country'];\n }\n if (typeof raw['nationality'] === 'string') {\n claims.nationality = raw['nationality'];\n }\n if (typeof raw['family_name_birth'] === 'string') {\n claims.family_name_birth = raw['family_name_birth'];\n }\n\n for (const [key, value] of Object.entries(raw)) {\n if (\n !(key in claims) &&\n !key.startsWith('_sd') &&\n key !== 'iss' &&\n key !== 'exp' &&\n key !== 'iat' &&\n key !== 'cnf' &&\n key !== 'vct'\n ) {\n claims[key] = value;\n }\n }\n\n return claims;\n}\n\n/**\n * Best-effort extraction of a country code hint from an issuer URL or string.\n */\nfunction extractCountryHint(issuer: string): string {\n try {\n const url = new URL(issuer);\n const tld = url.hostname.split('.').pop()?.toUpperCase();\n if (tld && tld.length === 2) {\n return tld;\n }\n } catch {\n // Not a valid URL\n }\n return '';\n}\n\n/**\n * SD-JWT VC credential parser.\n *\n * Decodes and cryptographically validates SD-JWT Verifiable Credentials:\n * - JWT signature verification via x5c public key (jose)\n * - Issuer certificate trust chain verification\n * - Disclosure hash integrity verification\n * - Key binding JWT signature and sd_hash verification\n * - Selective disclosure claim extraction\n */\nexport class SdJwtParser implements ICredentialParser {\n readonly format: CredentialFormat = 'sd-jwt-vc';\n\n canParse(vpToken: unknown): boolean {\n return typeof vpToken === 'string' && vpToken.includes('~');\n }\n\n async parse(vpToken: unknown, options: ParseOptions): Promise<PresentationResult> {\n if (typeof vpToken !== 'string') {\n throw new MalformedCredentialError('VP token must be a string');\n }\n\n const allowedAlgorithms = options.allowedAlgorithms ?? DEFAULT_ALLOWED_ALGORITHMS;\n\n const invalidResult = (error: string): PresentationResult => ({\n valid: false,\n format: this.format,\n claims: {},\n issuer: { certificate: new Uint8Array(), country: '' },\n error,\n });\n\n // Step 1: Split the SD-JWT into components\n let parts: ReturnType<typeof splitSdJwt>;\n try {\n parts = splitSdJwt(vpToken);\n } catch {\n throw new MalformedCredentialError('Failed to split SD-JWT structure');\n }\n\n // Step 2: Peek at issuer JWT header (need alg and x5c before verification)\n let header: ReturnType<typeof decodeProtectedHeader>;\n try {\n header = decodeProtectedHeader(parts.jwt);\n } catch {\n throw new MalformedCredentialError('Failed to decode SD-JWT issuer JWT header');\n }\n\n // Step 3: Check algorithm against allowlist\n const alg = header.alg;\n if (typeof alg !== 'string' || !allowedAlgorithms.includes(alg)) {\n return invalidResult(`Unsupported algorithm: ${alg}`);\n }\n\n // Step 4: Extract public key from x5c certificate\n const x5cArray = header.x5c;\n if (!Array.isArray(x5cArray) || x5cArray.length === 0 || typeof x5cArray[0] !== 'string') {\n throw new MalformedCredentialError('Missing or invalid x5c in JWT header');\n }\n\n let issuerKey: Awaited<ReturnType<typeof importX509>>;\n let issuerCertBytes: Uint8Array;\n try {\n issuerKey = await importX509(derToPem(x5cArray[0]), alg);\n issuerCertBytes = base64ToBytes(x5cArray[0]);\n } catch (err) {\n if (err instanceof MalformedCredentialError) throw err;\n throw new MalformedCredentialError('Failed to import issuer certificate');\n }\n\n // Step 5: Verify issuer JWT signature (also validates exp, iat via jose)\n let payload: Record<string, unknown>;\n try {\n const result = await jwtVerify(parts.jwt, issuerKey, { algorithms: allowedAlgorithms });\n payload = result.payload as unknown as Record<string, unknown>;\n } catch {\n return invalidResult('Issuer JWT signature verification failed');\n }\n\n // Step 6: Trust check — certificate must be in the trusted set\n const issuerString = typeof payload['iss'] === 'string' ? payload['iss'] : '';\n const issuerInfo: IssuerInfo = {\n certificate: issuerCertBytes,\n country: extractCountryHint(issuerString),\n };\n\n if (options.trustedCertificates.length > 0) {\n const isTrusted = options.trustedCertificates.some((trusted) => bytesEqual(trusted, issuerCertBytes));\n if (!isTrusted) {\n return invalidResult('Issuer certificate is not trusted');\n }\n }\n\n // Step 7: Verify disclosure hashes against _sd array\n const sdArray = payload['_sd'];\n if (parts.disclosures.length > 0) {\n if (!Array.isArray(sdArray) || sdArray.length === 0) {\n return invalidResult('Disclosures present but no _sd array in issuer JWT');\n }\n for (const disclosure of parts.disclosures) {\n const hashBytes = await sha256Hasher(disclosure, 'sha-256');\n const hashB64url = bytesToBase64url(hashBytes);\n if (!sdArray.includes(hashB64url)) {\n return invalidResult('Disclosure hash mismatch');\n }\n }\n }\n\n // Step 8: Verify key binding JWT (if present)\n if (parts.kbJwt) {\n // Extract holder public key from cnf claim\n const cnf = payload['cnf'] as Record<string, unknown> | undefined;\n if (!cnf || typeof cnf !== 'object' || !cnf['jwk']) {\n throw new MalformedCredentialError('Missing cnf.jwk in issuer JWT for key binding');\n }\n\n let holderKey: Awaited<ReturnType<typeof importJWK>>;\n try {\n const kbHeader = decodeProtectedHeader(parts.kbJwt);\n const kbAlg = kbHeader.alg;\n if (typeof kbAlg !== 'string' || !allowedAlgorithms.includes(kbAlg)) {\n return invalidResult(`Unsupported KB-JWT algorithm: ${kbAlg}`);\n }\n holderKey = await importJWK(cnf['jwk'] as Record<string, unknown>, kbAlg);\n } catch (err) {\n if (err instanceof MalformedCredentialError) throw err;\n throw new MalformedCredentialError('Failed to import holder key from cnf.jwk');\n }\n\n // Verify KB-JWT signature\n let kbPayload: Record<string, unknown>;\n try {\n const kbResult = await jwtVerify(parts.kbJwt, holderKey, {\n algorithms: allowedAlgorithms,\n ...(options.audience ? { audience: options.audience } : {}),\n });\n kbPayload = kbResult.payload as unknown as Record<string, unknown>;\n } catch {\n return invalidResult('Key binding JWT signature verification failed');\n }\n\n // Validate nonce — must be present and match when KB-JWT is used\n if (kbPayload['nonce'] !== options.nonce) {\n return invalidResult('Key binding JWT nonce does not match');\n }\n\n // Verify sd_hash — hash of the SD-JWT content before the KB-JWT\n const disclosurePart = parts.disclosures.length > 0 ? parts.disclosures.join('~') + '~' : '';\n const sdJwtForHash = parts.jwt + '~' + disclosurePart;\n const sdHashBytes = await sha256Hasher(sdJwtForHash, 'sha-256');\n const expectedSdHash = bytesToBase64url(sdHashBytes);\n if (kbPayload['sd_hash'] !== expectedSdHash) {\n return invalidResult('Key binding JWT sd_hash does not match');\n }\n }\n\n // Step 9: Decode disclosures and extract claims\n let resolvedClaims: Record<string, unknown>;\n try {\n const decoded = await decodeSdJwt(vpToken, sha256Hasher);\n resolvedClaims = await getClaims<Record<string, unknown>>(\n decoded.jwt.payload,\n decoded.disclosures,\n sha256Hasher\n );\n } catch {\n throw new MalformedCredentialError('Failed to decode SD-JWT disclosures');\n }\n\n return {\n valid: true,\n format: this.format,\n claims: mapToCredentialClaims(resolvedClaims),\n issuer: issuerInfo,\n };\n }\n}\n","import { decode } from 'cbor-x';\n\nimport { MalformedCredentialError } from '../errors.js';\nimport type { IssuerInfo } from '../types/issuer.js';\nimport type { CredentialFormat, CredentialClaims, PresentationResult } from '../types/presentation.js';\n\nimport type { ICredentialParser, ParseOptions } from './parser.interface.js';\n\n/**\n * Runtime check for binary data. Returns true for Uint8Array and Node.js Buffer\n * without referencing the Buffer type (which is unavailable in DOM-only tsconfig).\n * Buffer extends Uint8Array, so `instanceof Uint8Array` catches both.\n */\nfunction isBinaryData(value: unknown): value is Uint8Array {\n return value instanceof Uint8Array;\n}\n\n/**\n * Checks whether two Uint8Array instances contain identical bytes.\n */\nfunction bytesEqual(a: Uint8Array, b: Uint8Array): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false;\n }\n return true;\n}\n\n/**\n * Represents a single IssuerSignedItem element from an mDOC nameSpace.\n * ISO 18013-5 Section 8.3.2.1.2.\n */\ninterface IssuerSignedItem {\n digestID: number;\n random: Uint8Array | unknown;\n elementIdentifier: string;\n elementValue: unknown;\n}\n\n/**\n * Simplified DeviceResponse structure from ISO 18013-5.\n * Only the fields required for claim extraction and trust validation.\n */\ninterface MdocDocument {\n docType: string;\n issuerSigned: {\n nameSpaces: Record<string, IssuerSignedItem[]>;\n issuerAuth: unknown[];\n };\n}\n\ninterface DeviceResponse {\n version: string;\n documents: MdocDocument[];\n status: number;\n}\n\n/**\n * Extracts the issuer certificate bytes from a COSE_Sign1 issuerAuth structure.\n *\n * The issuerAuth is a COSE_Sign1 array: [protected, unprotected, payload, signature].\n * The protected header (index 0) is CBOR-encoded and may contain the x5chain (label 33)\n * with the issuer certificate. The unprotected header (index 1) may also carry it.\n *\n * If neither header contains a certificate, the raw protected bytes are returned\n * as a fallback for trust matching (test/simplified scenarios).\n */\nfunction extractCertificateFromIssuerAuth(issuerAuth: unknown[]): Uint8Array {\n // Try unprotected header first (index 1) -- it's already decoded as a Map or object\n const unprotected = issuerAuth[1];\n if (unprotected && typeof unprotected === 'object') {\n // x5chain is COSE header label 33\n const certFromUnprotected = extractX5Chain(unprotected);\n if (certFromUnprotected) return certFromUnprotected;\n }\n\n // Try protected header (index 0) -- CBOR-encoded bytes\n const protectedHeader = issuerAuth[0];\n if (isBinaryData(protectedHeader)) {\n try {\n const decoded = decode(protectedHeader) as unknown;\n if (decoded && typeof decoded === 'object') {\n const certFromProtected = extractX5Chain(decoded);\n if (certFromProtected) return certFromProtected;\n }\n } catch {\n // Protected header could not be decoded -- fall through\n }\n // Return raw protected bytes as fallback identifier\n return new Uint8Array(protectedHeader);\n }\n\n return new Uint8Array();\n}\n\n/**\n * Extracts certificate bytes from an x5chain (label 33) in a COSE header.\n * The header can be a plain object or a Map.\n */\nfunction extractX5Chain(header: unknown): Uint8Array | null {\n if (header instanceof Map) {\n const cert = header.get(33) as unknown;\n if (isBinaryData(cert)) {\n return new Uint8Array(cert);\n }\n } else if (typeof header === 'object' && header !== null) {\n const rec = header as Record<string | number, unknown>;\n const cert = rec[33] ?? rec['x5chain'] ?? rec['33'];\n if (isBinaryData(cert)) {\n return new Uint8Array(cert);\n }\n }\n return null;\n}\n\n/**\n * Maps raw mDOC IssuerSignedItem elements to the CredentialClaims structure,\n * picking known age/residency fields and preserving any additional identifiers.\n */\nfunction mapToCredentialClaims(items: IssuerSignedItem[]): CredentialClaims {\n const claims: CredentialClaims = {};\n\n for (const item of items) {\n const key = item.elementIdentifier;\n const value = item.elementValue;\n\n switch (key) {\n case 'age_over_18':\n if (typeof value === 'boolean') claims.age_over_18 = value;\n break;\n case 'age_over_21':\n if (typeof value === 'boolean') claims.age_over_21 = value;\n break;\n case 'resident_country':\n if (typeof value === 'string') claims.resident_country = value;\n break;\n case 'nationality':\n if (typeof value === 'string') claims.nationality = value;\n break;\n case 'family_name_birth':\n if (typeof value === 'string') claims.family_name_birth = value;\n break;\n default:\n claims[key] = value;\n break;\n }\n }\n\n return claims;\n}\n\n/**\n * Extracts validity period from the issuerAuth payload.\n *\n * The payload (index 2) of the COSE_Sign1 is CBOR-encoded and should\n * contain a MobileSecurityObject with a validityInfo field carrying\n * `validFrom` and `validUntil` dates.\n */\nfunction extractValidityPeriod(issuerAuth: unknown[]): { validFrom?: Date; validUntil?: Date } {\n const payload = issuerAuth[2];\n if (!payload) return {};\n\n try {\n // payload can be raw CBOR bytes or already decoded\n const decoded = isBinaryData(payload) ? (decode(payload) as unknown) : payload;\n\n if (decoded && typeof decoded === 'object') {\n const obj = decoded as Record<string, unknown>;\n const validityInfo = obj['validityInfo'] as Record<string, unknown> | undefined;\n if (validityInfo) {\n return {\n validFrom:\n validityInfo['validFrom'] instanceof Date\n ? validityInfo['validFrom']\n : typeof validityInfo['validFrom'] === 'string'\n ? new Date(validityInfo['validFrom'])\n : undefined,\n validUntil:\n validityInfo['validUntil'] instanceof Date\n ? validityInfo['validUntil']\n : typeof validityInfo['validUntil'] === 'string'\n ? new Date(validityInfo['validUntil'])\n : undefined,\n };\n }\n }\n } catch {\n // Could not decode payload -- validity check will be skipped\n }\n\n return {};\n}\n\n/**\n * mDOC / mDL credential parser.\n *\n * Decodes and validates mDOC (Mobile Document) credentials as specified in\n * ISO 18013-5 and the EUDI Wallet ecosystem. Processes CBOR-encoded\n * DeviceResponse structures containing:\n * - Document type validation (eu.europa.ec.eudi.pid.1)\n * - Issuer certificate trust chain verification via COSE_Sign1 issuerAuth\n * - Validity period checking\n * - Claim extraction from IssuerSignedItem nameSpace elements\n */\nexport class MdocParser implements ICredentialParser {\n readonly format: CredentialFormat = 'mdoc';\n\n /**\n * Returns true when the token is binary data (Uint8Array or Buffer),\n * indicating a CBOR-encoded mDOC DeviceResponse.\n */\n canParse(vpToken: unknown): boolean {\n return isBinaryData(vpToken);\n }\n\n /**\n * Parses and validates an mDOC DeviceResponse token.\n *\n * @throws {MalformedCredentialError} when the CBOR structure cannot be decoded\n * or does not match the expected DeviceResponse format\n */\n async parse(vpToken: unknown, options: ParseOptions): Promise<PresentationResult> {\n if (!isBinaryData(vpToken)) {\n throw new MalformedCredentialError('VP token must be a Uint8Array or Buffer');\n }\n\n const invalidResult = (error: string): PresentationResult => ({\n valid: false,\n format: this.format,\n claims: {},\n issuer: { certificate: new Uint8Array(), country: '' },\n error,\n });\n\n // Step 1: Decode the CBOR DeviceResponse\n let deviceResponse: DeviceResponse;\n try {\n deviceResponse = decode(vpToken) as DeviceResponse;\n } catch {\n throw new MalformedCredentialError('Failed to decode CBOR DeviceResponse');\n }\n\n // Step 2: Validate basic DeviceResponse structure\n if (\n !deviceResponse ||\n typeof deviceResponse !== 'object' ||\n !Array.isArray(deviceResponse.documents) ||\n deviceResponse.documents.length === 0\n ) {\n throw new MalformedCredentialError('Invalid DeviceResponse structure: missing or empty documents array');\n }\n\n const document = deviceResponse.documents[0];\n if (!document.issuerSigned || !document.issuerSigned.nameSpaces || !document.issuerSigned.issuerAuth) {\n throw new MalformedCredentialError('Invalid mDOC document: missing issuerSigned data');\n }\n\n // Step 3: Extract issuer certificate from COSE_Sign1 issuerAuth\n const issuerAuth = document.issuerSigned.issuerAuth;\n if (!Array.isArray(issuerAuth) || issuerAuth.length < 4) {\n throw new MalformedCredentialError('Invalid issuerAuth: expected COSE_Sign1 array with 4 elements');\n }\n\n const issuerCertBytes = extractCertificateFromIssuerAuth(issuerAuth);\n const issuerInfo: IssuerInfo = {\n certificate: issuerCertBytes,\n country: '',\n };\n\n // Step 4: Verify trust -- certificate must be in the trusted set\n if (options.trustedCertificates.length > 0) {\n const isTrusted = options.trustedCertificates.some((trusted) => bytesEqual(trusted, issuerCertBytes));\n if (!isTrusted) {\n return invalidResult('Issuer certificate is not trusted');\n }\n } else if (issuerCertBytes.length === 0) {\n return invalidResult('No issuer certificate found and no trusted certificates configured');\n }\n\n // Step 5: Check validity period\n const { validUntil } = extractValidityPeriod(issuerAuth);\n if (validUntil) {\n const now = new Date();\n if (validUntil < now) {\n return invalidResult('Credential has expired');\n }\n }\n\n // Step 6: Extract claims from nameSpaces\n // Prefer the EUDI PID namespace, fall back to the first available namespace\n const pidNamespace = 'eu.europa.ec.eudi.pid.1';\n const nameSpaces = document.issuerSigned.nameSpaces;\n const items: IssuerSignedItem[] =\n nameSpaces[pidNamespace] ?? nameSpaces[document.docType] ?? Object.values(nameSpaces)[0] ?? [];\n\n const claims = mapToCredentialClaims(items);\n\n // Try to derive country from resident_country claim\n if (claims.resident_country && typeof claims.resident_country === 'string') {\n issuerInfo.country = claims.resident_country;\n }\n\n return {\n valid: true,\n format: this.format,\n claims,\n issuer: issuerInfo,\n };\n }\n}\n","import { v4 as uuidv4 } from 'uuid';\n\nimport type { AuthorizationRequestInput, AuthorizationRequest } from './types/authorization.js';\n\nexport function createAuthorizationRequest(input: AuthorizationRequestInput): AuthorizationRequest {\n const state = input.state ?? uuidv4();\n\n const presentationDefinition = {\n id: uuidv4(),\n input_descriptors: input.requestedAttributes.map((attr, index) => ({\n id: `descriptor_${index}`,\n format: Object.fromEntries(\n input.acceptedFormats.map((fmt) => {\n if (fmt === 'sd-jwt-vc') return ['vc+sd-jwt', { 'sd-jwt_alg_values': ['ES256'] }];\n return ['mso_mdoc', { alg: ['ES256'] }];\n })\n ),\n constraints: {\n fields: [\n {\n path: [`$.${attr}`, `$['${attr}']`],\n filter: { type: attr.startsWith('age_over') ? 'boolean' : 'string' },\n },\n ],\n },\n })),\n };\n\n const params = new URLSearchParams({\n response_type: 'vp_token',\n response_mode: 'direct_post',\n response_uri: input.responseUri,\n client_id: input.clientId,\n nonce: input.nonce,\n state,\n presentation_definition: JSON.stringify(presentationDefinition),\n });\n\n return {\n uri: `openid4vp://authorize?${params.toString()}`,\n presentationDefinition,\n nonce: input.nonce,\n state,\n };\n}\n","import { MdocParser } from './parsers/mdoc.parser.js';\nimport type { ParseOptions, ICredentialParser } from './parsers/parser.interface.js';\nimport { SdJwtParser } from './parsers/sd-jwt.parser.js';\nimport type { PresentationResult } from './types/presentation.js';\n\nconst parsers: ICredentialParser[] = [new SdJwtParser(), new MdocParser()];\n\nexport async function parsePresentation(vpToken: unknown, options: ParseOptions): Promise<PresentationResult> {\n for (const parser of parsers) {\n if (parser.canParse(vpToken)) {\n return parser.parse(vpToken, options);\n }\n }\n\n return {\n valid: false,\n format: 'sd-jwt-vc',\n claims: {},\n issuer: { certificate: new Uint8Array(), country: '' },\n error: 'Unsupported credential format',\n };\n}\n\nexport type { ParseOptions } from './parsers/parser.interface.js';\n","export const VERSION = '0.2.0';\n\nexport type {\n CredentialFormat,\n CredentialClaims,\n PresentationResult,\n IssuerInfo,\n AuthorizationRequestInput,\n AuthorizationRequest,\n} from './types/index.js';\n\nexport type { ICredentialParser, ParseOptions } from './parsers/parser.interface.js';\n\nexport { SdJwtParser } from './parsers/sd-jwt.parser.js';\nexport { MdocParser } from './parsers/mdoc.parser.js';\n\nexport {\n InvalidSignatureError,\n ExpiredCredentialError,\n UnsupportedFormatError,\n MalformedCredentialError,\n NonceValidationError,\n} from './errors.js';\n\nexport { createAuthorizationRequest } from './authorization.js';\n\nexport { parsePresentation } from './presentation.js';\n"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/parsers/sd-jwt.parser.ts","../src/parsers/mdoc.parser.ts","../src/authorization.ts","../src/presentation.ts","../src/index.ts"],"names":["splitSdJwt","decodeProtectedHeader","importX509","jwtVerify","importJWK","decodeSdJwt","getClaims","bytesEqual","decode","mapToCredentialClaims","uuidv4"],"mappings":"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","file":"index.cjs","sourcesContent":["export class InvalidSignatureError extends Error {\n constructor(message = 'Credential signature validation failed') {\n super(message);\n this.name = 'InvalidSignatureError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class ExpiredCredentialError extends Error {\n constructor(message = 'Credential has expired') {\n super(message);\n this.name = 'ExpiredCredentialError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class UnsupportedFormatError extends Error {\n constructor(format: string) {\n super(`Unsupported credential format: ${format}`);\n this.name = 'UnsupportedFormatError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class MalformedCredentialError extends Error {\n constructor(message = 'Credential structure is malformed') {\n super(message);\n this.name = 'MalformedCredentialError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class NonceValidationError extends Error {\n constructor(message = 'Nonce does not match expected value') {\n super(message);\n this.name = 'NonceValidationError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n","import { splitSdJwt, decodeSdJwt, getClaims } from '@sd-jwt/decode';\nimport { decodeProtectedHeader, jwtVerify, importX509, importJWK } from 'jose';\n\nimport { MalformedCredentialError } from '../errors.js';\nimport type { IssuerInfo } from '../types/issuer.js';\nimport type { CredentialFormat, CredentialClaims, PresentationResult } from '../types/presentation.js';\n\nimport type { ICredentialParser, ParseOptions } from './parser.interface.js';\n\n/**\n * Hasher function signature expected by @sd-jwt/decode.\n * Inlined here to avoid a direct dependency on @sd-jwt/types.\n */\ntype SdJwtHasher = (data: string | ArrayBuffer, alg: string) => Promise<Uint8Array>;\n\nconst DEFAULT_ALLOWED_ALGORITHMS = ['ES256', 'ES384', 'ES512'];\n\n/**\n * SHA-256 hasher implementation using the Web Crypto API.\n * Compatible with the @sd-jwt/decode Hasher signature.\n */\nconst sha256Hasher: SdJwtHasher = async (data: string | ArrayBuffer, _alg: string): Promise<Uint8Array> => {\n const encoder = new TextEncoder();\n const input = typeof data === 'string' ? encoder.encode(data) : data;\n const hashBuffer = await crypto.subtle.digest('SHA-256', input);\n return new Uint8Array(hashBuffer);\n};\n\n// Standard base64 alphabet for decoding x5c certificate entries\nconst BASE64_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n/**\n * Decodes a standard base64-encoded string into raw bytes.\n * Does not depend on Node.js Buffer or browser atob.\n */\nfunction base64ToBytes(base64: string): Uint8Array<ArrayBuffer> {\n const cleaned = base64.replace(/=+$/, '');\n const byteLength = Math.floor((cleaned.length * 3) / 4);\n const buffer = new ArrayBuffer(byteLength);\n const bytes = new Uint8Array(buffer);\n\n let byteIndex = 0;\n for (let i = 0; i < cleaned.length; i += 4) {\n const a = BASE64_CHARS.indexOf(cleaned[i]);\n const b = i + 1 < cleaned.length ? BASE64_CHARS.indexOf(cleaned[i + 1]) : 0;\n const c = i + 2 < cleaned.length ? BASE64_CHARS.indexOf(cleaned[i + 2]) : 0;\n const d = i + 3 < cleaned.length ? BASE64_CHARS.indexOf(cleaned[i + 3]) : 0;\n\n bytes[byteIndex++] = (a << 2) | (b >> 4);\n if (byteIndex < byteLength) bytes[byteIndex++] = ((b & 0x0f) << 4) | (c >> 2);\n if (byteIndex < byteLength) bytes[byteIndex++] = ((c & 0x03) << 6) | d;\n }\n\n return bytes;\n}\n\n/**\n * Checks whether two Uint8Array instances contain identical bytes.\n */\nfunction bytesEqual(a: Uint8Array, b: Uint8Array): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false;\n }\n return true;\n}\n\n/**\n * Converts a base64-encoded DER certificate to PEM format for jose.importX509.\n */\nfunction derToPem(base64Der: string): string {\n const lines = base64Der.match(/.{1,64}/g) || [];\n return `-----BEGIN CERTIFICATE-----\\n${lines.join('\\n')}\\n-----END CERTIFICATE-----`;\n}\n\n/**\n * Encodes a Uint8Array to base64url (no padding).\n * Used by disclosure hash verification (Task 5) and KB-JWT verification (Task 6).\n */\nfunction bytesToBase64url(bytes: Uint8Array): string {\n let binary = '';\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n return globalThis.btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\n/**\n * Maps raw decoded claims to the CredentialClaims structure,\n * picking known age/residency fields and preserving any extra keys.\n */\nfunction mapToCredentialClaims(raw: Record<string, unknown>): CredentialClaims {\n const claims: CredentialClaims = {};\n\n if (typeof raw['age_over_18'] === 'boolean') {\n claims.age_over_18 = raw['age_over_18'];\n }\n if (typeof raw['age_over_21'] === 'boolean') {\n claims.age_over_21 = raw['age_over_21'];\n }\n if (typeof raw['resident_country'] === 'string') {\n claims.resident_country = raw['resident_country'];\n }\n if (typeof raw['nationality'] === 'string') {\n claims.nationality = raw['nationality'];\n }\n if (typeof raw['family_name_birth'] === 'string') {\n claims.family_name_birth = raw['family_name_birth'];\n }\n\n for (const [key, value] of Object.entries(raw)) {\n if (\n !(key in claims) &&\n !key.startsWith('_sd') &&\n key !== 'iss' &&\n key !== 'exp' &&\n key !== 'iat' &&\n key !== 'cnf' &&\n key !== 'vct'\n ) {\n claims[key] = value;\n }\n }\n\n return claims;\n}\n\n/**\n * Best-effort extraction of a country code hint from an issuer URL or string.\n */\nfunction extractCountryHint(issuer: string): string {\n try {\n const url = new URL(issuer);\n const tld = url.hostname.split('.').pop()?.toUpperCase();\n if (tld && tld.length === 2) {\n return tld;\n }\n } catch {\n // Not a valid URL\n }\n return '';\n}\n\n/**\n * SD-JWT VC credential parser.\n *\n * Decodes and cryptographically validates SD-JWT Verifiable Credentials:\n * - JWT signature verification via x5c public key (jose)\n * - Issuer certificate trust chain verification\n * - Disclosure hash integrity verification\n * - Key binding JWT signature and sd_hash verification\n * - Selective disclosure claim extraction\n */\nexport class SdJwtParser implements ICredentialParser {\n readonly format: CredentialFormat = 'sd-jwt-vc';\n\n canParse(vpToken: unknown): boolean {\n return typeof vpToken === 'string' && vpToken.includes('~');\n }\n\n async parse(vpToken: unknown, options: ParseOptions): Promise<PresentationResult> {\n if (typeof vpToken !== 'string') {\n throw new MalformedCredentialError('VP token must be a string');\n }\n\n const allowedAlgorithms = options.allowedAlgorithms ?? DEFAULT_ALLOWED_ALGORITHMS;\n\n const invalidResult = (error: string): PresentationResult => ({\n valid: false,\n format: this.format,\n claims: {},\n issuer: { certificate: new Uint8Array(), country: '' },\n error,\n });\n\n // Step 1: Split the SD-JWT into components\n let parts: ReturnType<typeof splitSdJwt>;\n try {\n parts = splitSdJwt(vpToken);\n } catch {\n throw new MalformedCredentialError('Failed to split SD-JWT structure');\n }\n\n // Step 2: Peek at issuer JWT header (need alg and x5c before verification)\n let header: ReturnType<typeof decodeProtectedHeader>;\n try {\n header = decodeProtectedHeader(parts.jwt);\n } catch {\n throw new MalformedCredentialError('Failed to decode SD-JWT issuer JWT header');\n }\n\n // Step 3: Check algorithm against allowlist\n const alg = header.alg;\n if (typeof alg !== 'string' || !allowedAlgorithms.includes(alg)) {\n return invalidResult(`Unsupported algorithm: ${alg}`);\n }\n\n // Step 4: Extract public key from x5c certificate\n const x5cArray = header.x5c;\n if (!Array.isArray(x5cArray) || x5cArray.length === 0 || typeof x5cArray[0] !== 'string') {\n throw new MalformedCredentialError('Missing or invalid x5c in JWT header');\n }\n\n let issuerKey: Awaited<ReturnType<typeof importX509>>;\n let issuerCertBytes: Uint8Array;\n try {\n issuerKey = await importX509(derToPem(x5cArray[0]), alg);\n issuerCertBytes = base64ToBytes(x5cArray[0]);\n } catch (err) {\n if (err instanceof MalformedCredentialError) throw err;\n throw new MalformedCredentialError('Failed to import issuer certificate');\n }\n\n // Step 5: Verify issuer JWT signature (also validates exp, iat via jose)\n let payload: Record<string, unknown>;\n try {\n const result = await jwtVerify(parts.jwt, issuerKey, { algorithms: allowedAlgorithms });\n payload = result.payload as unknown as Record<string, unknown>;\n } catch {\n return invalidResult('Issuer JWT signature verification failed');\n }\n\n // Step 6: Trust check — certificate must be in the trusted set\n // unless the caller explicitly opts out via skipTrustCheck.\n const issuerString = typeof payload['iss'] === 'string' ? payload['iss'] : '';\n const issuerInfo: IssuerInfo = {\n certificate: issuerCertBytes,\n country: extractCountryHint(issuerString),\n };\n\n if (options.trustedCertificates.length === 0) {\n if (options.skipTrustCheck !== true) {\n throw new MalformedCredentialError(\n 'trustedCertificates must not be empty unless skipTrustCheck is true'\n );\n }\n } else {\n const isTrusted = options.trustedCertificates.some((trusted) => bytesEqual(trusted, issuerCertBytes));\n if (!isTrusted) {\n return invalidResult('Issuer certificate is not trusted');\n }\n }\n\n // Step 7: Verify disclosure hashes against _sd array\n const sdArray = payload['_sd'];\n if (parts.disclosures.length > 0) {\n if (!Array.isArray(sdArray) || sdArray.length === 0) {\n return invalidResult('Disclosures present but no _sd array in issuer JWT');\n }\n for (const disclosure of parts.disclosures) {\n const hashBytes = await sha256Hasher(disclosure, 'sha-256');\n const hashB64url = bytesToBase64url(hashBytes);\n if (!sdArray.includes(hashB64url)) {\n return invalidResult('Disclosure hash mismatch');\n }\n }\n }\n\n // Step 8: Verify key binding JWT (if present)\n if (parts.kbJwt) {\n // Extract holder public key from cnf claim\n const cnf = payload['cnf'] as Record<string, unknown> | undefined;\n if (!cnf || typeof cnf !== 'object' || !cnf['jwk']) {\n throw new MalformedCredentialError('Missing cnf.jwk in issuer JWT for key binding');\n }\n\n let holderKey: Awaited<ReturnType<typeof importJWK>>;\n try {\n const kbHeader = decodeProtectedHeader(parts.kbJwt);\n const kbAlg = kbHeader.alg;\n if (typeof kbAlg !== 'string' || !allowedAlgorithms.includes(kbAlg)) {\n return invalidResult(`Unsupported KB-JWT algorithm: ${kbAlg}`);\n }\n holderKey = await importJWK(cnf['jwk'] as Record<string, unknown>, kbAlg);\n } catch (err) {\n if (err instanceof MalformedCredentialError) throw err;\n throw new MalformedCredentialError('Failed to import holder key from cnf.jwk');\n }\n\n // Verify KB-JWT signature\n let kbPayload: Record<string, unknown>;\n try {\n const kbResult = await jwtVerify(parts.kbJwt, holderKey, {\n algorithms: allowedAlgorithms,\n ...(options.audience ? { audience: options.audience } : {}),\n });\n kbPayload = kbResult.payload as unknown as Record<string, unknown>;\n } catch {\n return invalidResult('Key binding JWT signature verification failed');\n }\n\n // Validate nonce — must be present and match when KB-JWT is used\n if (kbPayload['nonce'] !== options.nonce) {\n return invalidResult('Key binding JWT nonce does not match');\n }\n\n // Verify sd_hash — hash of the SD-JWT content before the KB-JWT\n const disclosurePart = parts.disclosures.length > 0 ? parts.disclosures.join('~') + '~' : '';\n const sdJwtForHash = parts.jwt + '~' + disclosurePart;\n const sdHashBytes = await sha256Hasher(sdJwtForHash, 'sha-256');\n const expectedSdHash = bytesToBase64url(sdHashBytes);\n if (kbPayload['sd_hash'] !== expectedSdHash) {\n return invalidResult('Key binding JWT sd_hash does not match');\n }\n }\n\n // Step 9: Decode disclosures and extract claims\n let resolvedClaims: Record<string, unknown>;\n try {\n const decoded = await decodeSdJwt(vpToken, sha256Hasher);\n resolvedClaims = await getClaims<Record<string, unknown>>(\n decoded.jwt.payload,\n decoded.disclosures,\n sha256Hasher\n );\n } catch {\n throw new MalformedCredentialError('Failed to decode SD-JWT disclosures');\n }\n\n return {\n valid: true,\n format: this.format,\n claims: mapToCredentialClaims(resolvedClaims),\n issuer: issuerInfo,\n };\n }\n}\n","import { decode } from 'cbor-x';\n\nimport { MalformedCredentialError } from '../errors.js';\nimport type { IssuerInfo } from '../types/issuer.js';\nimport type { CredentialFormat, CredentialClaims, PresentationResult } from '../types/presentation.js';\n\nimport type { ICredentialParser, ParseOptions } from './parser.interface.js';\n\n/**\n * Runtime check for binary data. Returns true for Uint8Array and Node.js Buffer\n * without referencing the Buffer type (which is unavailable in DOM-only tsconfig).\n * Buffer extends Uint8Array, so `instanceof Uint8Array` catches both.\n */\nfunction isBinaryData(value: unknown): value is Uint8Array {\n return value instanceof Uint8Array;\n}\n\n/**\n * Checks whether two Uint8Array instances contain identical bytes.\n */\nfunction bytesEqual(a: Uint8Array, b: Uint8Array): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false;\n }\n return true;\n}\n\n/**\n * Represents a single IssuerSignedItem element from an mDOC nameSpace.\n * ISO 18013-5 Section 8.3.2.1.2.\n */\ninterface IssuerSignedItem {\n digestID: number;\n random: Uint8Array | unknown;\n elementIdentifier: string;\n elementValue: unknown;\n}\n\n/**\n * Simplified DeviceResponse structure from ISO 18013-5.\n * Only the fields required for claim extraction and trust validation.\n */\ninterface MdocDocument {\n docType: string;\n issuerSigned: {\n nameSpaces: Record<string, IssuerSignedItem[]>;\n issuerAuth: unknown[];\n };\n}\n\ninterface DeviceResponse {\n version: string;\n documents: MdocDocument[];\n status: number;\n}\n\n/**\n * Extracts the issuer certificate bytes from a COSE_Sign1 issuerAuth structure.\n *\n * The issuerAuth is a COSE_Sign1 array: [protected, unprotected, payload, signature].\n * The protected header (index 0) is CBOR-encoded and may contain the x5chain (label 33)\n * with the issuer certificate. The unprotected header (index 1) may also carry it.\n *\n * If neither header contains a certificate, the raw protected bytes are returned\n * as a fallback for trust matching (test/simplified scenarios).\n */\nfunction extractCertificateFromIssuerAuth(issuerAuth: unknown[]): Uint8Array {\n // Try unprotected header first (index 1) -- it's already decoded as a Map or object\n const unprotected = issuerAuth[1];\n if (unprotected && typeof unprotected === 'object') {\n // x5chain is COSE header label 33\n const certFromUnprotected = extractX5Chain(unprotected);\n if (certFromUnprotected) return certFromUnprotected;\n }\n\n // Try protected header (index 0) -- CBOR-encoded bytes\n const protectedHeader = issuerAuth[0];\n if (isBinaryData(protectedHeader)) {\n try {\n const decoded = decode(protectedHeader) as unknown;\n if (decoded && typeof decoded === 'object') {\n const certFromProtected = extractX5Chain(decoded);\n if (certFromProtected) return certFromProtected;\n }\n } catch {\n // Protected header could not be decoded -- fall through\n }\n // Return raw protected bytes as fallback identifier\n return new Uint8Array(protectedHeader);\n }\n\n return new Uint8Array();\n}\n\n/**\n * Extracts certificate bytes from an x5chain (label 33) in a COSE header.\n * The header can be a plain object or a Map.\n */\nfunction extractX5Chain(header: unknown): Uint8Array | null {\n if (header instanceof Map) {\n const cert = header.get(33) as unknown;\n if (isBinaryData(cert)) {\n return new Uint8Array(cert);\n }\n } else if (typeof header === 'object' && header !== null) {\n const rec = header as Record<string | number, unknown>;\n const cert = rec[33] ?? rec['x5chain'] ?? rec['33'];\n if (isBinaryData(cert)) {\n return new Uint8Array(cert);\n }\n }\n return null;\n}\n\n/**\n * Maps raw mDOC IssuerSignedItem elements to the CredentialClaims structure,\n * picking known age/residency fields and preserving any additional identifiers.\n */\nfunction mapToCredentialClaims(items: IssuerSignedItem[]): CredentialClaims {\n const claims: CredentialClaims = {};\n\n for (const item of items) {\n const key = item.elementIdentifier;\n const value = item.elementValue;\n\n switch (key) {\n case 'age_over_18':\n if (typeof value === 'boolean') claims.age_over_18 = value;\n break;\n case 'age_over_21':\n if (typeof value === 'boolean') claims.age_over_21 = value;\n break;\n case 'resident_country':\n if (typeof value === 'string') claims.resident_country = value;\n break;\n case 'nationality':\n if (typeof value === 'string') claims.nationality = value;\n break;\n case 'family_name_birth':\n if (typeof value === 'string') claims.family_name_birth = value;\n break;\n default:\n claims[key] = value;\n break;\n }\n }\n\n return claims;\n}\n\n/**\n * Extracts validity period from the issuerAuth payload.\n *\n * The payload (index 2) of the COSE_Sign1 is CBOR-encoded and should\n * contain a MobileSecurityObject with a validityInfo field carrying\n * `validFrom` and `validUntil` dates.\n */\nfunction extractValidityPeriod(issuerAuth: unknown[]): { validFrom?: Date; validUntil?: Date } {\n const payload = issuerAuth[2];\n if (!payload) return {};\n\n try {\n // payload can be raw CBOR bytes or already decoded\n const decoded = isBinaryData(payload) ? (decode(payload) as unknown) : payload;\n\n if (decoded && typeof decoded === 'object') {\n const obj = decoded as Record<string, unknown>;\n const validityInfo = obj['validityInfo'] as Record<string, unknown> | undefined;\n if (validityInfo) {\n return {\n validFrom:\n validityInfo['validFrom'] instanceof Date\n ? validityInfo['validFrom']\n : typeof validityInfo['validFrom'] === 'string'\n ? new Date(validityInfo['validFrom'])\n : undefined,\n validUntil:\n validityInfo['validUntil'] instanceof Date\n ? validityInfo['validUntil']\n : typeof validityInfo['validUntil'] === 'string'\n ? new Date(validityInfo['validUntil'])\n : undefined,\n };\n }\n }\n } catch {\n // Could not decode payload -- validity check will be skipped\n }\n\n return {};\n}\n\n/**\n * mDOC / mDL credential parser.\n *\n * Decodes and validates mDOC (Mobile Document) credentials as specified in\n * ISO 18013-5 and the EUDI Wallet ecosystem. Processes CBOR-encoded\n * DeviceResponse structures containing:\n * - Document type validation (eu.europa.ec.eudi.pid.1)\n * - Issuer certificate trust chain verification via COSE_Sign1 issuerAuth\n * - Validity period checking\n * - Claim extraction from IssuerSignedItem nameSpace elements\n */\nexport class MdocParser implements ICredentialParser {\n readonly format: CredentialFormat = 'mdoc';\n\n /**\n * Returns true when the token is binary data (Uint8Array or Buffer),\n * indicating a CBOR-encoded mDOC DeviceResponse.\n */\n canParse(vpToken: unknown): boolean {\n return isBinaryData(vpToken);\n }\n\n /**\n * Parses and validates an mDOC DeviceResponse token.\n *\n * @throws {MalformedCredentialError} when the CBOR structure cannot be decoded\n * or does not match the expected DeviceResponse format\n */\n async parse(vpToken: unknown, options: ParseOptions): Promise<PresentationResult> {\n if (!isBinaryData(vpToken)) {\n throw new MalformedCredentialError('VP token must be a Uint8Array or Buffer');\n }\n\n const invalidResult = (error: string): PresentationResult => ({\n valid: false,\n format: this.format,\n claims: {},\n issuer: { certificate: new Uint8Array(), country: '' },\n error,\n });\n\n // Step 1: Decode the CBOR DeviceResponse\n let deviceResponse: DeviceResponse;\n try {\n deviceResponse = decode(vpToken) as DeviceResponse;\n } catch {\n throw new MalformedCredentialError('Failed to decode CBOR DeviceResponse');\n }\n\n // Step 2: Validate basic DeviceResponse structure\n if (\n !deviceResponse ||\n typeof deviceResponse !== 'object' ||\n !Array.isArray(deviceResponse.documents) ||\n deviceResponse.documents.length === 0\n ) {\n throw new MalformedCredentialError('Invalid DeviceResponse structure: missing or empty documents array');\n }\n\n const document = deviceResponse.documents[0];\n if (!document.issuerSigned || !document.issuerSigned.nameSpaces || !document.issuerSigned.issuerAuth) {\n throw new MalformedCredentialError('Invalid mDOC document: missing issuerSigned data');\n }\n\n // Step 3: Extract issuer certificate from COSE_Sign1 issuerAuth\n const issuerAuth = document.issuerSigned.issuerAuth;\n if (!Array.isArray(issuerAuth) || issuerAuth.length < 4) {\n throw new MalformedCredentialError('Invalid issuerAuth: expected COSE_Sign1 array with 4 elements');\n }\n\n const issuerCertBytes = extractCertificateFromIssuerAuth(issuerAuth);\n const issuerInfo: IssuerInfo = {\n certificate: issuerCertBytes,\n country: '',\n };\n\n // Step 4: Verify trust -- certificate must be in the trusted set\n // unless the caller explicitly opts out via skipTrustCheck.\n if (options.trustedCertificates.length === 0) {\n if (options.skipTrustCheck !== true) {\n throw new MalformedCredentialError(\n 'trustedCertificates must not be empty unless skipTrustCheck is true'\n );\n }\n } else {\n const isTrusted = options.trustedCertificates.some((trusted) => bytesEqual(trusted, issuerCertBytes));\n if (!isTrusted) {\n return invalidResult('Issuer certificate is not trusted');\n }\n }\n\n // Step 5: Check validity period\n const { validUntil } = extractValidityPeriod(issuerAuth);\n if (validUntil) {\n const now = new Date();\n if (validUntil < now) {\n return invalidResult('Credential has expired');\n }\n }\n\n // Step 6: Extract claims from nameSpaces\n // Prefer the EUDI PID namespace, fall back to the first available namespace\n const pidNamespace = 'eu.europa.ec.eudi.pid.1';\n const nameSpaces = document.issuerSigned.nameSpaces;\n const items: IssuerSignedItem[] =\n nameSpaces[pidNamespace] ?? nameSpaces[document.docType] ?? Object.values(nameSpaces)[0] ?? [];\n\n const claims = mapToCredentialClaims(items);\n\n // Try to derive country from resident_country claim\n if (claims.resident_country && typeof claims.resident_country === 'string') {\n issuerInfo.country = claims.resident_country;\n }\n\n return {\n valid: true,\n format: this.format,\n claims,\n issuer: issuerInfo,\n };\n }\n}\n","import { v4 as uuidv4 } from 'uuid';\n\nimport type { AuthorizationRequestInput, AuthorizationRequest } from './types/authorization.js';\n\nexport function createAuthorizationRequest(input: AuthorizationRequestInput): AuthorizationRequest {\n const state = input.state ?? uuidv4();\n\n const presentationDefinition = {\n id: uuidv4(),\n input_descriptors: input.requestedAttributes.map((attr, index) => ({\n id: `descriptor_${index}`,\n format: Object.fromEntries(\n input.acceptedFormats.map((fmt) => {\n if (fmt === 'sd-jwt-vc') return ['vc+sd-jwt', { 'sd-jwt_alg_values': ['ES256'] }];\n return ['mso_mdoc', { alg: ['ES256'] }];\n })\n ),\n constraints: {\n fields: [\n {\n path: [`$.${attr}`, `$['${attr}']`],\n filter: { type: attr.startsWith('age_over') ? 'boolean' : 'string' },\n },\n ],\n },\n })),\n };\n\n const params = new URLSearchParams({\n response_type: 'vp_token',\n response_mode: 'direct_post',\n response_uri: input.responseUri,\n client_id: input.clientId,\n nonce: input.nonce,\n state,\n presentation_definition: JSON.stringify(presentationDefinition),\n });\n\n return {\n uri: `openid4vp://authorize?${params.toString()}`,\n presentationDefinition,\n nonce: input.nonce,\n state,\n };\n}\n","import { MdocParser } from './parsers/mdoc.parser.js';\nimport type { ParseOptions, ICredentialParser } from './parsers/parser.interface.js';\nimport { SdJwtParser } from './parsers/sd-jwt.parser.js';\nimport type { PresentationResult } from './types/presentation.js';\n\nconst parsers: ICredentialParser[] = [new SdJwtParser(), new MdocParser()];\n\nexport async function parsePresentation(vpToken: unknown, options: ParseOptions): Promise<PresentationResult> {\n for (const parser of parsers) {\n if (parser.canParse(vpToken)) {\n return parser.parse(vpToken, options);\n }\n }\n\n return {\n valid: false,\n format: 'sd-jwt-vc',\n claims: {},\n issuer: { certificate: new Uint8Array(), country: '' },\n error: 'Unsupported credential format',\n };\n}\n\nexport type { ParseOptions } from './parsers/parser.interface.js';\n","export const VERSION = '0.2.1';\n\nexport type {\n CredentialFormat,\n CredentialClaims,\n PresentationResult,\n IssuerInfo,\n AuthorizationRequestInput,\n AuthorizationRequest,\n} from './types/index.js';\n\nexport type { ICredentialParser, ParseOptions } from './parsers/parser.interface.js';\n\nexport { SdJwtParser } from './parsers/sd-jwt.parser.js';\nexport { MdocParser } from './parsers/mdoc.parser.js';\n\nexport {\n InvalidSignatureError,\n ExpiredCredentialError,\n UnsupportedFormatError,\n MalformedCredentialError,\n NonceValidationError,\n} from './errors.js';\n\nexport { createAuthorizationRequest } from './authorization.js';\n\nexport { parsePresentation } from './presentation.js';\n"]}
package/dist/index.d.cts CHANGED
@@ -44,6 +44,13 @@ interface ParseOptions {
44
44
  audience?: string;
45
45
  /** Allowed JWT signature algorithms. Defaults to ['ES256', 'ES384', 'ES512']. */
46
46
  allowedAlgorithms?: string[];
47
+ /**
48
+ * Explicit opt-in to skip the trust check. When omitted or `false`,
49
+ * `trustedCertificates` must be non-empty — otherwise parsing throws
50
+ * `MalformedCredentialError`. Set to `true` for demo/mock environments
51
+ * where no trusted issuer set is available.
52
+ */
53
+ skipTrustCheck?: boolean;
47
54
  }
48
55
  interface ICredentialParser {
49
56
  readonly format: CredentialFormat;
@@ -114,6 +121,6 @@ declare function createAuthorizationRequest(input: AuthorizationRequestInput): A
114
121
 
115
122
  declare function parsePresentation(vpToken: unknown, options: ParseOptions): Promise<PresentationResult>;
116
123
 
117
- declare const VERSION = "0.2.0";
124
+ declare const VERSION = "0.2.1";
118
125
 
119
126
  export { type AuthorizationRequest, type AuthorizationRequestInput, type CredentialClaims, type CredentialFormat, ExpiredCredentialError, type ICredentialParser, InvalidSignatureError, type IssuerInfo, MalformedCredentialError, MdocParser, NonceValidationError, type ParseOptions, type PresentationResult, SdJwtParser, UnsupportedFormatError, VERSION, createAuthorizationRequest, parsePresentation };
package/dist/index.d.ts CHANGED
@@ -44,6 +44,13 @@ interface ParseOptions {
44
44
  audience?: string;
45
45
  /** Allowed JWT signature algorithms. Defaults to ['ES256', 'ES384', 'ES512']. */
46
46
  allowedAlgorithms?: string[];
47
+ /**
48
+ * Explicit opt-in to skip the trust check. When omitted or `false`,
49
+ * `trustedCertificates` must be non-empty — otherwise parsing throws
50
+ * `MalformedCredentialError`. Set to `true` for demo/mock environments
51
+ * where no trusted issuer set is available.
52
+ */
53
+ skipTrustCheck?: boolean;
47
54
  }
48
55
  interface ICredentialParser {
49
56
  readonly format: CredentialFormat;
@@ -114,6 +121,6 @@ declare function createAuthorizationRequest(input: AuthorizationRequestInput): A
114
121
 
115
122
  declare function parsePresentation(vpToken: unknown, options: ParseOptions): Promise<PresentationResult>;
116
123
 
117
- declare const VERSION = "0.2.0";
124
+ declare const VERSION = "0.2.1";
118
125
 
119
126
  export { type AuthorizationRequest, type AuthorizationRequestInput, type CredentialClaims, type CredentialFormat, ExpiredCredentialError, type ICredentialParser, InvalidSignatureError, type IssuerInfo, MalformedCredentialError, MdocParser, NonceValidationError, type ParseOptions, type PresentationResult, SdJwtParser, UnsupportedFormatError, VERSION, createAuthorizationRequest, parsePresentation };
package/dist/index.js CHANGED
@@ -181,7 +181,13 @@ var SdJwtParser = class {
181
181
  certificate: issuerCertBytes,
182
182
  country: extractCountryHint(issuerString)
183
183
  };
184
- if (options.trustedCertificates.length > 0) {
184
+ if (options.trustedCertificates.length === 0) {
185
+ if (options.skipTrustCheck !== true) {
186
+ throw new MalformedCredentialError(
187
+ "trustedCertificates must not be empty unless skipTrustCheck is true"
188
+ );
189
+ }
190
+ } else {
185
191
  const isTrusted = options.trustedCertificates.some((trusted) => bytesEqual(trusted, issuerCertBytes));
186
192
  if (!isTrusted) {
187
193
  return invalidResult("Issuer certificate is not trusted");
@@ -397,13 +403,17 @@ var MdocParser = class {
397
403
  certificate: issuerCertBytes,
398
404
  country: ""
399
405
  };
400
- if (options.trustedCertificates.length > 0) {
406
+ if (options.trustedCertificates.length === 0) {
407
+ if (options.skipTrustCheck !== true) {
408
+ throw new MalformedCredentialError(
409
+ "trustedCertificates must not be empty unless skipTrustCheck is true"
410
+ );
411
+ }
412
+ } else {
401
413
  const isTrusted = options.trustedCertificates.some((trusted) => bytesEqual2(trusted, issuerCertBytes));
402
414
  if (!isTrusted) {
403
415
  return invalidResult("Issuer certificate is not trusted");
404
416
  }
405
- } else if (issuerCertBytes.length === 0) {
406
- return invalidResult("No issuer certificate found and no trusted certificates configured");
407
417
  }
408
418
  const { validUntil } = extractValidityPeriod(issuerAuth);
409
419
  if (validUntil) {
@@ -484,7 +494,7 @@ async function parsePresentation(vpToken, options) {
484
494
  }
485
495
 
486
496
  // src/index.ts
487
- var VERSION = "0.2.0";
497
+ var VERSION = "0.2.1";
488
498
 
489
499
  export { ExpiredCredentialError, InvalidSignatureError, MalformedCredentialError, MdocParser, NonceValidationError, SdJwtParser, UnsupportedFormatError, VERSION, createAuthorizationRequest, parsePresentation };
490
500
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/parsers/sd-jwt.parser.ts","../src/parsers/mdoc.parser.ts","../src/authorization.ts","../src/presentation.ts","../src/index.ts"],"names":["bytesEqual","mapToCredentialClaims","uuidv4"],"mappings":"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","file":"index.js","sourcesContent":["export class InvalidSignatureError extends Error {\n constructor(message = 'Credential signature validation failed') {\n super(message);\n this.name = 'InvalidSignatureError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class ExpiredCredentialError extends Error {\n constructor(message = 'Credential has expired') {\n super(message);\n this.name = 'ExpiredCredentialError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class UnsupportedFormatError extends Error {\n constructor(format: string) {\n super(`Unsupported credential format: ${format}`);\n this.name = 'UnsupportedFormatError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class MalformedCredentialError extends Error {\n constructor(message = 'Credential structure is malformed') {\n super(message);\n this.name = 'MalformedCredentialError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class NonceValidationError extends Error {\n constructor(message = 'Nonce does not match expected value') {\n super(message);\n this.name = 'NonceValidationError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n","import { splitSdJwt, decodeSdJwt, getClaims } from '@sd-jwt/decode';\nimport { decodeProtectedHeader, jwtVerify, importX509, importJWK } from 'jose';\n\nimport { MalformedCredentialError } from '../errors.js';\nimport type { IssuerInfo } from '../types/issuer.js';\nimport type { CredentialFormat, CredentialClaims, PresentationResult } from '../types/presentation.js';\n\nimport type { ICredentialParser, ParseOptions } from './parser.interface.js';\n\n/**\n * Hasher function signature expected by @sd-jwt/decode.\n * Inlined here to avoid a direct dependency on @sd-jwt/types.\n */\ntype SdJwtHasher = (data: string | ArrayBuffer, alg: string) => Promise<Uint8Array>;\n\nconst DEFAULT_ALLOWED_ALGORITHMS = ['ES256', 'ES384', 'ES512'];\n\n/**\n * SHA-256 hasher implementation using the Web Crypto API.\n * Compatible with the @sd-jwt/decode Hasher signature.\n */\nconst sha256Hasher: SdJwtHasher = async (data: string | ArrayBuffer, _alg: string): Promise<Uint8Array> => {\n const encoder = new TextEncoder();\n const input = typeof data === 'string' ? encoder.encode(data) : data;\n const hashBuffer = await crypto.subtle.digest('SHA-256', input);\n return new Uint8Array(hashBuffer);\n};\n\n// Standard base64 alphabet for decoding x5c certificate entries\nconst BASE64_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n/**\n * Decodes a standard base64-encoded string into raw bytes.\n * Does not depend on Node.js Buffer or browser atob.\n */\nfunction base64ToBytes(base64: string): Uint8Array<ArrayBuffer> {\n const cleaned = base64.replace(/=+$/, '');\n const byteLength = Math.floor((cleaned.length * 3) / 4);\n const buffer = new ArrayBuffer(byteLength);\n const bytes = new Uint8Array(buffer);\n\n let byteIndex = 0;\n for (let i = 0; i < cleaned.length; i += 4) {\n const a = BASE64_CHARS.indexOf(cleaned[i]);\n const b = i + 1 < cleaned.length ? BASE64_CHARS.indexOf(cleaned[i + 1]) : 0;\n const c = i + 2 < cleaned.length ? BASE64_CHARS.indexOf(cleaned[i + 2]) : 0;\n const d = i + 3 < cleaned.length ? BASE64_CHARS.indexOf(cleaned[i + 3]) : 0;\n\n bytes[byteIndex++] = (a << 2) | (b >> 4);\n if (byteIndex < byteLength) bytes[byteIndex++] = ((b & 0x0f) << 4) | (c >> 2);\n if (byteIndex < byteLength) bytes[byteIndex++] = ((c & 0x03) << 6) | d;\n }\n\n return bytes;\n}\n\n/**\n * Checks whether two Uint8Array instances contain identical bytes.\n */\nfunction bytesEqual(a: Uint8Array, b: Uint8Array): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false;\n }\n return true;\n}\n\n/**\n * Converts a base64-encoded DER certificate to PEM format for jose.importX509.\n */\nfunction derToPem(base64Der: string): string {\n const lines = base64Der.match(/.{1,64}/g) || [];\n return `-----BEGIN CERTIFICATE-----\\n${lines.join('\\n')}\\n-----END CERTIFICATE-----`;\n}\n\n/**\n * Encodes a Uint8Array to base64url (no padding).\n * Used by disclosure hash verification (Task 5) and KB-JWT verification (Task 6).\n */\nfunction bytesToBase64url(bytes: Uint8Array): string {\n let binary = '';\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n return globalThis.btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\n/**\n * Maps raw decoded claims to the CredentialClaims structure,\n * picking known age/residency fields and preserving any extra keys.\n */\nfunction mapToCredentialClaims(raw: Record<string, unknown>): CredentialClaims {\n const claims: CredentialClaims = {};\n\n if (typeof raw['age_over_18'] === 'boolean') {\n claims.age_over_18 = raw['age_over_18'];\n }\n if (typeof raw['age_over_21'] === 'boolean') {\n claims.age_over_21 = raw['age_over_21'];\n }\n if (typeof raw['resident_country'] === 'string') {\n claims.resident_country = raw['resident_country'];\n }\n if (typeof raw['nationality'] === 'string') {\n claims.nationality = raw['nationality'];\n }\n if (typeof raw['family_name_birth'] === 'string') {\n claims.family_name_birth = raw['family_name_birth'];\n }\n\n for (const [key, value] of Object.entries(raw)) {\n if (\n !(key in claims) &&\n !key.startsWith('_sd') &&\n key !== 'iss' &&\n key !== 'exp' &&\n key !== 'iat' &&\n key !== 'cnf' &&\n key !== 'vct'\n ) {\n claims[key] = value;\n }\n }\n\n return claims;\n}\n\n/**\n * Best-effort extraction of a country code hint from an issuer URL or string.\n */\nfunction extractCountryHint(issuer: string): string {\n try {\n const url = new URL(issuer);\n const tld = url.hostname.split('.').pop()?.toUpperCase();\n if (tld && tld.length === 2) {\n return tld;\n }\n } catch {\n // Not a valid URL\n }\n return '';\n}\n\n/**\n * SD-JWT VC credential parser.\n *\n * Decodes and cryptographically validates SD-JWT Verifiable Credentials:\n * - JWT signature verification via x5c public key (jose)\n * - Issuer certificate trust chain verification\n * - Disclosure hash integrity verification\n * - Key binding JWT signature and sd_hash verification\n * - Selective disclosure claim extraction\n */\nexport class SdJwtParser implements ICredentialParser {\n readonly format: CredentialFormat = 'sd-jwt-vc';\n\n canParse(vpToken: unknown): boolean {\n return typeof vpToken === 'string' && vpToken.includes('~');\n }\n\n async parse(vpToken: unknown, options: ParseOptions): Promise<PresentationResult> {\n if (typeof vpToken !== 'string') {\n throw new MalformedCredentialError('VP token must be a string');\n }\n\n const allowedAlgorithms = options.allowedAlgorithms ?? DEFAULT_ALLOWED_ALGORITHMS;\n\n const invalidResult = (error: string): PresentationResult => ({\n valid: false,\n format: this.format,\n claims: {},\n issuer: { certificate: new Uint8Array(), country: '' },\n error,\n });\n\n // Step 1: Split the SD-JWT into components\n let parts: ReturnType<typeof splitSdJwt>;\n try {\n parts = splitSdJwt(vpToken);\n } catch {\n throw new MalformedCredentialError('Failed to split SD-JWT structure');\n }\n\n // Step 2: Peek at issuer JWT header (need alg and x5c before verification)\n let header: ReturnType<typeof decodeProtectedHeader>;\n try {\n header = decodeProtectedHeader(parts.jwt);\n } catch {\n throw new MalformedCredentialError('Failed to decode SD-JWT issuer JWT header');\n }\n\n // Step 3: Check algorithm against allowlist\n const alg = header.alg;\n if (typeof alg !== 'string' || !allowedAlgorithms.includes(alg)) {\n return invalidResult(`Unsupported algorithm: ${alg}`);\n }\n\n // Step 4: Extract public key from x5c certificate\n const x5cArray = header.x5c;\n if (!Array.isArray(x5cArray) || x5cArray.length === 0 || typeof x5cArray[0] !== 'string') {\n throw new MalformedCredentialError('Missing or invalid x5c in JWT header');\n }\n\n let issuerKey: Awaited<ReturnType<typeof importX509>>;\n let issuerCertBytes: Uint8Array;\n try {\n issuerKey = await importX509(derToPem(x5cArray[0]), alg);\n issuerCertBytes = base64ToBytes(x5cArray[0]);\n } catch (err) {\n if (err instanceof MalformedCredentialError) throw err;\n throw new MalformedCredentialError('Failed to import issuer certificate');\n }\n\n // Step 5: Verify issuer JWT signature (also validates exp, iat via jose)\n let payload: Record<string, unknown>;\n try {\n const result = await jwtVerify(parts.jwt, issuerKey, { algorithms: allowedAlgorithms });\n payload = result.payload as unknown as Record<string, unknown>;\n } catch {\n return invalidResult('Issuer JWT signature verification failed');\n }\n\n // Step 6: Trust check — certificate must be in the trusted set\n const issuerString = typeof payload['iss'] === 'string' ? payload['iss'] : '';\n const issuerInfo: IssuerInfo = {\n certificate: issuerCertBytes,\n country: extractCountryHint(issuerString),\n };\n\n if (options.trustedCertificates.length > 0) {\n const isTrusted = options.trustedCertificates.some((trusted) => bytesEqual(trusted, issuerCertBytes));\n if (!isTrusted) {\n return invalidResult('Issuer certificate is not trusted');\n }\n }\n\n // Step 7: Verify disclosure hashes against _sd array\n const sdArray = payload['_sd'];\n if (parts.disclosures.length > 0) {\n if (!Array.isArray(sdArray) || sdArray.length === 0) {\n return invalidResult('Disclosures present but no _sd array in issuer JWT');\n }\n for (const disclosure of parts.disclosures) {\n const hashBytes = await sha256Hasher(disclosure, 'sha-256');\n const hashB64url = bytesToBase64url(hashBytes);\n if (!sdArray.includes(hashB64url)) {\n return invalidResult('Disclosure hash mismatch');\n }\n }\n }\n\n // Step 8: Verify key binding JWT (if present)\n if (parts.kbJwt) {\n // Extract holder public key from cnf claim\n const cnf = payload['cnf'] as Record<string, unknown> | undefined;\n if (!cnf || typeof cnf !== 'object' || !cnf['jwk']) {\n throw new MalformedCredentialError('Missing cnf.jwk in issuer JWT for key binding');\n }\n\n let holderKey: Awaited<ReturnType<typeof importJWK>>;\n try {\n const kbHeader = decodeProtectedHeader(parts.kbJwt);\n const kbAlg = kbHeader.alg;\n if (typeof kbAlg !== 'string' || !allowedAlgorithms.includes(kbAlg)) {\n return invalidResult(`Unsupported KB-JWT algorithm: ${kbAlg}`);\n }\n holderKey = await importJWK(cnf['jwk'] as Record<string, unknown>, kbAlg);\n } catch (err) {\n if (err instanceof MalformedCredentialError) throw err;\n throw new MalformedCredentialError('Failed to import holder key from cnf.jwk');\n }\n\n // Verify KB-JWT signature\n let kbPayload: Record<string, unknown>;\n try {\n const kbResult = await jwtVerify(parts.kbJwt, holderKey, {\n algorithms: allowedAlgorithms,\n ...(options.audience ? { audience: options.audience } : {}),\n });\n kbPayload = kbResult.payload as unknown as Record<string, unknown>;\n } catch {\n return invalidResult('Key binding JWT signature verification failed');\n }\n\n // Validate nonce — must be present and match when KB-JWT is used\n if (kbPayload['nonce'] !== options.nonce) {\n return invalidResult('Key binding JWT nonce does not match');\n }\n\n // Verify sd_hash — hash of the SD-JWT content before the KB-JWT\n const disclosurePart = parts.disclosures.length > 0 ? parts.disclosures.join('~') + '~' : '';\n const sdJwtForHash = parts.jwt + '~' + disclosurePart;\n const sdHashBytes = await sha256Hasher(sdJwtForHash, 'sha-256');\n const expectedSdHash = bytesToBase64url(sdHashBytes);\n if (kbPayload['sd_hash'] !== expectedSdHash) {\n return invalidResult('Key binding JWT sd_hash does not match');\n }\n }\n\n // Step 9: Decode disclosures and extract claims\n let resolvedClaims: Record<string, unknown>;\n try {\n const decoded = await decodeSdJwt(vpToken, sha256Hasher);\n resolvedClaims = await getClaims<Record<string, unknown>>(\n decoded.jwt.payload,\n decoded.disclosures,\n sha256Hasher\n );\n } catch {\n throw new MalformedCredentialError('Failed to decode SD-JWT disclosures');\n }\n\n return {\n valid: true,\n format: this.format,\n claims: mapToCredentialClaims(resolvedClaims),\n issuer: issuerInfo,\n };\n }\n}\n","import { decode } from 'cbor-x';\n\nimport { MalformedCredentialError } from '../errors.js';\nimport type { IssuerInfo } from '../types/issuer.js';\nimport type { CredentialFormat, CredentialClaims, PresentationResult } from '../types/presentation.js';\n\nimport type { ICredentialParser, ParseOptions } from './parser.interface.js';\n\n/**\n * Runtime check for binary data. Returns true for Uint8Array and Node.js Buffer\n * without referencing the Buffer type (which is unavailable in DOM-only tsconfig).\n * Buffer extends Uint8Array, so `instanceof Uint8Array` catches both.\n */\nfunction isBinaryData(value: unknown): value is Uint8Array {\n return value instanceof Uint8Array;\n}\n\n/**\n * Checks whether two Uint8Array instances contain identical bytes.\n */\nfunction bytesEqual(a: Uint8Array, b: Uint8Array): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false;\n }\n return true;\n}\n\n/**\n * Represents a single IssuerSignedItem element from an mDOC nameSpace.\n * ISO 18013-5 Section 8.3.2.1.2.\n */\ninterface IssuerSignedItem {\n digestID: number;\n random: Uint8Array | unknown;\n elementIdentifier: string;\n elementValue: unknown;\n}\n\n/**\n * Simplified DeviceResponse structure from ISO 18013-5.\n * Only the fields required for claim extraction and trust validation.\n */\ninterface MdocDocument {\n docType: string;\n issuerSigned: {\n nameSpaces: Record<string, IssuerSignedItem[]>;\n issuerAuth: unknown[];\n };\n}\n\ninterface DeviceResponse {\n version: string;\n documents: MdocDocument[];\n status: number;\n}\n\n/**\n * Extracts the issuer certificate bytes from a COSE_Sign1 issuerAuth structure.\n *\n * The issuerAuth is a COSE_Sign1 array: [protected, unprotected, payload, signature].\n * The protected header (index 0) is CBOR-encoded and may contain the x5chain (label 33)\n * with the issuer certificate. The unprotected header (index 1) may also carry it.\n *\n * If neither header contains a certificate, the raw protected bytes are returned\n * as a fallback for trust matching (test/simplified scenarios).\n */\nfunction extractCertificateFromIssuerAuth(issuerAuth: unknown[]): Uint8Array {\n // Try unprotected header first (index 1) -- it's already decoded as a Map or object\n const unprotected = issuerAuth[1];\n if (unprotected && typeof unprotected === 'object') {\n // x5chain is COSE header label 33\n const certFromUnprotected = extractX5Chain(unprotected);\n if (certFromUnprotected) return certFromUnprotected;\n }\n\n // Try protected header (index 0) -- CBOR-encoded bytes\n const protectedHeader = issuerAuth[0];\n if (isBinaryData(protectedHeader)) {\n try {\n const decoded = decode(protectedHeader) as unknown;\n if (decoded && typeof decoded === 'object') {\n const certFromProtected = extractX5Chain(decoded);\n if (certFromProtected) return certFromProtected;\n }\n } catch {\n // Protected header could not be decoded -- fall through\n }\n // Return raw protected bytes as fallback identifier\n return new Uint8Array(protectedHeader);\n }\n\n return new Uint8Array();\n}\n\n/**\n * Extracts certificate bytes from an x5chain (label 33) in a COSE header.\n * The header can be a plain object or a Map.\n */\nfunction extractX5Chain(header: unknown): Uint8Array | null {\n if (header instanceof Map) {\n const cert = header.get(33) as unknown;\n if (isBinaryData(cert)) {\n return new Uint8Array(cert);\n }\n } else if (typeof header === 'object' && header !== null) {\n const rec = header as Record<string | number, unknown>;\n const cert = rec[33] ?? rec['x5chain'] ?? rec['33'];\n if (isBinaryData(cert)) {\n return new Uint8Array(cert);\n }\n }\n return null;\n}\n\n/**\n * Maps raw mDOC IssuerSignedItem elements to the CredentialClaims structure,\n * picking known age/residency fields and preserving any additional identifiers.\n */\nfunction mapToCredentialClaims(items: IssuerSignedItem[]): CredentialClaims {\n const claims: CredentialClaims = {};\n\n for (const item of items) {\n const key = item.elementIdentifier;\n const value = item.elementValue;\n\n switch (key) {\n case 'age_over_18':\n if (typeof value === 'boolean') claims.age_over_18 = value;\n break;\n case 'age_over_21':\n if (typeof value === 'boolean') claims.age_over_21 = value;\n break;\n case 'resident_country':\n if (typeof value === 'string') claims.resident_country = value;\n break;\n case 'nationality':\n if (typeof value === 'string') claims.nationality = value;\n break;\n case 'family_name_birth':\n if (typeof value === 'string') claims.family_name_birth = value;\n break;\n default:\n claims[key] = value;\n break;\n }\n }\n\n return claims;\n}\n\n/**\n * Extracts validity period from the issuerAuth payload.\n *\n * The payload (index 2) of the COSE_Sign1 is CBOR-encoded and should\n * contain a MobileSecurityObject with a validityInfo field carrying\n * `validFrom` and `validUntil` dates.\n */\nfunction extractValidityPeriod(issuerAuth: unknown[]): { validFrom?: Date; validUntil?: Date } {\n const payload = issuerAuth[2];\n if (!payload) return {};\n\n try {\n // payload can be raw CBOR bytes or already decoded\n const decoded = isBinaryData(payload) ? (decode(payload) as unknown) : payload;\n\n if (decoded && typeof decoded === 'object') {\n const obj = decoded as Record<string, unknown>;\n const validityInfo = obj['validityInfo'] as Record<string, unknown> | undefined;\n if (validityInfo) {\n return {\n validFrom:\n validityInfo['validFrom'] instanceof Date\n ? validityInfo['validFrom']\n : typeof validityInfo['validFrom'] === 'string'\n ? new Date(validityInfo['validFrom'])\n : undefined,\n validUntil:\n validityInfo['validUntil'] instanceof Date\n ? validityInfo['validUntil']\n : typeof validityInfo['validUntil'] === 'string'\n ? new Date(validityInfo['validUntil'])\n : undefined,\n };\n }\n }\n } catch {\n // Could not decode payload -- validity check will be skipped\n }\n\n return {};\n}\n\n/**\n * mDOC / mDL credential parser.\n *\n * Decodes and validates mDOC (Mobile Document) credentials as specified in\n * ISO 18013-5 and the EUDI Wallet ecosystem. Processes CBOR-encoded\n * DeviceResponse structures containing:\n * - Document type validation (eu.europa.ec.eudi.pid.1)\n * - Issuer certificate trust chain verification via COSE_Sign1 issuerAuth\n * - Validity period checking\n * - Claim extraction from IssuerSignedItem nameSpace elements\n */\nexport class MdocParser implements ICredentialParser {\n readonly format: CredentialFormat = 'mdoc';\n\n /**\n * Returns true when the token is binary data (Uint8Array or Buffer),\n * indicating a CBOR-encoded mDOC DeviceResponse.\n */\n canParse(vpToken: unknown): boolean {\n return isBinaryData(vpToken);\n }\n\n /**\n * Parses and validates an mDOC DeviceResponse token.\n *\n * @throws {MalformedCredentialError} when the CBOR structure cannot be decoded\n * or does not match the expected DeviceResponse format\n */\n async parse(vpToken: unknown, options: ParseOptions): Promise<PresentationResult> {\n if (!isBinaryData(vpToken)) {\n throw new MalformedCredentialError('VP token must be a Uint8Array or Buffer');\n }\n\n const invalidResult = (error: string): PresentationResult => ({\n valid: false,\n format: this.format,\n claims: {},\n issuer: { certificate: new Uint8Array(), country: '' },\n error,\n });\n\n // Step 1: Decode the CBOR DeviceResponse\n let deviceResponse: DeviceResponse;\n try {\n deviceResponse = decode(vpToken) as DeviceResponse;\n } catch {\n throw new MalformedCredentialError('Failed to decode CBOR DeviceResponse');\n }\n\n // Step 2: Validate basic DeviceResponse structure\n if (\n !deviceResponse ||\n typeof deviceResponse !== 'object' ||\n !Array.isArray(deviceResponse.documents) ||\n deviceResponse.documents.length === 0\n ) {\n throw new MalformedCredentialError('Invalid DeviceResponse structure: missing or empty documents array');\n }\n\n const document = deviceResponse.documents[0];\n if (!document.issuerSigned || !document.issuerSigned.nameSpaces || !document.issuerSigned.issuerAuth) {\n throw new MalformedCredentialError('Invalid mDOC document: missing issuerSigned data');\n }\n\n // Step 3: Extract issuer certificate from COSE_Sign1 issuerAuth\n const issuerAuth = document.issuerSigned.issuerAuth;\n if (!Array.isArray(issuerAuth) || issuerAuth.length < 4) {\n throw new MalformedCredentialError('Invalid issuerAuth: expected COSE_Sign1 array with 4 elements');\n }\n\n const issuerCertBytes = extractCertificateFromIssuerAuth(issuerAuth);\n const issuerInfo: IssuerInfo = {\n certificate: issuerCertBytes,\n country: '',\n };\n\n // Step 4: Verify trust -- certificate must be in the trusted set\n if (options.trustedCertificates.length > 0) {\n const isTrusted = options.trustedCertificates.some((trusted) => bytesEqual(trusted, issuerCertBytes));\n if (!isTrusted) {\n return invalidResult('Issuer certificate is not trusted');\n }\n } else if (issuerCertBytes.length === 0) {\n return invalidResult('No issuer certificate found and no trusted certificates configured');\n }\n\n // Step 5: Check validity period\n const { validUntil } = extractValidityPeriod(issuerAuth);\n if (validUntil) {\n const now = new Date();\n if (validUntil < now) {\n return invalidResult('Credential has expired');\n }\n }\n\n // Step 6: Extract claims from nameSpaces\n // Prefer the EUDI PID namespace, fall back to the first available namespace\n const pidNamespace = 'eu.europa.ec.eudi.pid.1';\n const nameSpaces = document.issuerSigned.nameSpaces;\n const items: IssuerSignedItem[] =\n nameSpaces[pidNamespace] ?? nameSpaces[document.docType] ?? Object.values(nameSpaces)[0] ?? [];\n\n const claims = mapToCredentialClaims(items);\n\n // Try to derive country from resident_country claim\n if (claims.resident_country && typeof claims.resident_country === 'string') {\n issuerInfo.country = claims.resident_country;\n }\n\n return {\n valid: true,\n format: this.format,\n claims,\n issuer: issuerInfo,\n };\n }\n}\n","import { v4 as uuidv4 } from 'uuid';\n\nimport type { AuthorizationRequestInput, AuthorizationRequest } from './types/authorization.js';\n\nexport function createAuthorizationRequest(input: AuthorizationRequestInput): AuthorizationRequest {\n const state = input.state ?? uuidv4();\n\n const presentationDefinition = {\n id: uuidv4(),\n input_descriptors: input.requestedAttributes.map((attr, index) => ({\n id: `descriptor_${index}`,\n format: Object.fromEntries(\n input.acceptedFormats.map((fmt) => {\n if (fmt === 'sd-jwt-vc') return ['vc+sd-jwt', { 'sd-jwt_alg_values': ['ES256'] }];\n return ['mso_mdoc', { alg: ['ES256'] }];\n })\n ),\n constraints: {\n fields: [\n {\n path: [`$.${attr}`, `$['${attr}']`],\n filter: { type: attr.startsWith('age_over') ? 'boolean' : 'string' },\n },\n ],\n },\n })),\n };\n\n const params = new URLSearchParams({\n response_type: 'vp_token',\n response_mode: 'direct_post',\n response_uri: input.responseUri,\n client_id: input.clientId,\n nonce: input.nonce,\n state,\n presentation_definition: JSON.stringify(presentationDefinition),\n });\n\n return {\n uri: `openid4vp://authorize?${params.toString()}`,\n presentationDefinition,\n nonce: input.nonce,\n state,\n };\n}\n","import { MdocParser } from './parsers/mdoc.parser.js';\nimport type { ParseOptions, ICredentialParser } from './parsers/parser.interface.js';\nimport { SdJwtParser } from './parsers/sd-jwt.parser.js';\nimport type { PresentationResult } from './types/presentation.js';\n\nconst parsers: ICredentialParser[] = [new SdJwtParser(), new MdocParser()];\n\nexport async function parsePresentation(vpToken: unknown, options: ParseOptions): Promise<PresentationResult> {\n for (const parser of parsers) {\n if (parser.canParse(vpToken)) {\n return parser.parse(vpToken, options);\n }\n }\n\n return {\n valid: false,\n format: 'sd-jwt-vc',\n claims: {},\n issuer: { certificate: new Uint8Array(), country: '' },\n error: 'Unsupported credential format',\n };\n}\n\nexport type { ParseOptions } from './parsers/parser.interface.js';\n","export const VERSION = '0.2.0';\n\nexport type {\n CredentialFormat,\n CredentialClaims,\n PresentationResult,\n IssuerInfo,\n AuthorizationRequestInput,\n AuthorizationRequest,\n} from './types/index.js';\n\nexport type { ICredentialParser, ParseOptions } from './parsers/parser.interface.js';\n\nexport { SdJwtParser } from './parsers/sd-jwt.parser.js';\nexport { MdocParser } from './parsers/mdoc.parser.js';\n\nexport {\n InvalidSignatureError,\n ExpiredCredentialError,\n UnsupportedFormatError,\n MalformedCredentialError,\n NonceValidationError,\n} from './errors.js';\n\nexport { createAuthorizationRequest } from './authorization.js';\n\nexport { parsePresentation } from './presentation.js';\n"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/parsers/sd-jwt.parser.ts","../src/parsers/mdoc.parser.ts","../src/authorization.ts","../src/presentation.ts","../src/index.ts"],"names":["bytesEqual","mapToCredentialClaims","uuidv4"],"mappings":"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","file":"index.js","sourcesContent":["export class InvalidSignatureError extends Error {\n constructor(message = 'Credential signature validation failed') {\n super(message);\n this.name = 'InvalidSignatureError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class ExpiredCredentialError extends Error {\n constructor(message = 'Credential has expired') {\n super(message);\n this.name = 'ExpiredCredentialError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class UnsupportedFormatError extends Error {\n constructor(format: string) {\n super(`Unsupported credential format: ${format}`);\n this.name = 'UnsupportedFormatError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class MalformedCredentialError extends Error {\n constructor(message = 'Credential structure is malformed') {\n super(message);\n this.name = 'MalformedCredentialError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class NonceValidationError extends Error {\n constructor(message = 'Nonce does not match expected value') {\n super(message);\n this.name = 'NonceValidationError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n","import { splitSdJwt, decodeSdJwt, getClaims } from '@sd-jwt/decode';\nimport { decodeProtectedHeader, jwtVerify, importX509, importJWK } from 'jose';\n\nimport { MalformedCredentialError } from '../errors.js';\nimport type { IssuerInfo } from '../types/issuer.js';\nimport type { CredentialFormat, CredentialClaims, PresentationResult } from '../types/presentation.js';\n\nimport type { ICredentialParser, ParseOptions } from './parser.interface.js';\n\n/**\n * Hasher function signature expected by @sd-jwt/decode.\n * Inlined here to avoid a direct dependency on @sd-jwt/types.\n */\ntype SdJwtHasher = (data: string | ArrayBuffer, alg: string) => Promise<Uint8Array>;\n\nconst DEFAULT_ALLOWED_ALGORITHMS = ['ES256', 'ES384', 'ES512'];\n\n/**\n * SHA-256 hasher implementation using the Web Crypto API.\n * Compatible with the @sd-jwt/decode Hasher signature.\n */\nconst sha256Hasher: SdJwtHasher = async (data: string | ArrayBuffer, _alg: string): Promise<Uint8Array> => {\n const encoder = new TextEncoder();\n const input = typeof data === 'string' ? encoder.encode(data) : data;\n const hashBuffer = await crypto.subtle.digest('SHA-256', input);\n return new Uint8Array(hashBuffer);\n};\n\n// Standard base64 alphabet for decoding x5c certificate entries\nconst BASE64_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n/**\n * Decodes a standard base64-encoded string into raw bytes.\n * Does not depend on Node.js Buffer or browser atob.\n */\nfunction base64ToBytes(base64: string): Uint8Array<ArrayBuffer> {\n const cleaned = base64.replace(/=+$/, '');\n const byteLength = Math.floor((cleaned.length * 3) / 4);\n const buffer = new ArrayBuffer(byteLength);\n const bytes = new Uint8Array(buffer);\n\n let byteIndex = 0;\n for (let i = 0; i < cleaned.length; i += 4) {\n const a = BASE64_CHARS.indexOf(cleaned[i]);\n const b = i + 1 < cleaned.length ? BASE64_CHARS.indexOf(cleaned[i + 1]) : 0;\n const c = i + 2 < cleaned.length ? BASE64_CHARS.indexOf(cleaned[i + 2]) : 0;\n const d = i + 3 < cleaned.length ? BASE64_CHARS.indexOf(cleaned[i + 3]) : 0;\n\n bytes[byteIndex++] = (a << 2) | (b >> 4);\n if (byteIndex < byteLength) bytes[byteIndex++] = ((b & 0x0f) << 4) | (c >> 2);\n if (byteIndex < byteLength) bytes[byteIndex++] = ((c & 0x03) << 6) | d;\n }\n\n return bytes;\n}\n\n/**\n * Checks whether two Uint8Array instances contain identical bytes.\n */\nfunction bytesEqual(a: Uint8Array, b: Uint8Array): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false;\n }\n return true;\n}\n\n/**\n * Converts a base64-encoded DER certificate to PEM format for jose.importX509.\n */\nfunction derToPem(base64Der: string): string {\n const lines = base64Der.match(/.{1,64}/g) || [];\n return `-----BEGIN CERTIFICATE-----\\n${lines.join('\\n')}\\n-----END CERTIFICATE-----`;\n}\n\n/**\n * Encodes a Uint8Array to base64url (no padding).\n * Used by disclosure hash verification (Task 5) and KB-JWT verification (Task 6).\n */\nfunction bytesToBase64url(bytes: Uint8Array): string {\n let binary = '';\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n return globalThis.btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\n/**\n * Maps raw decoded claims to the CredentialClaims structure,\n * picking known age/residency fields and preserving any extra keys.\n */\nfunction mapToCredentialClaims(raw: Record<string, unknown>): CredentialClaims {\n const claims: CredentialClaims = {};\n\n if (typeof raw['age_over_18'] === 'boolean') {\n claims.age_over_18 = raw['age_over_18'];\n }\n if (typeof raw['age_over_21'] === 'boolean') {\n claims.age_over_21 = raw['age_over_21'];\n }\n if (typeof raw['resident_country'] === 'string') {\n claims.resident_country = raw['resident_country'];\n }\n if (typeof raw['nationality'] === 'string') {\n claims.nationality = raw['nationality'];\n }\n if (typeof raw['family_name_birth'] === 'string') {\n claims.family_name_birth = raw['family_name_birth'];\n }\n\n for (const [key, value] of Object.entries(raw)) {\n if (\n !(key in claims) &&\n !key.startsWith('_sd') &&\n key !== 'iss' &&\n key !== 'exp' &&\n key !== 'iat' &&\n key !== 'cnf' &&\n key !== 'vct'\n ) {\n claims[key] = value;\n }\n }\n\n return claims;\n}\n\n/**\n * Best-effort extraction of a country code hint from an issuer URL or string.\n */\nfunction extractCountryHint(issuer: string): string {\n try {\n const url = new URL(issuer);\n const tld = url.hostname.split('.').pop()?.toUpperCase();\n if (tld && tld.length === 2) {\n return tld;\n }\n } catch {\n // Not a valid URL\n }\n return '';\n}\n\n/**\n * SD-JWT VC credential parser.\n *\n * Decodes and cryptographically validates SD-JWT Verifiable Credentials:\n * - JWT signature verification via x5c public key (jose)\n * - Issuer certificate trust chain verification\n * - Disclosure hash integrity verification\n * - Key binding JWT signature and sd_hash verification\n * - Selective disclosure claim extraction\n */\nexport class SdJwtParser implements ICredentialParser {\n readonly format: CredentialFormat = 'sd-jwt-vc';\n\n canParse(vpToken: unknown): boolean {\n return typeof vpToken === 'string' && vpToken.includes('~');\n }\n\n async parse(vpToken: unknown, options: ParseOptions): Promise<PresentationResult> {\n if (typeof vpToken !== 'string') {\n throw new MalformedCredentialError('VP token must be a string');\n }\n\n const allowedAlgorithms = options.allowedAlgorithms ?? DEFAULT_ALLOWED_ALGORITHMS;\n\n const invalidResult = (error: string): PresentationResult => ({\n valid: false,\n format: this.format,\n claims: {},\n issuer: { certificate: new Uint8Array(), country: '' },\n error,\n });\n\n // Step 1: Split the SD-JWT into components\n let parts: ReturnType<typeof splitSdJwt>;\n try {\n parts = splitSdJwt(vpToken);\n } catch {\n throw new MalformedCredentialError('Failed to split SD-JWT structure');\n }\n\n // Step 2: Peek at issuer JWT header (need alg and x5c before verification)\n let header: ReturnType<typeof decodeProtectedHeader>;\n try {\n header = decodeProtectedHeader(parts.jwt);\n } catch {\n throw new MalformedCredentialError('Failed to decode SD-JWT issuer JWT header');\n }\n\n // Step 3: Check algorithm against allowlist\n const alg = header.alg;\n if (typeof alg !== 'string' || !allowedAlgorithms.includes(alg)) {\n return invalidResult(`Unsupported algorithm: ${alg}`);\n }\n\n // Step 4: Extract public key from x5c certificate\n const x5cArray = header.x5c;\n if (!Array.isArray(x5cArray) || x5cArray.length === 0 || typeof x5cArray[0] !== 'string') {\n throw new MalformedCredentialError('Missing or invalid x5c in JWT header');\n }\n\n let issuerKey: Awaited<ReturnType<typeof importX509>>;\n let issuerCertBytes: Uint8Array;\n try {\n issuerKey = await importX509(derToPem(x5cArray[0]), alg);\n issuerCertBytes = base64ToBytes(x5cArray[0]);\n } catch (err) {\n if (err instanceof MalformedCredentialError) throw err;\n throw new MalformedCredentialError('Failed to import issuer certificate');\n }\n\n // Step 5: Verify issuer JWT signature (also validates exp, iat via jose)\n let payload: Record<string, unknown>;\n try {\n const result = await jwtVerify(parts.jwt, issuerKey, { algorithms: allowedAlgorithms });\n payload = result.payload as unknown as Record<string, unknown>;\n } catch {\n return invalidResult('Issuer JWT signature verification failed');\n }\n\n // Step 6: Trust check — certificate must be in the trusted set\n // unless the caller explicitly opts out via skipTrustCheck.\n const issuerString = typeof payload['iss'] === 'string' ? payload['iss'] : '';\n const issuerInfo: IssuerInfo = {\n certificate: issuerCertBytes,\n country: extractCountryHint(issuerString),\n };\n\n if (options.trustedCertificates.length === 0) {\n if (options.skipTrustCheck !== true) {\n throw new MalformedCredentialError(\n 'trustedCertificates must not be empty unless skipTrustCheck is true'\n );\n }\n } else {\n const isTrusted = options.trustedCertificates.some((trusted) => bytesEqual(trusted, issuerCertBytes));\n if (!isTrusted) {\n return invalidResult('Issuer certificate is not trusted');\n }\n }\n\n // Step 7: Verify disclosure hashes against _sd array\n const sdArray = payload['_sd'];\n if (parts.disclosures.length > 0) {\n if (!Array.isArray(sdArray) || sdArray.length === 0) {\n return invalidResult('Disclosures present but no _sd array in issuer JWT');\n }\n for (const disclosure of parts.disclosures) {\n const hashBytes = await sha256Hasher(disclosure, 'sha-256');\n const hashB64url = bytesToBase64url(hashBytes);\n if (!sdArray.includes(hashB64url)) {\n return invalidResult('Disclosure hash mismatch');\n }\n }\n }\n\n // Step 8: Verify key binding JWT (if present)\n if (parts.kbJwt) {\n // Extract holder public key from cnf claim\n const cnf = payload['cnf'] as Record<string, unknown> | undefined;\n if (!cnf || typeof cnf !== 'object' || !cnf['jwk']) {\n throw new MalformedCredentialError('Missing cnf.jwk in issuer JWT for key binding');\n }\n\n let holderKey: Awaited<ReturnType<typeof importJWK>>;\n try {\n const kbHeader = decodeProtectedHeader(parts.kbJwt);\n const kbAlg = kbHeader.alg;\n if (typeof kbAlg !== 'string' || !allowedAlgorithms.includes(kbAlg)) {\n return invalidResult(`Unsupported KB-JWT algorithm: ${kbAlg}`);\n }\n holderKey = await importJWK(cnf['jwk'] as Record<string, unknown>, kbAlg);\n } catch (err) {\n if (err instanceof MalformedCredentialError) throw err;\n throw new MalformedCredentialError('Failed to import holder key from cnf.jwk');\n }\n\n // Verify KB-JWT signature\n let kbPayload: Record<string, unknown>;\n try {\n const kbResult = await jwtVerify(parts.kbJwt, holderKey, {\n algorithms: allowedAlgorithms,\n ...(options.audience ? { audience: options.audience } : {}),\n });\n kbPayload = kbResult.payload as unknown as Record<string, unknown>;\n } catch {\n return invalidResult('Key binding JWT signature verification failed');\n }\n\n // Validate nonce — must be present and match when KB-JWT is used\n if (kbPayload['nonce'] !== options.nonce) {\n return invalidResult('Key binding JWT nonce does not match');\n }\n\n // Verify sd_hash — hash of the SD-JWT content before the KB-JWT\n const disclosurePart = parts.disclosures.length > 0 ? parts.disclosures.join('~') + '~' : '';\n const sdJwtForHash = parts.jwt + '~' + disclosurePart;\n const sdHashBytes = await sha256Hasher(sdJwtForHash, 'sha-256');\n const expectedSdHash = bytesToBase64url(sdHashBytes);\n if (kbPayload['sd_hash'] !== expectedSdHash) {\n return invalidResult('Key binding JWT sd_hash does not match');\n }\n }\n\n // Step 9: Decode disclosures and extract claims\n let resolvedClaims: Record<string, unknown>;\n try {\n const decoded = await decodeSdJwt(vpToken, sha256Hasher);\n resolvedClaims = await getClaims<Record<string, unknown>>(\n decoded.jwt.payload,\n decoded.disclosures,\n sha256Hasher\n );\n } catch {\n throw new MalformedCredentialError('Failed to decode SD-JWT disclosures');\n }\n\n return {\n valid: true,\n format: this.format,\n claims: mapToCredentialClaims(resolvedClaims),\n issuer: issuerInfo,\n };\n }\n}\n","import { decode } from 'cbor-x';\n\nimport { MalformedCredentialError } from '../errors.js';\nimport type { IssuerInfo } from '../types/issuer.js';\nimport type { CredentialFormat, CredentialClaims, PresentationResult } from '../types/presentation.js';\n\nimport type { ICredentialParser, ParseOptions } from './parser.interface.js';\n\n/**\n * Runtime check for binary data. Returns true for Uint8Array and Node.js Buffer\n * without referencing the Buffer type (which is unavailable in DOM-only tsconfig).\n * Buffer extends Uint8Array, so `instanceof Uint8Array` catches both.\n */\nfunction isBinaryData(value: unknown): value is Uint8Array {\n return value instanceof Uint8Array;\n}\n\n/**\n * Checks whether two Uint8Array instances contain identical bytes.\n */\nfunction bytesEqual(a: Uint8Array, b: Uint8Array): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false;\n }\n return true;\n}\n\n/**\n * Represents a single IssuerSignedItem element from an mDOC nameSpace.\n * ISO 18013-5 Section 8.3.2.1.2.\n */\ninterface IssuerSignedItem {\n digestID: number;\n random: Uint8Array | unknown;\n elementIdentifier: string;\n elementValue: unknown;\n}\n\n/**\n * Simplified DeviceResponse structure from ISO 18013-5.\n * Only the fields required for claim extraction and trust validation.\n */\ninterface MdocDocument {\n docType: string;\n issuerSigned: {\n nameSpaces: Record<string, IssuerSignedItem[]>;\n issuerAuth: unknown[];\n };\n}\n\ninterface DeviceResponse {\n version: string;\n documents: MdocDocument[];\n status: number;\n}\n\n/**\n * Extracts the issuer certificate bytes from a COSE_Sign1 issuerAuth structure.\n *\n * The issuerAuth is a COSE_Sign1 array: [protected, unprotected, payload, signature].\n * The protected header (index 0) is CBOR-encoded and may contain the x5chain (label 33)\n * with the issuer certificate. The unprotected header (index 1) may also carry it.\n *\n * If neither header contains a certificate, the raw protected bytes are returned\n * as a fallback for trust matching (test/simplified scenarios).\n */\nfunction extractCertificateFromIssuerAuth(issuerAuth: unknown[]): Uint8Array {\n // Try unprotected header first (index 1) -- it's already decoded as a Map or object\n const unprotected = issuerAuth[1];\n if (unprotected && typeof unprotected === 'object') {\n // x5chain is COSE header label 33\n const certFromUnprotected = extractX5Chain(unprotected);\n if (certFromUnprotected) return certFromUnprotected;\n }\n\n // Try protected header (index 0) -- CBOR-encoded bytes\n const protectedHeader = issuerAuth[0];\n if (isBinaryData(protectedHeader)) {\n try {\n const decoded = decode(protectedHeader) as unknown;\n if (decoded && typeof decoded === 'object') {\n const certFromProtected = extractX5Chain(decoded);\n if (certFromProtected) return certFromProtected;\n }\n } catch {\n // Protected header could not be decoded -- fall through\n }\n // Return raw protected bytes as fallback identifier\n return new Uint8Array(protectedHeader);\n }\n\n return new Uint8Array();\n}\n\n/**\n * Extracts certificate bytes from an x5chain (label 33) in a COSE header.\n * The header can be a plain object or a Map.\n */\nfunction extractX5Chain(header: unknown): Uint8Array | null {\n if (header instanceof Map) {\n const cert = header.get(33) as unknown;\n if (isBinaryData(cert)) {\n return new Uint8Array(cert);\n }\n } else if (typeof header === 'object' && header !== null) {\n const rec = header as Record<string | number, unknown>;\n const cert = rec[33] ?? rec['x5chain'] ?? rec['33'];\n if (isBinaryData(cert)) {\n return new Uint8Array(cert);\n }\n }\n return null;\n}\n\n/**\n * Maps raw mDOC IssuerSignedItem elements to the CredentialClaims structure,\n * picking known age/residency fields and preserving any additional identifiers.\n */\nfunction mapToCredentialClaims(items: IssuerSignedItem[]): CredentialClaims {\n const claims: CredentialClaims = {};\n\n for (const item of items) {\n const key = item.elementIdentifier;\n const value = item.elementValue;\n\n switch (key) {\n case 'age_over_18':\n if (typeof value === 'boolean') claims.age_over_18 = value;\n break;\n case 'age_over_21':\n if (typeof value === 'boolean') claims.age_over_21 = value;\n break;\n case 'resident_country':\n if (typeof value === 'string') claims.resident_country = value;\n break;\n case 'nationality':\n if (typeof value === 'string') claims.nationality = value;\n break;\n case 'family_name_birth':\n if (typeof value === 'string') claims.family_name_birth = value;\n break;\n default:\n claims[key] = value;\n break;\n }\n }\n\n return claims;\n}\n\n/**\n * Extracts validity period from the issuerAuth payload.\n *\n * The payload (index 2) of the COSE_Sign1 is CBOR-encoded and should\n * contain a MobileSecurityObject with a validityInfo field carrying\n * `validFrom` and `validUntil` dates.\n */\nfunction extractValidityPeriod(issuerAuth: unknown[]): { validFrom?: Date; validUntil?: Date } {\n const payload = issuerAuth[2];\n if (!payload) return {};\n\n try {\n // payload can be raw CBOR bytes or already decoded\n const decoded = isBinaryData(payload) ? (decode(payload) as unknown) : payload;\n\n if (decoded && typeof decoded === 'object') {\n const obj = decoded as Record<string, unknown>;\n const validityInfo = obj['validityInfo'] as Record<string, unknown> | undefined;\n if (validityInfo) {\n return {\n validFrom:\n validityInfo['validFrom'] instanceof Date\n ? validityInfo['validFrom']\n : typeof validityInfo['validFrom'] === 'string'\n ? new Date(validityInfo['validFrom'])\n : undefined,\n validUntil:\n validityInfo['validUntil'] instanceof Date\n ? validityInfo['validUntil']\n : typeof validityInfo['validUntil'] === 'string'\n ? new Date(validityInfo['validUntil'])\n : undefined,\n };\n }\n }\n } catch {\n // Could not decode payload -- validity check will be skipped\n }\n\n return {};\n}\n\n/**\n * mDOC / mDL credential parser.\n *\n * Decodes and validates mDOC (Mobile Document) credentials as specified in\n * ISO 18013-5 and the EUDI Wallet ecosystem. Processes CBOR-encoded\n * DeviceResponse structures containing:\n * - Document type validation (eu.europa.ec.eudi.pid.1)\n * - Issuer certificate trust chain verification via COSE_Sign1 issuerAuth\n * - Validity period checking\n * - Claim extraction from IssuerSignedItem nameSpace elements\n */\nexport class MdocParser implements ICredentialParser {\n readonly format: CredentialFormat = 'mdoc';\n\n /**\n * Returns true when the token is binary data (Uint8Array or Buffer),\n * indicating a CBOR-encoded mDOC DeviceResponse.\n */\n canParse(vpToken: unknown): boolean {\n return isBinaryData(vpToken);\n }\n\n /**\n * Parses and validates an mDOC DeviceResponse token.\n *\n * @throws {MalformedCredentialError} when the CBOR structure cannot be decoded\n * or does not match the expected DeviceResponse format\n */\n async parse(vpToken: unknown, options: ParseOptions): Promise<PresentationResult> {\n if (!isBinaryData(vpToken)) {\n throw new MalformedCredentialError('VP token must be a Uint8Array or Buffer');\n }\n\n const invalidResult = (error: string): PresentationResult => ({\n valid: false,\n format: this.format,\n claims: {},\n issuer: { certificate: new Uint8Array(), country: '' },\n error,\n });\n\n // Step 1: Decode the CBOR DeviceResponse\n let deviceResponse: DeviceResponse;\n try {\n deviceResponse = decode(vpToken) as DeviceResponse;\n } catch {\n throw new MalformedCredentialError('Failed to decode CBOR DeviceResponse');\n }\n\n // Step 2: Validate basic DeviceResponse structure\n if (\n !deviceResponse ||\n typeof deviceResponse !== 'object' ||\n !Array.isArray(deviceResponse.documents) ||\n deviceResponse.documents.length === 0\n ) {\n throw new MalformedCredentialError('Invalid DeviceResponse structure: missing or empty documents array');\n }\n\n const document = deviceResponse.documents[0];\n if (!document.issuerSigned || !document.issuerSigned.nameSpaces || !document.issuerSigned.issuerAuth) {\n throw new MalformedCredentialError('Invalid mDOC document: missing issuerSigned data');\n }\n\n // Step 3: Extract issuer certificate from COSE_Sign1 issuerAuth\n const issuerAuth = document.issuerSigned.issuerAuth;\n if (!Array.isArray(issuerAuth) || issuerAuth.length < 4) {\n throw new MalformedCredentialError('Invalid issuerAuth: expected COSE_Sign1 array with 4 elements');\n }\n\n const issuerCertBytes = extractCertificateFromIssuerAuth(issuerAuth);\n const issuerInfo: IssuerInfo = {\n certificate: issuerCertBytes,\n country: '',\n };\n\n // Step 4: Verify trust -- certificate must be in the trusted set\n // unless the caller explicitly opts out via skipTrustCheck.\n if (options.trustedCertificates.length === 0) {\n if (options.skipTrustCheck !== true) {\n throw new MalformedCredentialError(\n 'trustedCertificates must not be empty unless skipTrustCheck is true'\n );\n }\n } else {\n const isTrusted = options.trustedCertificates.some((trusted) => bytesEqual(trusted, issuerCertBytes));\n if (!isTrusted) {\n return invalidResult('Issuer certificate is not trusted');\n }\n }\n\n // Step 5: Check validity period\n const { validUntil } = extractValidityPeriod(issuerAuth);\n if (validUntil) {\n const now = new Date();\n if (validUntil < now) {\n return invalidResult('Credential has expired');\n }\n }\n\n // Step 6: Extract claims from nameSpaces\n // Prefer the EUDI PID namespace, fall back to the first available namespace\n const pidNamespace = 'eu.europa.ec.eudi.pid.1';\n const nameSpaces = document.issuerSigned.nameSpaces;\n const items: IssuerSignedItem[] =\n nameSpaces[pidNamespace] ?? nameSpaces[document.docType] ?? Object.values(nameSpaces)[0] ?? [];\n\n const claims = mapToCredentialClaims(items);\n\n // Try to derive country from resident_country claim\n if (claims.resident_country && typeof claims.resident_country === 'string') {\n issuerInfo.country = claims.resident_country;\n }\n\n return {\n valid: true,\n format: this.format,\n claims,\n issuer: issuerInfo,\n };\n }\n}\n","import { v4 as uuidv4 } from 'uuid';\n\nimport type { AuthorizationRequestInput, AuthorizationRequest } from './types/authorization.js';\n\nexport function createAuthorizationRequest(input: AuthorizationRequestInput): AuthorizationRequest {\n const state = input.state ?? uuidv4();\n\n const presentationDefinition = {\n id: uuidv4(),\n input_descriptors: input.requestedAttributes.map((attr, index) => ({\n id: `descriptor_${index}`,\n format: Object.fromEntries(\n input.acceptedFormats.map((fmt) => {\n if (fmt === 'sd-jwt-vc') return ['vc+sd-jwt', { 'sd-jwt_alg_values': ['ES256'] }];\n return ['mso_mdoc', { alg: ['ES256'] }];\n })\n ),\n constraints: {\n fields: [\n {\n path: [`$.${attr}`, `$['${attr}']`],\n filter: { type: attr.startsWith('age_over') ? 'boolean' : 'string' },\n },\n ],\n },\n })),\n };\n\n const params = new URLSearchParams({\n response_type: 'vp_token',\n response_mode: 'direct_post',\n response_uri: input.responseUri,\n client_id: input.clientId,\n nonce: input.nonce,\n state,\n presentation_definition: JSON.stringify(presentationDefinition),\n });\n\n return {\n uri: `openid4vp://authorize?${params.toString()}`,\n presentationDefinition,\n nonce: input.nonce,\n state,\n };\n}\n","import { MdocParser } from './parsers/mdoc.parser.js';\nimport type { ParseOptions, ICredentialParser } from './parsers/parser.interface.js';\nimport { SdJwtParser } from './parsers/sd-jwt.parser.js';\nimport type { PresentationResult } from './types/presentation.js';\n\nconst parsers: ICredentialParser[] = [new SdJwtParser(), new MdocParser()];\n\nexport async function parsePresentation(vpToken: unknown, options: ParseOptions): Promise<PresentationResult> {\n for (const parser of parsers) {\n if (parser.canParse(vpToken)) {\n return parser.parse(vpToken, options);\n }\n }\n\n return {\n valid: false,\n format: 'sd-jwt-vc',\n claims: {},\n issuer: { certificate: new Uint8Array(), country: '' },\n error: 'Unsupported credential format',\n };\n}\n\nexport type { ParseOptions } from './parsers/parser.interface.js';\n","export const VERSION = '0.2.1';\n\nexport type {\n CredentialFormat,\n CredentialClaims,\n PresentationResult,\n IssuerInfo,\n AuthorizationRequestInput,\n AuthorizationRequest,\n} from './types/index.js';\n\nexport type { ICredentialParser, ParseOptions } from './parsers/parser.interface.js';\n\nexport { SdJwtParser } from './parsers/sd-jwt.parser.js';\nexport { MdocParser } from './parsers/mdoc.parser.js';\n\nexport {\n InvalidSignatureError,\n ExpiredCredentialError,\n UnsupportedFormatError,\n MalformedCredentialError,\n NonceValidationError,\n} from './errors.js';\n\nexport { createAuthorizationRequest } from './authorization.js';\n\nexport { parsePresentation } from './presentation.js';\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openeudi/openid4vp",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "OpenID4VP credential parsing and validation for EUDI Wallets (SD-JWT VC + mDOC)",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -36,7 +36,6 @@
36
36
  "@sphereon/pex": "5.0.0-unstable.28",
37
37
  "@sphereon/ssi-types": "^0.37.1",
38
38
  "cbor-x": "^1.6.0",
39
- "cose-js": "^0.9.0",
40
39
  "jose": "^6.1.3",
41
40
  "uuid": "^11.1.0"
42
41
  },
@@ -47,6 +46,10 @@
47
46
  "typescript": "^5.8.3",
48
47
  "vitest": "^4.0.18"
49
48
  },
49
+ "repository": {
50
+ "type": "git",
51
+ "url": "https://github.com/openeudi/openid4vp"
52
+ },
50
53
  "keywords": [
51
54
  "openid4vp",
52
55
  "eudi",
@@ -54,19 +57,5 @@
54
57
  "mdoc",
55
58
  "verifiable-credentials",
56
59
  "eidas"
57
- ],
58
- "publishConfig": {
59
- "access": "public",
60
- "provenance": true,
61
- "registry": "https://registry.npmjs.org"
62
- },
63
- "repository": {
64
- "type": "git",
65
- "url": "https://github.com/openeudi/openid4vp"
66
- },
67
- "homepage": "https://github.com/openeudi/openid4vp#readme",
68
- "bugs": {
69
- "url": "https://github.com/openeudi/openid4vp/issues"
70
- },
71
- "author": "OpenEUDI Contributors"
60
+ ]
72
61
  }