Skip to content

Commit 8daeccf

Browse files
jasnelltargos
authored andcommitted
src: shift more crypto impl details to ncrypto
PR-URL: #54028 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
1 parent 31adeea commit 8daeccf

14 files changed

+653
-479
lines changed

deps/ncrypto/ncrypto.cc

+437-23
Large diffs are not rendered by default.

deps/ncrypto/ncrypto.h

+83-15
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
#pragma once
22

3+
#include <cstddef>
34
#include <list>
45
#include <memory>
56
#include <optional>
67
#include <string>
78
#include <string_view>
8-
#include <vector>
99
#include "openssl/bn.h"
1010
#include <openssl/x509.h>
1111
#include <openssl/dh.h>
@@ -82,6 +82,15 @@ namespace ncrypto {
8282
void* operator new(size_t) = delete; \
8383
void operator delete(void*) = delete;
8484

85+
[[noreturn]] inline void unreachable() {
86+
#ifdef __GNUC__
87+
__builtin_unreachable();
88+
#elif defined(_MSC_VER)
89+
__assume(false);
90+
#else
91+
#endif
92+
}
93+
8594
// ============================================================================
8695
// Error handling utilities
8796

@@ -190,30 +199,92 @@ using SSLPointer = DeleteFnPtr<SSL, SSL_free>;
190199
using SSLSessionPointer = DeleteFnPtr<SSL_SESSION, SSL_SESSION_free>;
191200
using X509Pointer = DeleteFnPtr<X509, X509_free>;
192201

202+
// An unowned, unmanaged pointer to a buffer of data.
203+
template <typename T>
204+
struct Buffer {
205+
T* data = nullptr;
206+
size_t len = 0;
207+
};
208+
209+
// A managed pointer to a buffer of data. When destroyed the underlying
210+
// buffer will be freed.
211+
class DataPointer final {
212+
public:
213+
static DataPointer Alloc(size_t len);
214+
215+
DataPointer() = default;
216+
explicit DataPointer(void* data, size_t len);
217+
explicit DataPointer(const Buffer<void>& buffer);
218+
DataPointer(DataPointer&& other) noexcept;
219+
DataPointer& operator=(DataPointer&& other) noexcept;
220+
NCRYPTO_DISALLOW_COPY(DataPointer)
221+
~DataPointer();
222+
223+
inline bool operator==(std::nullptr_t) noexcept { return data_ == nullptr; }
224+
inline operator bool() const { return data_ != nullptr; }
225+
inline void* get() const noexcept { return data_; }
226+
inline size_t size() const noexcept { return len_; }
227+
void reset(void* data = nullptr, size_t len = 0);
228+
void reset(const Buffer<void>& buffer);
229+
230+
// Releases ownership of the underlying data buffer. It is the caller's
231+
// responsibility to ensure the buffer is appropriately freed.
232+
Buffer<void> release();
233+
234+
// Returns a Buffer struct that is a view of the underlying data.
235+
inline operator const Buffer<void>() const {
236+
return {
237+
.data = data_,
238+
.len = len_,
239+
};
240+
}
241+
242+
private:
243+
void* data_ = nullptr;
244+
size_t len_ = 0;
245+
};
246+
193247
class BignumPointer final {
194248
public:
195249
BignumPointer() = default;
196250
explicit BignumPointer(BIGNUM* bignum);
251+
explicit BignumPointer(const unsigned char* data, size_t len);
197252
BignumPointer(BignumPointer&& other) noexcept;
198253
BignumPointer& operator=(BignumPointer&& other) noexcept;
199254
NCRYPTO_DISALLOW_COPY(BignumPointer)
200255
~BignumPointer();
201256

202-
bool operator==(const BignumPointer& other) noexcept;
203-
bool operator==(const BIGNUM* other) noexcept;
204-
inline bool operator==(std::nullptr_t) noexcept { return bn_ == nullptr; }
257+
int operator<=>(const BignumPointer& other) const noexcept;
258+
int operator<=>(const BIGNUM* other) const noexcept;
205259
inline operator bool() const { return bn_ != nullptr; }
206260
inline BIGNUM* get() const noexcept { return bn_.get(); }
207261
void reset(BIGNUM* bn = nullptr);
262+
void reset(const unsigned char* data, size_t len);
208263
BIGNUM* release();
209264

210-
size_t byteLength();
265+
bool isZero() const;
266+
bool isOne() const;
211267

212-
std::vector<uint8_t> encode();
213-
std::vector<uint8_t> encodePadded(size_t size);
268+
bool setWord(unsigned long w);
269+
unsigned long getWord() const;
214270

215-
static std::vector<uint8_t> encode(const BIGNUM* bn);
216-
static std::vector<uint8_t> encodePadded(const BIGNUM* bn, size_t size);
271+
size_t byteLength() const;
272+
273+
DataPointer toHex() const;
274+
DataPointer encode() const;
275+
DataPointer encodePadded(size_t size) const;
276+
size_t encodeInto(unsigned char* out) const;
277+
size_t encodePaddedInto(unsigned char* out, size_t size) const;
278+
279+
static BignumPointer New();
280+
static BignumPointer NewSecure();
281+
static DataPointer Encode(const BIGNUM* bn);
282+
static DataPointer EncodePadded(const BIGNUM* bn, size_t size);
283+
static size_t EncodePaddedInto(const BIGNUM* bn, unsigned char* out, size_t size);
284+
static int GetBitCount(const BIGNUM* bn);
285+
static int GetByteCount(const BIGNUM* bn);
286+
static unsigned long GetWord(const BIGNUM* bn);
287+
static const BIGNUM* One();
217288

218289
private:
219290
DeleteFnPtr<BIGNUM, BN_clear_free> bn_;
@@ -269,12 +340,6 @@ bool testFipsEnabled();
269340
// ============================================================================
270341
// Various utilities
271342

272-
template <typename T>
273-
struct Buffer {
274-
T* data = nullptr;
275-
size_t len = 0;
276-
};
277-
278343
bool CSPRNG(void* buffer, size_t length) NCRYPTO_MUST_USE_RESULT;
279344

280345
// This callback is used to avoid the default passphrase callback in OpenSSL
@@ -286,6 +351,9 @@ int NoPasswordCallback(char* buf, int size, int rwflag, void* u);
286351

287352
int PasswordCallback(char* buf, int size, int rwflag, void* u);
288353

354+
bool SafeX509SubjectAltNamePrint(const BIOPointer& out, X509_EXTENSION* ext);
355+
bool SafeX509InfoAccessPrint(const BIOPointer& out, X509_EXTENSION* ext);
356+
289357
// ============================================================================
290358
// SPKAC
291359

src/crypto/crypto_aes.cc

+10-15
Original file line numberDiff line numberDiff line change
@@ -185,10 +185,7 @@ BignumPointer GetCounter(const AESCipherConfig& params) {
185185

186186
if (remainder == 0) {
187187
unsigned int byte_length = params.length / CHAR_BIT;
188-
return BignumPointer(BN_bin2bn(
189-
data + params.iv.size() - byte_length,
190-
byte_length,
191-
nullptr));
188+
return BignumPointer(data + params.iv.size() - byte_length, byte_length);
192189
}
193190

194191
unsigned int byte_length =
@@ -199,7 +196,7 @@ BignumPointer GetCounter(const AESCipherConfig& params) {
199196
data + params.iv.size());
200197
counter[0] &= ~(0xFF << remainder);
201198

202-
return BignumPointer(BN_bin2bn(counter.data(), counter.size(), nullptr));
199+
return BignumPointer(counter.data(), counter.size());
203200
}
204201

205202
std::vector<unsigned char> BlockWithZeroedCounter(
@@ -269,23 +266,22 @@ WebCryptoCipherStatus AES_CTR_Cipher(
269266
const AESCipherConfig& params,
270267
const ByteSource& in,
271268
ByteSource* out) {
272-
BignumPointer num_counters(BN_new());
273-
if (!BN_lshift(num_counters.get(), BN_value_one(), params.length))
269+
auto num_counters = BignumPointer::New();
270+
if (!BN_lshift(num_counters.get(), BignumPointer::One(), params.length))
274271
return WebCryptoCipherStatus::FAILED;
275272

276273
BignumPointer current_counter = GetCounter(params);
277274

278-
BignumPointer num_output(BN_new());
275+
auto num_output = BignumPointer::New();
279276

280-
if (!BN_set_word(num_output.get(), CeilDiv(in.size(), kAesBlockSize)))
277+
if (!num_output.setWord(CeilDiv(in.size(), kAesBlockSize)))
281278
return WebCryptoCipherStatus::FAILED;
282279

283280
// Just like in chromium's implementation, if the counter will
284281
// be incremented more than there are counter values, we fail.
285-
if (BN_cmp(num_output.get(), num_counters.get()) > 0)
286-
return WebCryptoCipherStatus::FAILED;
282+
if (num_output > num_counters) return WebCryptoCipherStatus::FAILED;
287283

288-
BignumPointer remaining_until_reset(BN_new());
284+
auto remaining_until_reset = BignumPointer::New();
289285
if (!BN_sub(remaining_until_reset.get(),
290286
num_counters.get(),
291287
current_counter.get())) {
@@ -298,7 +294,7 @@ WebCryptoCipherStatus AES_CTR_Cipher(
298294
// Also just like in chromium's implementation, if we can process
299295
// the input without wrapping the counter, we'll do it as a single
300296
// call here. If we can't, we'll fallback to the a two-step approach
301-
if (BN_cmp(remaining_until_reset.get(), num_output.get()) >= 0) {
297+
if (remaining_until_reset >= num_output) {
302298
auto status = AES_CTR_Cipher2(key_data,
303299
cipher_mode,
304300
params,
@@ -309,8 +305,7 @@ WebCryptoCipherStatus AES_CTR_Cipher(
309305
return status;
310306
}
311307

312-
BN_ULONG blocks_part1 = BN_get_word(remaining_until_reset.get());
313-
BN_ULONG input_size_part1 = blocks_part1 * kAesBlockSize;
308+
BN_ULONG input_size_part1 = remaining_until_reset.getWord() * kAesBlockSize;
314309

315310
// Encrypt the first part...
316311
auto status =

0 commit comments

Comments
 (0)