2023-05-24 17:40:52 -07:00

106 lines
2.2 KiB
Go

package signer
import (
"context"
"crypto"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"io"
"log"
kms "cloud.google.com/go/kms/apiv1"
kmspb "cloud.google.com/go/kms/apiv1/kmspb"
)
// GCPSigner a GCP asymetric crypto signer
type GCPSigner struct {
crypto.Signer
ctx context.Context
client *kms.KeyManagementClient
key string
}
// NewGCPSSigner return a new instsance of NewGCPSSigner
func NewGCPSSigner(key string) *GCPSigner {
ctx := context.Background()
c, err := kms.NewKeyManagementClient(ctx)
if err != nil {
panic(err)
}
return &GCPSigner{
ctx: ctx,
client: c,
key: key,
}
}
// Public returns the public key from KMS
func (s *GCPSigner) Public() crypto.PublicKey {
response, err := s.client.GetPublicKey(s.ctx, &kmspb.GetPublicKeyRequest{
Name: s.key,
})
if err != nil {
log.Print(err.Error())
return nil
}
switch response.GetAlgorithm() {
case kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_2048_SHA256,
kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_3072_SHA256,
kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_4096_SHA256,
kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_4096_SHA512:
// awesome
default:
log.Print("crypto key has the wrong algorithm, must be rsa with PKCS1 padding")
return nil
}
pubPem := response.GetPem()
// pubAlg := response.GetAlgorithm()
pemBlock, _ := pem.Decode([]byte(pubPem))
publicKey, err := x509.ParsePKIXPublicKey(pemBlock.Bytes)
if err != nil {
log.Print(err.Error())
return nil
}
return publicKey
}
// Sign a digest with the private key in KMS
func (s *GCPSigner) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
var dig *kmspb.Digest = &kmspb.Digest{}
switch opts {
case crypto.SHA256:
dig.Digest = &kmspb.Digest_Sha256{
Sha256: digest,
}
case crypto.SHA384:
dig.Digest = &kmspb.Digest_Sha384{
Sha384: digest,
}
case crypto.SHA512:
dig.Digest = &kmspb.Digest_Sha512{
Sha512: digest,
}
}
response, err := s.client.AsymmetricSign(s.ctx, &kmspb.AsymmetricSignRequest{
Name: s.key,
Digest: dig,
})
if err != nil {
return nil, err
}
sig := response.GetSignature()
pubKey := s.Public()
rKey := pubKey.(*rsa.PublicKey)
err = rsa.VerifyPKCS1v15(rKey, crypto.SHA256, digest, sig)
if err != nil {
return nil, err
}
return sig, nil
}