certverifier.go raw

   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.
  20  package certverifier
  21  
  22  import (
  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.
  35  func 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.
  80  func 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  }
 123