@@ -12,6 +12,8 @@ import 'cbor.dart';
12
12
import 'errors.dart' ;
13
13
import 'request_id.dart' ;
14
14
import 'types.dart' ;
15
+ import 'utils/buffer_pipe.dart' ;
16
+ import 'utils/leb128.dart' ;
15
17
16
18
final AgentBLS _bls = AgentBLS ();
17
19
@@ -136,13 +138,13 @@ class Certificate {
136
138
required this .canisterId,
137
139
this .rootKey,
138
140
this .maxAgeInMinutes = 5 ,
139
- }) : assert (maxAgeInMinutes <= 5 ),
141
+ }) : assert (maxAgeInMinutes == null || maxAgeInMinutes <= 5 ),
140
142
cert = Cert .fromJson (cborDecode (cert));
141
143
142
144
final Cert cert;
143
145
final Principal canisterId;
144
146
final BinaryBlob ? rootKey;
145
- final int maxAgeInMinutes;
147
+ final int ? maxAgeInMinutes;
146
148
147
149
bool verified = false ;
148
150
@@ -155,6 +157,7 @@ class Certificate {
155
157
}
156
158
157
159
Future <bool > verify () async {
160
+ _verifyCertTime ();
158
161
final rootHash = await reconstruct (cert.tree);
159
162
final derKey = await _checkDelegation (cert.delegation);
160
163
final key = extractDER (derKey);
@@ -171,6 +174,35 @@ class Certificate {
171
174
}
172
175
}
173
176
177
+ void _verifyCertTime () {
178
+ final timeLookup = lookupEx (['time' ]);
179
+ if (timeLookup == null ) {
180
+ throw UnverifiedCertificateError ('Certificate does not contain a time.' );
181
+ }
182
+ final now = DateTime .now ();
183
+ final lebDecodedTime = lebDecode (BufferPipe (timeLookup));
184
+ final time = DateTime .fromMicrosecondsSinceEpoch (
185
+ (lebDecodedTime / BigInt .from (1000 )).toInt (),
186
+ );
187
+ // Signed time is after 5 minutes from now.
188
+ if (time.isAfter (now.add (const Duration (minutes: 5 )))) {
189
+ throw UnverifiedCertificateError (
190
+ 'Certificate is signed more than 5 minutes in the future.\n '
191
+ '|-- Certificate time: ${time .toIso8601String ()}\n '
192
+ '|-- Current time: ${now .toIso8601String ()}' ,
193
+ );
194
+ }
195
+ // Signed time is before [maxAgeInMinutes] minutes.
196
+ if (maxAgeInMinutes != null &&
197
+ time.isBefore (now.subtract (Duration (minutes: maxAgeInMinutes! )))) {
198
+ throw UnverifiedCertificateError (
199
+ 'Certificate is signed more than $maxAgeInMinutes minutes in the past.\n '
200
+ '|-- Certificate time: ${time .toIso8601String ()}\n '
201
+ '|-- Current time: ${now .toIso8601String ()}' ,
202
+ );
203
+ }
204
+ }
205
+
174
206
Future <Uint8List > _checkDelegation (CertDelegation ? d) async {
175
207
if (d == null ) {
176
208
if (rootKey == null ) {
@@ -184,6 +216,7 @@ class Certificate {
184
216
cert: d.certificate,
185
217
canisterId: canisterId,
186
218
rootKey: rootKey,
219
+ maxAgeInMinutes: null , // Do not check max age for delegation certificates
187
220
);
188
221
if (! (await cert.verify ())) {
189
222
throw UnverifiedCertificateError ('Fail to verify certificate.' );
0 commit comments