kmsp11/operation/ecdsa.cc (124 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/ecdsa.h" #include <string_view> #include "common/kms_client.h" #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 { // An implementation of SignerInterface that makes ECDSA signatures using Cloud // KMS. class EcdsaSigner : public KmsPrehashedSigner { public: static absl::StatusOr<std::unique_ptr<SignerInterface>> New( std::shared_ptr<Object> key, const CK_MECHANISM* mechanism); size_t signature_length() override; absl::Status CopySignature(std::string_view src, absl::Span<uint8_t> dest) override; virtual ~EcdsaSigner() {} private: EcdsaSigner(std::shared_ptr<Object> object, bssl::UniquePtr<EC_KEY> key) : KmsPrehashedSigner(object), key_(std::move(key)) {} bssl::UniquePtr<EC_KEY> key_; }; absl::StatusOr<std::unique_ptr<SignerInterface>> NewEcdsaSigner( std::shared_ptr<Object> key, const CK_MECHANISM* mechanism) { CK_MECHANISM inner_mechanism = {CKM_ECDSA, mechanism->pParameter, mechanism->ulParameterLen}; ASSIGN_OR_RETURN(auto signer, EcdsaSigner::New(key, &inner_mechanism)); switch (mechanism->mechanism) { case CKM_ECDSA: return signer; case CKM_ECDSA_SHA256: case CKM_ECDSA_SHA384: return KmsDigestingSigner::New(key, std::move(signer), mechanism); default: return NewInternalError( absl::StrFormat("Mechanism %#x not supported for ECDSA signing", mechanism->mechanism), SOURCE_LOCATION); } } absl::StatusOr<std::unique_ptr<SignerInterface>> EcdsaSigner::New( std::shared_ptr<Object> key, const CK_MECHANISM* mechanism) { RETURN_IF_ERROR(CheckKeyPreconditions(CKK_EC, CKO_PRIVATE_KEY, mechanism->mechanism, 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 EcdsaSigner( key, bssl::UniquePtr<EC_KEY>(EVP_PKEY_get1_EC_KEY(parsed_key.get())))); } size_t EcdsaSigner::signature_length() { return EcdsaSigLengthP1363(EC_KEY_get0_group(key_.get())); } absl::Status EcdsaSigner::CopySignature(std::string_view src, absl::Span<uint8_t> dest) { ASSIGN_OR_RETURN(std::vector<uint8_t> p1363_sig, EcdsaSigAsn1ToP1363(src, EC_KEY_get0_group(key_.get()))); if (p1363_sig.size() != signature_length()) { return NewInternalError( absl::StrFormat("unexpected signature length (got %d, want %d)", p1363_sig.size(), signature_length()), SOURCE_LOCATION); } std::copy(p1363_sig.begin(), p1363_sig.end(), dest.data()); return absl::OkStatus(); } class EcdsaVerifier : public VerifierInterface { public: static absl::StatusOr<std::unique_ptr<VerifierInterface>> New( std::shared_ptr<Object> key, const CK_MECHANISM* mechanism); Object* object() override { return object_.get(); }; absl::Status Verify(KmsClient* client, absl::Span<const uint8_t> digest, absl::Span<const uint8_t> signature) override; virtual ~EcdsaVerifier() {} private: EcdsaVerifier(std::shared_ptr<Object> object, bssl::UniquePtr<EC_KEY> key) : object_(object), key_(std::move(key)) {} std::shared_ptr<Object> object_; bssl::UniquePtr<EC_KEY> key_; }; absl::StatusOr<std::unique_ptr<VerifierInterface>> NewEcdsaVerifier( std::shared_ptr<Object> key, const CK_MECHANISM* mechanism) { CK_MECHANISM inner_mechanism = {CKM_ECDSA, mechanism->pParameter, mechanism->ulParameterLen}; ASSIGN_OR_RETURN(auto verifier, EcdsaVerifier::New(key, &inner_mechanism)); switch (mechanism->mechanism) { case CKM_ECDSA: return verifier; case CKM_ECDSA_SHA256: case CKM_ECDSA_SHA384: return KmsDigestingVerifier::New(key, std::move(verifier), mechanism); default: return NewInternalError( absl::StrFormat("Mechanism %#x not supported for ECDSA verification", mechanism->mechanism), SOURCE_LOCATION); } } absl::StatusOr<std::unique_ptr<VerifierInterface>> EcdsaVerifier::New( std::shared_ptr<Object> key, const CK_MECHANISM* mechanism) { RETURN_IF_ERROR( CheckKeyPreconditions(CKK_EC, CKO_PUBLIC_KEY, CKM_ECDSA, 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 EcdsaVerifier( key, bssl::UniquePtr<EC_KEY>(EVP_PKEY_get1_EC_KEY(parsed_key.get())))); } absl::Status EcdsaVerifier::Verify(KmsClient* client, absl::Span<const uint8_t> digest, absl::Span<const uint8_t> signature) { ASSIGN_OR_RETURN(const EVP_MD* md, DigestForMechanism(*object_->algorithm().digest_mechanism)); return EcdsaVerifyP1363(key_.get(), md, digest, signature); } } // namespace cloud_kms::kmsp11