|
| 1 | +import * as jose from 'jose'; |
| 2 | +import * as crypto from 'crypto'; |
| 3 | +import fs from 'fs'; |
| 4 | +import { Verifier, Document, MDoc, DeviceResponse } from '../../src/index'; |
| 5 | + |
| 6 | +describe('example 5: device response contains a partial x5chain of the issuer certificate', () => { |
| 7 | + it('issuer signature should be valid', async () => { |
| 8 | + const devicePrivatePEM = '-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEIKWuHzvetdYpe5cErlOrU1bipA0OFtbBpJBdXCzRIVbz\n-----END PRIVATE KEY-----'; |
| 9 | + const devicePrivateKey = await jose.exportJWK(crypto.createPrivateKey({ key: devicePrivatePEM })); |
| 10 | + const devicePublicKey: jose.JWK = { |
| 11 | + kty: devicePrivateKey.kty, |
| 12 | + crv: devicePrivateKey.crv, |
| 13 | + x: devicePrivateKey.x, |
| 14 | + }; |
| 15 | + |
| 16 | + // A test IACA Root Certificate that the Issuer has shared publicly |
| 17 | + // The openssl command to generate this certificate can be found @ https://github.com/auth0-lab/mdl/issues/37#issuecomment-2618717656 |
| 18 | + const issuerIacaRootCertificate = '-----BEGIN CERTIFICATE-----\nMIICuzCCAh2gAwIBAgIUS9ewqx43m6VHiP5koCeEd09JOIwwCgYIKoZIzj0EAwQw\nOzELMAkGA1UEBhMCVVMxDDAKBgNVBAoMA01ETDEeMBwGA1UEAwwVSUFDQSBSb290\nIENlcnRpZmljYXRlMB4XDTI1MDEyODEyNTUzNloXDTM1MDEyNjEyNTUzNlowOzEL\nMAkGA1UEBhMCVVMxDDAKBgNVBAoMA01ETDEeMBwGA1UEAwwVSUFDQSBSb290IENl\ncnRpZmljYXRlMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBBt6kxI26+zkCddEN\ntuCUddthenpnDC7yT2ZgNvisCl6ZXRYI+oljvxgky53SZ18qixN4jtvnUOx/UuE3\nYDo0pZMBjk7CX2aKE91tG3kMt0G0LRnHSnkioCTPcDd67pN5myw8oEGHF5PQC9ai\nRZd30V4faCz+kZGO0ilLWGL0EElWILKjgbswgbgwHQYDVR0OBBYEFLvAYj7DJGBy\nMlzxdrwHYrSRPb03MHYGA1UdIwRvMG2AFLvAYj7DJGByMlzxdrwHYrSRPb03oT+k\nPTA7MQswCQYDVQQGEwJVUzEMMAoGA1UECgwDTURMMR4wHAYDVQQDDBVJQUNBIFJv\nb3QgQ2VydGlmaWNhdGWCFEvXsKseN5ulR4j+ZKAnhHdPSTiMMA8GA1UdEwEB/wQF\nMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMEA4GLADCBhwJCAbauH2Uj\noaB7fcKJqBgXqWfSXm5wqo6tEECM4gjtmIKPJnVSBbfcTn2bw7zIl2eBHzRdPX85\nPliPBGxjzyAoQcZ3AkES0U2MiwkDdoyUrb3k3jGOo02ayiCmtfy7y1OVZQWaH2HF\nMgQBbITyFHAZ0HUNpWIT+8527nB7POnJkguMovTIcA==\n-----END CERTIFICATE-----\n'; |
| 19 | + const anotherIssuerRootCertificate = fs.readFileSync(`${__dirname}/issuer.pem`, 'utf-8'); |
| 20 | + |
| 21 | + // A test Document Signing Certificate that has been signed by the IACA Root Certificate above |
| 22 | + const issuerDocumentSigningCertificate = '-----BEGIN CERTIFICATE-----\nMIIB1zCCATigAwIBAgIURoTE4I1tg1T7wyVF6YJxJqu2SLgwCgYIKoZIzj0EAwIw\nOzELMAkGA1UEBhMCVVMxDDAKBgNVBAoMA01ETDEeMBwGA1UEAwwVSUFDQSBSb290\nIENlcnRpZmljYXRlMB4XDTI1MDEyODEyNTU0M1oXDTI2MDEyODEyNTU0M1owQjEL\nMAkGA1UEBhMCVVMxDDAKBgNVBAoMA01ETDElMCMGA1UEAwwcRG9jdW1lbnQgU2ln\nbmluZyBDZXJ0aWZpY2F0ZTAqMAUGAytlcAMhACis1tWdJ2MW+6zokonq9bxhsLO5\nR6E0bFiLnYEWR4t+o0IwQDAdBgNVHQ4EFgQUgxDu5pET///uNotJBKr1gZOZNogw\nHwYDVR0jBBgwFoAUu8BiPsMkYHIyXPF2vAditJE9vTcwCgYIKoZIzj0EAwIDgYwA\nMIGIAkIA4YMSiBuUGrfU1UKeCbYwzp0ZoQhcL+HNCEtgLFW6LtDB4tP+T9A/O5bS\nWV6P+e3mWti13BKCraPRUkKVQA1qyNcCQgFXTRr1Xt+ufVjl1XqnJo0KITN91TyL\n4GKJeBxGYWDFgyvbpCNUs5XeiGejkvhz/8E0fYzCqZmqEIlp6IcvgV8c0A==\n-----END CERTIFICATE-----\n'; |
| 23 | + const issuerDocumentSigningKeyPem = '-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEIEQLHY7fwKG6Av4VP3uByNKMyS7/sJKk4ntbzL8nSq0t\n-----END PRIVATE KEY-----\n'; |
| 24 | + const issuerDocumentSigningKey = await jose.exportJWK(crypto.createPrivateKey({ key: issuerDocumentSigningKeyPem })); |
| 25 | + |
| 26 | + const document = new Document('org.iso.18013.5.1.mDL') |
| 27 | + .addIssuerNameSpace('org.iso.18013.5.1', { |
| 28 | + family_name: 'Jones', |
| 29 | + given_name: 'Ava', |
| 30 | + birth_date: '2007-03-25', |
| 31 | + }) |
| 32 | + .useDigestAlgorithm('SHA-256') |
| 33 | + .addValidityInfo({ |
| 34 | + signed: new Date(), |
| 35 | + }) |
| 36 | + .addDeviceKeyInfo({ deviceKey: devicePublicKey }); |
| 37 | + |
| 38 | + const signedDoc = await document.sign({ |
| 39 | + issuerPrivateKey: issuerDocumentSigningKey, |
| 40 | + issuerCertificate: issuerDocumentSigningCertificate, |
| 41 | + alg: 'EdDSA', |
| 42 | + }); |
| 43 | + |
| 44 | + const issuerMDoc = new MDoc([signedDoc]).encode(); |
| 45 | + const presentationDefinition = { |
| 46 | + id: 'family_name_only', |
| 47 | + input_descriptors: [ |
| 48 | + { |
| 49 | + id: 'org.iso.18013.5.1.mDL', |
| 50 | + format: { mso_mdoc: { alg: ['EdDSA', 'ES256'] } }, |
| 51 | + constraints: { |
| 52 | + limit_disclosure: 'required', |
| 53 | + fields: [{ |
| 54 | + path: ["$['org.iso.18013.5.1']['family_name']"], |
| 55 | + intent_to_retain: false, |
| 56 | + }], |
| 57 | + }, |
| 58 | + }, |
| 59 | + ], |
| 60 | + }; |
| 61 | + |
| 62 | + const deviceResponseMDoc = await DeviceResponse.from(issuerMDoc) |
| 63 | + .usingPresentationDefinition(presentationDefinition) |
| 64 | + .usingSessionTranscriptForOID4VP('', '', '', '') |
| 65 | + .authenticateWithSignature(devicePrivateKey, 'EdDSA') |
| 66 | + .sign(); |
| 67 | + |
| 68 | + const verifier = new Verifier([issuerIacaRootCertificate, anotherIssuerRootCertificate]); |
| 69 | + const diagnosticInfo = await verifier.getDiagnosticInformation(deviceResponseMDoc.encode(), {}); |
| 70 | + |
| 71 | + expect(diagnosticInfo.issuerSignature).toEqual({ |
| 72 | + alg: 'EdDSA', |
| 73 | + digests: { 'org.iso.18013.5.1': 5 }, |
| 74 | + isValid: true, |
| 75 | + reasons: [], |
| 76 | + }); |
| 77 | + }); |
| 78 | +}); |
0 commit comments