@@ -21,6 +21,8 @@ contract CertManager is ICertManager {
2121 error InvalidExtension ();
2222 error InvalidBasicConstraints ();
2323 error InvalidSubjectPublicKey ();
24+ error InvalidCertAlgorithm ();
25+ error InvalidCertVersion ();
2426 error UnsupportedCriticalExtension ();
2527 error NotOwner ();
2628 error NotRevoker ();
@@ -306,7 +308,7 @@ contract CertManager is ICertManager {
306308
307309 Asn1Ptr root = certificate.root ();
308310 _requireAsn1Tag (certificate, root, 0x30 );
309- require (root.totalLength () == certificate.length , " invalid cert length " );
311+ if (root.totalLength () != certificate.length ) revert Asn1Decode. InvalidAsn1Length ( );
310312 Asn1Ptr tbsCertPtr = certificate.firstChildOf (root);
311313 _requireAsn1Tag (certificate, tbsCertPtr, 0x30 );
312314 return certificate.keccak (tbsCertPtr.header (), tbsCertPtr.totalLength ());
@@ -329,7 +331,7 @@ contract CertManager is ICertManager {
329331 bytes memory signatureHints
330332 ) internal view returns (VerifiedCert memory cert , bytes32 identity ) {
331333 Asn1Ptr root = certificate.root ();
332- require (root.totalLength () == certificate.length , " invalid cert length " );
334+ if (root.totalLength () != certificate.length ) revert Asn1Decode. InvalidAsn1Length ( );
333335 Asn1Ptr tbsCertPtr = certificate.firstChildOf (root);
334336 (uint64 notAfter , int64 maxPathLen , bytes32 issuerHash , bytes32 subjectHash , bytes memory pubKey ) =
335337 _parseTbs (certificate, tbsCertPtr, ca);
@@ -373,20 +375,20 @@ contract CertManager is ICertManager {
373375 _requireAsn1Tag (certificate, ptr, 0x30 );
374376 Asn1Ptr versionPtr = certificate.firstChildOf (ptr);
375377 _requireAsn1Tag (certificate, versionPtr, 0xa0 );
376- Asn1Ptr vPtr = certificate.firstChildOf (versionPtr);
377- Asn1Ptr serialPtr = certificate.nextSiblingOf (versionPtr);
378- Asn1Ptr sigAlgoPtr = certificate.nextSiblingOf (serialPtr);
378+ Asn1Ptr sigAlgoPtr = certificate.nextSiblingOf (certificate.nextSiblingOf (versionPtr));
379379 _requireAsn1Tag (certificate, sigAlgoPtr, 0x30 );
380380
381- require (certificate.keccak (sigAlgoPtr.content (), sigAlgoPtr.length ()) == CERT_ALGO_OID, "invalid cert sig algo " );
382- uint256 version = certificate.uintAt (vPtr);
381+ if (certificate.keccak (sigAlgoPtr.content (), sigAlgoPtr.length ()) != CERT_ALGO_OID) {
382+ revert InvalidCertAlgorithm ();
383+ }
383384 // as extensions are used in cert, version should be 3 (value 2) as per https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.1
384- require (version == 2 , " version should be 3 " );
385+ if (certificate. uintAt (certificate. firstChildOf (versionPtr)) != 2 ) revert InvalidCertVersion ( );
385386
386- (notAfter, maxPathLen, issuerHash, subjectHash, pubKey) = _parseTbsInner (certificate, sigAlgoPtr, ca);
387+ (notAfter, maxPathLen, issuerHash, subjectHash, pubKey) =
388+ _parseTbsInner (certificate, sigAlgoPtr, ca, ptr.content () + ptr.length ());
387389 }
388390
389- function _parseTbsInner (bytes memory certificate , Asn1Ptr sigAlgoPtr , bool ca )
391+ function _parseTbsInner (bytes memory certificate , Asn1Ptr sigAlgoPtr , bool ca , uint256 tbsEnd )
390392 internal
391393 view
392394 returns (uint64 notAfter , int64 maxPathLen , bytes32 issuerHash , bytes32 subjectHash , bytes memory pubKey )
@@ -411,6 +413,7 @@ contract CertManager is ICertManager {
411413 // skip optional subjectUniqueID
412414 extensionsPtr = certificate.nextSiblingOf (extensionsPtr);
413415 }
416+ if (extensionsPtr.content () + extensionsPtr.length () != tbsEnd) revert Asn1Decode.InvalidAsn1Length ();
414417
415418 notAfter = _verifyValidity (certificate, validityPtr);
416419 maxPathLen = _verifyExtensions (certificate, extensionsPtr, ca);
@@ -465,40 +468,48 @@ contract CertManager is ICertManager {
465468 returns (int64 maxPathLen )
466469 {
467470 if (certificate[extensionsPtr.header ()] != 0xa3 ) revert InvalidExtension ();
471+ uint256 end = extensionsPtr.content () + extensionsPtr.length ();
468472 extensionsPtr = certificate.firstChildOf (extensionsPtr);
469473 _requireAsn1Tag (certificate, extensionsPtr, 0x30 );
474+ if (extensionsPtr.content () + extensionsPtr.length () != end) revert InvalidExtension ();
470475 Asn1Ptr extensionPtr = certificate.firstChildOf (extensionsPtr);
471- uint256 end = extensionsPtr.content () + extensionsPtr.length ();
472476 bool basicConstraintsFound = false ;
473477 bool keyUsageFound = false ;
474478 maxPathLen = - 1 ;
475479
476480 while (true ) {
481+ uint256 extensionEnd = extensionPtr.content () + extensionPtr.length ();
482+ if (extensionEnd > end) revert InvalidExtension ();
477483 _requireAsn1Tag (certificate, extensionPtr, 0x30 );
478484 Asn1Ptr oidPtr = certificate.firstChildOf (extensionPtr);
479485 bytes32 oid = certificate.keccak (oidPtr.content (), oidPtr.length ());
480- Asn1Ptr valuePtr = certificate.nextSiblingOf (oidPtr);
481486 bool recognized = oid == BASIC_CONSTRAINTS_OID || oid == KEY_USAGE_OID;
482487
488+ Asn1Ptr valuePtr = certificate.nextSiblingOf (oidPtr);
489+
483490 if (certificate[valuePtr.header ()] == 0x01 ) {
484491 if (valuePtr.length () != 1 ) revert InvalidExtension ();
485492 if (! recognized && certificate[valuePtr.content ()] != 0x00 ) revert UnsupportedCriticalExtension ();
486493 valuePtr = certificate.nextSiblingOf (valuePtr);
487494 }
488495
496+ if (valuePtr.content () + valuePtr.length () != extensionEnd) revert InvalidExtension ();
497+
489498 if (recognized) {
490499 valuePtr = certificate.octetString (valuePtr);
491500
492501 if (oid == BASIC_CONSTRAINTS_OID) {
502+ if (basicConstraintsFound) revert InvalidExtension ();
493503 basicConstraintsFound = true ;
494504 maxPathLen = _verifyBasicConstraintsExtension (certificate, valuePtr, ca);
495505 } else {
506+ if (keyUsageFound) revert InvalidExtension ();
496507 keyUsageFound = true ;
497508 _verifyKeyUsageExtension (certificate, valuePtr, ca);
498509 }
499510 }
500511
501- if (extensionPtr. content () + extensionPtr. length () == end) {
512+ if (extensionEnd == end) {
502513 break ;
503514 }
504515 extensionPtr = certificate.nextSiblingOf (extensionPtr);
@@ -562,9 +573,9 @@ contract CertManager is ICertManager {
562573 // X.509 KeyUsage bits are MSB-first. bitstringUintAt keeps the first KeyUsage octet in the
563574 // low byte, so these masks continue to target the same bits for one- or multi-octet values.
564575 if (ca) {
565- require (value & 0x04 == 0x04 , " CertSign must be present " );
576+ if (value & 0x04 != 0x04 ) revert InvalidExtension ( );
566577 } else {
567- require (value & 0x80 == 0x80 , " DigitalSignature must be present " );
578+ if (value & 0x80 != 0x80 ) revert InvalidExtension ( );
568579 }
569580 }
570581
@@ -576,9 +587,11 @@ contract CertManager is ICertManager {
576587 ) internal view {
577588 Asn1Ptr sigAlgoPtr = certificate.nextSiblingOf (ptr);
578589 _requireAsn1Tag (certificate, sigAlgoPtr, 0x30 );
579- require (certificate.keccak (sigAlgoPtr.content (), sigAlgoPtr.length ()) == CERT_ALGO_OID, "invalid cert sig algo " );
590+ if (certificate.keccak (sigAlgoPtr.content (), sigAlgoPtr.length ()) != CERT_ALGO_OID) {
591+ revert InvalidCertAlgorithm ();
592+ }
580593 Asn1Ptr sigPtr = certificate.nextSiblingOf (sigAlgoPtr);
581- require (sigPtr.header () + sigPtr.totalLength () == certificate.length , " trailing cert fields " );
594+ if (sigPtr.header () + sigPtr.totalLength () != certificate.length ) revert Asn1Decode. InvalidAsn1Length ( );
582595
583596 bytes memory hash = Sha2Ext.sha384 (certificate, ptr.header (), ptr.totalLength ());
584597 bytes memory sigPacked = _certSignature (certificate, sigPtr);
0 commit comments