kmsp11/operation/rsassa_pkcs1.cc (169 lines of code) (raw):
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "kmsp11/operation/rsassa_pkcs1.h"
#include <string_view>
#include "common/openssl.h"
#include "common/status_macros.h"
#include "kmsp11/operation/crypter_interfaces.h"
#include "kmsp11/operation/kms_digesting_signer.h"
#include "kmsp11/operation/kms_digesting_verifier.h"
#include "kmsp11/operation/kms_prehashed_signer.h"
#include "kmsp11/operation/preconditions.h"
#include "kmsp11/util/crypto_utils.h"
#include "kmsp11/util/errors.h"
namespace cloud_kms::kmsp11 {
// Enum representing if the input data is a plain digest or an ASN.1 DigestInfo.
enum class ExpectedInput { kDigest, kAsn1DigestInfo };
namespace {
absl::StatusOr<std::vector<uint8_t>> ExtractDigest(
absl::Span<const uint8_t> digest_info_der, int expected_digest_nid) {
const uint8_t* data = digest_info_der.data();
bssl::UniquePtr<X509_SIG> digest_info(
d2i_X509_SIG(nullptr, &data, digest_info_der.size()));
if (!digest_info) {
return NewInvalidArgumentError(
absl::StrCat("error parsing DigestInfo: ", SslErrorToString()),
CKR_DATA_INVALID, SOURCE_LOCATION);
}
const X509_ALGOR* algorithm;
const ASN1_OCTET_STRING* digest;
X509_SIG_get0(digest_info.get(), &algorithm, &digest);
int got_nid = OBJ_obj2nid(algorithm->algorithm);
if (got_nid != expected_digest_nid) {
return NewInvalidArgumentError(
absl::StrFormat("digest algorithm NID mismatch (got %d, want %d)",
got_nid, expected_digest_nid),
CKR_DATA_INVALID, SOURCE_LOCATION);
}
return std::vector<uint8_t>(digest->data, digest->data + digest->length);
}
} // namespace
// An implementation of SignerInterface that makes RSASSA-PKCS1 signatures using
// Cloud KMS.
class RsaPkcs1Signer : public KmsPrehashedSigner {
public:
static absl::StatusOr<std::unique_ptr<SignerInterface>> New(
std::shared_ptr<Object> key, const CK_MECHANISM* mechanism,
ExpectedInput input_type = ExpectedInput::kAsn1DigestInfo);
size_t signature_length() override;
absl::Status Sign(KmsClient* client, absl::Span<const uint8_t> data,
absl::Span<uint8_t> signature) override;
virtual ~RsaPkcs1Signer() {}
private:
RsaPkcs1Signer(std::shared_ptr<Object> object, bssl::UniquePtr<RSA> key,
ExpectedInput input_type)
: KmsPrehashedSigner(object),
key_(std::move(key)),
input_type_(input_type) {}
bssl::UniquePtr<RSA> key_;
ExpectedInput input_type_;
};
absl::StatusOr<std::unique_ptr<SignerInterface>> NewRsaPkcs1Signer(
std::shared_ptr<Object> key, const CK_MECHANISM* mechanism) {
CK_MECHANISM inner_mechanism = {CKM_RSA_PKCS_PSS, mechanism->pParameter,
mechanism->ulParameterLen};
switch (mechanism->mechanism) {
case CKM_RSA_PKCS:
return RsaPkcs1Signer::New(key, &inner_mechanism);
case CKM_SHA256_RSA_PKCS:
case CKM_SHA512_RSA_PKCS: {
ASSIGN_OR_RETURN(
auto signer,
RsaPkcs1Signer::New(key, &inner_mechanism, ExpectedInput::kDigest));
return KmsDigestingSigner::New(key, std::move(signer), mechanism);
}
default:
return NewInternalError(
absl::StrFormat("Mechanism %#x not supported for RSA-PKCS#1 signing",
mechanism->mechanism),
SOURCE_LOCATION);
}
}
absl::StatusOr<std::unique_ptr<SignerInterface>> RsaPkcs1Signer::New(
std::shared_ptr<Object> key, const CK_MECHANISM* mechanism,
ExpectedInput input_type) {
RETURN_IF_ERROR(
CheckKeyPreconditions(CKK_RSA, CKO_PRIVATE_KEY, CKM_RSA_PKCS, key.get()));
RETURN_IF_ERROR(EnsureNoParameters(mechanism));
ASSIGN_OR_RETURN(std::string_view key_der,
key->attributes().Value(CKA_PUBLIC_KEY_INFO));
ASSIGN_OR_RETURN(bssl::UniquePtr<EVP_PKEY> parsed_key,
ParseX509PublicKeyDer(key_der));
return std::unique_ptr<SignerInterface>(new RsaPkcs1Signer(
key, bssl::UniquePtr<RSA>(EVP_PKEY_get1_RSA(parsed_key.get())),
input_type));
}
size_t RsaPkcs1Signer::signature_length() { return RSA_size(key_.get()); }
absl::Status RsaPkcs1Signer::Sign(KmsClient* client,
absl::Span<const uint8_t> data,
absl::Span<uint8_t> signature) {
if (input_type_ == ExpectedInput::kDigest) {
return KmsPrehashedSigner::Sign(client, data, signature);
}
ASSIGN_OR_RETURN(const EVP_MD* md,
DigestForMechanism(*object()->algorithm().digest_mechanism));
ASSIGN_OR_RETURN(std::vector<uint8_t> digest,
ExtractDigest(data, EVP_MD_type(md)));
return KmsPrehashedSigner::Sign(client, digest, signature);
}
class RsaPkcs1Verifier : public VerifierInterface {
public:
static absl::StatusOr<std::unique_ptr<VerifierInterface>> New(
std::shared_ptr<Object> key, const CK_MECHANISM* mechanism,
ExpectedInput input_type = ExpectedInput::kAsn1DigestInfo);
Object* object() override { return object_.get(); };
absl::Status Verify(KmsClient* client, absl::Span<const uint8_t> data,
absl::Span<const uint8_t> signature) override;
virtual ~RsaPkcs1Verifier() {}
private:
RsaPkcs1Verifier(std::shared_ptr<Object> object, bssl::UniquePtr<RSA> key,
ExpectedInput input_type)
: object_(object), key_(std::move(key)), input_type_(input_type) {}
std::shared_ptr<Object> object_;
bssl::UniquePtr<RSA> key_;
ExpectedInput input_type_;
};
absl::StatusOr<std::unique_ptr<VerifierInterface>> NewRsaPkcs1Verifier(
std::shared_ptr<Object> key, const CK_MECHANISM* mechanism) {
CK_MECHANISM inner_mechanism = {CKM_RSA_PKCS, mechanism->pParameter,
mechanism->ulParameterLen};
switch (mechanism->mechanism) {
case CKM_RSA_PKCS:
return RsaPkcs1Verifier::New(key, &inner_mechanism);
case CKM_SHA256_RSA_PKCS:
case CKM_SHA512_RSA_PKCS: {
ASSIGN_OR_RETURN(
auto verifier,
RsaPkcs1Verifier::New(key, &inner_mechanism, ExpectedInput::kDigest));
return KmsDigestingVerifier::New(key, std::move(verifier), mechanism);
}
default:
return NewInternalError(
absl::StrFormat(
"Mechanism %#x not supported for RSA-PKCS#1 verification",
mechanism->mechanism),
SOURCE_LOCATION);
}
}
absl::StatusOr<std::unique_ptr<VerifierInterface>> RsaPkcs1Verifier::New(
std::shared_ptr<Object> key, const CK_MECHANISM* mechanism,
ExpectedInput input_type) {
RETURN_IF_ERROR(
CheckKeyPreconditions(CKK_RSA, CKO_PUBLIC_KEY, CKM_RSA_PKCS, key.get()));
RETURN_IF_ERROR(EnsureNoParameters(mechanism));
ASSIGN_OR_RETURN(std::string_view key_der,
key->attributes().Value(CKA_PUBLIC_KEY_INFO));
ASSIGN_OR_RETURN(bssl::UniquePtr<EVP_PKEY> parsed_key,
ParseX509PublicKeyDer(key_der));
return std::unique_ptr<VerifierInterface>(new RsaPkcs1Verifier(
key, bssl::UniquePtr<RSA>(EVP_PKEY_get1_RSA(parsed_key.get())),
input_type));
}
absl::Status RsaPkcs1Verifier::Verify(KmsClient* client,
absl::Span<const uint8_t> data,
absl::Span<const uint8_t> signature) {
ASSIGN_OR_RETURN(const EVP_MD* md,
DigestForMechanism(*object_->algorithm().digest_mechanism));
if (input_type_ == ExpectedInput::kDigest) {
return RsaVerifyPkcs1(key_.get(), md, data, signature);
}
ASSIGN_OR_RETURN(std::vector<uint8_t> digest,
ExtractDigest(data, EVP_MD_type(md)));
return RsaVerifyPkcs1(key_.get(), md, digest, signature);
}
} // namespace cloud_kms::kmsp11