@@ -17,9 +17,12 @@ contract CertManager is ICertManager {
1717 using LibAsn1Ptr for Asn1Ptr;
1818 using LibBytes for bytes ;
1919
20+ error InvalidAsn1Tag ();
2021 error InvalidExtension ();
2122 error InvalidBasicConstraints ();
2223 error InvalidSubjectPublicKey ();
24+ error InvalidCertAlgorithm ();
25+ error InvalidCertVersion ();
2326 error UnsupportedCriticalExtension ();
2427 error NotOwner ();
2528 error NotRevoker ();
@@ -174,7 +177,10 @@ contract CertManager is ICertManager {
174177 /// {revokeCerts}; the same value is recorded on-chain when the cert is first verified, so a
175178 /// revocation applies to every byte-encoding of that certificate. Reverts on malformed DER.
176179 function computeCertId (bytes memory cert ) external pure returns (bytes32 ) {
177- Asn1Ptr tbsCertPtr = cert.firstChildOf (cert.root ());
180+ Asn1Ptr root = cert.root ();
181+ _requireAsn1Tag (cert, root, 0x30 );
182+ Asn1Ptr tbsCertPtr = cert.firstChildOf (root);
183+ _requireAsn1Tag (cert, tbsCertPtr, 0x30 );
178184 return _certIdentity (cert, tbsCertPtr);
179185 }
180186
@@ -301,11 +307,17 @@ contract CertManager is ICertManager {
301307 }
302308
303309 Asn1Ptr root = certificate.root ();
310+ _requireAsn1Tag (certificate, root, 0x30 );
304311 require (root.totalLength () == certificate.length , "invalid cert length " );
305312 Asn1Ptr tbsCertPtr = certificate.firstChildOf (root);
313+ _requireAsn1Tag (certificate, tbsCertPtr, 0x30 );
306314 return certificate.keccak (tbsCertPtr.header (), tbsCertPtr.totalLength ());
307315 }
308316
317+ function _requireAsn1Tag (bytes memory der , Asn1Ptr ptr , bytes1 tag ) internal pure {
318+ if (der[ptr.header ()] != tag) revert InvalidAsn1Tag ();
319+ }
320+
309321 function _isPinnedRootAlias (bytes32 certHash , VerifiedCert memory cert ) internal pure returns (bool ) {
310322 return certHash != ROOT_CA_CERT_HASH && cert.ca && cert.subjectHash == ROOT_CA_CERT_SUBJECT_HASH
311323 && cert.pubKey.length == ROOT_CA_CERT_PUB_KEY.length
@@ -367,38 +379,48 @@ contract CertManager is ICertManager {
367379 }
368380
369381 function _verifyTbsHeader (bytes memory certificate , Asn1Ptr ptr ) internal pure returns (Asn1Ptr sigAlgoPtr ) {
382+ _requireAsn1Tag (certificate, ptr, 0x30 );
370383 Asn1Ptr versionPtr = certificate.firstChildOf (ptr);
384+ _requireAsn1Tag (certificate, versionPtr, 0xa0 );
371385 Asn1Ptr vPtr = certificate.firstChildOf (versionPtr);
372- sigAlgoPtr = certificate.nextSiblingOf (certificate.nextSiblingOf (versionPtr));
386+ Asn1Ptr serialPtr = certificate.nextSiblingOf (versionPtr);
387+ sigAlgoPtr = certificate.nextSiblingOf (serialPtr);
388+ _requireAsn1Tag (certificate, sigAlgoPtr, 0x30 );
373389
374- require (certificate.keccak (sigAlgoPtr.content (), sigAlgoPtr.length ()) == CERT_ALGO_OID, "invalid cert sig algo " );
390+ if (certificate.keccak (sigAlgoPtr.content (), sigAlgoPtr.length ()) != CERT_ALGO_OID) {
391+ revert InvalidCertAlgorithm ();
392+ }
375393 uint256 version = certificate.uintAt (vPtr);
376394 // 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
377- require (version == 2 , " version should be 3 " );
395+ if (version != 2 ) revert InvalidCertVersion ( );
378396 }
379397
380398 function _parseTbsInner (bytes memory certificate , Asn1Ptr sigAlgoPtr , bool ca , uint256 tbsEnd )
381399 internal
382400 view
383401 returns (uint64 notAfter , int64 maxPathLen , bytes32 issuerHash , bytes32 subjectHash , bytes memory pubKey )
384402 {
385- Asn1Ptr issuerPtr = _nextSiblingWithin (certificate, sigAlgoPtr, tbsEnd);
403+ Asn1Ptr issuerPtr = certificate.nextSiblingOf (sigAlgoPtr);
404+ _requireAsn1Tag (certificate, issuerPtr, 0x30 );
386405 issuerHash = certificate.keccak (issuerPtr.content (), issuerPtr.length ());
387- Asn1Ptr validityPtr = _nextSiblingWithin (certificate, issuerPtr, tbsEnd);
388- Asn1Ptr subjectPtr = _nextSiblingWithin (certificate, validityPtr, tbsEnd);
406+ Asn1Ptr validityPtr = certificate.nextSiblingOf (issuerPtr);
407+ _requireAsn1Tag (certificate, validityPtr, 0x30 );
408+ Asn1Ptr subjectPtr = certificate.nextSiblingOf (validityPtr);
409+ _requireAsn1Tag (certificate, subjectPtr, 0x30 );
389410 subjectHash = certificate.keccak (subjectPtr.content (), subjectPtr.length ());
390- Asn1Ptr subjectPublicKeyInfoPtr = _nextSiblingWithin (certificate, subjectPtr, tbsEnd);
391- Asn1Ptr extensionsPtr = _nextSiblingWithin (certificate, subjectPublicKeyInfoPtr, tbsEnd);
411+ Asn1Ptr subjectPublicKeyInfoPtr = certificate.nextSiblingOf (subjectPtr);
412+ _requireAsn1Tag (certificate, subjectPublicKeyInfoPtr, 0x30 );
413+ Asn1Ptr extensionsPtr = certificate.nextSiblingOf (subjectPublicKeyInfoPtr);
392414
393415 if (certificate[extensionsPtr.header ()] == 0x81 ) {
394416 // skip optional issuerUniqueID
395- extensionsPtr = _nextSiblingWithin ( certificate, extensionsPtr, tbsEnd );
417+ extensionsPtr = certificate. nextSiblingOf ( extensionsPtr);
396418 }
397419 if (certificate[extensionsPtr.header ()] == 0x82 ) {
398420 // skip optional subjectUniqueID
399- extensionsPtr = _nextSiblingWithin ( certificate, extensionsPtr, tbsEnd );
421+ extensionsPtr = certificate. nextSiblingOf ( extensionsPtr);
400422 }
401- require (_requireAsn1NodeWithin (extensionsPtr, tbsEnd) == tbsEnd, " trailing tbs fields " );
423+ if (_requireAsn1NodeWithin (extensionsPtr, tbsEnd) != tbsEnd) revert Asn1Decode. InvalidAsn1Length ( );
402424
403425 notAfter = _verifyValidity (certificate, validityPtr);
404426 maxPathLen = _verifyExtensions (certificate, extensionsPtr, ca);
@@ -411,6 +433,7 @@ contract CertManager is ICertManager {
411433 returns (bytes memory subjectPubKey )
412434 {
413435 Asn1Ptr pubKeyAlgoPtr = certificate.firstChildOf (subjectPublicKeyInfoPtr);
436+ _requireAsn1Tag (certificate, pubKeyAlgoPtr, 0x30 );
414437 Asn1Ptr pubKeyAlgoIdPtr = certificate.firstChildOf (pubKeyAlgoPtr);
415438 Asn1Ptr algoParamsPtr = certificate.nextSiblingOf (pubKeyAlgoIdPtr);
416439 Asn1Ptr subjectPublicKeyPtr = certificate.nextSiblingOf (pubKeyAlgoPtr);
@@ -453,15 +476,17 @@ contract CertManager is ICertManager {
453476 {
454477 if (certificate[extensionsPtr.header ()] != 0xa3 ) revert InvalidExtension ();
455478 extensionsPtr = certificate.firstChildOf (extensionsPtr);
479+ _requireAsn1Tag (certificate, extensionsPtr, 0x30 );
456480 uint256 end = extensionsPtr.content () + extensionsPtr.length ();
457- Asn1Ptr extensionPtr = _firstChildWithin ( certificate, extensionsPtr, end );
481+ Asn1Ptr extensionPtr = certificate. firstChildOf ( extensionsPtr);
458482 bool basicConstraintsFound = false ;
459483 bool keyUsageFound = false ;
460484 maxPathLen = - 1 ;
461485
462486 while (true ) {
463487 uint256 extensionEnd = _requireAsn1NodeWithin (extensionPtr, end);
464- Asn1Ptr oidPtr = _firstChildWithin (certificate, extensionPtr, extensionEnd);
488+ _requireAsn1Tag (certificate, extensionPtr, 0x30 );
489+ Asn1Ptr oidPtr = certificate.firstChildOf (extensionPtr);
465490 bytes32 oid = certificate.keccak (oidPtr.content (), oidPtr.length ());
466491 bool recognized = oid == BASIC_CONSTRAINTS_OID || oid == KEY_USAGE_OID;
467492
@@ -473,17 +498,17 @@ contract CertManager is ICertManager {
473498 valuePtr = _nextSiblingWithin (certificate, valuePtr, extensionEnd);
474499 }
475500
476- require (_requireAsn1NodeWithin (valuePtr, extensionEnd) == extensionEnd, " trailing extension fields " );
501+ if (_requireAsn1NodeWithin (valuePtr, extensionEnd) != extensionEnd) revert InvalidExtension ( );
477502
478503 if (recognized) {
479504 valuePtr = certificate.octetString (valuePtr);
480505
481506 if (oid == BASIC_CONSTRAINTS_OID) {
482- require ( ! basicConstraintsFound, " duplicate basicConstraints " );
507+ if ( basicConstraintsFound) revert InvalidExtension ( );
483508 basicConstraintsFound = true ;
484509 maxPathLen = _verifyBasicConstraintsExtension (certificate, valuePtr, ca);
485510 } else {
486- require ( ! keyUsageFound, " duplicate keyUsage " );
511+ if ( keyUsageFound) revert InvalidExtension ( );
487512 keyUsageFound = true ;
488513 _verifyKeyUsageExtension (certificate, valuePtr, ca);
489514 }
@@ -550,12 +575,7 @@ contract CertManager is ICertManager {
550575
551576 function _requireAsn1NodeWithin (Asn1Ptr ptr , uint256 parentEnd ) internal pure returns (uint256 nodeEnd ) {
552577 nodeEnd = ptr.header () + ptr.totalLength ();
553- require (nodeEnd <= parentEnd, "ASN.1 node out of bounds " );
554- }
555-
556- function _firstChildWithin (bytes memory der , Asn1Ptr ptr , uint256 parentEnd ) internal pure returns (Asn1Ptr child ) {
557- child = der.firstChildOf (ptr);
558- _requireAsn1NodeWithin (child, parentEnd);
578+ if (nodeEnd > parentEnd) revert Asn1Decode.InvalidAsn1Length ();
559579 }
560580
561581 function _nextSiblingWithin (bytes memory der , Asn1Ptr ptr , uint256 parentEnd )
@@ -585,7 +605,10 @@ contract CertManager is ICertManager {
585605 bytes memory signatureHints
586606 ) internal view {
587607 Asn1Ptr sigAlgoPtr = certificate.nextSiblingOf (ptr);
588- require (certificate.keccak (sigAlgoPtr.content (), sigAlgoPtr.length ()) == CERT_ALGO_OID, "invalid cert sig algo " );
608+ _requireAsn1Tag (certificate, sigAlgoPtr, 0x30 );
609+ if (certificate.keccak (sigAlgoPtr.content (), sigAlgoPtr.length ()) != CERT_ALGO_OID) {
610+ revert InvalidCertAlgorithm ();
611+ }
589612 Asn1Ptr sigPtr = certificate.nextSiblingOf (sigAlgoPtr);
590613 require (sigPtr.header () + sigPtr.totalLength () == certificate.length , "trailing cert fields " );
591614
0 commit comments