kmsp11/util/crypto_utils.h (81 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. */ #ifndef KMSP11_UTIL_CRYPTO_UTILS_H_ #define KMSP11_UTIL_CRYPTO_UTILS_H_ #include <string> #include <vector> #include "absl/status/statusor.h" #include "absl/time/time.h" #include "common/kms_v1.h" #include "common/openssl.h" #include "kmsp11/cryptoki.h" namespace cloud_kms::kmsp11 { // Convert an ASN1_TIME structure to an absl::Time. absl::StatusOr<absl::Time> Asn1TimeToAbsl(const ASN1_TIME* time); // Convert the provided BIGNUM to big-endian binary, padding with leading zeroes // to fill dest. absl::Status BignumToBinary(const BIGNUM* src, absl::Span<uint8_t> dest); // Checks that BoringSSL is operating in FIPS mode, and that FIPS self-tests // pass. Returns FailedPrecondition if BoringSSL is not in FIPS mode; or // Internal if the self-tests fail. absl::Status CheckFipsSelfTest(); // Returns an EVP_MD* for the provided digest mechanism, or returns // InternalError if the provided mechanism is not a recognized digest. absl::StatusOr<const EVP_MD*> DigestForMechanism(CK_MECHANISM_TYPE mechanism); // Converts a signature in ASN.1 format (as returned by OpenSSL and Cloud KMS) // into IEEE P-1363 format (as required by PKCS #11). absl::StatusOr<std::vector<uint8_t>> EcdsaSigAsn1ToP1363( std::string_view asn1_sig, const EC_GROUP* group); // Returns the length of a signature in IEEE P-1363 format (with leading zeroes) // for the provided group. int EcdsaSigLengthP1363(const EC_GROUP* group); // Verifies that the provided signature in IEEE P-1363 format is a valid // signature over digest. absl::Status EcdsaVerifyP1363(EC_KEY* public_key, const EVP_MD* hash, absl::Span<const uint8_t> digest, absl::Span<const uint8_t> signature); // Encrypts plaintext using RSAES-OAEP with MGF-1, and writes it to ciphertext. // Ciphertext size must be exactly equal to the RSA modulus size. Hash is used // in both OAEP and MGF-1; OAEP labels are not supported. absl::Status EncryptRsaOaep(EVP_PKEY* key, const EVP_MD* hash, absl::Span<const uint8_t> plaintext, absl::Span<uint8_t> ciphertext); // Marshals an ASN.1 integer in DER format. absl::StatusOr<std::string> MarshalAsn1Integer(ASN1_INTEGER* value); // Marshals EC Parameters (always of choice NamedCurve) in DER format for the // provided key. // // Required to populate the attribute CKA_EC_PARAMS: // http://docs.oasis-open.org/pkcs11/pkcs11-curr/v2.40/errata01/os/pkcs11-curr-v2.40-errata01-os-complete.html#_Toc468937842 absl::StatusOr<std::string> MarshalEcParametersDer(BSSL_CONST EC_KEY* key); // Marshals the provided EC public key to an ASN.1 Octet String in DER format. // // Required to populate the attribute CKA_EC_POINT: // http://docs.oasis-open.org/pkcs11/pkcs11-curr/v2.40/errata01/os/pkcs11-curr-v2.40-errata01-os-complete.html#_Toc416960012 absl::StatusOr<std::string> MarshalEcPointToAsn1OctetStringDer( BSSL_CONST EC_KEY* key); // Marshals an X.509 certificate in DER format. absl::StatusOr<std::string> MarshalX509CertificateDer(X509* cert); // Marshals an X.509 name (subject or issuer) in DER format. absl::StatusOr<std::string> MarshalX509Name(X509_NAME* value); // Marshals a public key to X.509 SubjectPublicKeyInfo DER format. // // Required to populate the attribute CKA_PUBLIC_KEY_INFO: // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/errata01/os/pkcs11-base-v2.40-errata01-os-complete.html#_Toc441755781 absl::StatusOr<std::string> MarshalX509PublicKeyDer(BSSL_CONST EVP_PKEY* key); // Parses a private key in PKCS #8 PrivateKey PEM format. Returns // InvalidArgument if the provided key is malformed. absl::StatusOr<bssl::UniquePtr<EVP_PKEY>> ParsePkcs8PrivateKeyPem( std::string_view private_key_pem); // Marshals an ASN.1 DigestInfo in DER format. absl::StatusOr<std::string> MarshalX509Sig(X509_SIG* value); // Parses an X.509 certificate in DER format. Returns InvalidArgument if // the provided certificate is malformed. absl::StatusOr<bssl::UniquePtr<X509>> ParseX509CertificateDer( std::string_view certificate_der); // Parses an X.509 certificate in PEM format. Returns InvalidArgument if // the provided certificate is malformed. absl::StatusOr<bssl::UniquePtr<X509>> ParseX509CertificatePem( std::string_view certificate_pem); // Parses a public key in X.509 SubjectPublicKeyInfo DER format. Returns // InvalidArgument if the provided key is malformed. absl::StatusOr<bssl::UniquePtr<EVP_PKEY>> ParseX509PublicKeyDer( std::string_view public_key_der); // Parses a public key in X.509 SubjectPublicKeyInfo PEM format. Returns // InvalidArgument if the provided key is malformed. // Required to parse PEM public keys retrieved from Cloud KMS. absl::StatusOr<bssl::UniquePtr<EVP_PKEY>> ParseX509PublicKeyPem( std::string_view public_key_pem); // Retrieves len bytes of randomness from Boring's CSPRNG. std::string RandBytes(size_t len); // Uses Boring's CSPRNG to generate a random CK_ULONG for use as a Cryptoki // handle. Note that 0 is never returned, since 0 is CK_INVALID_HANDLE. CK_ULONG RandomHandle(); // Verifies that the provided RSA PKCS1 signature is valid over digest. absl::Status RsaVerifyPkcs1(RSA* public_key, const EVP_MD* hash, absl::Span<const uint8_t> digest, absl::Span<const uint8_t> signature); // Verifies that the provided RSA PSS signature is valid over digest. // PSS options are not configurable: MGF1 hash is always the same as the data // hash, and salt length always equals hash length. absl::Status RsaVerifyPss(EVP_PKEY* public_key, const EVP_MD* hash, absl::Span<const uint8_t> digest, absl::Span<const uint8_t> signature); // Verifies that the provided raw RSA PKCS #1 signature is valid over data. absl::Status RsaVerifyRawPkcs1(RSA* public_key, absl::Span<const uint8_t> data, absl::Span<const uint8_t> signature); // Returns whether or not the algorithm is a raw RSA PKCS #1 algorithm. bool IsRawRsaAlgorithm( kms_v1::CryptoKeyVersion::CryptoKeyVersionAlgorithm algorithm); // Build a DigestInfo structure, which is the expected input into a CKM_RSA_PKCS // signing operation. // http://docs.oasis-open.org/pkcs11/pkcs11-curr/v2.40/errata01/os/pkcs11-curr-v2.40-errata01-os-complete.html#_Toc441850410 absl::StatusOr<std::vector<uint8_t>> BuildRsaDigestInfo( int digest_nid, absl::Span<const uint8_t> digest); // Retrieves the contents of BoringSSL's error stack, and dumps it to a string. // If no errors are found on the stack, `default_message` is returned instead. std::string SslErrorToString( std::string_view default_message = "(error could not be retrieved from the SSL stack)"); // A replacement for std::allocator that zeroes before deallocating. // // Suggested usage: // std::vector<uint8_t, ZeroDeallocator<uint8_t>> t; template <typename T> struct ZeroDeallocator { using value_type = T; ZeroDeallocator() = default; template <class U> constexpr ZeroDeallocator(const ZeroDeallocator<U>&) noexcept {} T* allocate(std::size_t len) { return static_cast<T*>(std::malloc(len)); } void deallocate(T* ptr, std::size_t len) { OPENSSL_cleanse(ptr, len); std::free(ptr); } }; // A replacement for std::default_delete that zeroes before deleting. // // Suggested usage: // std::unique_ptr<std::string, ZeroDelete<std::string>> t; template <typename T> struct ZeroDelete { void operator()(T* value) const { if (value) { OPENSSL_cleanse(value->data(), value->size()); } delete value; } }; } // namespace cloud_kms::kmsp11 #endif // KMSP11_UTIL_CRYPTO_UTILS_H_