#!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";