From 07ecbb9789eb531695d5c9ced6c30a9f925aa5fd Mon Sep 17 00:00:00 2001 From: Ignacio Casal Quinteiro Date: Tue, 31 Oct 2023 12:31:51 +0100 Subject: [PATCH] Add option to allow building with BoringSSL To build with BoringSSL CRYPTO_INCLUDE_DIRS and CRYPTO_LIBRARY_DIRS must be defined Also fix all the compile issues when building with BoringSSL --- CMakeLists.txt | 19 +++++++++++++++++-- src/cbor.c | 14 +++++++++++--- src/ecdh.c | 4 ++-- src/es256.c | 36 ++++++++++++++++++++++++++++++----- src/es384.c | 28 +++++++++++++++++++++++---- src/rs1.c | 21 +++++++++++++++++++++ src/rs256.c | 51 +++++++++++++++++++++++++++++++++++++++++++++----- tools/base64.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 202 insertions(+), 21 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 097c7ffe..550a2d1b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,6 +44,7 @@ option(USE_HIDAPI "Use hidapi as the HID backend" OFF) option(USE_PCSC "Enable experimental PCSC support" ON) option(USE_WINHELLO "Abstract Windows Hello as a FIDO device" ON) option(NFC_LINUX "Enable NFC support on Linux" ON) +option(USE_BORINGSSL "Build with BoringSSL" OFF) add_definitions(-D_FIDO_MAJOR=${FIDO_MAJOR}) add_definitions(-D_FIDO_MINOR=${FIDO_MINOR}) @@ -85,7 +86,12 @@ if(NOT MSVC) elseif(CMAKE_SYSTEM_NAME STREQUAL "NetBSD") set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_NETBSD_SOURCE") endif() - set(FIDO_CFLAGS "${FIDO_CFLAGS} -std=c99") + + # With BoringSSL we need a newer standard than c99 + if(NOT USE_BORINGSSL) + set(FIDO_CFLAGS "${FIDO_CFLAGS} -std=c99") + endif() + set(CMAKE_C_FLAGS "${FIDO_CFLAGS} ${CMAKE_C_FLAGS}") endif() @@ -219,9 +225,18 @@ if(MSVC) else() include(FindPkgConfig) pkg_search_module(CBOR libcbor) - pkg_search_module(CRYPTO libcrypto) pkg_search_module(ZLIB zlib) + if(USE_BORINGSSL) + if((NOT CRYPTO_INCLUDE_DIRS) OR (NOT CRYPTO_LIBRARY_DIRS)) + message(FATAL_ERROR "please define " + "{CBOR,CRYPTO,ZLIB}_{INCLUDE,LIBRARY}_DIRS when " + "building with BoringSSL") + endif() + else() + pkg_search_module(CRYPTO libcrypto) + endif() + if(NOT CBOR_FOUND AND NOT HAVE_CBOR_H) message(FATAL_ERROR "could not find libcbor") endif() diff --git a/src/cbor.c b/src/cbor.c index ab99b34d..b1fe59a1 100644 --- a/src/cbor.c +++ b/src/cbor.c @@ -709,9 +709,13 @@ cbor_encode_pin_auth(const fido_dev_t *dev, const fido_blob_t *secret, if (prot == CTAP_PIN_PROTOCOL2 && key.len > 32) key.len = 32; - if ((md = EVP_sha256()) == NULL || HMAC(md, key.ptr, - (int)key.len, data->ptr, data->len, dgst, - &dgst_len) == NULL || dgst_len != SHA256_DIGEST_LENGTH) + if ((md = EVP_sha256()) == NULL || +#ifdef OPENSSL_IS_BORINGSSL + HMAC(md, key.ptr, key.len, data->ptr, data->len, dgst, &dgst_len) == NULL || +#else + HMAC(md, key.ptr, (int)key.len, data->ptr, data->len, dgst, &dgst_len) == NULL || +#endif + dgst_len != SHA256_DIGEST_LENGTH) return (NULL); outlen = (prot == CTAP_PIN_PROTOCOL1) ? 16 : dgst_len; @@ -758,7 +762,11 @@ cbor_encode_change_pin_auth(const fido_dev_t *dev, const fido_blob_t *secret, if ((ctx = HMAC_CTX_new()) == NULL || (md = EVP_sha256()) == NULL || +#ifdef OPENSSL_IS_BORINGSSL + HMAC_Init_ex(ctx, key.ptr, key.len, md, NULL) == 0 || +#else HMAC_Init_ex(ctx, key.ptr, (int)key.len, md, NULL) == 0 || +#endif HMAC_Update(ctx, new_pin_enc->ptr, new_pin_enc->len) == 0 || HMAC_Update(ctx, pin_hash_enc->ptr, pin_hash_enc->len) == 0 || HMAC_Final(ctx, dgst, &dgst_len) == 0 || diff --git a/src/ecdh.c b/src/ecdh.c index 878f9761..df43f902 100644 --- a/src/ecdh.c +++ b/src/ecdh.c @@ -7,7 +7,7 @@ #include #include -#if defined(LIBRESSL_VERSION_NUMBER) +#if defined(LIBRESSL_VERSION_NUMBER) || defined(OPENSSL_IS_BORINGSSL) #include #else #include @@ -16,7 +16,7 @@ #include "fido.h" #include "fido/es256.h" -#if defined(LIBRESSL_VERSION_NUMBER) +#if defined(LIBRESSL_VERSION_NUMBER) || defined(OPENSSL_IS_BORINGSSL) static int hkdf_sha256(uint8_t *key, const char *info, const fido_blob_t *secret) { diff --git a/src/es256.c b/src/es256.c index 17efb0ad..bafc093e 100644 --- a/src/es256.c +++ b/src/es256.c @@ -226,8 +226,10 @@ es256_sk_create(es256_sk_t *key) EVP_PKEY *k = NULL; const EC_KEY *ec; const BIGNUM *d; - int n; int ok = -1; +#ifndef OPENSSL_IS_BORINGSSL + int n; +#endif if ((pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL)) == NULL || EVP_PKEY_paramgen_init(pctx) <= 0 || @@ -245,8 +247,13 @@ es256_sk_create(es256_sk_t *key) if ((ec = EVP_PKEY_get0_EC_KEY(k)) == NULL || (d = EC_KEY_get0_private_key(ec)) == NULL || +#ifdef OPENSSL_IS_BORINGSSL + (BN_num_bytes(d) > sizeof(key->d)) || + (BN_bn2bin(d, key->d) > sizeof(key->d))) { +#else (n = BN_num_bytes(d)) < 0 || (size_t)n > sizeof(key->d) || (n = BN_bn2bin(d, key->d)) < 0 || (size_t)n > sizeof(key->d)) { +#endif fido_log_debug("%s: EC_KEY_get0_private_key", __func__); goto fail; } @@ -344,8 +351,13 @@ es256_pk_from_EC_KEY(es256_pk_t *pk, const EC_KEY *ec) size_t dx; size_t dy; int ok = FIDO_ERR_INTERNAL; +#ifdef OPENSSL_IS_BORINGSSL + size_t nx; + size_t ny; +#else int nx; int ny; +#endif if ((q = EC_KEY_get0_public_key(ec)) == NULL || (g = EC_GROUP_new_by_curve_name(es256_nid)) == NULL || @@ -364,9 +376,16 @@ es256_pk_from_EC_KEY(es256_pk_t *pk, const EC_KEY *ec) goto fail; } + nx = BN_num_bytes(x); + ny = BN_num_bytes(y); if (EC_POINT_get_affine_coordinates_GFp(g, q, x, y, bnctx) == 0 || - (nx = BN_num_bytes(x)) < 0 || (size_t)nx > sizeof(pk->x) || - (ny = BN_num_bytes(y)) < 0 || (size_t)ny > sizeof(pk->y)) { +#ifdef OPENSSL_IS_BORINGSSL + nx > sizeof(pk->x) || + ny > sizeof(pk->y)) { +#else + nx < 0 || (size_t)nx > sizeof(pk->x) || + ny < 0 || (size_t)ny > sizeof(pk->y)) { +#endif fido_log_debug("%s: EC_POINT_get_affine_coordinates_GFp", __func__); goto fail; @@ -375,8 +394,15 @@ es256_pk_from_EC_KEY(es256_pk_t *pk, const EC_KEY *ec) dx = sizeof(pk->x) - (size_t)nx; dy = sizeof(pk->y) - (size_t)ny; - if ((nx = BN_bn2bin(x, pk->x + dx)) < 0 || (size_t)nx > sizeof(pk->x) || - (ny = BN_bn2bin(y, pk->y + dy)) < 0 || (size_t)ny > sizeof(pk->y)) { + nx = BN_bn2bin(x, pk->x + dx); + ny = BN_bn2bin(y, pk->y + dy); +#ifdef OPENSSL_IS_BORINGSSL + if (nx > sizeof(pk->x) || + ny > sizeof(pk->y)) { +#else + if (nx < 0 || (size_t)nx > sizeof(pk->x) || + ny < 0 || (size_t)ny > sizeof(pk->y)) { +#endif fido_log_debug("%s: BN_bn2bin", __func__); goto fail; } diff --git a/src/es384.c b/src/es384.c index 013d285e..c215af9a 100644 --- a/src/es384.c +++ b/src/es384.c @@ -187,8 +187,13 @@ es384_pk_from_EC_KEY(es384_pk_t *pk, const EC_KEY *ec) size_t dx; size_t dy; int ok = FIDO_ERR_INTERNAL; +#ifdef OPENSSL_IS_BORINGSSL + size_t nx; + size_t ny; +#else int nx; int ny; +#endif if ((q = EC_KEY_get0_public_key(ec)) == NULL || (g = EC_GROUP_new_by_curve_name(NID_secp384r1)) == NULL || @@ -207,9 +212,16 @@ es384_pk_from_EC_KEY(es384_pk_t *pk, const EC_KEY *ec) goto fail; } + nx = BN_num_bytes(x); + ny = BN_num_bytes(y); if (EC_POINT_get_affine_coordinates_GFp(g, q, x, y, bnctx) == 0 || - (nx = BN_num_bytes(x)) < 0 || (size_t)nx > sizeof(pk->x) || - (ny = BN_num_bytes(y)) < 0 || (size_t)ny > sizeof(pk->y)) { +#ifdef OPENSSL_IS_BORINGSSL + nx > sizeof(pk->x) || + ny > sizeof(pk->y)) { +#else + nx < 0 || (size_t)nx > sizeof(pk->x) || + ny < 0 || (size_t)ny > sizeof(pk->y)) { +#endif fido_log_debug("%s: EC_POINT_get_affine_coordinates_GFp", __func__); goto fail; @@ -218,8 +230,16 @@ es384_pk_from_EC_KEY(es384_pk_t *pk, const EC_KEY *ec) dx = sizeof(pk->x) - (size_t)nx; dy = sizeof(pk->y) - (size_t)ny; - if ((nx = BN_bn2bin(x, pk->x + dx)) < 0 || (size_t)nx > sizeof(pk->x) || - (ny = BN_bn2bin(y, pk->y + dy)) < 0 || (size_t)ny > sizeof(pk->y)) { + nx = BN_bn2bin(x, pk->x + dx); + ny = BN_bn2bin(y, pk->y + dy); + if ( +#ifdef OPENSSL_IS_BORINGSSL + nx > sizeof(pk->x) || + ny > sizeof(pk->y)) { +#else + nx < 0 || (size_t)nx > sizeof(pk->x) || + ny < 0 || (size_t)ny > sizeof(pk->y)) { +#endif fido_log_debug("%s: BN_bn2bin", __func__); goto fail; } diff --git a/src/rs1.c b/src/rs1.c index 03636b5c..68b011ea 100644 --- a/src/rs1.c +++ b/src/rs1.c @@ -28,6 +28,27 @@ rs1_free_EVP_MD(EVP_MD *md) { freezero(md, sizeof(*md)); } +#elif defined(OPENSSL_IS_BORINGSSL) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wcast-qual" +static EVP_MD * +rs1_get_EVP_MD(void) +{ + const EVP_MD *md; + + if ((md = EVP_sha1()) == NULL) + return (NULL); + + return (EVP_MD *)md; +} +# pragma GCC diagnostic pop + +static void +rs1_free_EVP_MD(EVP_MD *md) +{ + // Do not free it + (void)md; +} #elif OPENSSL_VERSION_NUMBER >= 0x30000000 static EVP_MD * rs1_get_EVP_MD(void) diff --git a/src/rs256.c b/src/rs256.c index 59ceb948..de7ddac5 100644 --- a/src/rs256.c +++ b/src/rs256.c @@ -36,6 +36,27 @@ rs256_free_EVP_MD(EVP_MD *md) { freezero(md, sizeof(*md)); } +#elif defined(OPENSSL_IS_BORINGSSL) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wcast-qual" +static EVP_MD * +rs256_get_EVP_MD(void) +{ + const EVP_MD *md; + + if ((md = EVP_sha256()) == NULL) + return (NULL); + + return (EVP_MD *)md; +} +# pragma GCC diagnostic pop + +static void +rs256_free_EVP_MD(EVP_MD *md) +{ + // Do not free it + (void)md; +} #elif OPENSSL_VERSION_NUMBER >= 0x30000000 static EVP_MD * rs256_get_EVP_MD(void) @@ -214,7 +235,13 @@ rs256_pk_from_RSA(rs256_pk_t *pk, const RSA *rsa) const BIGNUM *n = NULL; const BIGNUM *e = NULL; const BIGNUM *d = NULL; - int k; +#ifdef OPENSSL_IS_BORINGSSL + size_t nx; + size_t ny; +#else + int nx; + int ny; +#endif if (RSA_bits(rsa) != 2048) { fido_log_debug("%s: invalid key length", __func__); @@ -228,14 +255,28 @@ rs256_pk_from_RSA(rs256_pk_t *pk, const RSA *rsa) return (FIDO_ERR_INTERNAL); } - if ((k = BN_num_bytes(n)) < 0 || (size_t)k > sizeof(pk->n) || - (k = BN_num_bytes(e)) < 0 || (size_t)k > sizeof(pk->e)) { + nx = BN_num_bytes(n); + ny = BN_num_bytes(e); +#ifdef OPENSSL_IS_BORINGSSL + if (nx > sizeof(pk->n) || + ny > sizeof(pk->e)) { +#else + if (nx < 0 || (size_t)nx > sizeof(pk->n) || + ny < 0 || (size_t)ny > sizeof(pk->e)) { +#endif fido_log_debug("%s: invalid key", __func__); return (FIDO_ERR_INTERNAL); } - if ((k = BN_bn2bin(n, pk->n)) < 0 || (size_t)k > sizeof(pk->n) || - (k = BN_bn2bin(e, pk->e)) < 0 || (size_t)k > sizeof(pk->e)) { + nx = BN_bn2bin(n, pk->n); + ny = BN_bn2bin(e, pk->e); +#ifdef OPENSSL_IS_BORINGSSL + if (nx > sizeof(pk->n) || + ny > sizeof(pk->e)) { +#else + if (nx < 0 || (size_t)nx > sizeof(pk->n) || + ny < 0 || (size_t)ny > sizeof(pk->e)) { +#endif fido_log_debug("%s: BN_bn2bin", __func__); return (FIDO_ERR_INTERNAL); } diff --git a/tools/base64.c b/tools/base64.c index 2cfa98dd..4cb9b8df 100644 --- a/tools/base64.c +++ b/tools/base64.c @@ -15,6 +15,55 @@ #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" +#ifdef OPENSSL_IS_BORINGSSL +int +base64_encode(const void *ptr, size_t len, char **out) +{ + size_t out_len; + + if (ptr == NULL || out == NULL || len > INT_MAX) + return (-1); + + *out = NULL; + + if (!EVP_EncodedLength(&out_len, len)) + return (-1); + + if ((*out = calloc(1, (size_t)out_len + 1)) == NULL) + return (-1); + + return EVP_EncodeBlock((uint8_t *)*out, (const uint8_t *)ptr, len) > 0 ? 1 : -1; +} + +int +base64_decode(const char *in, void **ptr, size_t *len) +{ + size_t alloc_len; + size_t in_len; + int ok = -1; + + if (in == NULL || ptr == NULL || len == NULL || strlen(in) > INT_MAX) + return (-1); + + in_len = strlen(in); + if (!EVP_DecodedLength(&alloc_len, in_len)) + goto fail; + + if ((*ptr = calloc(1, alloc_len + 1)) == NULL) + goto fail; + + ok = EVP_DecodeBase64(*ptr, len, alloc_len, (const uint8_t *)in, alloc_len); + +fail: + if (ok < 0) { + free(*ptr); + *ptr = NULL; + *len = 0; + } + + return (ok); +} +#else int base64_encode(const void *ptr, size_t len, char **out) { @@ -107,6 +156,7 @@ base64_decode(const char *in, void **ptr, size_t *len) return (ok); } +#endif // OPENSSL_IS_BORINGSSL int base64_read(FILE *f, struct blob *out)