@@ -796,4 +796,152 @@ def test_authority_info_access_ocsp_uris # GH-210
796796 assert_equal [ 'http://cacerts.digicert.com/DigiCertSHA2SecureServerCA.crt' ] , cert . ca_issuer_uris
797797 assert_not_match ( /#<OpenSSL::ASN1::/ , aia_ext . value )
798798 end
799+
800+ def test_dup_preserves_extensions
801+ rsa2048 = OpenSSL ::PKey ::RSA . new TEST_KEY_RSA2048
802+ ca = OpenSSL ::X509 ::Name . parse ( "/DC=org/DC=ruby-lang/CN=CA" )
803+
804+ ca_exts = [
805+ [ "basicConstraints" , "CA:TRUE" , true ] ,
806+ [ "keyUsage" , "keyCertSign, cRLSign" , true ] ,
807+ [ "subjectKeyIdentifier" , "hash" , false ] ,
808+ ]
809+
810+ now = Time . now
811+ cert = issue_cert ( ca , rsa2048 , 1 , ca_exts , nil , nil ,
812+ not_before : now , not_after : now + 3600 )
813+
814+ duped = cert . dup
815+
816+ assert_equal cert . extensions . size , duped . extensions . size ,
817+ "dup should preserve extensions"
818+ assert_equal cert . extensions . map ( &:oid ) . sort , duped . extensions . map ( &:oid ) . sort
819+ end
820+
821+ def test_dup_preserves_subject_and_issuer
822+ rsa2048 = OpenSSL ::PKey ::RSA . new TEST_KEY_RSA2048
823+ ca = OpenSSL ::X509 ::Name . parse ( "/DC=org/DC=ruby-lang/CN=CA" )
824+
825+ now = Time . now
826+ cert = issue_cert ( ca , rsa2048 , 42 , [ ] , nil , nil ,
827+ not_before : now , not_after : now + 3600 )
828+
829+ duped = cert . dup
830+
831+ assert_equal cert . subject . to_s , duped . subject . to_s
832+ assert_equal cert . issuer . to_s , duped . issuer . to_s
833+ assert_equal cert . serial , duped . serial
834+ assert_equal cert . version , duped . version
835+ assert_equal cert . not_before . to_i , duped . not_before . to_i
836+ assert_equal cert . not_after . to_i , duped . not_after . to_i
837+ end
838+
839+ def test_dup_produces_independent_copy
840+ rsa2048 = OpenSSL ::PKey ::RSA . new TEST_KEY_RSA2048
841+ ca = OpenSSL ::X509 ::Name . parse ( "/DC=org/DC=ruby-lang/CN=CA" )
842+
843+ ca_exts = [
844+ [ "basicConstraints" , "CA:TRUE" , true ] ,
845+ [ "subjectKeyIdentifier" , "hash" , false ] ,
846+ ]
847+
848+ now = Time . now
849+ cert = issue_cert ( ca , rsa2048 , 1 , ca_exts , nil , nil ,
850+ not_before : now , not_after : now + 3600 )
851+
852+ duped = cert . dup
853+
854+ # Modifying the dup's extensions should not affect the original
855+ duped . extensions = [ ]
856+ assert_equal 2 , cert . extensions . size ,
857+ "modifying duped cert's extensions should not affect original"
858+ end
859+
860+ def test_dup_to_der_matches_original
861+ rsa2048 = OpenSSL ::PKey ::RSA . new TEST_KEY_RSA2048
862+ ca = OpenSSL ::X509 ::Name . parse ( "/DC=org/DC=ruby-lang/CN=CA" )
863+
864+ ca_exts = [
865+ [ "basicConstraints" , "CA:TRUE" , true ] ,
866+ [ "keyUsage" , "keyCertSign, cRLSign" , true ] ,
867+ [ "subjectKeyIdentifier" , "hash" , false ] ,
868+ ]
869+
870+ now = Time . now
871+ cert = issue_cert ( ca , rsa2048 , 1 , ca_exts , nil , nil ,
872+ not_before : now , not_after : now + 3600 )
873+
874+ duped = cert . dup
875+
876+ assert_equal cert . to_der , duped . to_der
877+ end
878+
879+ def test_dup_preserves_live_subject_after_signed_cert_name_is_mutated
880+ rsa2048 = OpenSSL ::PKey ::RSA . new TEST_KEY_RSA2048
881+ ca = OpenSSL ::X509 ::Name . parse ( "/DC=org/DC=ruby-lang/CN=CA" )
882+
883+ now = Time . now
884+ cert = issue_cert ( ca , rsa2048 , 1 , [ ] , nil , nil ,
885+ not_before : now , not_after : now + 3600 )
886+
887+ cert . subject . add_entry ( "O" , "mutated" )
888+ duped = cert . dup
889+
890+ assert_equal cert . subject . to_a , duped . subject . to_a
891+ end
892+
893+ def test_dup_preserves_live_extensions_after_signed_cert_is_modified
894+ rsa2048 = OpenSSL ::PKey ::RSA . new TEST_KEY_RSA2048
895+ ca = OpenSSL ::X509 ::Name . parse ( "/DC=org/DC=ruby-lang/CN=CA" )
896+
897+ ca_exts = [
898+ [ "basicConstraints" , "CA:TRUE" , true ] ,
899+ [ "subjectKeyIdentifier" , "hash" , false ] ,
900+ ]
901+
902+ now = Time . now
903+ cert = issue_cert ( ca , rsa2048 , 1 , ca_exts , nil , nil ,
904+ not_before : now , not_after : now + 3600 )
905+
906+ cert . extensions = [ ]
907+ duped = cert . dup
908+
909+ assert_equal [ ] , duped . extensions . map ( &:oid )
910+ end
911+
912+ def test_dup_unsigned_cert_preserves_fields
913+ rsa2048 = OpenSSL ::PKey ::RSA . new TEST_KEY_RSA2048
914+
915+ cert = OpenSSL ::X509 ::Certificate . new
916+ cert . version = 2
917+ cert . serial = 99
918+ cert . subject = OpenSSL ::X509 ::Name . parse ( "/CN=unsigned" )
919+ cert . issuer = OpenSSL ::X509 ::Name . parse ( "/CN=issuer" )
920+ cert . not_before = Time . now
921+ cert . not_after = Time . now + 3600
922+ cert . public_key = rsa2048 . public_key
923+
924+ duped = cert . dup
925+
926+ assert_equal cert . subject . to_s , duped . subject . to_s
927+ assert_equal cert . issuer . to_s , duped . issuer . to_s
928+ assert_equal cert . serial , duped . serial
929+ assert_equal cert . version , duped . version
930+ assert_equal cert . public_key . to_der , duped . public_key . to_der
931+ end
932+
933+ def test_dup_unsigned_cert_deep_copies_names
934+ cert = OpenSSL ::X509 ::Certificate . new
935+ cert . subject = OpenSSL ::X509 ::Name . parse ( "/CN=unsigned" )
936+ cert . issuer = OpenSSL ::X509 ::Name . parse ( "/CN=issuer" )
937+
938+ duped = cert . dup
939+ duped . subject . add_entry ( "O" , "mutated" )
940+ duped . issuer . add_entry ( "O" , "mutated" )
941+
942+ assert_equal "/CN=unsigned" , cert . subject . to_s
943+ assert_equal "/CN=issuer" , cert . issuer . to_s
944+ assert_equal "/CN=unsigned/O=mutated" , duped . subject . to_s
945+ assert_equal "/CN=issuer/O=mutated" , duped . issuer . to_s
946+ end
799947end
0 commit comments