@@ -508,6 +508,47 @@ def test_tbs_bytes_reflects_current_extensions
508508 assert_equal false , seq . value . any? { |val | val . tag_class == :CONTEXT_SPECIFIC && val . tag == 3 }
509509 end
510510
511+ def test_tbs_bytes_reflects_extensions_removal
512+ cert = File . expand_path ( 'digicert.pem' , File . dirname ( __FILE__ ) )
513+ cert = OpenSSL ::X509 ::Certificate . new ( File . read ( cert ) )
514+
515+ assert cert . extensions . size > 1
516+ original = cert . tbs_bytes
517+
518+ dup = cert . dup
519+ removed_oid = cert . extensions . first . oid
520+ dup . extensions = dup . extensions . reject { |ext | ext . oid == removed_oid }
521+
522+ mutated = dup . tbs_bytes
523+ refute_equal original , mutated , 'tbs_bytes must reflect extensions= mutation'
524+ assert mutated . bytesize < original . bytesize , 'removing an extension must shrink tbs_bytes'
525+
526+ expected = cert . extensions . map ( &:oid ) . reject { |oid | oid == removed_oid }
527+ . map { |oid | OpenSSL ::ASN1 ::ObjectId . new ( oid ) . oid } # OID name -> identifier
528+ assert_equal expected , tbs_extension_oids ( mutated )
529+ end
530+
531+ # Extract the extension OIDs (in order) from a DER-encoded TBSCertificate
532+ def tbs_extension_oids ( tbs_der )
533+ tbs = OpenSSL ::ASN1 . decode ( tbs_der )
534+ assert_equal OpenSSL ::ASN1 ::Sequence , tbs . class
535+
536+ holder = tbs . value . find do |e |
537+ e . respond_to? ( :tag ) && e . tag == 3 && e . tag_class == :CONTEXT_SPECIFIC
538+ end
539+
540+ holder ? holder . value [ 0 ] . value . map { |ext | ext . value [ 0 ] . oid } : [ ]
541+ end
542+
543+ def test_tbs_bytes_unchanged_after_assigning_same_extensions
544+ cert = File . expand_path ( 'digicert.pem' , File . dirname ( __FILE__ ) )
545+ cert = OpenSSL ::X509 ::Certificate . new ( File . read ( cert ) )
546+
547+ dup = cert . dup
548+ dup . extensions = dup . extensions # reassign the same set
549+ assert_equal cert . tbs_bytes , dup . tbs_bytes
550+ end
551+
511552 def test_eq
512553 now = Time . now
513554 ca = OpenSSL ::X509 ::Name . parse ( '/DC=org/DC=ruby-lang/CN=CA' )
0 commit comments