@@ -606,6 +606,246 @@ public void testSignatureSchemes()
606606 }
607607 }
608608
609+ /**
610+ * Test SSLSession.hashCode().
611+ *
612+ * Verifies that WolfSSLImplementSSLSession declares its own hashCode()
613+ * method (not just inherited from Object). Tests hashCode consistency
614+ * and that different sessions produce different hash codes.
615+ */
616+ @ Test
617+ public void testSessionHashCode ()
618+ throws NoSuchAlgorithmException , KeyManagementException ,
619+ KeyStoreException , CertificateException , IOException ,
620+ NoSuchProviderException , UnrecoverableKeyException {
621+
622+ int ret ;
623+ SSLSession session ;
624+
625+ System .out .print ("\t Testing hashCode()" );
626+
627+ SSLContext ctx = tf .createSSLContext ("TLS" , engineProvider );
628+ SSLEngine client = ctx .createSSLEngine ("localhost" , 12345 );
629+ SSLEngine server = ctx .createSSLEngine ();
630+
631+ if (client == null || server == null ) {
632+ error ("\t \t ... failed" );
633+ fail ("failed to create engine" );
634+ return ;
635+ }
636+
637+ server .setUseClientMode (false );
638+ server .setNeedClientAuth (false );
639+ client .setUseClientMode (true );
640+
641+ ret = tf .testConnection (server , client , null , null , "Test hashCode" );
642+ if (ret != 0 ) {
643+ error ("\t \t ... failed" );
644+ fail ("failed to create connection" );
645+ return ;
646+ }
647+
648+ session = client .getSession ();
649+ if (session == null ) {
650+ error ("\t \t ... failed" );
651+ fail ("SSLEngine.getSession() returned null" );
652+ return ;
653+ }
654+
655+ /* Test that hashCode() method is declared in the session class
656+ * (not just inherited from Object). */
657+ try {
658+ session .getClass ().getDeclaredMethod ("hashCode" , new Class <?>[0 ]);
659+ } catch (NoSuchMethodException e ) {
660+ error ("\t \t ... failed" );
661+ fail ("SSLSession class does not declare hashCode() method" );
662+ return ;
663+ }
664+
665+ /* Test that hashCode() returns consistent value */
666+ int hash1 = session .hashCode ();
667+ int hash2 = session .hashCode ();
668+ if (hash1 != hash2 ) {
669+ error ("\t \t ... failed" );
670+ fail ("SSLSession.hashCode() not consistent: " +
671+ hash1 + " != " + hash2 );
672+ return ;
673+ }
674+
675+ /* Test that different session has different hashCode.
676+ * Create another connection */
677+ SSLContext ctx2 = tf .createSSLContext ("TLS" , engineProvider );
678+ SSLEngine client2 = ctx2 .createSSLEngine ("localhost" , 54321 );
679+ SSLEngine server2 = ctx2 .createSSLEngine ();
680+
681+ server2 .setUseClientMode (false );
682+ server2 .setNeedClientAuth (false );
683+ client2 .setUseClientMode (true );
684+
685+ ret = tf .testConnection (server2 , client2 , null , null ,
686+ "Test hashCode 2" );
687+ if (ret != 0 ) {
688+ error ("\t \t ... failed" );
689+ fail ("failed to create second connection" );
690+ return ;
691+ }
692+
693+ SSLSession session2 = client2 .getSession ();
694+ if (session2 == null ) {
695+ error ("\t \t ... failed" );
696+ fail ("Second SSLEngine.getSession() returned null" );
697+ return ;
698+ }
699+
700+ /* Test different sessions should have different hashCodes */
701+ int hash3 = session2 .hashCode ();
702+ if (hash1 == hash3 ) {
703+ /* Not a hard failure, just a warning since hashCode collisions
704+ * are technically allowed */
705+ System .out .println (" (warning: hash collision)" );
706+ }
707+
708+ pass ("\t \t ... passed" );
709+ }
710+
711+ @ Test
712+ public void testSessionEquals ()
713+ throws NoSuchAlgorithmException , KeyManagementException ,
714+ KeyStoreException , CertificateException , IOException ,
715+ NoSuchProviderException , UnrecoverableKeyException {
716+
717+ int ret ;
718+ SSLSession session ;
719+
720+ System .out .print ("\t Testing equals()" );
721+
722+ SSLContext ctx = tf .createSSLContext ("TLS" , engineProvider );
723+ SSLEngine client = ctx .createSSLEngine ("localhost" , 12345 );
724+ SSLEngine server = ctx .createSSLEngine ();
725+
726+ if (client == null || server == null ) {
727+ error ("\t \t ... failed" );
728+ fail ("failed to create engine" );
729+ return ;
730+ }
731+
732+ server .setUseClientMode (false );
733+ server .setNeedClientAuth (false );
734+ client .setUseClientMode (true );
735+
736+ ret = tf .testConnection (server , client , null , null , "Test equals" );
737+ if (ret != 0 ) {
738+ error ("\t \t ... failed" );
739+ fail ("failed to create connection" );
740+ return ;
741+ }
742+
743+ session = client .getSession ();
744+ if (session == null ) {
745+ error ("\t \t ... failed" );
746+ fail ("SSLEngine.getSession() returned null" );
747+ return ;
748+ }
749+
750+ /* Test that equals() method is declared in the session class
751+ * (not just inherited from Object). */
752+ try {
753+ session .getClass ().getDeclaredMethod ("equals" ,
754+ new Class <?>[] { Object .class });
755+ } catch (NoSuchMethodException e ) {
756+ error ("\t \t ... failed" );
757+ fail ("SSLSession class does not declare equals() method" );
758+ return ;
759+ }
760+
761+ /* Test reflexivity: session.equals(session) should be true */
762+ if (!session .equals (session )) {
763+ error ("\t \t ... failed" );
764+ fail ("SSLSession.equals() reflexivity failed" );
765+ return ;
766+ }
767+
768+ /* Test null: session.equals(null) should be false */
769+ if (session .equals (null )) {
770+ error ("\t \t ... failed" );
771+ fail ("SSLSession.equals(null) should return false" );
772+ return ;
773+ }
774+
775+ /* Test different type: session.equals(Object) should return false
776+ * when passed an incompatible type. This is intentional to verify
777+ * the equals() implementation handles type mismatches correctly. */
778+ Object differentType = "not a session" ;
779+ if (session .equals (differentType )) {
780+ error ("\t \t ... failed" );
781+ fail ("SSLSession.equals(Object) should return false for " +
782+ "incompatible type" );
783+ return ;
784+ }
785+
786+ /* Test hashCode/equals contract: equal objects must have same hash */
787+ if (session .equals (session ) &&
788+ session .hashCode () != session .hashCode ()) {
789+ error ("\t \t ... failed" );
790+ fail ("Equal sessions have different hashCodes" );
791+ return ;
792+ }
793+
794+ pass ("\t \t ... passed" );
795+ }
796+
797+ @ Test
798+ public void testSessionHashCodeBeforeHandshake ()
799+ throws NoSuchAlgorithmException , KeyManagementException ,
800+ KeyStoreException , CertificateException , IOException ,
801+ NoSuchProviderException , UnrecoverableKeyException {
802+
803+ System .out .print ("\t Testing hashCode() before HS" );
804+
805+ SSLContext ctx = tf .createSSLContext ("TLS" , engineProvider );
806+ SSLEngine engine = ctx .createSSLEngine ("localhost" , 12345 );
807+
808+ if (engine == null ) {
809+ error ("\t ... failed" );
810+ fail ("failed to create engine" );
811+ return ;
812+ }
813+
814+ engine .setUseClientMode (true );
815+
816+ /* Get session before handshake - may have null session ID */
817+ SSLSession session = engine .getSession ();
818+ if (session == null ) {
819+ /* Some implementations return null before handshake */
820+ pass ("\t ... passed (null session)" );
821+ return ;
822+ }
823+
824+ /* Test that hashCode() does not throw even if getId() returns
825+ * null or empty (session not yet established) */
826+ try {
827+ int hash = session .hashCode ();
828+ /* hashCode should work without throwing */
829+ } catch (Exception e ) {
830+ error ("\t ... failed" );
831+ fail ("hashCode() threw exception before handshake: " +
832+ e .getMessage ());
833+ return ;
834+ }
835+
836+ /* Test that equals() does not throw either */
837+ try {
838+ boolean eq = session .equals (session );
839+ } catch (Exception e ) {
840+ error ("\t ... failed" );
841+ fail ("equals() threw exception before handshake: " +
842+ e .getMessage ());
843+ return ;
844+ }
845+
846+ pass ("\t ... passed" );
847+ }
848+
609849 /**
610850 * Test SSLSocket.getSession() and calling methods on the
611851 * SSLSession retrieved. */
0 commit comments