@@ -38,6 +38,7 @@ import {
38
38
assertCredentialContext ,
39
39
assertDateString ,
40
40
checkContextVersion ,
41
+ compareTime ,
41
42
getContextForVersion
42
43
} from './helpers.js' ;
43
44
import { documentLoader as _documentLoader } from './documentLoader.js' ;
@@ -103,6 +104,10 @@ export {CredentialIssuancePurpose};
103
104
* @param {object } [options.documentLoader] - A document loader.
104
105
* @param {string|Date } [options.now] - A string representing date time in
105
106
* ISO 8601 format or an instance of Date. Defaults to current date time.
107
+ * @param {number } [options.maxClockSkew=300] - A maximum number of seconds
108
+ * that clocks may be skewed when checking capability expiration date-times
109
+ * against `date` and when comparing invocation proof creation time against
110
+ * delegation proof creation time.
106
111
*
107
112
* @throws {Error } If missing required properties.
108
113
*
@@ -112,7 +117,8 @@ export async function issue({
112
117
credential, suite,
113
118
purpose = new CredentialIssuancePurpose ( ) ,
114
119
documentLoader = defaultDocumentLoader ,
115
- now
120
+ now,
121
+ maxClockSkew = 300
116
122
} = { } ) {
117
123
// check to make sure the `suite` has required params
118
124
// Note: verificationMethod defaults to publicKey.id, in suite constructor
@@ -135,7 +141,7 @@ export async function issue({
135
141
}
136
142
137
143
// run common credential checks
138
- _checkCredential ( { credential, now, mode : 'issue' } ) ;
144
+ _checkCredential ( { credential, now, mode : 'issue' , maxClockSkew } ) ;
139
145
140
146
return jsigs . sign ( credential , { purpose, documentLoader, suite} ) ;
141
147
}
@@ -219,6 +225,10 @@ export async function derive({
219
225
* credential status if `credentialStatus` is present on the credential.
220
226
* @param {string|Date } [options.now] - A string representing date time in
221
227
* ISO 8601 format or an instance of Date. Defaults to current date time.
228
+ * @param {number } [options.maxClockSkew=300] - A maximum number of seconds
229
+ * that clocks may be skewed when checking capability expiration date-times
230
+ * against `date` and when comparing invocation proof creation time against
231
+ * delegation proof creation time.
222
232
*
223
233
* @returns {Promise<VerifyPresentationResult> } The verification result.
224
234
*/
@@ -264,6 +274,10 @@ export async function verify(options = {}) {
264
274
* credential status if `credentialStatus` is present on the credential.
265
275
* @param {string|Date } [options.now] - A string representing date time in
266
276
* ISO 8601 format or an instance of Date. Defaults to current date time.
277
+ * @param {number } [options.maxClockSkew=300] - A maximum number of seconds
278
+ * that clocks may be skewed when checking capability expiration date-times
279
+ * against `date` and when comparing invocation proof creation time against
280
+ * delegation proof creation time.
267
281
*
268
282
* @returns {Promise<VerifyCredentialResult> } The verification result.
269
283
*/
@@ -295,6 +309,10 @@ export async function verifyCredential(options = {}) {
295
309
* definition in the `verify()` docstring, for this param.
296
310
* @param {string|Date } [options.now] - A string representing date time in
297
311
* ISO 8601 format or an instance of Date. Defaults to current date time.
312
+ * @param {number } [options.maxClockSkew=300] - A maximum number of seconds
313
+ * that clocks may be skewed when checking capability expiration date-times
314
+ * against `date` and when comparing invocation proof creation time against
315
+ * delegation proof creation time.
298
316
*
299
317
* @throws {Error } If required parameters are missing (in `_checkCredential`).
300
318
*
@@ -306,10 +324,10 @@ export async function verifyCredential(options = {}) {
306
324
* @returns {Promise<VerifyCredentialResult> } The verification result.
307
325
*/
308
326
async function _verifyCredential ( options = { } ) {
309
- const { credential, checkStatus, now} = options ;
327
+ const { credential, checkStatus, now, maxClockSkew } = options ;
310
328
311
329
// run common credential checks
312
- _checkCredential ( { credential, now} ) ;
330
+ _checkCredential ( { credential, now, maxClockSkew } ) ;
313
331
314
332
// if credential status is provided, a `checkStatus` function must be given
315
333
if ( credential . credentialStatus && typeof options . checkStatus !== 'function' ) {
@@ -352,6 +370,10 @@ async function _verifyCredential(options = {}) {
352
370
* @param {string } [options.holder] - Optional presentation holder url.
353
371
* @param {string|Date } [options.now] - A string representing date time in
354
372
* ISO 8601 format or an instance of Date. Defaults to current date time.
373
+ * @param {number } [options.maxClockSkew=300] - A maximum number of seconds
374
+ * that clocks may be skewed when checking capability expiration date-times
375
+ * against `date` and when comparing invocation proof creation time against
376
+ * delegation proof creation time.
355
377
* @param {number } [options.version = 2.0] - The VC context version to use.
356
378
*
357
379
* @throws {TypeError } If verifiableCredential param is missing.
@@ -362,7 +384,7 @@ async function _verifyCredential(options = {}) {
362
384
* VerifiablePresentation.
363
385
*/
364
386
export function createPresentation ( {
365
- verifiableCredential, id, holder, now, version = 2.0
387
+ verifiableCredential, id, holder, now, version = 2.0 , maxClockSkew = 300
366
388
} = { } ) {
367
389
const initialContext = getContextForVersion ( { version} ) ;
368
390
const presentation = {
@@ -373,7 +395,7 @@ export function createPresentation({
373
395
const credentials = [ ] . concat ( verifiableCredential ) ;
374
396
// ensure all credentials are valid
375
397
for ( const credential of credentials ) {
376
- _checkCredential ( { credential, now} ) ;
398
+ _checkCredential ( { credential, now, maxClockSkew } ) ;
377
399
}
378
400
presentation . verifiableCredential = credentials ;
379
401
}
@@ -456,6 +478,10 @@ export async function signPresentation(options = {}) {
456
478
* credential status if `credentialStatus` is present on the credential.
457
479
* @param {string|Date } [options.now] - A string representing date time in
458
480
* ISO 8601 format or an instance of Date. Defaults to current date time.
481
+ * @param {number } [options.maxClockSkew=300] - A maximum number of seconds
482
+ * that clocks may be skewed when checking capability expiration date-times
483
+ * against `date` and when comparing invocation proof creation time against
484
+ * delegation proof creation time.
459
485
*
460
486
* @throws {Error } If presentation is missing required params.
461
487
*
@@ -571,14 +597,18 @@ const mustHaveType = [
571
597
* VerifiableCredential.
572
598
* @param {string|Date } [options.now] - A string representing date time in
573
599
* ISO 8601 format or an instance of Date. Defaults to current date time.
600
+ * @param {number } [options.maxClockSkew=300] - A maximum number of seconds
601
+ * that clocks may be skewed when checking capability expiration date-times
602
+ * against `date` and when comparing invocation proof creation time against
603
+ * delegation proof creation time.
574
604
* @param {string } [options.mode] - The mode of operation for this
575
605
* validation function, either `issue` or `verify`.
576
606
*
577
607
* @throws {Error }
578
608
* @private
579
609
*/
580
610
export function _checkCredential ( {
581
- credential, now = new Date ( ) , mode = 'verify'
611
+ credential, now = new Date ( ) , mode = 'verify' , maxClockSkew = 300
582
612
} = { } ) {
583
613
if ( typeof now === 'string' ) {
584
614
now = new Date ( now ) ;
@@ -617,15 +647,16 @@ export function _checkCredential({
617
647
assertDateString ( { credential, prop : 'expirationDate' } ) ;
618
648
if ( mode === 'verify' ) {
619
649
// check if `now` is after `expirationDate`
620
- if ( now > new Date ( credential . expirationDate ) ) {
650
+ const expirationDate = new Date ( credential . expirationDate ) ;
651
+ if ( compareTime ( { t1 : now , t2 : expirationDate , maxClockSkew} ) > 0 ) {
621
652
throw new Error ( 'Credential has expired.' ) ;
622
653
}
623
654
}
624
655
}
625
656
// check if `now` is before `issuanceDate` on verification
626
657
if ( mode === 'verify' ) {
627
658
const issuanceDate = new Date ( credential . issuanceDate ) ;
628
- if ( now < issuanceDate ) {
659
+ if ( compareTime ( { t1 : issuanceDate , t2 : now , maxClockSkew } ) > 0 ) {
629
660
throw new Error (
630
661
`The current date time (${ now . toISOString ( ) } ) is before the ` +
631
662
`"issuanceDate" (${ credential . issuanceDate } ).` ) ;
@@ -639,7 +670,7 @@ export function _checkCredential({
639
670
assertDateString ( { credential, prop : 'validUntil' } ) ;
640
671
if ( mode === 'verify' ) {
641
672
validUntil = new Date ( credential . validUntil ) ;
642
- if ( now > validUntil ) {
673
+ if ( compareTime ( { t1 : now , t2 : validUntil , maxClockSkew } ) > 0 ) {
643
674
throw new Error (
644
675
`The current date time (${ now . toISOString ( ) } ) is after ` +
645
676
`"validUntil" (${ credential . validUntil } ).` ) ;
@@ -651,7 +682,7 @@ export function _checkCredential({
651
682
if ( mode === 'verify' ) {
652
683
// check if `now` is before `validFrom`
653
684
validFrom = new Date ( credential . validFrom ) ;
654
- if ( now < validFrom ) {
685
+ if ( compareTime ( { t1 : validFrom , t2 : now , maxClockSkew } ) > 0 ) {
655
686
throw new Error (
656
687
`The current date time (${ now . toISOString ( ) } ) is before ` +
657
688
`"validFrom" (${ credential . validFrom } ).` ) ;
0 commit comments