remotesigner.go

  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 remotesigner offloads private key operations to S2Av2.
 20package remotesigner
 21
 22import (
 23	"crypto"
 24	"crypto/rsa"
 25	"crypto/x509"
 26	"fmt"
 27	"io"
 28
 29	"github.com/google/s2a-go/stream"
 30	"google.golang.org/grpc/codes"
 31	"google.golang.org/grpc/grpclog"
 32
 33	s2av2pb "github.com/google/s2a-go/internal/proto/v2/s2a_go_proto"
 34)
 35
 36// remoteSigner implementes the crypto.Signer interface.
 37type remoteSigner struct {
 38	leafCert  *x509.Certificate
 39	s2AStream stream.S2AStream
 40}
 41
 42// New returns an instance of RemoteSigner, an implementation of the
 43// crypto.Signer interface.
 44func New(leafCert *x509.Certificate, s2AStream stream.S2AStream) crypto.Signer {
 45	return &remoteSigner{leafCert, s2AStream}
 46}
 47
 48func (s *remoteSigner) Public() crypto.PublicKey {
 49	return s.leafCert.PublicKey
 50}
 51
 52func (s *remoteSigner) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) (signature []byte, err error) {
 53	signatureAlgorithm, err := getSignatureAlgorithm(opts, s.leafCert)
 54	if err != nil {
 55		return nil, err
 56	}
 57
 58	req, err := getSignReq(signatureAlgorithm, digest)
 59	if err != nil {
 60		return nil, err
 61	}
 62	if grpclog.V(1) {
 63		grpclog.Infof("Sending request to S2Av2 for signing operation.")
 64	}
 65	if err := s.s2AStream.Send(&s2av2pb.SessionReq{
 66		ReqOneof: &s2av2pb.SessionReq_OffloadPrivateKeyOperationReq{
 67			OffloadPrivateKeyOperationReq: req,
 68		},
 69	}); err != nil {
 70		grpclog.Infof("Failed to send request to S2Av2 for signing operation.")
 71		return nil, err
 72	}
 73
 74	resp, err := s.s2AStream.Recv()
 75	if err != nil {
 76		grpclog.Infof("Failed to receive signing operation response from S2Av2.")
 77		return nil, err
 78	}
 79
 80	if (resp.GetStatus() != nil) && (resp.GetStatus().Code != uint32(codes.OK)) {
 81		return nil, fmt.Errorf("failed to offload signing with private key to S2A: %d, %v", resp.GetStatus().Code, resp.GetStatus().Details)
 82	}
 83
 84	return resp.GetOffloadPrivateKeyOperationResp().GetOutBytes(), nil
 85}
 86
 87// getCert returns the leafCert field in s.
 88func (s *remoteSigner) getCert() *x509.Certificate {
 89	return s.leafCert
 90}
 91
 92// getStream returns the s2AStream field in s.
 93func (s *remoteSigner) getStream() stream.S2AStream {
 94	return s.s2AStream
 95}
 96
 97func getSignReq(signatureAlgorithm s2av2pb.SignatureAlgorithm, digest []byte) (*s2av2pb.OffloadPrivateKeyOperationReq, error) {
 98	if (signatureAlgorithm == s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_RSA_PKCS1_SHA256) || (signatureAlgorithm == s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_ECDSA_SECP256R1_SHA256) || (signatureAlgorithm == s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_RSA_PSS_RSAE_SHA256) {
 99		return &s2av2pb.OffloadPrivateKeyOperationReq{
100			Operation:          s2av2pb.OffloadPrivateKeyOperationReq_SIGN,
101			SignatureAlgorithm: signatureAlgorithm,
102			InBytes: &s2av2pb.OffloadPrivateKeyOperationReq_Sha256Digest{
103				Sha256Digest: digest,
104			},
105		}, nil
106	} else if (signatureAlgorithm == s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_RSA_PKCS1_SHA384) || (signatureAlgorithm == s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_ECDSA_SECP384R1_SHA384) || (signatureAlgorithm == s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_RSA_PSS_RSAE_SHA384) {
107		return &s2av2pb.OffloadPrivateKeyOperationReq{
108			Operation:          s2av2pb.OffloadPrivateKeyOperationReq_SIGN,
109			SignatureAlgorithm: signatureAlgorithm,
110			InBytes: &s2av2pb.OffloadPrivateKeyOperationReq_Sha384Digest{
111				Sha384Digest: digest,
112			},
113		}, nil
114	} else if (signatureAlgorithm == s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_RSA_PKCS1_SHA512) || (signatureAlgorithm == s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_ECDSA_SECP521R1_SHA512) || (signatureAlgorithm == s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_RSA_PSS_RSAE_SHA512) || (signatureAlgorithm == s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_ED25519) {
115		return &s2av2pb.OffloadPrivateKeyOperationReq{
116			Operation:          s2av2pb.OffloadPrivateKeyOperationReq_SIGN,
117			SignatureAlgorithm: signatureAlgorithm,
118			InBytes: &s2av2pb.OffloadPrivateKeyOperationReq_Sha512Digest{
119				Sha512Digest: digest,
120			},
121		}, nil
122	} else {
123		return nil, fmt.Errorf("unknown signature algorithm: %v", signatureAlgorithm)
124	}
125}
126
127// getSignatureAlgorithm returns the signature algorithm that S2A must use when
128// performing a signing operation that has been offloaded by an application
129// using the crypto/tls libraries.
130func getSignatureAlgorithm(opts crypto.SignerOpts, leafCert *x509.Certificate) (s2av2pb.SignatureAlgorithm, error) {
131	if opts == nil || leafCert == nil {
132		return s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_UNSPECIFIED, fmt.Errorf("unknown signature algorithm")
133	}
134	switch leafCert.PublicKeyAlgorithm {
135	case x509.RSA:
136		if rsaPSSOpts, ok := opts.(*rsa.PSSOptions); ok {
137			return rsaPSSAlgorithm(rsaPSSOpts)
138		}
139		return rsaPPKCS1Algorithm(opts)
140	case x509.ECDSA:
141		return ecdsaAlgorithm(opts)
142	case x509.Ed25519:
143		return s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_ED25519, nil
144	default:
145		return s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_UNSPECIFIED, fmt.Errorf("unknown signature algorithm: %q", leafCert.PublicKeyAlgorithm)
146	}
147}
148
149func rsaPSSAlgorithm(opts *rsa.PSSOptions) (s2av2pb.SignatureAlgorithm, error) {
150	switch opts.HashFunc() {
151	case crypto.SHA256:
152		return s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_RSA_PSS_RSAE_SHA256, nil
153	case crypto.SHA384:
154		return s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_RSA_PSS_RSAE_SHA384, nil
155	case crypto.SHA512:
156		return s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_RSA_PSS_RSAE_SHA512, nil
157	default:
158		return s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_UNSPECIFIED, fmt.Errorf("unknown signature algorithm")
159	}
160}
161
162func rsaPPKCS1Algorithm(opts crypto.SignerOpts) (s2av2pb.SignatureAlgorithm, error) {
163	switch opts.HashFunc() {
164	case crypto.SHA256:
165		return s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_RSA_PKCS1_SHA256, nil
166	case crypto.SHA384:
167		return s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_RSA_PKCS1_SHA384, nil
168	case crypto.SHA512:
169		return s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_RSA_PKCS1_SHA512, nil
170	default:
171		return s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_UNSPECIFIED, fmt.Errorf("unknown signature algorithm")
172	}
173}
174
175func ecdsaAlgorithm(opts crypto.SignerOpts) (s2av2pb.SignatureAlgorithm, error) {
176	switch opts.HashFunc() {
177	case crypto.SHA256:
178		return s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_ECDSA_SECP256R1_SHA256, nil
179	case crypto.SHA384:
180		return s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_ECDSA_SECP384R1_SHA384, nil
181	case crypto.SHA512:
182		return s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_ECDSA_SECP521R1_SHA512, nil
183	default:
184		return s2av2pb.SignatureAlgorithm_S2A_SSL_SIGN_UNSPECIFIED, fmt.Errorf("unknown signature algorithm")
185	}
186}