1
18
19 package fakes2av2
20
21 import (
22 "context"
23 "crypto"
24 "crypto/rand"
25 "crypto/sha256"
26 "crypto/tls"
27 "errors"
28 "fmt"
29 "log"
30 "net"
31 "sync"
32 "testing"
33 "time"
34
35 "github.com/google/go-cmp/cmp"
36 "google.golang.org/grpc"
37 "google.golang.org/grpc/codes"
38 "google.golang.org/grpc/credentials/insecure"
39 "google.golang.org/protobuf/testing/protocmp"
40
41 commonpb "github.com/google/s2a-go/internal/proto/v2/common_go_proto"
42 s2av2ctx "github.com/google/s2a-go/internal/proto/v2/s2a_context_go_proto"
43 s2av2pb "github.com/google/s2a-go/internal/proto/v2/s2a_go_proto"
44 )
45
46 const (
47 defaultTimeout = 10.0 * time.Second
48 )
49
50 func startFakeS2Av2Server(wg *sync.WaitGroup) (address string, stop func(), err error) {
51
52 listener, err := net.Listen("tcp", ":0")
53 address = listener.Addr().String()
54 if err != nil {
55 log.Fatalf("Failed to listen on address %s: %v", listener.Addr().String(), err)
56 }
57 s := grpc.NewServer()
58 log.Printf("Server: started gRPC Fake S2Av2 Server on address: %s", listener.Addr().String())
59 s2av2pb.RegisterS2AServiceServer(s, &Server{ExpectedToken: "valid_token"})
60 go func() {
61 wg.Done()
62 if err := s.Serve(listener); err != nil {
63 log.Printf("Failed to serve: %v", err)
64 }
65 }()
66 return address, func() { s.Stop() }, nil
67 }
68
69 func TestSetUpSession(t *testing.T) {
70
71 var wg sync.WaitGroup
72 wg.Add(1)
73 address, stop, err := startFakeS2Av2Server(&wg)
74 wg.Wait()
75 if err != nil {
76 log.Fatalf("Failed to set up fake S2Av2 server.")
77 }
78
79 for _, tc := range []struct {
80 description string
81 request *s2av2pb.SessionReq
82 expErr error
83 expectedResponse *s2av2pb.SessionResp
84 }{
85 {
86 description: "Get TLS config for client.",
87 request: &s2av2pb.SessionReq{
88 AuthenticationMechanisms: []*s2av2pb.AuthenticationMechanism{
89 {
90 MechanismOneof: &s2av2pb.AuthenticationMechanism_Token{Token: "valid_token"},
91 },
92 },
93 ReqOneof: &s2av2pb.SessionReq_GetTlsConfigurationReq{
94 GetTlsConfigurationReq: &s2av2pb.GetTlsConfigurationReq{
95 ConnectionSide: commonpb.ConnectionSide_CONNECTION_SIDE_CLIENT,
96 },
97 },
98 },
99 expectedResponse: &s2av2pb.SessionResp{
100 Status: &s2av2pb.Status{
101 Code: uint32(codes.OK),
102 },
103 RespOneof: &s2av2pb.SessionResp_GetTlsConfigurationResp{
104 GetTlsConfigurationResp: &s2av2pb.GetTlsConfigurationResp{
105 TlsConfiguration: &s2av2pb.GetTlsConfigurationResp_ClientTlsConfiguration_{
106 ClientTlsConfiguration: &s2av2pb.GetTlsConfigurationResp_ClientTlsConfiguration{
107 CertificateChain: []string{
108 string(clientCert),
109 },
110 MinTlsVersion: commonpb.TLSVersion_TLS_VERSION_1_3,
111 MaxTlsVersion: commonpb.TLSVersion_TLS_VERSION_1_3,
112 },
113 },
114 },
115 },
116 },
117 },
118 {
119 description: "Get TLS config for server.",
120 request: &s2av2pb.SessionReq{
121 AuthenticationMechanisms: []*s2av2pb.AuthenticationMechanism{
122 {
123 MechanismOneof: &s2av2pb.AuthenticationMechanism_Token{Token: "valid_token"},
124 },
125 },
126 ReqOneof: &s2av2pb.SessionReq_GetTlsConfigurationReq{
127 GetTlsConfigurationReq: &s2av2pb.GetTlsConfigurationReq{
128 ConnectionSide: commonpb.ConnectionSide_CONNECTION_SIDE_SERVER,
129 },
130 },
131 },
132 expectedResponse: &s2av2pb.SessionResp{
133 Status: &s2av2pb.Status{
134 Code: uint32(codes.OK),
135 },
136 RespOneof: &s2av2pb.SessionResp_GetTlsConfigurationResp{
137 GetTlsConfigurationResp: &s2av2pb.GetTlsConfigurationResp{
138 TlsConfiguration: &s2av2pb.GetTlsConfigurationResp_ServerTlsConfiguration_{
139 ServerTlsConfiguration: &s2av2pb.GetTlsConfigurationResp_ServerTlsConfiguration{
140 CertificateChain: []string{
141 string(serverCert),
142 },
143 MinTlsVersion: commonpb.TLSVersion_TLS_VERSION_1_3,
144 MaxTlsVersion: commonpb.TLSVersion_TLS_VERSION_1_3,
145 TlsResumptionEnabled: false,
146 RequestClientCertificate: s2av2pb.GetTlsConfigurationResp_ServerTlsConfiguration_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY,
147 MaxOverheadOfTicketAead: 0,
148 },
149 },
150 },
151 },
152 },
153 },
154 {
155 description: "Get TLS config error -- invalid connection side",
156 request: &s2av2pb.SessionReq{
157 AuthenticationMechanisms: []*s2av2pb.AuthenticationMechanism{
158 {
159 MechanismOneof: &s2av2pb.AuthenticationMechanism_Token{Token: "valid_token"},
160 },
161 },
162 ReqOneof: &s2av2pb.SessionReq_GetTlsConfigurationReq{
163 GetTlsConfigurationReq: &s2av2pb.GetTlsConfigurationReq{
164 ConnectionSide: commonpb.ConnectionSide_CONNECTION_SIDE_UNSPECIFIED,
165 },
166 },
167 },
168 expectedResponse: &s2av2pb.SessionResp{
169 Status: &s2av2pb.Status{
170 Code: uint32(codes.InvalidArgument),
171 Details: "unknown ConnectionSide: CONNECTION_SIDE_UNSPECIFIED",
172 },
173 },
174 },
175 {
176 description: "Get TLS config error -- invalid token",
177 request: &s2av2pb.SessionReq{
178 AuthenticationMechanisms: []*s2av2pb.AuthenticationMechanism{
179 {
180 MechanismOneof: &s2av2pb.AuthenticationMechanism_Token{Token: "invalid_token"},
181 },
182 },
183 ReqOneof: &s2av2pb.SessionReq_GetTlsConfigurationReq{
184 GetTlsConfigurationReq: &s2av2pb.GetTlsConfigurationReq{
185 ConnectionSide: commonpb.ConnectionSide_CONNECTION_SIDE_UNSPECIFIED,
186 },
187 },
188 },
189 expErr: errors.New("rpc error: code = Unknown desc = SessionReq has no AuthenticationMechanism with a valid token"),
190 },
191 {
192 description: "Get server TLS config -- empty authmechanisms (S2A_ACCESS_TOKEN env var not set)",
193 request: &s2av2pb.SessionReq{
194 AuthenticationMechanisms: []*s2av2pb.AuthenticationMechanism{},
195 ReqOneof: &s2av2pb.SessionReq_GetTlsConfigurationReq{
196 GetTlsConfigurationReq: &s2av2pb.GetTlsConfigurationReq{
197 ConnectionSide: commonpb.ConnectionSide_CONNECTION_SIDE_SERVER,
198 },
199 },
200 },
201 expectedResponse: &s2av2pb.SessionResp{
202 Status: &s2av2pb.Status{
203 Code: uint32(codes.OK),
204 },
205 RespOneof: &s2av2pb.SessionResp_GetTlsConfigurationResp{
206 GetTlsConfigurationResp: &s2av2pb.GetTlsConfigurationResp{
207 TlsConfiguration: &s2av2pb.GetTlsConfigurationResp_ServerTlsConfiguration_{
208 ServerTlsConfiguration: &s2av2pb.GetTlsConfigurationResp_ServerTlsConfiguration{
209 CertificateChain: []string{
210 string(serverCert),
211 },
212 MinTlsVersion: commonpb.TLSVersion_TLS_VERSION_1_3,
213 MaxTlsVersion: commonpb.TLSVersion_TLS_VERSION_1_3,
214 TlsResumptionEnabled: false,
215 RequestClientCertificate: s2av2pb.GetTlsConfigurationResp_ServerTlsConfiguration_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY,
216 MaxOverheadOfTicketAead: 0,
217 },
218 },
219 },
220 },
221 },
222 },
223 {
224 description: "Client Peer Verification",
225 request: &s2av2pb.SessionReq{
226 ReqOneof: &s2av2pb.SessionReq_ValidatePeerCertificateChainReq{
227 ValidatePeerCertificateChainReq: &s2av2pb.ValidatePeerCertificateChainReq{
228 Mode: s2av2pb.ValidatePeerCertificateChainReq_SPIFFE,
229 PeerOneof: &s2av2pb.ValidatePeerCertificateChainReq_ClientPeer_{
230 ClientPeer: &s2av2pb.ValidatePeerCertificateChainReq_ClientPeer{
231 CertificateChain: [][]byte{clientDERCert},
232 },
233 },
234 },
235 },
236 },
237 expectedResponse: &s2av2pb.SessionResp{
238 Status: &s2av2pb.Status{
239 Code: uint32(codes.OK),
240 Details: "",
241 },
242 RespOneof: &s2av2pb.SessionResp_ValidatePeerCertificateChainResp{
243 ValidatePeerCertificateChainResp: &s2av2pb.ValidatePeerCertificateChainResp{
244 ValidationResult: s2av2pb.ValidatePeerCertificateChainResp_SUCCESS,
245 ValidationDetails: "client peer verification succeeded",
246 Context: &s2av2ctx.S2AContext{},
247 },
248 },
249 },
250 },
251 {
252 description: "Client Peer Verification -- failure",
253 request: &s2av2pb.SessionReq{
254 ReqOneof: &s2av2pb.SessionReq_ValidatePeerCertificateChainReq{
255 ValidatePeerCertificateChainReq: &s2av2pb.ValidatePeerCertificateChainReq{
256 Mode: s2av2pb.ValidatePeerCertificateChainReq_SPIFFE,
257 PeerOneof: &s2av2pb.ValidatePeerCertificateChainReq_ClientPeer_{
258 ClientPeer: &s2av2pb.ValidatePeerCertificateChainReq_ClientPeer{
259 CertificateChain: [][]byte{},
260 },
261 },
262 },
263 },
264 },
265 expectedResponse: &s2av2pb.SessionResp{
266 Status: &s2av2pb.Status{
267 Code: uint32(codes.OK),
268 Details: "",
269 },
270 RespOneof: &s2av2pb.SessionResp_ValidatePeerCertificateChainResp{
271 ValidatePeerCertificateChainResp: &s2av2pb.ValidatePeerCertificateChainResp{
272 ValidationResult: s2av2pb.ValidatePeerCertificateChainResp_FAILURE,
273 ValidationDetails: "client peer verification failed: client cert chain is empty",
274 Context: &s2av2ctx.S2AContext{},
275 },
276 },
277 },
278 },
279 {
280 description: "Server Peer Verification",
281 request: &s2av2pb.SessionReq{
282 ReqOneof: &s2av2pb.SessionReq_ValidatePeerCertificateChainReq{
283 ValidatePeerCertificateChainReq: &s2av2pb.ValidatePeerCertificateChainReq{
284 Mode: s2av2pb.ValidatePeerCertificateChainReq_SPIFFE,
285 PeerOneof: &s2av2pb.ValidatePeerCertificateChainReq_ServerPeer_{
286 ServerPeer: &s2av2pb.ValidatePeerCertificateChainReq_ServerPeer{
287 CertificateChain: [][]byte{serverDERCert},
288 },
289 },
290 },
291 },
292 },
293 expectedResponse: &s2av2pb.SessionResp{
294 Status: &s2av2pb.Status{
295 Code: uint32(codes.OK),
296 Details: "",
297 },
298 RespOneof: &s2av2pb.SessionResp_ValidatePeerCertificateChainResp{
299 ValidatePeerCertificateChainResp: &s2av2pb.ValidatePeerCertificateChainResp{
300 ValidationResult: s2av2pb.ValidatePeerCertificateChainResp_SUCCESS,
301 ValidationDetails: "server peer verification succeeded",
302 Context: &s2av2ctx.S2AContext{},
303 },
304 },
305 },
306 },
307 } {
308 t.Run(tc.description, func(t *testing.T) {
309
310 opts := []grpc.DialOption{
311 grpc.WithTransportCredentials(insecure.NewCredentials()),
312 grpc.WithReturnConnectionError(),
313 grpc.WithBlock(),
314 }
315 conn, err := grpc.Dial(address, opts...)
316 if err != nil {
317 t.Fatalf("Client: failed to connect: %v", err)
318 }
319 defer conn.Close()
320 c := s2av2pb.NewS2AServiceClient(conn)
321 log.Printf("Client: connected to: %s", address)
322 ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
323 defer cancel()
324
325
326 callOpts := []grpc.CallOption{}
327 cstream, err := c.SetUpSession(ctx, callOpts...)
328 if err != nil {
329 t.Fatalf("Client: failed to setup bidirectional streaming RPC session: %v", err)
330 }
331 log.Printf("Client: set up bidirectional streaming RPC session.")
332
333
334 if err := cstream.Send(tc.request); err != nil {
335 t.Fatalf("Client: failed to send SessionReq: %v", err)
336 }
337 log.Printf("Client: sent SessionReq")
338
339
340 resp, err := cstream.Recv()
341 if err != tc.expErr {
342 if (err != nil) && (tc.expErr != nil) {
343 if err.Error() != tc.expErr.Error() {
344 t.Fatalf("err = %v, expErr = %v", err.Error(), tc.expErr.Error())
345 }
346 } else {
347 t.Fatalf("err = %v, expErr = %v", err, tc.expErr)
348 }
349 }
350 log.Printf("Client: received SessionResp")
351 if diff := cmp.Diff(tc.expectedResponse, resp, protocmp.Transform()); diff != "" {
352 t.Errorf("cstream.Recv() returned incorrect SessionResp, (-want +got):\n%s", diff)
353 }
354 log.Printf("resp matches tc.expectedResponse")
355 })
356 }
357 stop()
358 }
359
360 func TestSetUpSessionPrivateKeyOperation(t *testing.T) {
361
362 var wg sync.WaitGroup
363 wg.Add(1)
364 address, stop, err := startFakeS2Av2Server(&wg)
365 wg.Wait()
366 if err != nil {
367 log.Fatalf("Failed to set up fake S2Av2 server.")
368 }
369
370
371 clientTLSCert, err := tls.X509KeyPair(clientCert, clientKey)
372 if err != nil {
373 log.Fatalf("Failed during test setup: %v", err)
374 }
375
376 serverTLSCert, err := tls.X509KeyPair(serverCert, serverKey)
377 if err != nil {
378 log.Fatalf("Failed during test setup: %v", err)
379 }
380
381 testString := "Generate hash and sign this."
382
383
384
385 hsha256 := sha256.Sum256([]byte(testString))
386
387 var opts crypto.Hash = crypto.SHA256
388 signedWithClientKey, err := clientTLSCert.PrivateKey.(crypto.Signer).Sign(rand.Reader, hsha256[:], opts)
389 if err != nil {
390 log.Fatalf("Failed during test setup: %v", err)
391 }
392 signedWithServerKey, err := serverTLSCert.PrivateKey.(crypto.Signer).Sign(rand.Reader, hsha256[:], opts)
393 if err != nil {
394 log.Fatalf("Failed during test setup: %v", err)
395 }
396
397 for _, tc := range []struct {
398 description string
399 connSide commonpb.ConnectionSide
400 request *s2av2pb.SessionReq
401 expectedResponse *s2av2pb.SessionResp
402 }{
403
404 {
405 description: "client side private key operation",
406 connSide: commonpb.ConnectionSide_CONNECTION_SIDE_CLIENT,
407 request: &s2av2pb.SessionReq{
408 ReqOneof: &s2av2pb.SessionReq_OffloadPrivateKeyOperationReq{
409 OffloadPrivateKeyOperationReq: &s2av2pb.OffloadPrivateKeyOperationReq{
410 Operation: s2av2pb.OffloadPrivateKeyOperationReq_SIGN,
411 SignatureAlgorithm: s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_RSA_PKCS1_SHA256,
412 InBytes: &s2av2pb.OffloadPrivateKeyOperationReq_Sha256Digest{
413 Sha256Digest: []byte(hsha256[:]),
414 },
415 },
416 },
417 },
418 expectedResponse: &s2av2pb.SessionResp{
419 Status: &s2av2pb.Status{
420 Code: uint32(codes.OK),
421 },
422 RespOneof: &s2av2pb.SessionResp_OffloadPrivateKeyOperationResp{
423 OffloadPrivateKeyOperationResp: &s2av2pb.OffloadPrivateKeyOperationResp{
424 OutBytes: signedWithClientKey,
425 },
426 },
427 },
428 },
429 {
430 description: "server side private key operation",
431 connSide: commonpb.ConnectionSide_CONNECTION_SIDE_SERVER,
432 request: &s2av2pb.SessionReq{
433 ReqOneof: &s2av2pb.SessionReq_OffloadPrivateKeyOperationReq{
434 OffloadPrivateKeyOperationReq: &s2av2pb.OffloadPrivateKeyOperationReq{
435 Operation: s2av2pb.OffloadPrivateKeyOperationReq_SIGN,
436 SignatureAlgorithm: s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_RSA_PKCS1_SHA256,
437 InBytes: &s2av2pb.OffloadPrivateKeyOperationReq_Sha256Digest{
438 Sha256Digest: []byte(hsha256[:]),
439 },
440 },
441 },
442 },
443 expectedResponse: &s2av2pb.SessionResp{
444 Status: &s2av2pb.Status{
445 Code: uint32(codes.OK),
446 },
447 RespOneof: &s2av2pb.SessionResp_OffloadPrivateKeyOperationResp{
448 OffloadPrivateKeyOperationResp: &s2av2pb.OffloadPrivateKeyOperationResp{
449 OutBytes: signedWithServerKey,
450 },
451 },
452 },
453 },
454 {
455 description: "client side private key operation -- invalid signature algorithm",
456 connSide: commonpb.ConnectionSide_CONNECTION_SIDE_CLIENT,
457 request: &s2av2pb.SessionReq{
458 ReqOneof: &s2av2pb.SessionReq_OffloadPrivateKeyOperationReq{
459 OffloadPrivateKeyOperationReq: &s2av2pb.OffloadPrivateKeyOperationReq{
460 Operation: s2av2pb.OffloadPrivateKeyOperationReq_SIGN,
461 SignatureAlgorithm: s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_UNSPECIFIED,
462 InBytes: &s2av2pb.OffloadPrivateKeyOperationReq_Sha256Digest{
463 Sha256Digest: []byte(hsha256[:]),
464 },
465 },
466 },
467 },
468 expectedResponse: &s2av2pb.SessionResp{
469 Status: &s2av2pb.Status{
470 Code: uint32(codes.InvalidArgument),
471 Details: fmt.Sprintf("invalid signature algorithm: %v", s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_UNSPECIFIED),
472 },
473 },
474 },
475 } {
476 t.Run(tc.description, func(t *testing.T) {
477
478 opts := []grpc.DialOption{
479 grpc.WithTransportCredentials(insecure.NewCredentials()),
480 grpc.WithReturnConnectionError(),
481 grpc.WithBlock(),
482 }
483 conn, err := grpc.Dial(address, opts...)
484 if err != nil {
485 t.Fatalf("Client: failed to connect: %v", err)
486 }
487 defer conn.Close()
488 c := s2av2pb.NewS2AServiceClient(conn)
489 log.Printf("Client: connected to: %s", address)
490 ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
491 defer cancel()
492
493
494 callOpts := []grpc.CallOption{}
495 cstream, err := c.SetUpSession(ctx, callOpts...)
496 if err != nil {
497 t.Fatalf("Client: failed to setup bidirectional streaming RPC session: %v", err)
498 }
499 log.Printf("Client: set up bidirectional streaming RPC session.")
500
501
502
503 if err := cstream.Send(&s2av2pb.SessionReq{
504 AuthenticationMechanisms: []*s2av2pb.AuthenticationMechanism{
505 {
506 MechanismOneof: &s2av2pb.AuthenticationMechanism_Token{
507 Token: "valid_token",
508 },
509 },
510 },
511 ReqOneof: &s2av2pb.SessionReq_GetTlsConfigurationReq{
512 GetTlsConfigurationReq: &s2av2pb.GetTlsConfigurationReq{
513 ConnectionSide: tc.connSide,
514 },
515 },
516 }); err != nil {
517 t.Fatalf("Setup failed: failed to send initial SessionReq for TLS config: %v", err)
518 }
519
520 if _, err := cstream.Recv(); err != nil {
521 t.Fatalf("Setup failed: failed to receive initial SessionResp for TLS config: %v", err)
522 }
523
524
525 if err := cstream.Send(tc.request); err != nil {
526 t.Fatalf("Client: failed to send SessionReq: %v", err)
527 }
528 log.Printf("Client: sent SessionReq")
529
530
531 resp, err := cstream.Recv()
532 if err != nil {
533 t.Fatalf("Client: failed to receive SessionResp: %v", err)
534 }
535 log.Printf("Client: received SessionResp")
536 if diff := cmp.Diff(tc.expectedResponse, resp, protocmp.Transform()); diff != "" {
537 t.Errorf("cstream.Recv() returned incorrect SessionResp, (-want +got):\n%s", diff)
538 }
539 log.Printf("resp matches tc.expectedResponse")
540 })
541 }
542 stop()
543 }
544
View as plain text