#!perl -wl # Dumps the contents of a simple Smart Health Card. # Input the mostly numeric text decoded from a QR code, e.g. (from https://spec.smarthealth.cards/examples/ ): # shc:/56762909524320603460292437404460312229595326546034602925407728043360287028647167452228092861333145643765314159064022030645045908564355034142454136403706366541713724123638030437562204673740753232392543344332605736010645292953127074242843503861221276716638370841727136710336077042394332675730226770544222601121257021736673065528340559522923650441330426325035757340575658432034345960112704044325260824656173256921003638395062653365562543595852673966226766345222242373550421410404577163557156556540004331083266342936065427506158605533125032505026733958416004583609726208664139360760577774725965211064453725000470326420420075375611276204102312585575273853712105257203316528097232693173222956503170307267544445767409247677276476365777660670532056076245296629764103582305383776282730531245383635060004042920505725280023354528570544074532073665226329232458045652456875314500772559236964003307327041106370296529072552360055573237045341316871254238066824724408560437331253765255061226102377777438421011542812755872522634552207126903605421333150360022435527080426550674505577222253063359122445327165345831355903287433326404264023110553344423752762343970033030340559076438243426110521393008681224566824682935593271686068275326306568354036736106716028102840532940717569714443530422614557316069432661112475384021386033350839403372072264430968605439693550312134730543765744752052252225530312353561590035093223396155575922614111012505071157527321107273713038661226537428220036716467425620702100207160256805602022602345362403700611090306552967080373540427247345202111033743565430360431445562455368113774 # Copyright 2021 Ken Takusagawa # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or (at # your option) any later version. # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . use MIME::Base64 qw(decode_base64url); use Compress::Zlib; # for in-memory decompression # Compress::Zlib uses Exporter / EXPORT to not require specifying what to import $_=<>; chomp; # https://spec.smarthealth.cards/ # https://spec.smarthealth.cards/examples/ # source code which generated the examples above: # https://github.com/smart-on-fhir/health-cards/blob/main/generate-examples/src/index.ts (typescript) die unless s,^shc:/,,; die unless /^\d+$/; # this does not handle chunking die unless (length$_)%2==0; while(/(\d\d)/g){ $n=$1; $n+=45; $c=chr($n); $s.=$c; } #print $s; # the contents of $s is a JWS: # https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-signature # the list of possible "alg" is in https://datatracker.ietf.org/doc/html/rfc7518 # no Ed25519 @F=split /\./,$s; die unless @F==3; $first=decode_base64url($F[0]); print "JWS Protected Header = ",$first; die unless $first =~ /"kid":"([^"]+)"/; $kid=$1; $kid=decode_base64url($kid); $hex=unpack("H*",$kid); # https://datatracker.ietf.org/doc/html/rfc7638 # "JWK Members Used in the Thumbprint Computation" # Print as hex to easily compare with output of sha256sum. print "key id (hex, ",length($kid)*8," bits) = ",$hex; # how to fetch the public key: # https://github.com/the-commons-project/vci-directory # The JSON Web Key Set must be available at <> + /.well-known/jwks.json. $dec=decode_base64url($F[1]); # negative MAX_WBITS enables "rawdeflate" or RFC 1951, otherwise you get 1950. ($inflateobject, $status)=inflateInit(-WindowBits => -MAX_WBITS); die unless $status == Z_OK; ($out,$status)= $inflateobject->inflate(\$dec); print "JWS Payload = ",$out; # which vaccine https://www2a.cdc.gov/vaccines/iis/iisstandards/vaccines.asp?rpt=cvx # code 207 = moderna, code 208 = pfizer die unless $status == Z_STREAM_END; die if $dec; # remaining string should be empty. $third=$F[2]; print "JWS Signature (base64url) = ",$third; $dec=decode_base64url($third); print "signature length = ",length($dec)*8," bits";