@@ -11,6 +11,7 @@ import (
11
11
"crypto/tls"
12
12
"crypto/x509"
13
13
"encoding/hex"
14
+ "encoding/pem"
14
15
"errors"
15
16
"fmt"
16
17
"io"
@@ -2486,6 +2487,272 @@ func TestSessionResume(t *testing.T) {
2486
2487
}
2487
2488
_ = res .c .Close ()
2488
2489
})
2490
+
2491
+ t .Run ("resumed client cert" , func (t * testing.T ) {
2492
+ ctx , cancel := context .WithTimeout (context .Background (), 10 * time .Second )
2493
+ defer cancel ()
2494
+
2495
+ type result struct {
2496
+ c * Conn
2497
+ err error
2498
+ }
2499
+ clientRes := make (chan result , 1 )
2500
+
2501
+ commonCert , err := selfsign .GenerateSelfSignedWithDNS ("example.com" )
2502
+
2503
+ certPool := x509 .NewCertPool ()
2504
+ certPool .AppendCertsFromPEM (pem .EncodeToMemory (& pem.Block {Type : "CERTIFICATE" , Bytes : commonCert .Certificate [0 ]}))
2505
+
2506
+ ss := & memSessStore {}
2507
+
2508
+ id , _ := hex .DecodeString ("9b9fc92255634d9fb109febed42166717bb8ded8c738ba71bc7f2a0d9dae0306" )
2509
+ secret , _ := hex .DecodeString ("2e942a37aca5241deb2295b5fcedac221c7078d2503d2b62aeb48c880d7da73c001238b708559686b9da6e829c05ead7" )
2510
+
2511
+ s := Session {ID : id , Secret : secret }
2512
+
2513
+ ca , cb := dpipe .Pipe ()
2514
+
2515
+ _ = ss .Set (id , s )
2516
+ _ = ss .Set ([]byte (ca .RemoteAddr ().String ()+ "_" + commonCert .Leaf .Subject .CommonName ), s )
2517
+
2518
+ go func () {
2519
+ config := & Config {
2520
+ CipherSuites : []CipherSuiteID {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 },
2521
+ ServerName : commonCert .Leaf .Subject .CommonName ,
2522
+ SessionStore : ss ,
2523
+ RootCAs : certPool ,
2524
+ Certificates : nil , // Client shouldn't need to send a cert to resume a session
2525
+ MTU : 100 ,
2526
+ }
2527
+ c , err := ClientWithContext (ctx , ca , config )
2528
+ clientRes <- result {c , err }
2529
+ }()
2530
+
2531
+ config := & Config {
2532
+ CipherSuites : []CipherSuiteID {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 },
2533
+ SessionStore : ss ,
2534
+ ClientCAs : certPool ,
2535
+ Certificates : []tls.Certificate {commonCert },
2536
+ MTU : 100 ,
2537
+ ClientAuth : RequireAndVerifyClientCert ,
2538
+ }
2539
+ server , err := testServer (ctx , cb , config , true )
2540
+ if err != nil {
2541
+ t .Fatalf ("TestSessionResume: Server failed(%v)" , err )
2542
+ }
2543
+
2544
+ actualSessionID := server .ConnectionState ().SessionID
2545
+ actualMasterSecret := server .ConnectionState ().masterSecret
2546
+ if ! bytes .Equal (actualSessionID , id ) {
2547
+ t .Errorf ("TestSessionResumetion: SessionID Mismatch: expected(%v) actual(%v)" , id , actualSessionID )
2548
+ }
2549
+ if ! bytes .Equal (actualMasterSecret , secret ) {
2550
+ t .Errorf ("TestSessionResumetion: masterSecret Mismatch: expected(%v) actual(%v)" , secret , actualMasterSecret )
2551
+ }
2552
+
2553
+ defer func () {
2554
+ _ = server .Close ()
2555
+ }()
2556
+
2557
+ res := <- clientRes
2558
+ if res .err != nil {
2559
+ t .Fatal (res .err )
2560
+ }
2561
+ _ = res .c .Close ()
2562
+ })
2563
+
2564
+ t .Run ("new session client cert" , func (t * testing.T ) {
2565
+ ctx , cancel := context .WithTimeout (context .Background (), 10 * time .Second )
2566
+ defer cancel ()
2567
+
2568
+ type result struct {
2569
+ c * Conn
2570
+ err error
2571
+ }
2572
+ clientRes := make (chan result , 1 )
2573
+
2574
+ commonCert , err := selfsign .GenerateSelfSignedWithDNS ("example.com" )
2575
+
2576
+ certPool := x509 .NewCertPool ()
2577
+ certPool .AppendCertsFromPEM (pem .EncodeToMemory (& pem.Block {Type : "CERTIFICATE" , Bytes : commonCert .Certificate [0 ]}))
2578
+
2579
+ s1 := & memSessStore {}
2580
+ s2 := & memSessStore {}
2581
+
2582
+ ca , cb := dpipe .Pipe ()
2583
+ go func () {
2584
+ config := & Config {
2585
+ ServerName : commonCert .Leaf .Subject .CommonName ,
2586
+ SessionStore : s1 ,
2587
+ RootCAs : certPool ,
2588
+ Certificates : []tls.Certificate {commonCert },
2589
+ }
2590
+ c , err := ClientWithContext (ctx , ca , config )
2591
+ clientRes <- result {c , err }
2592
+ }()
2593
+
2594
+ config := & Config {
2595
+ SessionStore : s2 ,
2596
+ ClientAuth : RequireAndVerifyClientCert ,
2597
+ ClientCAs : certPool ,
2598
+ Certificates : []tls.Certificate {commonCert },
2599
+ }
2600
+ server , err := testServer (ctx , cb , config , false )
2601
+ if err != nil {
2602
+ t .Fatalf ("TestSessionResumetion: Server failed(%v)" , err )
2603
+ }
2604
+
2605
+ actualSessionID := server .ConnectionState ().SessionID
2606
+ actualMasterSecret := server .ConnectionState ().masterSecret
2607
+ ss , _ := s2 .Get (actualSessionID )
2608
+ if ! bytes .Equal (actualMasterSecret , ss .Secret ) {
2609
+ t .Errorf ("TestSessionResumetion: masterSecret Mismatch: expected/actual:\n (%v)\n (%v)" , ss .Secret , actualMasterSecret )
2610
+ }
2611
+
2612
+ if ss .Expiry .Unix () != commonCert .Leaf .NotAfter .Unix () {
2613
+ t .Errorf ("TestSessionResumption: expected server session store to contain certificate expiry" )
2614
+ }
2615
+
2616
+ defer func () {
2617
+ _ = server .Close ()
2618
+ }()
2619
+
2620
+ res := <- clientRes
2621
+ if res .err != nil {
2622
+ t .Fatal (res .err )
2623
+ }
2624
+ cs , _ := s1 .Get ([]byte (ca .RemoteAddr ().String () + "_" + commonCert .Leaf .Subject .CommonName ))
2625
+ if ! bytes .Equal (actualMasterSecret , cs .Secret ) {
2626
+ t .Errorf ("TestSessionResumetion: masterSecret Mismatch: expected/actual\n (%v)\n (%v)" , cs .Secret , actualMasterSecret )
2627
+ }
2628
+
2629
+ if cs .Expiry .Unix () != commonCert .Leaf .NotAfter .Unix () {
2630
+ t .Errorf ("TestSessionResumption: expected client session store to contain certificate expiry" )
2631
+ }
2632
+
2633
+ _ = res .c .Close ()
2634
+ })
2635
+
2636
+ t .Run ("expire client cert session" , func (t * testing.T ) {
2637
+ ctx , cancel := context .WithTimeout (context .Background (), 10 * time .Second )
2638
+ defer cancel ()
2639
+
2640
+ type result struct {
2641
+ c * Conn
2642
+ err error
2643
+ }
2644
+ clientRes := make (chan result , 1 )
2645
+
2646
+ commonCert , err := selfsign .GenerateSelfSignedWithDNS ("example.com" )
2647
+
2648
+ if err != nil {
2649
+ t .Fatal (err )
2650
+ }
2651
+ certPool := x509 .NewCertPool ()
2652
+ certPool .AppendCertsFromPEM (pem .EncodeToMemory (& pem.Block {Type : "CERTIFICATE" , Bytes : commonCert .Certificate [0 ]}))
2653
+
2654
+ ss := & memSessStore {}
2655
+
2656
+ id , _ := hex .DecodeString ("9b9fc92255634d9fb109febed42166717bb8ded8c738ba71bc7f2a0d9dae0306" )
2657
+ secret , _ := hex .DecodeString ("2e942a37aca5241deb2295b5fcedac221c7078d2503d2b62aeb48c880d7da73c001238b708559686b9da6e829c05ead7" )
2658
+
2659
+ oldClientSessionTime := time .Now ().Add (time .Hour )
2660
+ clientSession := Session {
2661
+ ID : id ,
2662
+ Secret : secret ,
2663
+ Expiry : oldClientSessionTime ,
2664
+ }
2665
+
2666
+ expiredServerSession := Session {
2667
+ ID : id ,
2668
+ Secret : secret ,
2669
+ Expiry : time .Now ().Add (- time .Hour ), // server should treat this as expired session and force a new cert verification
2670
+ }
2671
+
2672
+ ca , cb := dpipe .Pipe ()
2673
+
2674
+ _ = ss .Set (id , expiredServerSession )
2675
+ _ = ss .Set ([]byte (ca .RemoteAddr ().String ()+ "_" + commonCert .Leaf .Subject .CommonName ), clientSession )
2676
+
2677
+ go func () {
2678
+ config := & Config {
2679
+ CipherSuites : []CipherSuiteID {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 },
2680
+ ServerName : commonCert .Leaf .Subject .CommonName ,
2681
+ SessionStore : ss ,
2682
+ RootCAs : certPool ,
2683
+ Certificates : []tls.Certificate {commonCert },
2684
+ MTU : 1200 , // MTU must be able to fit cert chain in one packet
2685
+ }
2686
+ c , err := ClientWithContext (ctx , ca , config )
2687
+ clientRes <- result {c , err }
2688
+ }()
2689
+
2690
+ config := & Config {
2691
+ CipherSuites : []CipherSuiteID {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 },
2692
+ SessionStore : ss ,
2693
+ ClientCAs : certPool ,
2694
+ Certificates : []tls.Certificate {commonCert },
2695
+ MTU : 1200 ,
2696
+ ClientAuth : RequireAndVerifyClientCert ,
2697
+ }
2698
+ server , err := testServer (ctx , cb , config , false )
2699
+ if err != nil {
2700
+ t .Fatalf ("TestSessionResume: Server failed(%v)" , err )
2701
+ }
2702
+
2703
+ actualSessionID := server .ConnectionState ().SessionID
2704
+ actualMasterSecret := server .ConnectionState ().masterSecret
2705
+ if bytes .Equal (actualSessionID , id ) {
2706
+ t .Errorf ("TestSessionResumption: SessionID Mismatch: expected new session ID(%v) actual(%v)" , id , actualSessionID )
2707
+ }
2708
+
2709
+ if bytes .Equal (actualMasterSecret , secret ) {
2710
+ t .Errorf ("TestSessionResumption: masterSecret Mismatch: expected new master secret (%v) actual(%v)" , secret , actualMasterSecret )
2711
+ }
2712
+
2713
+ defer func () {
2714
+ _ = server .Close ()
2715
+ }()
2716
+
2717
+ res := <- clientRes
2718
+ if res .err != nil {
2719
+ t .Fatal (res .err )
2720
+ }
2721
+
2722
+ _ , ok := ss .Map .Load (hex .EncodeToString (expiredServerSession .ID ))
2723
+ if ok {
2724
+ t .Errorf ("expected server to have deleted session" )
2725
+ }
2726
+
2727
+ cSess , ok := ss .Map .Load (hex .EncodeToString ([]byte (ca .RemoteAddr ().String () + "_" + commonCert .Leaf .Subject .CommonName )))
2728
+ if ! ok {
2729
+ t .Errorf ("expected client store to have cached new session ID" )
2730
+ }
2731
+
2732
+ newClientSession := cSess .(Session )
2733
+ if bytes .Equal (secret , newClientSession .Secret ) {
2734
+ t .Errorf ("expected : expected client session store to contain new master secret (%v) actual(%v)" , secret , newClientSession .Secret )
2735
+ }
2736
+
2737
+ if newClientSession .Expiry .Unix () == oldClientSessionTime .Unix () {
2738
+ t .Errorf ("expected new client session to have updated" )
2739
+ }
2740
+
2741
+ if newClientSession .Expiry .Unix () != commonCert .Leaf .NotAfter .Unix () {
2742
+ t .Errorf ("expected new client session to expire with client cert" )
2743
+ }
2744
+
2745
+ sSess , ok := ss .Map .Load (hex .EncodeToString (newClientSession .ID ))
2746
+ if ! ok {
2747
+ t .Errorf ("expected server store to have cached new client session ID" )
2748
+ }
2749
+ newServerSession := sSess .(Session )
2750
+
2751
+ if ! bytes .Equal (newServerSession .Secret , newClientSession .Secret ) {
2752
+ t .Errorf ("expected : expected session store to contain new shared secret (%v) actual(%v)" , newServerSession .Secret , newClientSession .Secret )
2753
+ }
2754
+ _ = res .c .Close ()
2755
+ })
2489
2756
}
2490
2757
2491
2758
type memSessStore struct {
@@ -2507,7 +2774,16 @@ func (ms *memSessStore) Get(key []byte) (Session, error) {
2507
2774
return Session {}, nil
2508
2775
}
2509
2776
2510
- return v .(Session ), nil
2777
+ session := v .(Session )
2778
+ if session .Expiry .IsZero () {
2779
+ return session , nil
2780
+ }
2781
+
2782
+ if time .Now ().After (session .Expiry ) {
2783
+ _ = ms .Del (key )
2784
+ return Session {}, nil
2785
+ }
2786
+ return session , nil
2511
2787
}
2512
2788
2513
2789
func (ms * memSessStore ) Del (key []byte ) error {
0 commit comments