@@ -349,40 +349,51 @@ contract CertManager is ICertManager {
349349 view
350350 returns (uint64 notAfter , int64 maxPathLen , bytes32 issuerHash , bytes32 subjectHash , bytes memory pubKey )
351351 {
352+ Asn1Ptr sigAlgoPtr = _verifyTbsHeader (certificate, ptr);
353+
354+ (notAfter, maxPathLen, issuerHash, subjectHash, pubKey) =
355+ _parseTbsInner (certificate, sigAlgoPtr, ca, ptr.content () + ptr.length ());
356+ }
357+
358+ function _verifyTbsHeader (bytes memory certificate , Asn1Ptr ptr ) internal pure returns (Asn1Ptr sigAlgoPtr ) {
352359 Asn1Ptr versionPtr = certificate.firstChildOf (ptr);
353360 Asn1Ptr vPtr = certificate.firstChildOf (versionPtr);
354- Asn1Ptr serialPtr = certificate.nextSiblingOf (versionPtr);
355- Asn1Ptr sigAlgoPtr = certificate.nextSiblingOf (serialPtr);
361+ sigAlgoPtr = certificate.nextSiblingOf (certificate.nextSiblingOf (versionPtr));
356362
357363 require (certificate.keccak (sigAlgoPtr.content (), sigAlgoPtr.length ()) == CERT_ALGO_OID, "invalid cert sig algo " );
358364 uint256 version = certificate.uintAt (vPtr);
359365 // 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
360366 require (version == 2 , "version should be 3 " );
361-
362- (notAfter, maxPathLen, issuerHash, subjectHash, pubKey) = _parseTbsInner (certificate, sigAlgoPtr, ca);
363367 }
364368
365- function _parseTbsInner (bytes memory certificate , Asn1Ptr sigAlgoPtr , bool ca )
369+ function _parseTbsInner (bytes memory certificate , Asn1Ptr sigAlgoPtr , bool ca , uint256 tbsEnd )
366370 internal
367371 view
368372 returns (uint64 notAfter , int64 maxPathLen , bytes32 issuerHash , bytes32 subjectHash , bytes memory pubKey )
369373 {
370374 Asn1Ptr issuerPtr = certificate.nextSiblingOf (sigAlgoPtr);
375+ _requireAsn1NodeWithin (issuerPtr, tbsEnd);
371376 issuerHash = certificate.keccak (issuerPtr.content (), issuerPtr.length ());
372377 Asn1Ptr validityPtr = certificate.nextSiblingOf (issuerPtr);
378+ _requireAsn1NodeWithin (validityPtr, tbsEnd);
373379 Asn1Ptr subjectPtr = certificate.nextSiblingOf (validityPtr);
380+ _requireAsn1NodeWithin (subjectPtr, tbsEnd);
374381 subjectHash = certificate.keccak (subjectPtr.content (), subjectPtr.length ());
375382 Asn1Ptr subjectPublicKeyInfoPtr = certificate.nextSiblingOf (subjectPtr);
383+ _requireAsn1NodeWithin (subjectPublicKeyInfoPtr, tbsEnd);
376384 Asn1Ptr extensionsPtr = certificate.nextSiblingOf (subjectPublicKeyInfoPtr);
377385
378386 if (certificate[extensionsPtr.header ()] == 0x81 ) {
379387 // skip optional issuerUniqueID
388+ _requireAsn1NodeWithin (extensionsPtr, tbsEnd);
380389 extensionsPtr = certificate.nextSiblingOf (extensionsPtr);
381390 }
382391 if (certificate[extensionsPtr.header ()] == 0x82 ) {
383392 // skip optional subjectUniqueID
393+ _requireAsn1NodeWithin (extensionsPtr, tbsEnd);
384394 extensionsPtr = certificate.nextSiblingOf (extensionsPtr);
385395 }
396+ require (_requireAsn1NodeWithin (extensionsPtr, tbsEnd) == tbsEnd, "trailing tbs fields " );
386397
387398 notAfter = _verifyValidity (certificate, validityPtr);
388399 maxPathLen = _verifyExtensions (certificate, extensionsPtr, ca);
@@ -442,30 +453,40 @@ contract CertManager is ICertManager {
442453 maxPathLen = - 1 ;
443454
444455 while (true ) {
456+ uint256 extensionEnd = _requireAsn1NodeWithin (extensionPtr, end);
445457 Asn1Ptr oidPtr = certificate.firstChildOf (extensionPtr);
458+ _requireAsn1NodeWithin (oidPtr, extensionEnd);
446459 bytes32 oid = certificate.keccak (oidPtr.content (), oidPtr.length ());
447460
448- if (oid == BASIC_CONSTRAINTS_OID || oid == KEY_USAGE_OID) {
449- Asn1Ptr valuePtr = certificate. nextSiblingOf (oidPtr );
461+ Asn1Ptr valuePtr = certificate. nextSiblingOf (oidPtr);
462+ _requireAsn1NodeWithin ( valuePtr, extensionEnd );
450463
451- if (certificate[valuePtr.header ()] == 0x01 ) {
452- // skip optional critical bool
453- require (valuePtr.length () == 1 , "invalid critical bool value " );
454- valuePtr = certificate.nextSiblingOf (valuePtr);
455- }
464+ if (certificate[valuePtr.header ()] == 0x01 ) {
465+ // skip optional critical bool
466+ require (valuePtr.length () == 1 , "invalid critical bool value " );
467+ valuePtr = certificate.nextSiblingOf (valuePtr);
468+ _requireAsn1NodeWithin (valuePtr, extensionEnd);
469+ }
456470
457- valuePtr = certificate.octetString (valuePtr);
471+ require (_requireAsn1NodeWithin (valuePtr, extensionEnd) == extensionEnd, "trailing extension fields " );
472+
473+ if (oid == BASIC_CONSTRAINTS_OID || oid == KEY_USAGE_OID) {
474+ Asn1Ptr valueNodePtr = valuePtr;
475+
476+ valuePtr = certificate.octetString (valueNodePtr);
458477
459478 if (oid == BASIC_CONSTRAINTS_OID) {
479+ require (! basicConstraintsFound, "duplicate basicConstraints " );
460480 basicConstraintsFound = true ;
461481 maxPathLen = _verifyBasicConstraintsExtension (certificate, valuePtr, ca);
462482 } else {
483+ require (! keyUsageFound, "duplicate keyUsage " );
463484 keyUsageFound = true ;
464485 _verifyKeyUsageExtension (certificate, valuePtr, ca);
465486 }
466487 }
467488
468- if (extensionPtr. content () + extensionPtr. length () == end) {
489+ if (extensionEnd == end) {
469490 break ;
470491 }
471492 extensionPtr = certificate.nextSiblingOf (extensionPtr);
@@ -526,6 +547,11 @@ contract CertManager is ICertManager {
526547 require (childEnd <= parentEnd, "basicConstraints out of bounds " );
527548 }
528549
550+ function _requireAsn1NodeWithin (Asn1Ptr ptr , uint256 parentEnd ) internal pure returns (uint256 nodeEnd ) {
551+ nodeEnd = ptr.header () + ptr.totalLength ();
552+ require (nodeEnd <= parentEnd, "ASN.1 node out of bounds " );
553+ }
554+
529555 function _verifyKeyUsageExtension (bytes memory certificate , Asn1Ptr valuePtr , bool ca ) internal pure {
530556 uint256 value = certificate.bitstringUintAt (valuePtr);
531557 // X.509 KeyUsage bits are MSB-first. bitstringUintAt keeps the first KeyUsage octet in the
0 commit comments