Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Safe memory storage #1997

Merged
merged 16 commits into from
Mar 21, 2024
Merged

Safe memory storage #1997

merged 16 commits into from
Mar 21, 2024

Conversation

Harrm
Copy link
Contributor

@Harrm Harrm commented Mar 1, 2024

Referenced issues

resolves https://github.com/qdrvm/KAGOME-audit/issues/29

Description of the Change

Storage for private keys and seeds is allocated in secure OpenSSL heap.

Benefits

  • Secure heap won't be swapped on disk or appear in core dumps, it is also protected from reads due to out-of-bounds UB
  • Private key memory is properly cleaned up when no longer needed

Possible Drawbacks

  • Data leaks to insecure memory due to interaction with dependencies, primarily libp2p
  • Secure store is limited in size and in the current implementation its size is fixed in compile time

Usage Examples or Tests

Alternate Designs

@Harrm Harrm requested review from turuslan and iceseer March 5, 2024 09:39
@Harrm Harrm marked this pull request as ready for review March 5, 2024 09:39
Comment on lines +1 to +9
/**
* Copyright Quadrivium LLC
* All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*/

#include "crypto/common.hpp"

namespace kagome::crypto {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove empty .cpp file

core/crypto/common.hpp Outdated Show resolved Hide resolved

namespace kagome::crypto::bip39 {
namespace constants {
constexpr size_t BIP39_SEED_LEN_512 = 64u;
} // namespace constants

using Bip39Seed = common::Buffer;
struct Bip39Tag;
using Bip39Seed = PrivateKey<constants::BIP39_SEED_LEN_512, Bip39Tag>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revert, Bip39Seed is variable size.
https://github.com/paritytech/polkadot-sdk/blob/8f8297e9debe79139e3a41be8b54a5fcd603f783/substrate/primitives/core/src/crypto.rs#L966-L991
from_string_with_seed() { if let Some(hex) { Self::Seed::fromHex(hex) } }

core/crypto/common.hpp Show resolved Hide resolved
@@ -71,7 +70,7 @@ namespace kagome::crypto {
* Create a seed from its bytes
*/
virtual outcome::result<Seed> toSeed(
common::BufferView bytes) const noexcept = 0;
SecureCleanGuard<uint8_t> bytes) const noexcept = 0;
Copy link
Contributor

@turuslan turuslan Mar 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revert to (span) (or (const SecureCleanGuard &))?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? I want to make the user to clean up the memory used to iniitalize the seed.

core/crypto/pbkdf2/pbkdf2_provider.hpp Outdated Show resolved Hide resolved
core/crypto/common.hpp Show resolved Hide resolved
Comment on lines +67 to +68
template <std::output_iterator<uint8_t> Iter>
outcome::result<void> unhex_to(std::string_view hex, Iter out) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

out is vector or array or span

Suggested change
template <std::output_iterator<uint8_t> Iter>
outcome::result<void> unhex_to(std::string_view hex, Iter out) {
template <typename T>
outcome::result<void> unhex_to(std::string_view hex, T &out) {
if constexpr (requires { out.resize(); }) {
out.resize(hex.size() / 2);
} else if (hex.size() != out.size() * 2) {
return ERROR;
}

core/common/hexutil.hpp Outdated Show resolved Hide resolved
Comment on lines +65 to +66
.secret_key = crypto::Ed25519PrivateKey::from(
crypto::SecureCleanGuard(private_key_bytes)),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.secret_key = crypto::Ed25519PrivateKey::from(
crypto::SecureCleanGuard(private_key_bytes)),
.secret_key = fromSpan<crypto::Ed25519PrivateKey>(libp2p_key.privateKey.data).value(),

Comment on lines +163 to +167
template <size_t Offset, size_t Length>
BufferView view() const {
return std::span(*this).template subspan<Offset, Length>();
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Don't add Buffer member function.
  2. Use std::span{}.subspan<_, _>() directly.
  3. Must check size.
  4. May make free function for any span.
Suggested change
template <size_t Offset, size_t Length>
BufferView view() const {
return std::span(*this).template subspan<Offset, Length>();
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But why?

Comment on lines 97 to 102
if (seed.size() != HEX_SEED_STR_LENGTH) {
return bip39::MnemonicError::INVALID_SEED_LENGTH;
}
SecureBuffer<> bytes(HEX_SEED_BIT_LENGTH, 0);
OUTCOME_TRY(common::unhexWith0x(seed, bytes.begin()));
OUTCOME_TRY(seed, Bip39Seed::from(std::move(bytes)));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If Mnemonic.seed is Bip39Seed, and Bip39Seed is not vector but byte[64]

Suggested change
if (seed.size() != HEX_SEED_STR_LENGTH) {
return bip39::MnemonicError::INVALID_SEED_LENGTH;
}
SecureBuffer<> bytes(HEX_SEED_BIT_LENGTH, 0);
OUTCOME_TRY(common::unhexWith0x(seed, bytes.begin()));
OUTCOME_TRY(seed, Bip39Seed::from(std::move(bytes)));
Bip39Seed seed;
// ed25519/sr25519/ecdsa/bandersnatch seeds are 32 bytes
OUTCOME_TRY(common::unhexWith0x(seed, std::span{seed}.first(32));
mnemonic.seed = std::move(seed);

@@ -29,12 +30,12 @@ namespace kagome::crypto::bip39 {
struct Mnemonic {
using Words = std::vector<std::string>;

boost::variant<common::Buffer, Words> seed;
std::variant<Words, Bip39Seed> seed;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not Bip39Seed (byte[64]).
May rename to entropy.
Must be variant<Words, vector> or variant<Words, byte[32]> (because current crypto types use 32 bytes seed).

core/crypto/crypto_store/crypto_store_impl.cpp Outdated Show resolved Hide resolved
core/crypto/pbkdf2/pbkdf2_provider.hpp Show resolved Hide resolved
@Harrm Harrm merged commit 3848227 into master Mar 21, 2024
9 of 10 checks passed
@Harrm Harrm deleted the feature/safe-memory branch March 21, 2024 11:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants