Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
matrix:
os: [windows-latest, ubuntu-latest, macos-latest]
crypto: [OPENSSL_1_1, OPENSSL_3, BORINGSSL]
no_alloc: [OFF, ON]
include:
- os: windows-latest
vcpkg-cmake-file: "$env:VCPKG_INSTALLATION_ROOT\\scripts\\buildsystems\\vcpkg.cmake"
Expand Down Expand Up @@ -58,8 +59,12 @@ jobs:
key: ${{ runner.os }}-${{ hashFiles( '**/vcpkg.json' ) }}

- name: configure to use clang-tidy and sanitizers
run: >
cmake -B "${{ env.CMAKE_BUILD_DIR }}" -DTESTING=ON -DCLANG_TIDY=ON -DSANITIZERS=ON -DCMAKE_TOOLCHAIN_FILE="${{ matrix.vcpkg-cmake-file}}" -DCRYPTO="${{ matrix.crypto }}" -DVCPKG_MANIFEST_DIR="alternatives/${{ matrix.crypto }}"
run: cmake -B "${{ env.CMAKE_BUILD_DIR }}"
-DTESTING=ON -DCLANG_TIDY=ON -DSANITIZERS=ON
-DCMAKE_TOOLCHAIN_FILE="${{ matrix.vcpkg-cmake-file}}"
-DCRYPTO="${{ matrix.crypto }}"
-DVCPKG_MANIFEST_DIR="alternatives/${{ matrix.crypto }}"
-DNO_ALLOC="${{ matrix.no_alloc }}"

- name: build
run: |
Expand Down
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ project(sframe
option(TESTING "Build tests" OFF)
option(CLANG_TIDY "Perform linting with clang-tidy" OFF)
option(SANITIZERS "Enable sanitizers" OFF)
option(NO_ALLOC "Build without needing an allocator" OFF)

# Use -DCRYPTO=(OPENSSL_1_1 | OPENSSL_3 | BORINGSSL) to configure crypto
if(NOT DEFINED CRYPTO)
Expand Down Expand Up @@ -49,6 +50,11 @@ if(CLANG_TIDY)
endif()
endif()

if(NO_ALLOC)
message(STATUS "Configuring no-allocator version")
add_definitions(-DNO_ALLOC)
endif()

###
### Dependencies
###
Expand Down
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ devB: CMakeLists.txt test/CMakeLists.txt
-DCLANG_TIDY=ON -DSANITIZERS=ON \
-DCRYPTO=BORINGSSL -DVCPKG_MANIFEST_DIR=${BORINGSSL_MANIFEST}

dev-nostd: CMakeLists.txt test/CMakeLists.txt
cmake -B${BUILD_DIR} -DCMAKE_BUILD_TYPE=Debug -DCLANG_TIDY=ON -DTESTING=ON -DSANITIZERS=ON -DNO_ALLOC=ON .

${TEST_BIN}: ${LIB} test/*
cmake --build ${BUILD_DIR} --target sframe_test

Expand Down
45 changes: 45 additions & 0 deletions include/sframe/map.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
#pragma once

#ifdef NO_ALLOC

#include <sframe/vector.h>

namespace sframe {

template<typename K, typename V, size_t N>
class map : private vector<std::optional<std::pair<K, V>>, N>
{
Expand Down Expand Up @@ -64,3 +68,44 @@ class map : private vector<std::optional<std::pair<K, V>>, N>
std::replace_if(this->begin(), this->end(), to_erase, std::nullopt);
}
};

} // namespace sframe

#else // ifdef NO_ALLOC

#include <map>

namespace sframe {

// NOTE: NOT RECOMMENDED FOR USE OUTSIDE THIS LIBRARY
//
// We have used public inheritance from std::map<T> to simplify the interface
// here. This works fine for the use cases we have within this library. If you
// choose to use this map type outside this library, you MUST NOT store it as a
// std::map<T> pointer or reference. This will cause memory leaks, because the
// destructor ~std::map<T> is not virtual.
template<typename K, typename V, size_t N>
class map : public std::map<K, V>
{
private:
using parent = std::map<K, V>;

public:
bool contains(const K& key) const { return this->count(key) > 0; }

template<typename F>
void erase_if_key(F&& f)
{
for (auto iter = this->begin(); iter != this->end();) {
if (f(iter->first)) {
iter = this->erase(iter);
} else {
++iter;
}
}
}
};

} // namespace sframe

#endif // def NO_ALLOC
24 changes: 18 additions & 6 deletions include/sframe/sframe.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,22 @@
#include <sframe/map.h>
#include <sframe/vector.h>

// These constants define the size of certain internal data structures if
// we are configured not to depend on dynamic allocations, i.e., if the NO_ALLOC
// flag is set. If you are using an allocator, you can ignore them.
//
// Note that these constants must be the same at the time when the library is
// built as at the time when it is used. If you are using a pre-built binary,
// you must make sure that these parameters have the same values as when the
// library was built.
#ifndef SFRAME_MAX_KEYS
#define SFRAME_MAX_KEYS 200
#endif

#ifndef SFRAME_EPOCH_BITS
#define SFRAME_EPOCH_BITS 4
#endif

namespace sframe {

struct crypto_error : std::runtime_error
Expand Down Expand Up @@ -58,7 +74,6 @@ using owned_bytes = vector<uint8_t, N>;

using KeyID = uint64_t;
using Counter = uint64_t;

class Header;

enum struct KeyUsage
Expand Down Expand Up @@ -106,10 +121,8 @@ class Context
static constexpr size_t max_metadata_size = 512;

protected:
static constexpr size_t max_keys = 200;

CipherSuite suite;
map<KeyID, KeyRecord, max_keys> keys;
map<KeyID, KeyRecord, SFRAME_MAX_KEYS> keys;

output_bytes protect_inner(const Header& header,
output_bytes ciphertext,
Expand Down Expand Up @@ -185,8 +198,7 @@ class MLSContext : protected Context
const size_t epoch_bits;
const size_t epoch_mask;

// XXX(RLB) Make this an attribute of the class?
static constexpr size_t max_epochs = 16;
static constexpr size_t max_epochs = 1 << SFRAME_EPOCH_BITS;
vector<std::optional<EpochKeys>, max_epochs> epoch_cache;
};

Expand Down
59 changes: 59 additions & 0 deletions include/sframe/vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

#include <gsl/gsl-lite.hpp>

#ifdef NO_ALLOC

namespace sframe {

template<typename T, size_t N>
class vector
{
Expand Down Expand Up @@ -81,3 +85,58 @@ class vector
operator gsl::span<const T>() const { return gsl::span(_data).first(_size); }
operator gsl::span<T>() { return gsl::span(_data).first(_size); }
};

} // namespace sframe

#else // ifdef NO_ALLOC

#include <vector>

namespace sframe {

// NOTE: NOT RECOMMENDED FOR USE OUTSIDE THIS LIBRARY
//
// We have used public inheritance from std::vector<T> to simplify the interface
// here. This works fine for the use cases we have within this library. If you
// choose to use this vector type outside this library, you MUST NOT store it as
// a std::vector<T> pointer or reference. This will cause memory leaks, because
// the destructor ~std::vector<T> is not virtual.
template<typename T, size_t N>
class vector : public std::vector<T>
{
private:
using parent = std::vector<T>;

public:
constexpr vector()
: parent(N)
{
}

constexpr vector(size_t size)
: parent(size)
{
}

constexpr vector(gsl::span<const T> content)
: parent(content.begin(), content.end())
{
}

template<size_t M>
constexpr vector(const vector<T, M>& content)
: parent(content)
{
}

void append(gsl::span<const T> content)
{
const auto start = this->size();
this->resize(start + content.size());
std::copy(content.begin(), content.end(), this->begin() + start);
}
};

} // namespace sframe

#endif // def NO_ALLOC
3 changes: 0 additions & 3 deletions src/crypto.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
#include "crypto.h"
#include "header.h"

#include <openssl/err.h>
#include <openssl/evp.h>

namespace sframe {

size_t
Expand Down
13 changes: 6 additions & 7 deletions src/crypto_openssl11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,23 +149,22 @@ hkdf_expand(CipherSuite suite, input_bytes prk, input_bytes info, size_t size)

auto block = owned_bytes<max_hkdf_extract_size>(0);
const auto block_size = cipher_digest_size(suite);
auto counter = uint8_t(0x01);
auto counter = owned_bytes<1>();
counter[0] = 0x01;
while (out.size() < size) {
// for (auto start = size_t(0); start < out.size(); start += block_size) {
auto h = HMAC(suite, prk);
h.write(block);
h.write(info);
h.write(owned_bytes<1>{ counter });
h.write(counter);

block.resize(block.capacity());
const auto md = h.digest(block);
block.resize(md.size());
block.resize(block_size);
h.digest(block);

const auto remaining = size - out.size();
const auto to_write = (remaining < block_size) ? remaining : block_size;
out.append(input_bytes(block).first(to_write));

counter += 1;
counter[0] += 1;
}

return out;
Expand Down
Loading