Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clarification re multiple QR codes #178

Open
littleforest opened this issue Sep 7, 2021 · 15 comments
Open

Clarification re multiple QR codes #178

littleforest opened this issue Sep 7, 2021 · 15 comments

Comments

@littleforest
Copy link

I have followed the spec for how to handle the case when the JWS needs to be split up into multiple chunks to create multiple QR codes, and have run the resulting numeric and QR code PNGs through the SMART Health Cards Dev Tools validator successfully. However, when I try to read any of these QR codes with the SMART Health Card Verifier iOS app, I just get an error that it is an unsupported QR code. Are multiple QR codes not yet supported on these apps, or is there some way that they need to be displayed so that they get picked up correctly by the reader? I am having no trouble with single QR codes getting read correctly by the app.

@jmandel
Copy link
Member

jmandel commented Sep 10, 2021

@jpp9 or @jdkizer9 may be able to comment on this?

@jasonxylee
Copy link

jasonxylee commented Sep 10, 2021

Commenting on this as I have also ran into this issue.

According to the SMART Health card specs - it says that Any JWS longer than 1195 characters SHALL be split into "chunks" of length 1191 or smaller;

To implement this logic, I followed the code in the repo at index.ts L179. The result I get is an array of 2 qr code segments that look like this:

[
    { data: 'shc:/1/2/', mode: 'byte' },
    {
      data: '567629095...cut for brevity',
      mode: 'numeric'
    }
  ],
  [
    { data: 'shc:/2/2/', mode: 'byte' },
    {
      data: '4152740303077303... cut for brevity',
      mode: 'numeric'
    }
  ]

However, when using the verifier portal to try to validate the qr code data, the the qr numeric data produces an invalid JWS string. This is shown in the screenshot below. (Using mock data of course)

Screen Shot 2021-09-10 at 10 29 06 AM

I fear that this error is the reason why the validator apps are failing when there are multiple qr codes, because the qr codes that have the numeric data embedded in them don't produce a valid JWS string, making it hard for a node library like node-jose to correctly decode the data and verify.

I would love some guidance on how we should go about fixing this. Perhaps there was a different logic to take for chunking the JWS string once it's longer than 1195 characters in the JWS string.

Appreciate the time, thank you.

@ljoy913
Copy link

ljoy913 commented Sep 10, 2021

@jasonxylee
The shc data in the image above (shc:/5676...) is a single-part QR code. The header should be shc:/1/2/5676.... for part-1 of the 2 part code.

Are you encoding the array of 2 parts into a single part instead of encoding each part individually?

The invalid JWS error is the result of the jws missing the signature segment at the end.

@jasonxylee
Copy link

@ljoy913 Thank you for your response, the verifier portal does not accept shc/1/2 in the beginning as you can see here:

Screen Shot 2021-09-10 at 11 45 14 AM

Can you please clarify what you mean when you say

"Are you encoding the array of 2 parts into a single part instead of encoding each part individually?"

@dleve123
Copy link
Contributor

dleve123 commented Sep 10, 2021

@jasonxylee It appears that you're missing a second trailing / to denote the N number of numerically-encoded QR chunks that compose your SHC JWS.

Example from the docs:

in a longer JWS, the second chunk in a set of three might produce a QR code like shc:/2/3/56762909524320603460292437404460

Note the shc:/2/3/... component of this.

@jasonxylee
Copy link

@dleve123 - Thank you, I made sure that I included a trailing / to denote the N number of numerically-encoded QR Chunks. Please see example below:

Screen Shot 2021-09-10 at 12 08 05 PM

@ljoy913
Copy link

ljoy913 commented Sep 10, 2021

@jasonxylee
could you send me the entire shc string from your image?

@jasonxylee
Copy link

@ljoy913 Yes, i am including both 1/2, and 2/2 for the numeric qr code:

qrCodeSegments:  [
  [
    { data: 'shc:/1/2/', mode: 'byte' },
    {
      data: '5676290952432060346029243740446031222959532654603460292540772804336028702864716745222809286367633725110556251231413959243862294052654537416441393864407554645528456145365265417239235971386441573762257534412460573601104558125312707424285350387022726060772960720466520834633633704038336663112421394132762263203838547232245072111238626453286311101077744462274111765372275850275432004054681261420012084170086559776272530473346353414506696338101173557176620573415335655745003077692224714572264157636065595669085229546732717664532255443340121150715670726909530928770635687108336773401125711039083223115759205229566904352623300509070408041045722566717267346112630907362930057345567043040853230829444035370568057673094004664254606741676372523625061012333138046368272638715433417060691157617007404376032007396555523633670324336921100921263821090450422003256100726923206656270407285058107174356674360510622532303303672327316606764206597766064438396568123562212726744355656532572559554563591265084324754507552311723105377654655375505811501239335531774034426226307776400471722310572035316242770544005874652352712741440053273106635270703509622323657237505434233007335531312027652759412271352173311011327604550711',
      mode: 'numeric'
    }
  ],
  [
    { data: 'shc:/2/2/', mode: 'byte' },
    {
      data: '0674670505726763057164534252207754096856605506717307053053234371036100325456767362415205665564652530226624122339002269321003684530522907652227243833710304625810656640310612623642387343527509364331385642124063370556110839422770363238065763735812642441387623390826250005370734773636324158085968617528614568566568063977350572563309223057115665243456100334723839281140345624003907283754243443102834402634275028105050742854583836760434222723506225402634275030382832543556402636070755327558702145232956222222391140282064447443207059627321212029723241350036082638112462326307284421327558702145232956222222391140282064447443207059627321212029723425202328453174383676436125231062580707402032596273212923295622262039324431204236764358585862502522202964322574312845317436362253615936207626525007285655627321212029723425202328453174383676435859582477262274256232630728282935753658224561215422762638112424206407754050452129561139326406754050441229551139326405754050440829551139326404754050440429551139326403754050447529552439255659091150014063427539570650587730582869717262213564666245422208330539403008035034115671414177034264052142643057335362276074390063735711763426034230306650253161085600571152200033534374',
      mode: 'numeric'
    }
  ]
]

@ljoy913
Copy link

ljoy913 commented Sep 10, 2021

"Are you encoding the array of 2 parts into a single part instead of encoding each part individually?"

Your shc header for part one should be shc:/1/2/<data> for part 1-of-2
Since it was a single part header: shc:/<data>, something is wrong with the encoding process. I was asking if you are passing the array of two parts to your QR encoder and getting a single QR in return - or - making two calls to the encoder, one for each part, resulting in a QR code for each part?

The verifier cannot validate a single part of a multi-part QR code.
The data from each part is concatenated together to form a single valid JWS string and so all parts are required to continue the validation. It would be like trying to validate the first half of an xml file.

@ljoy913
Copy link

ljoy913 commented Sep 10, 2021

@jasonxylee
And you're are trying to generate 2 QR codes from this data? or just validate the data is valid with the tools?

@jasonxylee
Copy link

@ljoy913 Thank you for the explanation, i see now that we weren't supposed to separate them out..

We are using the 2 numeric qr codes right now to generate 2 separate QR codes. But I guess it cannot be done that way if it cannot be verified separately.

So then my question now is, once the JWS string is over 1195 characters, and we chunk it into multiple chunks, do we merge all the chunks together to create one QR code? My understanding from reading the SMART Health card documentation was that each chunk represented one QR code, however I guess that could have been a mistake.

@ljoy913
Copy link

ljoy913 commented Sep 10, 2021

@jasonxylee
2 separate QR codes is correct.

You just cannot verify them one at a time in the verifier portal.
If you scan each with the scanner, it will create two entries in the UI and verification will understand an validate them as one. For example (3-part encoding):

image

There is a limitation with the UI that you can only manually enter a single set of numeric data if you are not using the scanner.

Did you try scanning both of your resulting QR codes in the verifier?

@littleforest
Copy link
Author

2 separate QR codes is correct.

@ljoy913 could you please comment on how these separate QR codes should be read in the SMART Health Card apps? As I noted in the original question, I have run the 2 QR codes through the SMART Health Cards Dev Tools validator like so:

node . --path ../cr_access/tmp/qrcode_0.png  --path ../cr_access/tmp/qrcode_1.png --type qr

and received a successful validation message (other than the warning that I didn't need to split into 2, which I just did for testing):

Validation results
SMART Health Card Dev Tools v1.0.2-0

QR images (2)
   │  
   ├─ Debug
   │    · segment 1: type: byte, content: shc:/1/2/
   │    · segment 2: type: numeric, content: 5676295953265460346029254077280433602870286471674522280928631264532675413762453938051241546229775565412733622528382763214061400656627006380645713263676840033604446204593427546031222909524320603460292437404460573601594529536112327424284350386441566212373456700653206230200326662522122830415459042968056727405600213266685008057503034069712275414143407675085035653262126254093764597612100403126576504268030456696061330537675056324145776459251105452964067467766441563157580943085660305368233352552226673037537100386468056868250472766674325871390675291210283543433506606572574127073266572211257107040832373707317535755329117458261045124160340423670611755303032755636337255966663534386803125950750524610853526610375774316866685464606620412352277709326538335868607507247674206409395743296745295575602321302838033832662843052335346034385804265669403521747368446656226056203300
   │    · qrcode_0.png = shc:/1/2/5676295953265460346029254077280433602870286471674522280928631264532675413762453938051241546229775565412733622528382763214061400656627006380645713263676840033604446204593427546031222909524320603460292437404460573601594529536112327424284350386441566212373456700653206230200326662522122830415459042968056727405600213266685008057503034069712275414143407675085035653262126254093764597612100403126576504268030456696061330537675056324145776459251105452964067467766441563157580943085660305368233352552226673037537100386468056868250472766674325871390675291210283543433506606572574127073266572211257107040832373707317535755329117458261045124160340423670611755303032755636337255966663534386803125950750524610853526610375774316866685464606620412352277709326538335868607507247674206409395743296745295575602321302838033832662843052335346034385804265669403521747368446656226056203300
   │    · segment 1: type: byte, content: shc:/2/2/
   │    · segment 2: type: numeric, content: 5841397457110032522958614340670461235061563326577027563620434077753143370704421024035744384506503357523874104531646334264361263505672050057328120661073531602053356611682122255309523967596460381200702230626676103238353454751254226239062261772425360854223365216876373575053706382037065559100308424323213710417261230532285045770804700864310760442331373843553931570363082238103744705527262675756461762060036463667563257267290338296842777630660973563755523165767444223331676356616341350443051109563772072264637553771026692462357161414237744434602738395228040373562975600575057400046755664053232923335060687307545770777158395069732329684170594159546977310034725912082129424171505653003577243900502036012141571020096032615477715758616166085758423144356643553039615210055935410406555275413968107326332145590322440665557641422260706167273608216625533242097709723829274167315774
   │    · qrcode_1.png = shc:/2/2/5841397457110032522958614340670461235061563326577027563620434077753143370704421024035744384506503357523874104531646334264361263505672050057328120661073531602053356611682122255309523967596460381200702230626676103238353454751254226239062261772425360854223365216876373575053706382037065559100308424323213710417261230532285045770804700864310760442331373843553931570363082238103744705527262675756461762060036463667563257267290338296842777630660973563755523165767444223331676356616341350443051109563772072264637553771026692462357161414237744434602738395228040373562975600575057400046755664053232923335060687307545770777158395069732329684170594159546977310034725912082129424171505653003577243900502036012141571020096032615477715758616166085758423144356643553039615210055935410406555275413968107326332145590322440665557641422260706167273608216625533242097709723829274167315774
   │  
   ├─ Info
   │    · qrcode_0.png decoded
   │    · qrcode_1.png decoded
   │  
   └─ QR numeric (2)
         │  
         ├─ Debug
         │    · shc:/1/2/... = eyJhbGciOiJFUzI1NiIsImtpZCI6Il9mbGxVRkZTS29VckJzdnVHNkFISHlBUjU3eks3S3ZtMlpqU0Q1Yk1hOHciLCJ6aXAiOiJERUYifQ.hZJbj9MwEIX_SmVek9ROes3bAkKA0GoFC9IKVch1Jq2pHUe-BMoq_52x00UrtCxVVXUyx5_PnMk9kc6Rmhy97109ny_Wq01erijN2Rp_eMVZzmhF82ZJm3wpymVeLfg6X5eiKbqDNadCGpKRbt-Smq2qqF1uyowMgtT3xJ97IPXXP3inufVH4MofC8Ft415MRR4LxPxbJ8wgG7Z9ViO1Dp38xb00HdllRFhooPOSq09h_x2Ej5bao7RfwLqoqcmioAVDaHz6MnSNgqix4EywAm6TfXJpZJdxiDBKIS0SMoIX2DPOiOSg1GerUPBwvqYoeCieAN-
         │    · shc:/2/2/... = gVTwf8-MaJgjXUp1jD_jeNGfsHeQAXUzxLXR41W7E0fYSZ3_NfaSw7ZLmlOGXjGP2pA_2vI93j4PLiAbPo8qBCFb6aTphmiS9-sCKkoy7MSPOcx9cCkT3CjzEFQ5cCNnBqyRPx2R3SAR3dh705WXDBR7VujD2MI_Zz51s5mL4iYDLRSXdTLf0l5CS7RYsdHGGxxmjyAi0mloxlFupJ0SJqWzyKo6veRdaLnywYCNLplejlVP1X286eRu4Cmlxbz7GrEkPtjVWRwYOiHSTaI10veJxi2x2w-1pdoUbDJDN_iqv4cfsztgT_rvDJqVshVhcrzL-Ouh95BJWVt_eb-PzET-_AQ.BVf7A6iMjcztfgjjo5fgWLYPoXdKTja72hPV13daxVTq7vGNBZh0CY3ndyVWCisjpHQ5BoFbMW6z6uSJHVpLfw
         │    · JWS = eyJhbGciOiJFUzI1NiIsImtpZCI6Il9mbGxVRkZTS29VckJzdnVHNkFISHlBUjU3eks3S3ZtMlpqU0Q1Yk1hOHciLCJ6aXAiOiJERUYifQ.hZJbj9MwEIX_SmVek9ROes3bAkKA0GoFC9IKVch1Jq2pHUe-BMoq_52x00UrtCxVVXUyx5_PnMk9kc6Rmhy97109ny_Wq01erijN2Rp_eMVZzmhF82ZJm3wpymVeLfg6X5eiKbqDNadCGpKRbt-Smq2qqF1uyowMgtT3xJ97IPXXP3inufVH4MofC8Ft415MRR4LxPxbJ8wgG7Z9ViO1Dp38xb00HdllRFhooPOSq09h_x2Ej5bao7RfwLqoqcmioAVDaHz6MnSNgqix4EywAm6TfXJpZJdxiDBKIS0SMoIX2DPOiOSg1GerUPBwvqYoeCieAN-gVTwf8-MaJgjXUp1jD_jeNGfsHeQAXUzxLXR41W7E0fYSZ3_NfaSw7ZLmlOGXjGP2pA_2vI93j4PLiAbPo8qBCFb6aTphmiS9-sCKkoy7MSPOcx9cCkT3CjzEFQ5cCNnBqyRPx2R3SAR3dh705WXDBR7VujD2MI_Zz51s5mL4iYDLRSXdTLf0l5CS7RYsdHGGxxmjyAi0mloxlFupJ0SJqWzyKo6veRdaLnywYCNLplejlVP1X286eRu4Cmlxbz7GrEkPtjVWRwYOiHSTaI10veJxi2x2w-1pdoUbDJDN_iqv4cfsztgT_rvDJqVshVhcrzL-Ouh95BJWVt_eb-PzET-_AQ.BVf7A6iMjcztfgjjo5fgWLYPoXdKTja72hPV13daxVTq7vGNBZh0CY3ndyVWCisjpHQ5BoFbMW6z6uSJHVpLfw
         │  
         ├─ Info
         │    · shc:/1/2/... decoded
         │    · shc:/2/2/... decoded
         │    · All shc parts decoded
         │  
         ├─ Warning
         │    · JWS of size 868 (<= 1191) didn't need to be split in 2 chunks
         │  
         └─ JWS-compact
               │  
               ├─ Debug
               │    · JWS.header = {"alg":"ES256","kid":"_fllUFFSKoUrBsvuG6AHHyAR57zK7Kvm2ZjSD5bMa8w","zip":"DEF"}
               │    · JWS.signature = 0557fb03a88c8dcced7e08e3a397e058b60fa1774a4e36bbda13d5d7775ac554eaeef18d059874098de77725560a2b23a4743906815b316eb3eae4891d5a4b7f
               │    · Downloaded issuer key(s) : 
               │    · Key 0:
               │    · {
               │         "crv": "P-256",
               │         "kty": "EC",
               │         "x": "t7t42SeAjfW_qcZg2QOvKw2FwV6Sk-Nj1ere40ScO8I",
               │         "y": "5BV0yKzhwSq9_Hni69yiBq-ATizUdFHjAzHmv8vWjiA",
               │         "kid": "_fllUFFSKoUrBsvuG6AHHyAR57zK7Kvm2ZjSD5bMa8w",
               │         "use": "sig",
               │         "alg": "ES256"
               │      }
               │  
               ├─ Info
               │    · JWS payload inflated
               │    · Retrieving issuer key from https://4768-2600-1700-a3a1-1030-d50d-5c25-34a7-72cd.ngrok.io/.well-known/jwks.json
               │    · Validating key : key[_fllUFFSKoUrBsvuG6AHHyAR57zK7Kvm2ZjSD5bMa8w]
               │    · JWS signature verified
               │  
               └─ JWS.payload
                     │  
                     ├─ Debug
                     │    · JWS Payload Contents:
                     │    · {
                     │         "iss": "https://4768-2600-1700-a3a1-1030-d50d-5c25-34a7-72cd.ngrok.io",
                     │         "nbf": 1631030582,
                     │         "vc": {
                     │            "type": [
                     │               "https://smarthealth.cards#health-card",
                     │               "https://smarthealth.cards#covid19",
                     │               "https://smarthealth.cards#immunization"
                     │            ],
                     │            "credentialSubject": {
                     │               "fhirVersion": "4.0.1",
                     │               "fhirBundle": {
                     │                  "resourceType": "Bundle",
                     │                  "type": "collection",
                     │                  "entry": [
                     │                     {
                     │                        "fullUrl": "resource:0",
                     │                        "resource": {
                     │                           "resourceType": "Patient",
                     │                           "name": [ { "family": "Peabody", "given": [ "Henry" ] } ],
                     │                           "birthDate": "1950-01-01"
                     │                        }
                     │                     },
                     │                     {
                     │                        "fullUrl": "resource:1",
                     │                        "resource": {
                     │                           "resourceType": "Immunization",
                     │                           "meta": { "security": [ { "code": "IAL1.2" } ] },
                     │                           "status": "completed",
                     │                           "vaccineCode": { "coding": [ { "system": "http://hl7.org/fhir/sid/cvx", "code": "208" } ] },
                     │                           "patient": { "reference": "resource:0" },
                     │                           "occurrenceDateTime": "2021-08-31",
                     │                           "manufacturer": {
                     │                              "identifier": { "system": "http://hl7.org/fhir/sid/mvx", "value": "PFR" }
                     │                           },
                     │                           "performer": [
                     │                              {
                     │                                 "actor": { "display": "1 Park Avenue, 1 Park Avenue, New York, NY, 10016" }
                     │                              }
                     │                           ],
                     │                           "lotNumber": "123_J9"
                     │                        }
                     │                     }
                     │                  ]
                     │               }
                     │            }
                     │         }
                     │      }
                     │  
                     ├─ Info
                     │    · JWS Payload validated
                     │  
                     └─ FhirBundle
                           │  
                           ├─ Debug
                           │    · FHIR Bundle Contents:
                           │    · {
                           │         "resourceType": "Bundle",
                           │         "type": "collection",
                           │         "entry": [
                           │            {
                           │               "fullUrl": "resource:0",
                           │               "resource": {
                           │                  "resourceType": "Patient",
                           │                  "name": [ { "family": "Peabody", "given": [ "Henry" ] } ],
                           │                  "birthDate": "1950-01-01"
                           │               }
                           │            },
                           │            {
                           │               "fullUrl": "resource:1",
                           │               "resource": {
                           │                  "resourceType": "Immunization",
                           │                  "meta": { "security": [ { "code": "IAL1.2" } ] },
                           │                  "status": "completed",
                           │                  "vaccineCode": { "coding": [ { "system": "http://hl7.org/fhir/sid/cvx", "code": "208" } ] },
                           │                  "patient": { "reference": "resource:0" },
                           │                  "occurrenceDateTime": "2021-08-31",
                           │                  "manufacturer": { "identifier": { "system": "http://hl7.org/fhir/sid/mvx", "value": "PFR" } },
                           │                  "performer": [ { "actor": { "display": "1 Park Avenue, 1 Park Avenue, New York, NY, 10016" } } ],
                           │                  "lotNumber": "123_J9"
                           │               }
                           │            }
                           │         ]
                           │      }
                           │  
                           └─ Info
                                · FHIR bundle validated

Validation completed

But I get errors when scanning the QR codes with the app readers.

@ljoy913
Copy link

ljoy913 commented Sep 10, 2021

@littleforest
Sorry, I am not the person that can help with that app, but in out verifier portal
You would click 'Scan code' to bring up the scanner.
Scan the one of the qr codes. (you can scan out of order)
After the first scan, it will detect it as being multi-part and wait to scan the 2nd part.
Scan the 2nd code, and it should close the scanner and the verification should continue.

@littleforest
Copy link
Author

My 2 QR codes worked fine in the verifier portal. I'm guessing the issue must be that the current app readers out there do not have the capability to read multiple QR codes? I can close this ticket if that is likely the case. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants