1/*
2 *
3 * Copyright 2022 Google LLC
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19// Package certverifier offloads verifications to S2Av2.
20package certverifier
21
22import (
23 "crypto/x509"
24 "fmt"
25
26 "github.com/google/s2a-go/stream"
27 "google.golang.org/grpc/codes"
28 "google.golang.org/grpc/grpclog"
29
30 s2av2pb "github.com/google/s2a-go/internal/proto/v2/s2a_go_proto"
31)
32
33// VerifyClientCertificateChain builds a SessionReq, sends it to S2Av2 and
34// receives a SessionResp.
35func VerifyClientCertificateChain(verificationMode s2av2pb.ValidatePeerCertificateChainReq_VerificationMode, s2AStream stream.S2AStream) func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
36 return func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
37 // Offload verification to S2Av2.
38 if grpclog.V(1) {
39 grpclog.Infof("Sending request to S2Av2 for client peer cert chain validation.")
40 }
41 if err := s2AStream.Send(&s2av2pb.SessionReq{
42 ReqOneof: &s2av2pb.SessionReq_ValidatePeerCertificateChainReq{
43 ValidatePeerCertificateChainReq: &s2av2pb.ValidatePeerCertificateChainReq{
44 Mode: verificationMode,
45 PeerOneof: &s2av2pb.ValidatePeerCertificateChainReq_ClientPeer_{
46 ClientPeer: &s2av2pb.ValidatePeerCertificateChainReq_ClientPeer{
47 CertificateChain: rawCerts,
48 },
49 },
50 },
51 },
52 }); err != nil {
53 grpclog.Infof("Failed to send request to S2Av2 for client peer cert chain validation.")
54 return err
55 }
56
57 // Get the response from S2Av2.
58 resp, err := s2AStream.Recv()
59 if err != nil {
60 grpclog.Infof("Failed to receive client peer cert chain validation response from S2Av2.")
61 return err
62 }
63
64 // Parse the response.
65 if (resp.GetStatus() != nil) && (resp.GetStatus().Code != uint32(codes.OK)) {
66 return fmt.Errorf("failed to offload client cert verification to S2A: %d, %v", resp.GetStatus().Code, resp.GetStatus().Details)
67
68 }
69
70 if resp.GetValidatePeerCertificateChainResp().ValidationResult != s2av2pb.ValidatePeerCertificateChainResp_SUCCESS {
71 return fmt.Errorf("client cert verification failed: %v", resp.GetValidatePeerCertificateChainResp().ValidationDetails)
72 }
73
74 return nil
75 }
76}
77
78// VerifyServerCertificateChain builds a SessionReq, sends it to S2Av2 and
79// receives a SessionResp.
80func VerifyServerCertificateChain(hostname string, verificationMode s2av2pb.ValidatePeerCertificateChainReq_VerificationMode, s2AStream stream.S2AStream, serverAuthorizationPolicy []byte) func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
81 return func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
82 // Offload verification to S2Av2.
83 if grpclog.V(1) {
84 grpclog.Infof("Sending request to S2Av2 for server peer cert chain validation.")
85 }
86 if err := s2AStream.Send(&s2av2pb.SessionReq{
87 ReqOneof: &s2av2pb.SessionReq_ValidatePeerCertificateChainReq{
88 ValidatePeerCertificateChainReq: &s2av2pb.ValidatePeerCertificateChainReq{
89 Mode: verificationMode,
90 PeerOneof: &s2av2pb.ValidatePeerCertificateChainReq_ServerPeer_{
91 ServerPeer: &s2av2pb.ValidatePeerCertificateChainReq_ServerPeer{
92 CertificateChain: rawCerts,
93 ServerHostname: hostname,
94 SerializedUnrestrictedClientPolicy: serverAuthorizationPolicy,
95 },
96 },
97 },
98 },
99 }); err != nil {
100 grpclog.Infof("Failed to send request to S2Av2 for server peer cert chain validation.")
101 return err
102 }
103
104 // Get the response from S2Av2.
105 resp, err := s2AStream.Recv()
106 if err != nil {
107 grpclog.Infof("Failed to receive server peer cert chain validation response from S2Av2.")
108 return err
109 }
110
111 // Parse the response.
112 if (resp.GetStatus() != nil) && (resp.GetStatus().Code != uint32(codes.OK)) {
113 return fmt.Errorf("failed to offload server cert verification to S2A: %d, %v", resp.GetStatus().Code, resp.GetStatus().Details)
114 }
115
116 if resp.GetValidatePeerCertificateChainResp().ValidationResult != s2av2pb.ValidatePeerCertificateChainResp_SUCCESS {
117 return fmt.Errorf("server cert verification failed: %v", resp.GetValidatePeerCertificateChainResp().ValidationDetails)
118 }
119
120 return nil
121 }
122}