blob: 2e7d3d7652061af3231d7dee396dc9a7a6ff7eda [file] [log] [blame]
// Copyright 2018 Google Inc.
//
// 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 "tink/subtle/pem_parser_boringssl.h"
#include <memory>
#include <vector>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/strings/string_view.h"
#include "openssl/base.h"
#include "openssl/bio.h"
#include "openssl/bn.h"
#include "openssl/evp.h"
#include "openssl/pem.h"
#include "openssl/rsa.h"
#include "tink/subtle/subtle_util_boringssl.h"
#include "tink/util/status.h"
#include "tink/util/statusor.h"
#include "tink/util/test_matchers.h"
#include "tink/util/test_util.h"
namespace crypto {
namespace tink {
namespace subtle {
namespace {
class PemParserTest : public ::testing::Test {
public:
PemParserTest() : rsa_(RSA_new()) {}
void SetUp() override {
// Create a new RSA key and output to PEM.
ASSERT_THAT(rsa_, testing::NotNull());
bssl::UniquePtr<BIGNUM> e(BN_new());
ASSERT_THAT(e, testing::NotNull());
BN_set_word(e.get(), RSA_F4);
// Generate a 2048 bits RSA key pair.
EXPECT_EQ(RSA_generate_key_ex(rsa_.get(), 2048, e.get(), /*cb=*/nullptr), 1)
<< SubtleUtilBoringSSL::GetErrors();
// Write keys to PEM.
bssl::UniquePtr<BIO> pub_key_pem_bio(BIO_new(BIO_s_mem()));
bssl::UniquePtr<BIO> prv_key_pem_bio(BIO_new(BIO_s_mem()));
// Write in PEM format.
EXPECT_EQ(PEM_write_bio_RSA_PUBKEY(pub_key_pem_bio.get(), rsa_.get()), 1)
<< SubtleUtilBoringSSL::GetErrors();
EXPECT_EQ(
PEM_write_bio_RSAPrivateKey(prv_key_pem_bio.get(), rsa_.get(),
/*enc=*/nullptr, /*kstr=*/nullptr,
/*klen=*/0, /*cb=*/nullptr, /*u=*/nullptr),
1)
<< SubtleUtilBoringSSL::GetErrors();
pem_rsa_pub_key_.resize(pub_key_pem_bio->num_write + 1);
pem_rsa_prv_key_.resize(prv_key_pem_bio->num_write + 1);
EXPECT_EQ(BIO_read(pub_key_pem_bio.get(), pem_rsa_pub_key_.data(),
pub_key_pem_bio->num_write),
pub_key_pem_bio->num_write);
EXPECT_EQ(BIO_read(prv_key_pem_bio.get(), pem_rsa_prv_key_.data(),
prv_key_pem_bio->num_write),
prv_key_pem_bio->num_write);
}
protected:
// PEM encoded 2048 bit RSA key pair.
std::vector<char> pem_rsa_pub_key_;
std::vector<char> pem_rsa_prv_key_;
// Holds the RSA object.
bssl::UniquePtr<RSA> rsa_;
};
// Corrupts `container` by modifying one the elements in the middle.
template <class ContainerType>
void Corrupt(ContainerType* container) {
if (container->empty()) {
return;
}
std::vector<char> corrupted(container->begin(), container->end());
size_t pos = corrupted.size() / 2;
corrupted[pos] ^= 1;
container->assign(corrupted.begin(), corrupted.end());
}
// Test we can correctly parse an RSA public key.
TEST_F(PemParserTest, ReadRsaPublicKey) {
auto key_statusor = PemParser::ParseRsaPublicKey(
absl::string_view(pem_rsa_pub_key_.data(), pem_rsa_pub_key_.size()));
ASSERT_TRUE(key_statusor.ok()) << SubtleUtilBoringSSL::GetErrors();
// Verify exponent and modulus are correctly set.
auto key = std::move(key_statusor.ValueOrDie());
const BIGNUM *e_bn, *n_bn;
RSA_get0_key(rsa_.get(), &n_bn, &e_bn, nullptr);
EXPECT_EQ(key->e,
SubtleUtilBoringSSL::bn2str(e_bn, BN_num_bytes(e_bn)).ValueOrDie());
EXPECT_EQ(key->n,
SubtleUtilBoringSSL::bn2str(n_bn, BN_num_bytes(n_bn)).ValueOrDie());
}
// Test we can correctly parse an RSA private key.
TEST_F(PemParserTest, ReadRsaPrivatekey) {
auto key_statusor = PemParser::ParseRsaPrivateKey(
absl::string_view(pem_rsa_prv_key_.data(), pem_rsa_prv_key_.size()));
ASSERT_TRUE(key_statusor.ok()) << SubtleUtilBoringSSL::GetErrors();
// Verify exponents and modulus.
auto key = std::move(key_statusor.ValueOrDie());
const BIGNUM *e_bn, *n_bn, *d_bn;
RSA_get0_key(rsa_.get(), &n_bn, &e_bn, &d_bn);
EXPECT_EQ(key->e,
SubtleUtilBoringSSL::bn2str(e_bn, BN_num_bytes(e_bn)).ValueOrDie());
EXPECT_EQ(key->n,
SubtleUtilBoringSSL::bn2str(n_bn, BN_num_bytes(n_bn)).ValueOrDie());
EXPECT_EQ(key->d,
SubtleUtilBoringSSL::bn2str(d_bn, BN_num_bytes(d_bn)).ValueOrDie());
// Verify private key factors.
const BIGNUM *p_bn, *q_bn;
RSA_get0_factors(rsa_.get(), &p_bn, &q_bn);
EXPECT_EQ(key->p,
SubtleUtilBoringSSL::bn2str(p_bn, BN_num_bytes(p_bn)).ValueOrDie());
EXPECT_EQ(key->q,
SubtleUtilBoringSSL::bn2str(q_bn, BN_num_bytes(q_bn)).ValueOrDie());
// Verify CRT parameters.
const BIGNUM *dp_bn, *dq_bn, *crt_bn;
RSA_get0_crt_params(rsa_.get(), &dp_bn, &dq_bn, &crt_bn);
EXPECT_EQ(
key->dp,
SubtleUtilBoringSSL::bn2str(dp_bn, BN_num_bytes(dp_bn)).ValueOrDie());
EXPECT_EQ(
key->dq,
SubtleUtilBoringSSL::bn2str(dq_bn, BN_num_bytes(dq_bn)).ValueOrDie());
EXPECT_EQ(
key->crt,
SubtleUtilBoringSSL::bn2str(crt_bn, BN_num_bytes(crt_bn)).ValueOrDie());
}
TEST_F(PemParserTest, ReadRsaPublicKeyInvalid) {
Corrupt(&pem_rsa_pub_key_);
EXPECT_TRUE(
!PemParser::ParseRsaPrivateKey(
absl::string_view(pem_rsa_pub_key_.data(), pem_rsa_pub_key_.size()))
.ok());
}
TEST_F(PemParserTest, ReadRsaPrivateKeyInvalid) {
Corrupt(&pem_rsa_prv_key_);
EXPECT_TRUE(
!PemParser::ParseRsaPrivateKey(
absl::string_view(pem_rsa_prv_key_.data(), pem_rsa_prv_key_.size()))
.ok());
}
} // namespace
} // namespace subtle
} // namespace tink
} // namespace crypto