func()

in fakekms/asymmetric_rpcs.go [133:224]


func (f *fakeKMS) AsymmetricSign(ctx context.Context, req *kmspb.AsymmetricSignRequest) (*kmspb.AsymmetricSignResponse, error) {
	if err := allowlist("name", "data", "data_crc32c", "digest.sha256", "digest.sha384", "digest.sha512", "digest_crc32c").check(req); err != nil {
		return nil, err
	}

	name, err := parseCryptoKeyVersionName(req.Name)
	if err != nil {
		return nil, err
	}

	ckv, err := f.cryptoKeyVersion(name)
	if err != nil {
		return nil, err
	}

	if ckv.pb.State != kmspb.CryptoKeyVersion_ENABLED {
		return nil, errFailedPrecondition("key version %s is not enabled", name)
	}

	def, _ := algorithmDef(ckv.pb.Algorithm)
	if def.Purpose != kmspb.CryptoKey_ASYMMETRIC_SIGN {
		return nil, errFailedPrecondition("keys with algorithm %s may not be used for signing",
			nameForValue(kmspb.CryptoKeyVersion_CryptoKeyVersionAlgorithm_name, int32(ckv.pb.Algorithm)))
	}

	if req.DataCrc32C != nil && req.DigestCrc32C != nil {
		return nil, errInvalidArgument("only one of digest_crc32c or data_crc32c must be set")
	}

	opts := def.Opts.(crypto.SignerOpts)

	var data []byte
	switch {
	case req.Digest != nil && req.Data != nil:
		return nil, errInvalidArgument("only one of digest or data must be set")
	case req.Digest == nil && req.Data == nil:
		return nil, errInvalidArgument("at least one of digest or data must be set")
	case opts.HashFunc() == crypto.Hash(0): // algorithm doesn't support prehashed data
		if req.Data == nil {
			return nil, errInvalidArgument("data is empty")
		}
		dataChecksum := crc32c(req.Data)
		if req.DataCrc32C != nil && dataChecksum.Value != req.DataCrc32C.Value {
			return nil, errInvalidArgument("invalid data checksum")
		}
		data = req.Data
	case req.Data != nil:
		if req.Digest != nil {
			return nil, errInvalidArgument("digest should be empty")
		}
		// Validate checksum before computing the digest
		dataChecksum := crc32c(req.Data)
		if req.DataCrc32C != nil && dataChecksum.Value != req.DataCrc32C.Value {
			return nil, errInvalidArgument("invalid data checksum")
		}
		data = req.Data
		h := opts.HashFunc().New()
		h.Write(data)
		data = h.Sum(nil)
	case opts.HashFunc() == crypto.SHA256:
		data = req.Digest.GetSha256()
	case opts.HashFunc() == crypto.SHA384:
		data = req.Digest.GetSha384()
	case opts.HashFunc() == crypto.SHA512:
		data = req.Digest.GetSha512()
	default:
		return nil, errInternal("unsupported hash: %d", opts.HashFunc())
	}

	if opts.HashFunc() != crypto.Hash(0) && len(data) != opts.HashFunc().Size() {
		return nil, errInvalidArgument("len(digest)=%d, want %d", len(data), opts.HashFunc().Size())
	}

	dataChecksum := crc32c(data)
	if req.DigestCrc32C != nil && dataChecksum.Value != req.DigestCrc32C.Value {
		return nil, errInvalidArgument("invalid digest checksum")
	}

	sig, err := ckv.keyMaterial.(crypto.Signer).Sign(rand.Reader, data, opts)
	if err != nil {
		return nil, errInternal("signing failed: %v", err)
	}

	return &kmspb.AsymmetricSignResponse{
		Name:                 req.Name,
		Signature:            sig,
		SignatureCrc32C:      crc32c(sig),
		VerifiedDataCrc32C:   req.DataCrc32C != nil,
		VerifiedDigestCrc32C: req.DigestCrc32C != nil,
		ProtectionLevel:      ckv.pb.ProtectionLevel,
	}, nil
}