Skip to content
File

Blob: tun/server/keyless_cache_test.go

go152 lines
1package server
2 
3import (
4 "context"
5 "crypto/tls"
6 "crypto/x509"
7 "errors"
8 "testing"
9 "time"
10 
11 "go.miragespace.co/specter/spec/mocks"
12 "go.miragespace.co/specter/spec/rpc"
13 "go.miragespace.co/specter/spec/transport"
14 
15 "github.com/stretchr/testify/mock"
16 "github.com/stretchr/testify/require"
17 "github.com/twitchtv/twirp"
18 "go.uber.org/zap/zaptest"
19)
20 
21func TestComputeKeylessTTL_UsesBaseWhenNoLeaf(t *testing.T) {
22 as := require.New(t)
23 
24 now := time.Now()
25 cert := &tls.Certificate{}
26 
27 ttl := computeKeylessTTL(cert, now)
28 
29 as.Equal(keylessPositiveTTL, ttl)
30}
31 
32func TestComputeKeylessTTL_ClampedByExpiry(t *testing.T) {
33 as := require.New(t)
34 
35 now := time.Now()
36 leaf := &x509.Certificate{NotAfter: now.Add(2 * time.Minute)}
37 cert := &tls.Certificate{Leaf: leaf}
38 
39 ttl := computeKeylessTTL(cert, now)
40 
41 expected := 2*time.Minute - keylessExpirySkew
42 as.InDelta(expected.Seconds(), ttl.Seconds(), 0.01)
43}
44 
45func TestComputeKeylessTTL_ExpiredUsesShortTTL(t *testing.T) {
46 as := require.New(t)
47 
48 now := time.Now()
49 leaf := &x509.Certificate{NotAfter: now.Add(-time.Minute)}
50 cert := &tls.Certificate{Leaf: leaf}
51 
52 ttl := computeKeylessTTL(cert, now)
53 
54 as.Equal(time.Second, ttl)
55}
56 
57func TestKeylessCertLoaderSuccess(t *testing.T) {
58 as := require.New(t)
59 logger := zaptest.NewLogger(t)
60 
61 provider := new(mocks.CertProvider)
62 s := &Server{
63 Config: Config{
64 Logger: logger,
65 CertProvider: provider,
66 },
67 }
68 
69 hostname := "example.com"
70 leaf := &x509.Certificate{NotAfter: time.Now().Add(time.Hour)}
71 tlsCert := &tls.Certificate{
72 Certificate: [][]byte{{1, 2, 3}},
73 Leaf: leaf,
74 }
75 
76 delegate := &transport.StreamDelegate{}
77 provider.On("GetCertificateWithContext",
78 mock.Anything,
79 mock.MatchedBy(func(chi *tls.ClientHelloInfo) bool {
80 as.Equal(hostname, chi.ServerName)
81 as.NotNil(chi.Conn)
82 return true
83 }),
84 ).Return(tlsCert, nil)
85 
86 ctx := rpc.WithDelegation(context.Background(), delegate)
87 ret, err := s.keylessCertLoader(ctx, hostname)
88 
89 as.NoError(err)
90 as.NoError(ret.Value.err)
91 as.Same(tlsCert, ret.Value.cert)
92 as.True(ret.TTL > 0)
93 as.True(ret.Cost > 0)
94 
95 provider.AssertExpectations(t)
96}
97 
98func TestKeylessCertLoaderProviderError(t *testing.T) {
99 as := require.New(t)
100 logger := zaptest.NewLogger(t)
101 
102 provider := new(mocks.CertProvider)
103 s := &Server{
104 Config: Config{
105 Logger: logger,
106 CertProvider: provider,
107 },
108 }
109 
110 hostname := "example.com"
111 delegate := &transport.StreamDelegate{}
112 provErr := errors.New("boom")
113 
114 provider.On("GetCertificateWithContext", mock.Anything, mock.Anything).
115 Return((*tls.Certificate)(nil), provErr)
116 
117 ctx := rpc.WithDelegation(context.Background(), delegate)
118 ret, err := s.keylessCertLoader(ctx, hostname)
119 
120 as.NoError(err)
121 as.Equal(provErr, ret.Value.err)
122 as.Equal(keylessFailedTTL, ret.TTL)
123 
124 provider.AssertExpectations(t)
125}
126 
127func TestKeylessCertLoaderMissingDelegation(t *testing.T) {
128 as := require.New(t)
129 logger := zaptest.NewLogger(t)
130 
131 provider := new(mocks.CertProvider)
132 s := &Server{
133 Config: Config{
134 Logger: logger,
135 CertProvider: provider,
136 },
137 }
138 
139 hostname := "example.com"
140 
141 ret, err := s.keylessCertLoader(context.Background(), hostname)
142 
143 as.NoError(err)
144 as.NotNil(ret.Value.err)
145 twerr, ok := ret.Value.err.(twirp.Error)
146 as.True(ok)
147 as.Equal(twirp.Internal, twerr.Code())
148 as.Equal(keylessFailedTTL, ret.TTL)
149 
150 provider.AssertExpectations(t)
151}