From d46baaac9c1fe58e8a28845731ae7b28780f247c Mon Sep 17 00:00:00 2001 From: "mattm@chromium.org" Date: Thu, 22 May 2014 04:36:07 +0000 Subject: Add OpenSSL BIO method that writes to a std::string. BUG=none Review URL: https://codereview.chromium.org/286263006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@272100 0039d316-1c4b-4281-b951-d872f2087c98 --- crypto/crypto.gyp | 10 +++++ crypto/crypto.gypi | 2 + crypto/openssl_bio_string.cc | 77 +++++++++++++++++++++++++++++++++++ crypto/openssl_bio_string.h | 29 +++++++++++++ crypto/openssl_bio_string_unittest.cc | 66 ++++++++++++++++++++++++++++++ 5 files changed, 184 insertions(+) create mode 100644 crypto/openssl_bio_string.cc create mode 100644 crypto/openssl_bio_string.h create mode 100644 crypto/openssl_bio_string_unittest.cc (limited to 'crypto') diff --git a/crypto/crypto.gyp b/crypto/crypto.gyp index ec1e278..0c472ff 100644 --- a/crypto/crypto.gyp +++ b/crypto/crypto.gyp @@ -132,6 +132,8 @@ 'ec_signature_creator_openssl.cc', 'encryptor_openssl.cc', 'hmac_openssl.cc', + 'openssl_bio_string.cc', + 'openssl_bio_string.h', 'openssl_util.cc', 'openssl_util.h', 'rsa_private_key_openssl.cc', @@ -158,6 +160,7 @@ 'hkdf_unittest.cc', 'hmac_unittest.cc', 'nss_util_unittest.cc', + 'openssl_bio_string_unittest.cc', 'p224_unittest.cc', 'p224_spake_unittest.cc', 'random_unittest.cc', @@ -205,10 +208,17 @@ 'msvs_disabled_warnings': [4267, ], }], [ 'use_openssl==1', { + 'dependencies': [ + '../third_party/openssl/openssl.gyp:openssl', + ], 'sources!': [ 'nss_util_unittest.cc', 'rsa_private_key_nss_unittest.cc', ], + }, { + 'sources!': [ + 'openssl_bio_string_unittest.cc', + ], }], ], }, diff --git a/crypto/crypto.gypi b/crypto/crypto.gypi index a2dfe47..de65e19 100644 --- a/crypto/crypto.gypi +++ b/crypto/crypto.gypi @@ -68,6 +68,8 @@ 'nss_util.cc', 'nss_util.h', 'nss_util_internal.h', + 'openssl_bio_string.cc', + 'openssl_bio_string.h', 'openssl_util.cc', 'openssl_util.h', 'p224.cc', diff --git a/crypto/openssl_bio_string.cc b/crypto/openssl_bio_string.cc new file mode 100644 index 0000000..4880500 --- /dev/null +++ b/crypto/openssl_bio_string.cc @@ -0,0 +1,77 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "crypto/openssl_bio_string.h" + +#include +#include + +namespace crypto { + +namespace { + +int bio_string_write(BIO* bio, const char* data, int len) { + reinterpret_cast(bio->ptr)->append(data, len); + return len; +} + +int bio_string_puts(BIO* bio, const char* data) { + // Note: unlike puts(), BIO_puts does not add a newline. + return bio_string_write(bio, data, strlen(data)); +} + +long bio_string_ctrl(BIO* bio, int cmd, long num, void* ptr) { + std::string* str = reinterpret_cast(bio->ptr); + switch (cmd) { + case BIO_CTRL_RESET: + str->clear(); + return 1; + case BIO_C_FILE_SEEK: + return -1; + case BIO_C_FILE_TELL: + return str->size(); + case BIO_CTRL_FLUSH: + return 1; + default: + return 0; + } +} + +int bio_string_new(BIO* bio) { + bio->ptr = NULL; + bio->init = 0; + return 1; +} + +int bio_string_free(BIO* bio) { + // The string is owned by the caller, so there's nothing to do here. + return bio != NULL; +} + +BIO_METHOD bio_string_methods = { + // TODO(mattm): Should add some type number too? (bio.h uses 1-24) + BIO_TYPE_SOURCE_SINK, + "bio_string", + bio_string_write, + NULL, /* read */ + bio_string_puts, + NULL, /* gets */ + bio_string_ctrl, + bio_string_new, + bio_string_free, + NULL, /* callback_ctrl */ +}; + +} // namespace + +BIO* BIO_new_string(std::string* out) { + BIO* bio = BIO_new(&bio_string_methods); + if (!bio) + return bio; + bio->ptr = out; + bio->init = 1; + return bio; +} + +} // namespace crypto diff --git a/crypto/openssl_bio_string.h b/crypto/openssl_bio_string.h new file mode 100644 index 0000000..70d4331 --- /dev/null +++ b/crypto/openssl_bio_string.h @@ -0,0 +1,29 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CRYPTO_OPENSSL_BIO_STRING_H_ +#define CRYPTO_OPENSSL_BIO_STRING_H_ + +#include + +#include "crypto/crypto_export.h" + +// From +typedef struct bio_st BIO; + +namespace crypto { + +// Creates a new BIO that can be used with OpenSSL's various output functions, +// and which will write all output directly into |out|. This is primarily +// intended as a utility to reduce the amount of copying and separate +// allocations when performing extensive string modifications or streaming +// within OpenSSL. +// +// Note: |out| must remain valid for the duration of the BIO. +BIO* CRYPTO_EXPORT BIO_new_string(std::string* out); + +} // namespace crypto + +#endif // CRYPTO_OPENSSL_BIO_STRING_H_ + diff --git a/crypto/openssl_bio_string_unittest.cc b/crypto/openssl_bio_string_unittest.cc new file mode 100644 index 0000000..39d3a9a --- /dev/null +++ b/crypto/openssl_bio_string_unittest.cc @@ -0,0 +1,66 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "crypto/openssl_bio_string.h" + +#include + +#include "crypto/openssl_util.h" +#include "testing/gtest/include/gtest/gtest.h" + +TEST(OpenSSLBIOString, TestWrite) { + std::string s; + const std::string expected1("a one\nb 2\n"); + const std::string expected2("c d e f"); + const std::string expected3("g h i"); + { + crypto::ScopedOpenSSL bio(crypto::BIO_new_string(&s)); + ASSERT_TRUE(bio.get()); + + EXPECT_EQ(static_cast(expected1.size()), + BIO_printf(bio.get(), "a %s\nb %i\n", "one", 2)); + EXPECT_EQ(expected1, s); + EXPECT_EQ(static_cast(expected1.size()), BIO_tell(bio.get())); + + EXPECT_EQ(1, BIO_flush(bio.get())); + EXPECT_EQ(-1, BIO_seek(bio.get(), 0)); + EXPECT_EQ(expected1, s); + + EXPECT_EQ(static_cast(expected2.size()), + BIO_write(bio.get(), expected2.data(), expected2.size())); + EXPECT_EQ(expected1 + expected2, s); + EXPECT_EQ(static_cast(expected1.size() + expected2.size()), + BIO_tell(bio.get())); + + EXPECT_EQ(static_cast(expected3.size()), + BIO_puts(bio.get(), expected3.c_str())); + EXPECT_EQ(expected1 + expected2 + expected3, s); + EXPECT_EQ(static_cast(expected1.size() + expected2.size() + + expected3.size()), + BIO_tell(bio.get())); + } + EXPECT_EQ(expected1 + expected2 + expected3, s); +} + +TEST(OpenSSLBIOString, TestReset) { + std::string s; + const std::string expected1("a b c\n"); + const std::string expected2("d e f g\n"); + { + crypto::ScopedOpenSSL bio(crypto::BIO_new_string(&s)); + ASSERT_TRUE(bio.get()); + + EXPECT_EQ(static_cast(expected1.size()), + BIO_write(bio.get(), expected1.data(), expected1.size())); + EXPECT_EQ(expected1, s); + + EXPECT_EQ(1, BIO_reset(bio.get())); + EXPECT_EQ(std::string(), s); + + EXPECT_EQ(static_cast(expected2.size()), + BIO_write(bio.get(), expected2.data(), expected2.size())); + EXPECT_EQ(expected2, s); + } + EXPECT_EQ(expected2, s); +} -- cgit v1.1