@@ -5,6 +5,18 @@ import { resolveKey, addCachedKeys } from './resolver';
5
5
6
6
const URI_SCHEMA = 'shc' ;
7
7
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
+
8
20
/*
9
21
* I am not sure if I should build this by hand.
10
22
*/
@@ -34,60 +46,71 @@ export async function sign(payload, privateKey) {
34
46
const fields = { zip : 'DEF' } ;
35
47
const body = pako . deflateRaw ( bodyString ) ;
36
48
37
- const signed = await JWS . createSign ( { format : 'compact' , fields } , signingKey )
49
+ return await JWS . createSign ( { format : 'compact' , fields } , signingKey )
38
50
. update ( Buffer . from ( body ) )
39
51
. final ( ) ;
40
-
41
- return signed ;
42
52
}
43
53
44
- async function jwsParts ( token ) {
54
+ function jwsParse ( token ) {
45
55
let [ headerEnc , bodyEnc , signatureEnc ] = token . split ( "." ) ;
46
- const header = JSON . parse ( base64url . decode ( headerEnc ) ) ;
56
+ const headerRaw = base64url . decode ( headerEnc ) ;
47
57
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 } ;
54
60
}
55
61
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 ;
61
68
}
62
69
63
- async function verifyAndReturnPayload ( jws , publicKeyArray ) {
70
+ export async function verify ( jws , publicKeyArray ) {
64
71
if ( publicKeyArray ) {
65
72
addCachedKeys ( publicKeyArray ) ;
66
73
}
74
+
75
+ let rawPayload ;
76
+ try {
77
+ rawPayload = jwsParse ( jws ) ;
78
+ } catch ( err ) {
79
+ console . log ( err ) ;
80
+ return { status : INVALID_SIGNING_FORMAT }
81
+ }
67
82
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
+ }
69
89
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 }
71
91
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 ) ;
76
93
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
+ }
83
101
84
- export async function verify ( jws , pubkeyKey ) {
85
102
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 } ;
88
111
} catch ( err ) {
89
112
console . log ( err ) ;
90
- return false ;
113
+ return { status : INVALID_SIGNATURE , contents : rawPayload . body , issuer : issuer , raw : rawPayload }
91
114
}
92
115
}
93
116
@@ -122,24 +145,31 @@ export async function unpack(uri) {
122
145
}
123
146
}
124
147
125
- return await fromBase10 ( data ) ;
148
+ try {
149
+ return await fromBase10 ( data ) ;
150
+ } catch ( err ) {
151
+ console . log ( err ) ;
152
+ return undefined
153
+ }
126
154
}
127
155
128
156
export async function pack ( payload ) {
129
157
return URI_SCHEMA + ':/' + await toBase10 ( payload ) ;
130
158
}
131
159
132
160
export async function debug ( uri ) {
133
- return await jwsParts ( await unpack ( uri ) ) ;
161
+ return jwsInflate ( jwsParse ( await unpack ( uri ) ) ) ;
134
162
}
135
163
136
164
export 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 } ;
142
169
}
170
+
171
+ const verified = await verify ( jws , publicKeyArray ) ;
172
+ return { ...verified , qr : uri } ;
143
173
}
144
174
export async function signAndPack ( payload , publicKeyPem , privateKeyP8 ) {
145
175
return await pack ( await sign ( payload , publicKeyPem , privateKeyP8 ) ) ;
0 commit comments