UNPKG

vess-mdl

Version:

Parse and and validate MDOC CBOR encoded binaries according to ISO 18013-5.

405 lines 40.5 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Verifier = void 0; const compare_versions_1 = require("compare-versions"); const x509_1 = require("@peculiar/x509"); const jose_1 = require("jose"); const buffer_1 = require("buffer"); const cose_kit_1 = require("cose-kit"); const uncrypto_1 = __importDefault(require("uncrypto")); const utils_1 = require("./utils"); const checkCallback_1 = require("./checkCallback"); const parser_1 = require("./parser"); const DeviceSignedDocument_1 = require("./model/DeviceSignedDocument"); const MDL_NAMESPACE = 'org.iso.18013.5.1'; const DIGEST_ALGS = { 'SHA-256': 'sha256', 'SHA-384': 'sha384', 'SHA-512': 'sha512', }; class Verifier { /** * * @param issuersRootCertificates The IACA root certificates list of the supported issuers. */ constructor(issuersRootCertificates) { this.issuersRootCertificates = issuersRootCertificates; } async verifyIssuerSignature(issuerAuth, disableCertificateChainValidation, onCheckG) { const onCheck = (0, checkCallback_1.onCatCheck)(onCheckG, 'ISSUER_AUTH'); const { certificate, countryName } = issuerAuth; const verificationKey = certificate ? (await (0, jose_1.importX509)(certificate.toString(), issuerAuth.algName)) : undefined; if (!disableCertificateChainValidation) { try { await issuerAuth.verifyX509Chain(this.issuersRootCertificates); onCheck({ status: 'PASSED', check: 'Issuer certificate must be valid', id: checkCallback_1.VerificationAssessmentId.ISSUER_AUTH.IssuerCertificateValidity, }); } catch (err) { onCheck({ status: 'FAILED', check: 'Issuer certificate must be valid', id: checkCallback_1.VerificationAssessmentId.ISSUER_AUTH.IssuerCertificateValidity, reason: err.message, }); } } const verificationResult = verificationKey && await issuerAuth.verify(verificationKey); onCheck({ status: verificationResult ? 'PASSED' : 'FAILED', check: 'Issuer signature must be valid', id: checkCallback_1.VerificationAssessmentId.ISSUER_AUTH.IssuerSignatureValidity, }); // Validity const { validityInfo } = issuerAuth.decodedPayload; const now = new Date(); onCheck({ status: certificate && validityInfo && (validityInfo.signed < certificate.notBefore || validityInfo.signed > certificate.notAfter) ? 'FAILED' : 'PASSED', check: 'The MSO signed date must be within the validity period of the certificate', id: checkCallback_1.VerificationAssessmentId.ISSUER_AUTH.MsoSignedDateWithinCertificateValidity, reason: `The MSO signed date (${validityInfo.signed.toUTCString()}) must be within the validity period of the certificate (${certificate.notBefore.toUTCString()} to ${certificate.notAfter.toUTCString()})`, }); onCheck({ status: validityInfo && (now < validityInfo.validFrom || now > validityInfo.validUntil) ? 'FAILED' : 'PASSED', check: 'The MSO must be valid at the time of verification', id: checkCallback_1.VerificationAssessmentId.ISSUER_AUTH.MsoValidityAtVerificationTime, reason: `The MSO must be valid at the time of verification (${now.toUTCString()})`, }); onCheck({ status: countryName ? 'PASSED' : 'FAILED', check: 'Country name (C) must be present in the issuer certificate\'s subject distinguished name', id: checkCallback_1.VerificationAssessmentId.ISSUER_AUTH.IssuerSubjectCountryNamePresence, }); } async verifyDeviceSignature(document, options) { const onCheck = (0, checkCallback_1.onCatCheck)(options.onCheck, 'DEVICE_AUTH'); if (!(document instanceof DeviceSignedDocument_1.DeviceSignedDocument)) { onCheck({ status: 'FAILED', check: 'The document is not signed by the device.', id: checkCallback_1.VerificationAssessmentId.DEVICE_AUTH.DocumentDeviceSignaturePresence, }); return; } const { deviceAuth, nameSpaces } = document.deviceSigned; const { docType } = document; const { deviceKeyInfo } = document.issuerSigned.issuerAuth.decodedPayload; const { deviceKey: deviceKeyCoseKey } = deviceKeyInfo || {}; // Prevent cloning of the mdoc and mitigate man in the middle attacks if (!deviceAuth.deviceMac && !deviceAuth.deviceSignature) { onCheck({ status: 'FAILED', check: 'Device Auth must contain a deviceSignature or deviceMac element', id: checkCallback_1.VerificationAssessmentId.DEVICE_AUTH.DeviceAuthSignatureOrMacPresence, }); return; } if (!options.sessionTranscriptBytes) { onCheck({ status: 'FAILED', check: 'Session Transcript Bytes missing from options, aborting device signature check', id: checkCallback_1.VerificationAssessmentId.DEVICE_AUTH.SessionTranscriptProvided, }); return; } const deviceAuthenticationBytes = (0, utils_1.calculateDeviceAutenticationBytes)(options.sessionTranscriptBytes, docType, nameSpaces); if (!deviceKeyCoseKey) { onCheck({ status: 'FAILED', check: 'Issuer signature must contain the device key.', id: checkCallback_1.VerificationAssessmentId.DEVICE_AUTH.DeviceKeyAvailableInIssuerAuth, reason: 'Unable to verify deviceAuth signature: missing device key in issuerAuth', }); return; } if (deviceAuth.deviceSignature) { const deviceKey = await (0, cose_kit_1.importCOSEKey)(deviceKeyCoseKey); // ECDSA/EdDSA authentication try { const ds = deviceAuth.deviceSignature; const verificationResult = await new cose_kit_1.Sign1(ds.protectedHeaders, ds.unprotectedHeaders, deviceAuthenticationBytes, ds.signature).verify(deviceKey); onCheck({ status: verificationResult ? 'PASSED' : 'FAILED', check: 'Device signature must be valid', id: checkCallback_1.VerificationAssessmentId.DEVICE_AUTH.DeviceSignatureValidity, }); } catch (err) { onCheck({ status: 'FAILED', check: 'Device signature must be valid', id: checkCallback_1.VerificationAssessmentId.DEVICE_AUTH.DeviceSignatureValidity, reason: `Unable to verify deviceAuth signature (ECDSA/EdDSA): ${err.message}`, }); } return; } // MAC authentication onCheck({ status: deviceAuth.deviceMac ? 'PASSED' : 'FAILED', check: 'Device MAC must be present when using MAC authentication', id: checkCallback_1.VerificationAssessmentId.DEVICE_AUTH.DeviceMacPresence, }); if (!deviceAuth.deviceMac) { return; } onCheck({ status: deviceAuth.deviceMac.hasSupportedAlg() ? 'PASSED' : 'FAILED', check: 'Device MAC must use alg 5 (HMAC 256/256)', id: checkCallback_1.VerificationAssessmentId.DEVICE_AUTH.DeviceMacAlgorithmCorrectness, }); if (!deviceAuth.deviceMac.hasSupportedAlg()) { return; } onCheck({ status: options.ephemeralPrivateKey ? 'PASSED' : 'FAILED', check: 'Ephemeral private key must be present when using MAC authentication', id: checkCallback_1.VerificationAssessmentId.DEVICE_AUTH.EphemeralKeyPresence, }); if (!options.ephemeralPrivateKey) { return; } try { const ephemeralMacKey = await (0, utils_1.calculateEphemeralMacKey)(options.ephemeralPrivateKey, deviceKeyCoseKey, options.sessionTranscriptBytes); const isValid = await deviceAuth.deviceMac.verify(ephemeralMacKey, undefined, deviceAuthenticationBytes); onCheck({ status: isValid ? 'PASSED' : 'FAILED', check: 'Device MAC must be valid', id: checkCallback_1.VerificationAssessmentId.DEVICE_AUTH.DeviceMacValidity, }); } catch (err) { onCheck({ status: 'FAILED', check: 'Device MAC must be valid', id: checkCallback_1.VerificationAssessmentId.DEVICE_AUTH.DeviceMacValidity, reason: `Unable to verify deviceAuth MAC: ${err.message}`, }); } } async verifyData(mdoc, onCheckG) { // Confirm that the mdoc data has not changed since issuance const { issuerAuth } = mdoc.issuerSigned; const { valueDigests, digestAlgorithm } = issuerAuth.decodedPayload; const onCheck = (0, checkCallback_1.onCatCheck)(onCheckG, 'DATA_INTEGRITY'); onCheck({ status: digestAlgorithm && DIGEST_ALGS[digestAlgorithm] ? 'PASSED' : 'FAILED', check: 'Issuer Auth must include a supported digestAlgorithm element', id: checkCallback_1.VerificationAssessmentId.DATA_INTEGRITY.IssuerAuthDigestAlgorithmSupported, }); const nameSpaces = mdoc.issuerSigned.nameSpaces || {}; await Promise.all(Object.keys(nameSpaces).map(async (ns) => { onCheck({ status: valueDigests.has(ns) ? 'PASSED' : 'FAILED', check: `Issuer Auth must include digests for namespace: ${ns}`, id: checkCallback_1.VerificationAssessmentId.DATA_INTEGRITY.IssuerAuthNamespaceDigestPresence, }); const verifications = await Promise.all(nameSpaces[ns].map(async (ev) => { const isValid = await ev.isValid(ns, issuerAuth); return { ev, ns, isValid }; })); verifications.filter((v) => v.isValid).forEach((v) => { onCheck({ status: 'PASSED', check: `The calculated digest for ${ns}/${v.ev.elementIdentifier} attribute must match the digest in the issuerAuth element`, id: checkCallback_1.VerificationAssessmentId.DATA_INTEGRITY.AttributeDigestMatch, }); }); verifications.filter((v) => !v.isValid).forEach((v) => { onCheck({ status: 'FAILED', check: `The calculated digest for ${ns}/${v.ev.elementIdentifier} attribute must match the digest in the issuerAuth element`, id: checkCallback_1.VerificationAssessmentId.DATA_INTEGRITY.AttributeDigestMatch, }); }); if (ns === MDL_NAMESPACE) { const issuer = issuerAuth.certificate.issuerName; if (!issuer) { onCheck({ status: 'FAILED', check: "The 'issuing_country' if present must match the 'countryName' in the subject field within the DS certificate", id: checkCallback_1.VerificationAssessmentId.DATA_INTEGRITY.IssuingCountryMatchesCertificate, reason: "The 'issuing_country' and 'issuing_jurisdiction' cannot be verified because the DS certificate was not provided", }); } else { const invalidCountry = verifications.filter((v) => v.ns === ns && v.ev.elementIdentifier === 'issuing_country') .find((v) => !v.isValid || !v.ev.matchCertificate(ns, issuerAuth)); onCheck({ status: invalidCountry ? 'FAILED' : 'PASSED', check: "The 'issuing_country' if present must match the 'countryName' in the subject field within the DS certificate", id: checkCallback_1.VerificationAssessmentId.DATA_INTEGRITY.IssuingCountryMatchesCertificate, reason: invalidCountry ? `The 'issuing_country' (${invalidCountry.ev.elementValue}) must match the 'countryName' (${issuerAuth.countryName}) in the subject field within the issuer certificate` : undefined, }); const invalidJurisdiction = verifications.filter((v) => v.ns === ns && v.ev.elementIdentifier === 'issuing_jurisdiction') .find((v) => !v.isValid || (issuerAuth.stateOrProvince && !v.ev.matchCertificate(ns, issuerAuth))); onCheck({ status: invalidJurisdiction ? 'FAILED' : 'PASSED', check: "The 'issuing_jurisdiction' if present must match the 'stateOrProvinceName' in the subject field within the DS certificate", id: checkCallback_1.VerificationAssessmentId.DATA_INTEGRITY.IssuingJurisdictionMatchesCertificate, reason: invalidJurisdiction ? `The 'issuing_jurisdiction' (${invalidJurisdiction.ev.elementValue}) must match the 'stateOrProvinceName' (${issuerAuth.stateOrProvince}) in the subject field within the issuer certificate` : undefined, }); } } })); } /** * Parse and validate a DeviceResponse as specified in ISO/IEC 18013-5 (Device Retrieval section). * * @param encodedDeviceResponse * @param options.encodedSessionTranscript The CBOR encoded SessionTranscript. * @param options.ephemeralReaderKey The private part of the ephemeral key used in the session where the DeviceResponse was obtained. This is only required if the DeviceResponse is using the MAC method for device authentication. */ async verify(encodedDeviceResponse, options = {}) { const onCheck = (0, checkCallback_1.buildCallback)(options.onCheck); const dr = (0, parser_1.parse)(encodedDeviceResponse); onCheck({ status: dr.version ? 'PASSED' : 'FAILED', check: 'Device Response must include "version" element.', id: checkCallback_1.VerificationAssessmentId.DOCUMENT_FORMAT.DeviceResponseVersionPresence, category: 'DOCUMENT_FORMAT', }); onCheck({ status: (0, compare_versions_1.compareVersions)(dr.version, '1.0') >= 0 ? 'PASSED' : 'FAILED', check: 'Device Response version must be 1.0 or greater', id: checkCallback_1.VerificationAssessmentId.DOCUMENT_FORMAT.DeviceResponseVersionSupported, category: 'DOCUMENT_FORMAT', }); onCheck({ status: dr.documents && dr.documents.length > 0 ? 'PASSED' : 'FAILED', check: 'Device Response must include at least one document.', id: checkCallback_1.VerificationAssessmentId.DOCUMENT_FORMAT.DeviceResponseDocumentPresence, category: 'DOCUMENT_FORMAT', }); for (const document of dr.documents) { const { issuerAuth } = document.issuerSigned; await this.verifyIssuerSignature(issuerAuth, options.disableCertificateChainValidation, onCheck); await this.verifyDeviceSignature(document, { ephemeralPrivateKey: options.ephemeralReaderKey, sessionTranscriptBytes: options.encodedSessionTranscript, onCheck, }); await this.verifyData(document, onCheck); } return dr; } async getDiagnosticInformation(encodedDeviceResponse, options) { const dr = []; const decoded = await this.verify( // @ts-ignore encodedDeviceResponse, { ...options, onCheck: (check) => dr.push(check), }); const document = decoded.documents[0]; const { issuerAuth } = document.issuerSigned; const issuerCert = issuerAuth.x5chain && issuerAuth.x5chain.length > 0 && new x509_1.X509Certificate(issuerAuth.x5chain[0]); const attributes = (await Promise.all(Object.keys(document.issuerSigned.nameSpaces).map(async (ns) => { const items = document.issuerSigned.nameSpaces[ns]; return Promise.all(items.map(async (item) => { const isValid = await item.isValid(ns, issuerAuth); return { ns, id: item.elementIdentifier, value: item.elementValue, isValid, matchCertificate: item.matchCertificate(ns, issuerAuth), }; })); }))).flat(); const deviceAttributes = document instanceof DeviceSignedDocument_1.DeviceSignedDocument ? Object.entries(document.deviceSigned.nameSpaces).map(([ns, items]) => { return Object.entries(items).map(([id, value]) => { return { ns, id, value, }; }); }).flat() : undefined; let deviceKey; if (document?.issuerSigned.issuerAuth) { const { deviceKeyInfo } = document.issuerSigned.issuerAuth.decodedPayload; if (deviceKeyInfo?.deviceKey) { deviceKey = (0, cose_kit_1.COSEKeyToJWK)(deviceKeyInfo.deviceKey); } } const disclosedAttributes = attributes.filter((attr) => attr.isValid).length; const totalAttributes = Array.from(document .issuerSigned .issuerAuth .decodedPayload .valueDigests .entries()).reduce((prev, [, digests]) => prev + digests.size, 0); return { general: { version: decoded.version, type: 'DeviceResponse', status: decoded.status, documents: decoded.documents.length, }, validityInfo: document.issuerSigned.issuerAuth.decodedPayload.validityInfo, issuerCertificate: issuerCert ? { subjectName: issuerCert.subjectName.toString(), pem: issuerCert.toString(), notBefore: issuerCert.notBefore, notAfter: issuerCert.notAfter, serialNumber: issuerCert.serialNumber, thumbprint: buffer_1.Buffer.from(await issuerCert.getThumbprint(uncrypto_1.default)).toString('hex'), } : undefined, issuerSignature: { alg: document.issuerSigned.issuerAuth.algName, isValid: dr .filter((check) => check.category === 'ISSUER_AUTH') .every((check) => check.status === 'PASSED'), reasons: dr .filter((check) => check.category === 'ISSUER_AUTH' && check.status === 'FAILED') .map((check) => check.reason ?? check.check), digests: Object.fromEntries(Array.from(document .issuerSigned .issuerAuth .decodedPayload .valueDigests .entries()).map(([ns, digests]) => [ns, digests.size])), }, deviceKey: { jwk: deviceKey, }, deviceSignature: document instanceof DeviceSignedDocument_1.DeviceSignedDocument ? { alg: document.deviceSigned.deviceAuth.deviceSignature?.algName ?? document.deviceSigned.deviceAuth.deviceMac?.algName, isValid: dr .filter((check) => check.category === 'DEVICE_AUTH') .every((check) => check.status === 'PASSED'), reasons: dr .filter((check) => check.category === 'DEVICE_AUTH' && check.status === 'FAILED') .map((check) => check.reason ?? check.check), } : undefined, dataIntegrity: { disclosedAttributes: `${disclosedAttributes} of ${totalAttributes}`, isValid: dr .filter((check) => check.category === 'DATA_INTEGRITY') .every((check) => check.status === 'PASSED'), reasons: dr .filter((check) => check.category === 'DATA_INTEGRITY' && check.status === 'FAILED') .map((check) => check.reason ?? check.check), }, attributes, deviceAttributes, }; } } exports.Verifier = Verifier; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVmVyaWZpZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbWRvYy9WZXJpZmllci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSx1REFBbUQ7QUFDbkQseUNBQWlEO0FBQ2pELCtCQUFnRDtBQUNoRCxtQ0FBZ0M7QUFDaEMsdUNBQThEO0FBQzlELHdEQUE4QjtBQUc5QixtQ0FHaUI7QUFLakIsbURBQStJO0FBRS9JLHFDQUFpQztBQUdqQyx1RUFBb0U7QUFFcEUsTUFBTSxhQUFhLEdBQUcsbUJBQW1CLENBQUM7QUFFMUMsTUFBTSxXQUFXLEdBQUc7SUFDbEIsU0FBUyxFQUFFLFFBQVE7SUFDbkIsU0FBUyxFQUFFLFFBQVE7SUFDbkIsU0FBUyxFQUFFLFFBQVE7Q0FDUyxDQUFDO0FBRS9CLE1BQWEsUUFBUTtJQUNuQjs7O09BR0c7SUFDSCxZQUE0Qix1QkFBaUM7UUFBakMsNEJBQXVCLEdBQXZCLHVCQUF1QixDQUFVO0lBQUksQ0FBQztJQUUxRCxLQUFLLENBQUMscUJBQXFCLENBQ2pDLFVBQXNCLEVBQ3RCLGlDQUEwQyxFQUMxQyxRQUF5QztRQUV6QyxNQUFNLE9BQU8sR0FBRyxJQUFBLDBCQUFVLEVBQUMsUUFBUSxFQUFFLGFBQWEsQ0FBQyxDQUFDO1FBQ3BELE1BQU0sRUFBRSxXQUFXLEVBQUUsV0FBVyxFQUFFLEdBQUcsVUFBVSxDQUFDO1FBQ2hELE1BQU0sZUFBZSxHQUF3QixXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxJQUFBLGlCQUFVLEVBQzFFLFdBQVcsQ0FBQyxRQUFRLEVBQUUsRUFDdEIsVUFBVSxDQUFDLE9BQU8sQ0FDbkIsQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7UUFFZixJQUFJLENBQUMsaUNBQWlDLEVBQUUsQ0FBQztZQUN2QyxJQUFJLENBQUM7Z0JBQ0gsTUFBTSxVQUFVLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDO2dCQUMvRCxPQUFP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