@@ -5,6 +5,18 @@ import { resolveKey, addCachedKeys } from './resolver';
55
66const URI_SCHEMA = 'shc' ;
77
8+ const NOT_SUPPORTED = "not_supported" ; // QR Standard not supported by this algorithm
9+ const INVALID_ENCODING = "invalid_encoding" ; // could not decode Base45 for DCC, Base10 for SHC
10+ const INVALID_COMPRESSION = "invalid_compression" ; // could not decompress the byte array
11+ const INVALID_SIGNING_FORMAT = "invalid_signing_format" ; // invalid COSE, JOSE, W3C VC Payload
12+ const KID_NOT_INCLUDED = "kid_not_included" ; // unable to resolve the issuer ID
13+ const ISSUER_NOT_TRUSTED = "issuer_not_trusted" ; // issuer is not found in the registry
14+ const TERMINATED_KEYS = "terminated_keys" ; // issuer was terminated by the registry
15+ const EXPIRED_KEYS = "expired_keys" ; // keys expired
16+ const REVOKED_KEYS = "revoked_keys" ; // keys were revoked by the issuer
17+ const INVALID_SIGNATURE = "invalid_signature" ; // signature doesn't match
18+ const VERIFIED = "verified" ; // Verified content.
19+
820/*
921 * I am not sure if I should build this by hand.
1022 */
@@ -34,60 +46,71 @@ export async function sign(payload, privateKey) {
3446 const fields = { zip : 'DEF' } ;
3547 const body = pako . deflateRaw ( bodyString ) ;
3648
37- const signed = await JWS . createSign ( { format : 'compact' , fields } , signingKey )
49+ return await JWS . createSign ( { format : 'compact' , fields } , signingKey )
3850 . update ( Buffer . from ( body ) )
3951 . final ( ) ;
40-
41- return signed ;
4252}
4353
44- async function jwsParts ( token ) {
54+ function jwsParse ( token ) {
4555 let [ headerEnc , bodyEnc , signatureEnc ] = token . split ( "." ) ;
46- const header = JSON . parse ( base64url . decode ( headerEnc ) ) ;
56+ const headerRaw = base64url . decode ( headerEnc ) ;
4757 const signature = base64url . decode ( signatureEnc ) ;
48- let bodyRaw = base64url . toBuffer ( bodyEnc ) ;
49- if ( header . zip == 'DEF' ) {
50- bodyRaw = Buffer . from ( pako . inflateRaw ( bodyRaw ) ) ;
51- }
52- let body = JSON . parse ( bodyRaw . toString ( ) ) ;
53- return { header, body, signature } ;
58+ const bodyRaw = base64url . toBuffer ( bodyEnc ) ;
59+ return { headerRaw, bodyRaw, signature } ;
5460}
5561
56- async function getVerificationKeyForJws ( jws ) {
57- let parsedJwsUnsafe = await jwsParts ( jws ) ;
58- let kid = parsedJwsUnsafe . header . kid ;
59- let iss = parsedJwsUnsafe . body . iss ;
60- return await resolveKey ( iss , kid ) ;
62+ function jwsInflate ( jwsRaw ) {
63+ jwsRaw . header = JSON . parse ( jwsRaw . headerRaw )
64+ if ( jwsRaw . header . zip == 'DEF' ) {
65+ jwsRaw . body = JSON . parse ( Buffer . from ( pako . inflateRaw ( jwsRaw . bodyRaw ) ) . toString ( ) ) ;
66+ }
67+ return jwsRaw ;
6168}
6269
63- async function verifyAndReturnPayload ( jws , publicKeyArray ) {
70+ export async function verify ( jws , publicKeyArray ) {
6471 if ( publicKeyArray ) {
6572 addCachedKeys ( publicKeyArray ) ;
6673 }
74+
75+ let rawPayload ;
76+ try {
77+ rawPayload = jwsParse ( jws ) ;
78+ } catch ( err ) {
79+ console . log ( err ) ;
80+ return { status : INVALID_SIGNING_FORMAT }
81+ }
6782
68- let issuer = await getVerificationKeyForJws ( jws ) ;
83+ try {
84+ rawPayload = jwsInflate ( rawPayload ) ;
85+ } catch ( err ) {
86+ console . log ( err ) ;
87+ return { status : INVALID_COMPRESSION , raw : rawPayload }
88+ }
6989
70- const verified = await JWS . createVerify ( await JWK . asKey ( issuer . didDocument ) ) . verify ( jws )
90+ if ( ! rawPayload . body . iss || ! rawPayload . header . kid ) return { status : KID_NOT_INCLUDED , contents : rawPayload . body , raw : rawPayload }
7191
72- let body = verified . payload ;
73- if ( ( verified . header ) . zip === 'DEF' ) {
74- body = Buffer . from ( pako . inflateRaw ( body ) ) ;
75- }
92+ let issuer = await resolveKey ( rawPayload . body . iss , rawPayload . header . kid ) ;
7693
77- return {
78- credential : JSON . parse ( body . toString ( ) ) ,
79- issuer : issuer ,
80- raw : await jwsParts ( jws )
81- } ;
82- }
94+ if ( ! issuer ) return { status : ISSUER_NOT_TRUSTED , contents : rawPayload . body , raw : rawPayload }
95+
96+ switch ( issuer . status ) {
97+ case "revoked" : return { status : REVOKED_KEYS , contents : rawPayload . body , issuer : issuer , raw : rawPayload }
98+ case "terminated" : return { status : TERMINATED_KEYS , contents : rawPayload . body , issuer : issuer , raw : rawPayload }
99+ case "expired" : return { status : EXPIRED_KEYS , contents : rawPayload . body , issuer : issuer , raw : rawPayload }
100+ }
83101
84- export async function verify ( jws , pubkeyKey ) {
85102 try {
86- await verifyAndReturnPayload ( jws , pubkeyKey ) ;
87- return true ;
103+ const verified = await JWS . createVerify ( await JWK . asKey ( issuer . didDocument ) ) . verify ( jws )
104+
105+ let body = verified . payload ;
106+ if ( ( verified . header ) . zip === 'DEF' ) {
107+ body = Buffer . from ( pako . inflateRaw ( body ) ) ;
108+ }
109+
110+ return { status : VERIFIED , contents : JSON . parse ( body . toString ( ) ) , issuer : issuer , raw : rawPayload } ;
88111 } catch ( err ) {
89112 console . log ( err ) ;
90- return false ;
113+ return { status : INVALID_SIGNATURE , contents : rawPayload . body , issuer : issuer , raw : rawPayload }
91114 }
92115}
93116
@@ -122,24 +145,31 @@ export async function unpack(uri) {
122145 }
123146 }
124147
125- return await fromBase10 ( data ) ;
148+ try {
149+ return await fromBase10 ( data ) ;
150+ } catch ( err ) {
151+ console . log ( err ) ;
152+ return undefined
153+ }
126154}
127155
128156export async function pack ( payload ) {
129157 return URI_SCHEMA + ':/' + await toBase10 ( payload ) ;
130158}
131159
132160export async function debug ( uri ) {
133- return await jwsParts ( await unpack ( uri ) ) ;
161+ return jwsInflate ( jwsParse ( await unpack ( uri ) ) ) ;
134162}
135163
136164export async function unpackAndVerify ( uri , publicKeyArray ) {
137- try {
138- return await verifyAndReturnPayload ( await unpack ( uri ) , publicKeyArray ) ;
139- } catch ( err ) {
140- console . log ( err ) ;
141- return undefined ;
165+ const jws = await unpack ( uri ) ;
166+
167+ if ( ! jws ) {
168+ return { status : INVALID_ENCODING , qr : uri } ;
142169 }
170+
171+ const verified = await verify ( jws , publicKeyArray ) ;
172+ return { ...verified , qr : uri } ;
143173}
144174export async function signAndPack ( payload , publicKeyPem , privateKeyP8 ) {
145175 return await pack ( await sign ( payload , publicKeyPem , privateKeyP8 ) ) ;
0 commit comments