FHIR Chat · JWS Headers · smart/health-cards

Stream: smart/health-cards

Topic: JWS Headers


view this post on Zulip Richard Braman (FLY.HEALTH) (Apr 27 2021 at 03:40):

Here's another question for the group. When I look at the JWS examples you provide, the header values for zip and type show up when I planainly parse the JWT. When I create the JWS in my code, these headers are "protected" meaningin they only show up if I validate the JWS. IS this a problem?

view this post on Zulip Josh Mandel (Apr 27 2021 at 03:43):

The term "protected" in the JWS spec means authenticated -- i.e., data that feeds into the digest that's used for creating a signature.

view this post on Zulip Josh Mandel (Apr 27 2021 at 03:44):

SMART Health Cards uses the JWS compact serialization (those three b64url-encoded strings separated by dots...), and in that serialization all headers are protected. That doesn't mean encrypted or anything -- just "signed over". It sounds like maybe your library is helping you avoid trouble by only showing you the decoded header after validation, to prevent your accidentally "trusting" header fields that haven't been validated. That's fair, but a verifier does need to peek into the headers (and payload!) before validating a Health Card, to extract the key id and issuer.

view this post on Zulip Josh Mandel (Apr 27 2021 at 03:44):

For reference, https://tools.ietf.org/html/rfc7515#section-3.1 is the source of truth:

In the JWS Compact Serialization, no JWS Unprotected Header is used.
In this case, the JOSE Header and the JWS Protected Header are the
same.

view this post on Zulip Richard Braman (FLY.HEALTH) (May 19 2021 at 06:22):

so, I have a shc that's passing all the validation exercises except for the JWS zip header, because as this post indicates, the zip header is protected. Is this a bug in the validator?
Here is my shc:

shc:/56762959532654603460292540772804336028702864716745222809286555723727457252633606564212243706667139775528376455295524257255600461382512334542083442422807532608753442593654622460573601064129336112327424350369044321331110425927776571536726202203307410204304072361397572223576275338636343003475090622077203282009541122650573355764774570117423400605723537365003453472121041055745074321282304566770577270772871417560050568310458036441612054635720572728412211753269442922345658506227625227065228453400220630090540255531326860766873637676682162403512203510400704335339612769770938403212720925005731652210400705571061033577215362656341036510230452290774342168660339056222566903555522723732215255263877277212583731664362075822076239306662402822664424122141712156452376620840211132607311742107732374615029080824575803326333072564253076302027120353353558740374334009203545603724063906773807773073747062635934074067267525385632401122375369373927356006632961390326630345254243557627703265662629225972312808242032047220606912313752277172716977562476366345583023281223210530117453525467564353300770123973634168033428537274396435353423607727382300267561434407257566066766033006313722100612043964703542005062327308587131273260395361077724281132602432630037033639093810393777580771527331055523322145235857532275375765552265384330642625344450416655114468713324310712084462647625097642613355065453645273405233635473532672250807296426607340616106740568283869621145397472743931507731215473057324047537443669653474014569403458115533303356072344263276283459642100507271410403222466611131101136642528412043114370743908731069603629086804331208665275763056401141375424110634716229533803712274

here is the error as shown in the validator:

{"message":"JWS header missing 'zip' property.","code":107,"level":3}

view this post on Zulip Reece Adamson (May 19 2021 at 11:43):

@Richard Braman (FLY.HEALTH) the example you provided appears to be missing the "zip": "DEF" header.

If we take just the numeric segment of your QR code (56762959...) and reconstruct the JWS

e.g. in node.js

const numeric = '56762959...'
const decoded = numeric.match(/(..?)/g).map(num => String.fromCharCode(parseInt(num, 10) + 45)).join('') // Split into groups of 2 numeric characters each of which represent a single JWS char
const header = decoded.split('.')[0]
console.log(header)
console.log(Buffer.from(header, 'base64').toString('utf8'))

You'll find that the header is eyJhbGciOiJFUzI1NiIsImtpZCI6InduRHZualQ3eW9ER3otTzdIRmdJdEFudi1jSF9NZW5OWWI4bG5xOWhQckEifQ

Base64 decoding this gives: {"alg":"ES256","kid":"wnDvnjT7yoDGz-O7HFgItAnv-cH_MenNYb8lnq9hPrA"}

You can contrast this with the Example 0 JWS from the spec where the JWS header is eyJ6aXAiOiJERUYiLCJhbGciOiJFUzI1NiIsImtpZCI6IjNLZmRnLVh3UC03Z1h5eXd0VWZVQUR3QnVtRE9QS01ReC1pRUxMMTFXOXMifQ and is Base64 decoded to {"zip":"DEF","alg":"ES256","kid":"3Kfdg-XwP-7gXyywtUfUADwBumDOPKMQx-iELL11W9s"}

view this post on Zulip Reece Adamson (May 19 2021 at 11:45):

I also reconstructed the payload and didn't see the "DEF": "zip" header there either (but it shouldn't be in the payload anyways)

e.g.

Reconstructed Payload

view this post on Zulip Christian Paquin (May 19 2021 at 13:14):

Richard Braman (FLY.HEALTH) said:

so, I have a shc that's passing all the validation exercises except for the JWS zip header, because as this post indicates, the zip header is protected. Is this a bug in the validator?
Here is my shc: [...]

You are indeed missing the zip header, as you can see when running the validator on the command line:
node . -p qrnumeric.txt -t qrnumeric -l debug
(where qrnumeric.txt contains the code your provided)

JWS-compact
         │
         ├─ Debug
         │    · JWS.header = {"alg":"ES256","kid":"wnDvnjT7yoDGz-O7HFgItAnv-cH_MenNYb8lnq9hPrA"}

view this post on Zulip Josh Mandel (May 19 2021 at 13:39):

I wonder if we should just make zip compression implicit, so it'd be okay for issuers to omit the header. It's not like we provide a way to create a health card without compressing the payload, so the header isn't really communicating information.(In future, if we ever need to describe different encoding options we could add a header like smw: 2 or whatever)

view this post on Zulip Richard Braman (FLY.HEALTH) (May 19 2021 at 16:56):

I got it working . it was some delicacy in the node-jose library. It works now.

shc:/5676290952432060346029243740446031222959532654603460292540772804336028702864716745222809286555723727457252633606564212243706667139775528376455295524257255600461382512334542083442422807532608753442593654622460573601064131315359332124357641683164721205433161770363323729743636592231672435701033715605205668066470535231125509532723583667282009546433353455254104555740007461400605723537365032205600121004753925074323282312355405250437631242760721441004250774094468595872767358275962686756442629703259273536502221767123105728083300270041037207426464715741533168546970663221581033285059396111127134544270350833767764776543670373241067366108507135074305220629353071721270355566653920092667616345400739033471710329042474635903296360345509626143206945753625742805414028074032445833106069526054672376700840371132377376585907726974585028250824576203326333072564253076305827120345575736740374273641203970756630536753046754633135077070085932114467427525395632031122415269563940676803633361390426630344634243557627723265662629227572312045222026520625567773312152277172716961562438366545585321245659581025544433003444733959631256546706766241713561263166240877067574304053092839750576361065367235525524642164031066065250345256047509067208382311445352757466607307542874223523265931675562332835002464057670034231646974120603742426540923393843301003096670033855326075676921107104636025336563590621713162670474734238036767735312554053042660457327676943221111627723384368397510073368603667633461431131702709730376744373066921295540263435082358013966744233703311673267701263207363746654436657302024660028770339323033202265225523764076720930105326283128430865526074596137753954684168533862550359522142430758445552587158

Last updated: Apr 12 2022 at 19:14 UTC