stateofca / opencred

OpenCred Verifiable Credentials Platform
BSD 3-Clause "New" or "Revised" License
46 stars 11 forks source link

opencred with CA DMV wallet UI; local network setup #5

Closed deshmukhrajvardhan closed 2 months ago

deshmukhrajvardhan commented 3 months ago

Hi folks :)

(tagging @mattcollier @kezike @ottonomy https://github.com/tmarkovski from the previous issue)

Aim: I have been working on getting opencreds up locally and using my CA DMV wallet to share mDL and verify it.

Note: Happy to contribute this to the repo so that we don't need to open ports to local machines globally. I was warned not to open ports to my machine due to security concerns.

The phone wallet communicates with the opencred endpoints, but the Credential selection UI on the wallet and then subsequent transfer doesn't take place.

Setup:

  1. Dev machine and phone with wallet should be on the same local network. Get the en0 ip after ifconfig

  2. Use that ip in the config.example.yaml section baseUri: http://<ip>:<port> port set in the app is 22080

  3. Generate signing keys opencred git:(main) ✗ npm run generate:prime256v1 id_token authorization_request vp_token and paste in config.example.yaml

  4. did config in config.example.yaml

    didWeb:
      mainEnabled: true
    config.example.yaml ``` app: server: baseUri: http://:22080 opencred: caStore: - pem: | -----BEGIN CERTIFICATE----- -----END CERTIFICATE----- signingKeys: - type: ES256 id: 2eb917931c154afc45c6b3c9f3dacc01a4cc60b6a4c1a8bb4a4ec0f7aa2d3a66 privateKeyPem: publicKeyPem: purpose: - id_token - authorization_request - vp_token relyingParties: - name: "Test Relying Party (Native)" clientId: "rp1" clientSecret: "DeepestAndDarkest" description: "Relying Party Test App" primaryLogo: "https://placekitten.com/200/200" primaryLink: "https://example.com" secondaryLogo: "https://placekitten.com/200/200" secondaryLink: "https://example2.com" homeLink: "https://example.com" explainerVideo: id: "" provider: youtube backgroundImage: "https://placekitten.com/800/200" redirectUri: "http://localhost:3000" idTokenExpirySeconds: 3600 claims: - name: "dl_number" path: "driversLicense.document_number" brand: cta: "#0B669D" primary: "#045199" header: "#0979c4" scopes: - name: "openid" description: "Open ID Connect" workflow: type: native id: z1A32xJZGqBeAEcMq56avmw2L initialStep: default steps: default: createChallenge: true verifiablePresentationRequest: > { "query": { "type": "QueryByExample", "credentialQuery": { "reason": "Please present your VC.", "example": { "type": [ "Iso18013DriversLicenseCredential" ] } } } } constraintsOverride: > { "fields": [ { "path": [ "$.vc.type" ], "filter": { "type": "string", "pattern": "Iso18013DriversLicenseCredential" } } ] } options: exchangeProtocols: - chapi - openid4vp defaultBrand: cta: "#0B669D" primary: "#045199" header: "#0979c4" enableAudit: true auditFields: - type: text id: given_name name: First Name path: "$.credentialSubject.given_name" required: true - type: text id: family_name name: Last Name path: "$.credentialSubject.family_name" required: false - type: date id: birth_date name: Date of Birth path: "$.credentialSubject.birth_date" required: true defaultLanguage: en translations: en: qrTitle: Login with your Wallet app qrPageExplain: Scan the following QR Code using the Wallet app on your phone. qrPageExplainHelp: (How do I do it?) qrFooter: "Note: Already on your phone with the Wallet app? Open the Wallet app, then come back and tap on the QR code above." qrFooterHelp: Difficulty using the Wallet app to login? revert to using password here qrDisclaimer: If you don't have a Wallet app download it from the app store. qrExplainerText: (How do I do it?) qrPageAnotherWay: Want to try another way? chapiPageAnotherWay: "Looking for a QR Code to scan with you wallet app instead?" loginCta: "Login with your credential wallet" loginExplain: "To login with your credential wallet, you will need to have the credential wallet app installed" appInstallExplain: "If you don't have a credential wallet yet, you can get one by downloading the credential wallet app " appCta: "Open wallet app" copyright: "Powered by OpenCred" pageTitle: "Login" home: "Home" didWeb: mainEnabled: true ```
  5. mkdir /etc/bedrock-config; cd opencreds; cp configs/config.example.yaml /etc/bedrock-config/combined.yaml

6.npm start build and bring up the service

7.1 Use http://0.0.0.0:22080/.well-known/did.json to see the published did:web

{
  "@context": [
    "https://www.w3.org/ns/did/v1"
  ],
  "id": "did:web:192.168.1.101:22080",
  "verificationMethod": [
    {
      "id": "did:web:192.168.1.101:22080#2eb917931c154afc45c6b3c9f3dacc01a4cc60b6a4c1a8bb4a4ec0f7aa2d3a66",
      "controller": "did:web:192.168.1.101:22080",
      "type": "JsonWebKey2020",
      "publicKeyJwk": {
        "kty": "EC",
        "x": "NFFfW7wohPR_ttv3DbSZpJVM-aD3eGf9YCYZQkwv4jU",
        "y": "QETxN1LCd7YMDctxfuaMX3NsGklf8SeYuCVLbDITxbM",
        "crv": "P-256"
      }
    }
  ],
  "assertionMethod": [
    "did:web:192.168.1.101:22080#2eb917931c154afc45c6b3c9f3dacc01a4cc60b6a4c1a8bb4a4ec0f7aa2d3a66"
  ]
}

7.2 use http://0.0.0.0:22080/api-docs/#/OIDC/OpenID%20Connect%20Login with the correct client_id and redirect_uri as specified in the config.example.yaml

  1. connect to mongodb mongosh mongodb://localhost:27017/opencred_localhost 8.1
    opencred_localhost> db.Exchanges.find().pretty()
    [
    {
    _id: ObjectId('6670c00e9116e372413d55c8'),
    id: 'z1ABpbVvGcJaDDW68seuk5vi1',
    workflowId: 'z1A32xJZGqBeAEcMq56avmw2L',
    sequence: 0,
    ttl: 900,
    state: 'pending',
    variables: {},
    step: 'default',
    challenge: 'z1AEgLn9VNyW1T5pFqXnuNYK2',
    accessToken: 'z1A5uUiyTn7PP45isgE58QzPZ',
    createdAt: ISODate('2024-06-17T23:00:30.093Z'),
    recordExpiresAt: ISODate('2024-06-18T23:15:30.093Z'),
    oidc: { code: null, state: '' }
    }
    ]
  2. use https://www.onlinewebtoolkit.com/base64-to-image-converter and paste the base 64 that you get in the above used swagger api "QR": "data:image/png;base64,.... This generates the QR code.
  3. Scan the QR code 10.1 It looks like this QR-code

10.2 Translates to this

openid4vp://?client_id=did:web:192.168.1.101:22080&request_uri=http://192.168.1.101:22080/workflows/z1A32xJZGqBeAEcMq56avmw2L/exchanges/z1ABpbVvGcJaDDW68seuk5vi1/openid/client/authorization/request
  1. You can either scan and continue or take the above and use curl on the request_uri from phone (using curl in terminal) gives you this:

    terminal
  2. and use the mongodb interface to see the updated exchange object:

    opencred_localhost> db.Exchanges.find().pretty()
    [
    {
    _id: ObjectId('6670c00e9116e372413d55c8'),
    id: 'z1ABpbVvGcJaDDW68seuk5vi1',
    workflowId: 'z1A32xJZGqBeAEcMq56avmw2L',
    sequence: 0,
    ttl: 900,
    state: 'pending',
    variables: {
      authorizationRequest: {
        response_type: 'vp_token',
        response_mode: 'direct_post',
        presentation_definition: {
          id: 'c6f127dc-33d6-47f3-8bcf-d196196866b5',
          input_descriptors: [
            {
              id: '0a6dd448-8dd1-494a-b2ef-938e56583d43',
              constraints: {
                fields: [
                  {
                    path: [ '$.vc.type' ],
                    filter: {
                      type: 'string',
                      pattern: 'Iso18013DriversLicenseCredential'
                    }
                  }
                ]
              },
              purpose: 'Please present your VC.',
              format: { jwt_vc_json: { alg: [ 'ES256' ] } }
            }
          ]
        },
        client_id: 'did:web:192.168.1.101:22080',
        client_id_scheme: 'did',
        nonce: 'z1AEgLn9VNyW1T5pFqXnuNYK2',
        response_uri: 'http://192.168.1.101:22080/workflows/z1A32xJZGqBeAEcMq56avmw2L/exchanges/z1ABpbVvGcJaDDW68seuk5vi1/openid/client/authorization/response',
        state: 'z1A4BrUYWyprc4HMGBEKR5kBi',
        client_metadata: {
          client_name: 'OpenCred Verifier',
          subject_syntax_types_supported: [ 'did:jwk' ],
          vp_formats: { jwt_vc: { alg: [ 'ES256' ] } }
        }
      }
    },
    step: 'default',
    challenge: 'z1AEgLn9VNyW1T5pFqXnuNYK2',
    accessToken: 'z1A5uUiyTn7PP45isgE58QzPZ',
    createdAt: ISODate('2024-06-17T23:00:30.093Z'),
    recordExpiresAt: ISODate('2024-06-18T23:15:30.093Z'),
    oidc: { code: null, state: '' },
    updatedAt: ISODate('2024-06-17T23:01:57.523Z')
    }
    ]

But the CA DMV app UI doesn't do anything, i also tried using the "Scan Website QR Code" To share online. Am i missing something? I don't have anything on http://locathost:3000 is that the issue?

deshmukhrajvardhan commented 3 months ago

@mattcollier Can you please take a look at the above? Are there any screenshots of the CA DMV app where it asks for permission to present VCs to the verifier?

mattcollier commented 2 months ago

cc: @ottonomy @kezike

ottonomy commented 2 months ago

@deshmukhrajvardhan can you be more specific about the UI not doing anything? What URL did you load (including query params?) There is a /login route and a /verification route that should load the UI. Login requires client_id, redirect_uri, and state params. Verification requires client_id and "variables".

If you open your dev tools after loading the UI, do you see any failed requests or console messages?

deshmukhrajvardhan commented 2 months ago

Thanks for the questions @ottonomy . I don't see the /verification endpoint in the swagger.

I've used the login route. I get the QR code from the response of this http://localhost:22080/context/login?client_id=rp1&redirect_uri=http%3A%2F%2Flocalhost%3A3000&scope=openid&response_type=code uri

Screenshot 2024-07-08 at 10 25 11 AM

Do you mean dev tools on the CA DMV Android app? If so, how do I open dev tools?

Screenshot 2024-07-08 at 10 24 46 AM
deshmukhrajvardhan commented 2 months ago

Hi @ottonomy , Did you get a change to look at the above comment? Ah! i didn't answer this one earlier.

more specific about the UI not doing anything?

I scan the QR code with my android (pixel7) camera and choose "CA DMV wallet" app. The app opens but i don't see anything, I also tried using the "Scan QR code" for online and in-person presentation, It doesn't proceed to any new UI, just brings me to apps homescreen or just keeps loading.

rgajam commented 2 months ago

Aim: Login and read mDL data

Hello, I'm almost at the same stage as @deshmukhrajvardhan. I opened the login page at: https://192.168.0.185:22443/login?client_id=rp1&redirect_uri=http://localhost:3000&scope=openid&response_type=code

I see the QR code on the webpage and when I scan it from CA DMV Android app to share online with "Scan website QR Code" from Android (Pixel 8 Pro) phone, it doesn't do anything, the app goes back to the app home screen and there's no change on the Login webpage. No errors on browser console log. I couldn't find any useful logs from Android logcat.

Does CA DMV Wallet app have any restrictions? (localhost URLs, etc.)

deshmukhrajvardhan commented 2 months ago

Update: I used adb logcat And see these errors

07-23 11:25:44.601 18338 18373 E flutter : [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: mDLException (10): unable to handle request
07-23 11:25:44.601 18338 18373 E flutter : Caused by:
07-23 11:25:44.601 18338 18373 E flutter :     0: unable to validate authorization request
07-23 11:25:44.601 18338 18373 E flutter :     1: unable to validate Authorization Request
07-23 11:25:44.601 18338 18373 E flutter :     2: unable to resolve verification method from 'kid' header
07-23 11:25:44.601 18338 18373 E flutter :     3: Unable to dereference DID URL: Error sending HTTP request (https://192.168.1.101/22080/did.json): error sending request for url (https://192.168.1.101/22080/did.json
07-23 11:25:44.615   562   578 W gralloc4: Unable to set buffer name ImageReader-864x1920f1u2816m2-1493-86: File name too long
07-23 11:27:12.005   562   578 W gralloc4: Unable to set buffer name SurfaceView[gov.ca.dmv.wallet/com.spruceid.app.credible.mdl.MainActivity]#3(BLAST Consumer)3: File name too long
07-23 11:27:12.008   562   578 W gralloc4: Unable to set buffer name bbq-adapter#10777(BLAST Consumer)10777: File name too long
Screenshot 2024-07-23 at 11 51 32 AM

It is using an incorrect url (and https) to get the did. I will work on debugging it. Hmm, seems like the did resolution steps on the wallet can't be influenced by opencred. Seems like the easiest way to resolve this is to host did on https://192.168.1.101/did.json

npm start doesn't host https endpoints, only http endpoints.

@ottonomy Any suggestions here?

deshmukhrajvardhan commented 2 months ago

Update: I have used mkcert

  1. On server 1.1 create certs

    cd opencred/node_modules/@bedrock/server/pki
    mkcert -key-file bedrock.localhost.key -cert-file bedrock.localhost.crt -CAROOT "192.168.1.101" localhost 127.0.0.1

    1.2 update verifiable-credentials/ca-dmv/opencred/configs/server.js

    config.express.httpOnly = false;
    config.express.fastifyOptions.trustProxy = true;
    config.server.port = 443;
    config.server.httpPort = 22080;
    config.server.bindAddr = ['0.0.0.0'];
    config.server.domain = 'localhost';

    and run npm start

  2. Share the CA cert rootCA.pem to your phone and install it. (Chrome is able to use it with no problem, BUT had problems with firefox and Termux)

    android-chrome CA-cert

But android log shows error due to unknown peer problem

08-02 14:32:15.038 28032 32182 I flutter : 2024-08-02T21:32:15.038080Z [NET] credible:app/shared/url_intent.dart: UrlIntent.verifyUrlIntent --- 2. Url Intent native call with string: "openid4vp://?client_id=did%3Aweb%3A192.168.1.101&request_uri=https%3A%2F%2F192.168.1.101%2Fworkflows%2Fz1A32xJZGqBeAEcMq56avmw2L%2Fexchanges%2Fz1A6mJyEMatsf6RVBxMMusFDZ%2Fopenid%2Fclient%2Fauthorization%2Frequest" ---
08-02 14:32:15.040 28032 32182 I flutter : 2024-08-02T21:32:15.039988Z [NET] credible:app/shared/web_share.dart: WebShare.verifyWebShare --- 2. Web Share native call with string: Web Share string not initialized ---
08-02 14:32:15.054 28032 32182 E flutter : [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Concurrent modification during iteration: Instance(length:2) of '_GrowableList'.
08-02 14:32:15.054 28032 32182 E flutter : #0      ListIterator.moveNext (dart:_internal/iterable.dart:348)
08-02 14:32:15.054 28032 32182 E flutter : #1      Future.forEach.<anonymous closure> (dart:async/future.dart:647)
08-02 14:32:15.054 28032 32182 E flutter : #2      Future.doWhile.<anonymous closure> (dart:async/future.dart:705)
08-02 14:32:15.054 28032 32182 E flutter : #3      _RootZone.runUnaryGuarded (dart:async/zone.dart:1594)
08-02 14:32:15.054 28032 32182 E flutter : #4      _RootZone.bindUnaryCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1633)
08-02 14:32:15.054 28032 32182 E flutter : #5      Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:846)
08-02 14:32:15.054 28032 32182 E flutter : #6      Future._propagateToListeners (dart:async/future_impl.dart:875)
08-02 14:32:15.054 28032 32182 E flutter : #7      Future._completeWithValue (dart:async/future_impl.dart:647)
08-02 14:32:15.054 28032 32182 E flutter : <asynchronous suspension>
08-02 14:32:15.054 28032 32182 E flutter : 
08-02 14:32:15.054 28032 32182 I flutter : 2024-08-02T21:32:15.054199Z [NET] credible:app/shared/url_intent.dart: UrlIntent._handleUrl Launching openid url scheme...
08-02 14:32:15.139 28032 32182 E flutter : [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: mDLException (10): unable to handle request
08-02 14:32:15.139 28032 32182 E flutter : 
08-02 14:32:15.139 28032 32182 E flutter : Caused by:
08-02 14:32:15.139 28032 32182 E flutter :     0: unable to validate authorization request
08-02 14:32:15.139 28032 32182 E flutter :     1: failed to GET https://192.168.1.101/workflows/z1A32xJZGqBeAEcMq56avmw2L/exchanges/z1A6mJyEMatsf6RVBxMMusFDZ/openid/client/authorization/request
08-02 14:32:15.139 28032 32182 E flutter :     2: error sending request for url (https://192.168.1.101/workflows/z1A32xJZGqBeAEcMq56avmw2L/exchanges/z1A6mJyEMatsf6RVBxMMusFDZ/openid/client/authorization/request): error trying to connect: invalid peer certificate: UnknownIssuer
08-02 14:32:15.139 28032 32182 E flutter :     3: error trying to connect: invalid peer certificate: UnknownIssuer
08-02 14:32:15.139 28032 32182 E flutter :     4: invalid peer certificate: UnknownIssuer
08-02 14:32:15.139 28032 32182 E flutter : #0      OID4VPPreparedResponse.fromJson (package:mdl/mdl.dart:275)
08-02 14:32:15.139 28032 32182 E flutter : #1      OID4VPHandler.prepare (package:mdl/mdl.dart:243)
08-02 14:32:15.139 28032 32182 E flutter : #2      RequestBloc._oid4VP (package:credible/app/pages/mdl/blocs/request.dart:158)
08-02 14:32:15.139 28032 32182 E flutter : <asynchronous suspension>
08-02 14:32:15.139 28032 32182 E flutter : #3      Stream.forEach.<anonymous closure> (dart:async/stream.dart:1200)
08-02 14:32:15.139 28032 32182 E flutter : <asynchronous suspension>
08-02 14:32:15.139 28032 32182 E flutter : 
08-02 14:32:15.191 28032 32182 I flutter : 2024-08-02T21:32:15.190915Z [NET] credible:app/shared/blocs/endpoint_inspect.dart: EndpointInspectBloc._request --- BLOC endpoint request ---
08-02 14:32:15.191 28032 32182 I flutter : 2024-08-02T21:32:15.191796Z [NET] credible:app/shared/blocs/endpoint_inspect.dart: EndpointInspectBloc._error.printWrapped.<anonymous closure> {"timestamp":"2024-08-02 21:32:15.191Z(UTC)","uri":"https://mdls.dmv.ca.gov/events/events/eXjuDkPOTyW7ZmggCO6Gkc","method":"GET","headers":{"X-Correlation-ID":"e1LVC-WoQl2H9lrJiulcBz+a65b64ea-cd3f-4bdc-95e2-84c38f1a1278","X-Installation-ID":"eXjuDkPOTyW7ZmggCO6Gkc","Authorization":"Bearer eMZFWr0RzaMCpC47ecQR","content-type":"application/json"},"data":null}

08-02 14:32:18.363 28032 32182 I flutter : 2024-08-02T21:32:18.363602Z [NET] credible:app/shared/blocs/endpoint_inspect.dart: EndpointInspectBloc._error.printWrapped.<anonymous closure> {"timestamp":"2024-08-02 21:32:18.363Z(UTC)","uri":"https://mdls.dmv.ca.gov/events/events/eXjuDkPOTyW7ZmggCO6Gkc","method":"GET","status":"200","data":[]}
deshmukhrajvardhan commented 2 months ago

Update: It was a cert issue and I resolved it using "Let's Encrypt" certs. For anyone interested, this video was helpful https://www.youtube.com/watch?v=qlcVx-k-02E&ab_channel=Wolfgang%27sChannel

User Approval Page User Approval Page User Approval Page User Approval Page