Skip to content

Commit 3c28f57

Browse files
committed
crapi: add OpenSSL EVP digest backend
Extend the crapi layer with a third cryptographic backend, selectable at build time with -DWITH_CRYPTO=openssl. This gives users and distribution maintainers an additional choice of crypto provider alongside the existing gcrypt and NSS backends. One concrete motivation is deployments that restrict cryptographic operations to a FIPS 140-3 validated library: on those systems OpenSSL may be the only permitted provider, making this backend necessary to run the filehash probes. The implementation uses the OpenSSL EVP high-level digest API, which provides a stable, uniform interface across OpenSSL 1.0.x, 1.1.x, and 3.x. A compile-time compatibility shim aliases EVP_MD_CTX_new() and EVP_MD_CTX_free() to their pre-1.1.0 equivalents (EVP_MD_CTX_create() and EVP_MD_CTX_destroy()) for builds against older OpenSSL releases. Because OpenSSL is already an unconditional build dependency of OpenSCAP (required by xmlsec), selecting this backend introduces no new external dependency. The supported digest algorithms are SHA-224, SHA-256, SHA-384, SHA-512, and optionally MD5 and SHA-1 (governed by the existing OPENSCAP_ENABLE_MD5 and OPENSCAP_ENABLE_SHA1 flags). RIPEMD-160, which is gcrypt-specific and not part of the OVAL specification, is intentionally not included: its status in OpenSSL 3.x is deprecated and requires loading the legacy provider explicitly.
1 parent 657a4ff commit 3c28f57

File tree

5 files changed

+170
-4
lines changed

5 files changed

+170
-4
lines changed

CMakeLists.txt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,15 +176,21 @@ check_library_exists(pthread pthread_setname_np "" HAVE_PTHREAD_SETNAME_NP)
176176
check_library_exists(pthread pthread_getname_np "" HAVE_PTHREAD_GETNAME_NP)
177177

178178
# WITH_CRYPTO
179-
set(WITH_CRYPTO "gcrypt" CACHE STRING "gcrypt|nss")
179+
set(WITH_CRYPTO "gcrypt" CACHE STRING "gcrypt|nss|openssl")
180+
set_property(CACHE WITH_CRYPTO PROPERTY STRINGS "gcrypt" "nss" "openssl")
180181
if(${WITH_CRYPTO} STREQUAL "nss")
181182
message("-- Using NSS")
182183
find_package(NSS)
184+
elseif(${WITH_CRYPTO} STREQUAL "openssl")
185+
message("-- Using OpenSSL for crypto backend")
186+
# OpenSSL is already a required dependency (see find_package(OpenSSL REQUIRED) above);
187+
# this flag tells the crapi layer to use it as the digest backend.
188+
set(OPENSCAP_CRYPTO_OPENSSL TRUE)
183189
else()
184190
message("-- Using GCrypt")
185191
find_package(GCrypt)
186192
endif()
187-
if(GCRYPT_FOUND OR NSS_FOUND)
193+
if(GCRYPT_FOUND OR NSS_FOUND OR OPENSCAP_CRYPTO_OPENSSL)
188194
set(CRYPTO_FOUND TRUE)
189195
endif()
190196

config.h.in

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@
2424
#define HAVE_NSS3
2525
#endif
2626

27+
#cmakedefine OPENSCAP_CRYPTO_OPENSSL
28+
#if defined(OPENSCAP_CRYPTO_OPENSSL)
29+
#define HAVE_OPENSSL_CRYPTO
30+
#endif
31+
2732
#define OSCAP_DEFAULT_SCHEMA_PATH "@OSCAP_DEFAULT_SCHEMA_PATH@"
2833
#define OSCAP_DEFAULT_XSLT_PATH "@OSCAP_DEFAULT_XSLT_PATH@"
2934
#define OSCAP_DEFAULT_CPE_PATH "@OSCAP_DEFAULT_CPE_PATH@"

src/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ if (ENABLE_PROBES)
5959
)
6060
endif()
6161
endif()
62-
if (HAVE_MMAN_H AND (GCRYPT_FOUND OR NSS_FOUND))
62+
if (HAVE_MMAN_H AND (GCRYPT_FOUND OR NSS_FOUND OR OPENSCAP_CRYPTO_OPENSSL))
6363
list(APPEND OBJECTS_TO_LINK_AGAINST
6464
$<TARGET_OBJECTS:crapi_object>
6565
)

src/OVAL/probes/crapi/crapi.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,17 @@ int crapi_init (void *unused)
4747

4848
return(0);
4949
}
50+
#elif defined(HAVE_OPENSSL_CRYPTO)
51+
#include <openssl/evp.h>
52+
#include <openssl/opensslv.h>
53+
int crapi_init (void *)
54+
{
55+
#if OPENSSL_VERSION_NUMBER < 0x10100000L
56+
/* OpenSSL < 1.1.0 requires explicit digest algorithm registration. */
57+
OpenSSL_add_all_digests();
58+
#endif
59+
return 0;
60+
}
5061
#else
5162
int crapi_init (void *unused)
5263
{

src/OVAL/probes/crapi/digest.c

Lines changed: 145 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,23 @@
4141
#include <sechash.h>
4242
#elif defined(HAVE_GCRYPT)
4343
#include <gcrypt.h>
44+
#elif defined(HAVE_OPENSSL_CRYPTO)
45+
#include <openssl/evp.h>
46+
#include <openssl/opensslv.h>
4447
#else
4548
#error "No crypto library available!"
4649
#endif
4750

51+
/*
52+
* Compatibility shim for OpenSSL < 1.1.0, which used EVP_MD_CTX_create() and
53+
* EVP_MD_CTX_destroy() instead of the EVP_MD_CTX_new() / EVP_MD_CTX_free()
54+
* names introduced in 1.1.0.
55+
*/
56+
#if defined(HAVE_OPENSSL_CRYPTO) && OPENSSL_VERSION_NUMBER < 0x10100000L
57+
# define EVP_MD_CTX_new() EVP_MD_CTX_create()
58+
# define EVP_MD_CTX_free(c) EVP_MD_CTX_destroy(c)
59+
#endif
60+
4861
#if defined(HAVE_NSS3)
4962
static int crapi_alg_t_to_lib_arg(crapi_alg_t alg)
5063
{
@@ -95,8 +108,72 @@ static int crapi_alg_t_to_lib_arg(crapi_alg_t alg)
95108
return -1;
96109
}
97110
}
111+
#elif defined(HAVE_OPENSSL_CRYPTO)
112+
static const EVP_MD *crapi_alg_t_to_evp_md(crapi_alg_t alg)
113+
{
114+
switch (alg) {
115+
#ifdef OPENSCAP_ENABLE_MD5
116+
case CRAPI_DIGEST_MD5:
117+
return EVP_md5();
118+
#endif
119+
#ifdef OPENSCAP_ENABLE_SHA1
120+
case CRAPI_DIGEST_SHA1:
121+
return EVP_sha1();
122+
#endif
123+
case CRAPI_DIGEST_SHA224:
124+
return EVP_sha224();
125+
case CRAPI_DIGEST_SHA256:
126+
return EVP_sha256();
127+
case CRAPI_DIGEST_SHA384:
128+
return EVP_sha384();
129+
case CRAPI_DIGEST_SHA512:
130+
return EVP_sha512();
131+
default:
132+
return NULL;
133+
}
134+
}
98135
#endif
99136

137+
#if defined(HAVE_OPENSSL_CRYPTO)
138+
/* Read fd and compute its digest using the streaming EVP API. */
139+
static int crapi_digest_fd_stream(int fd, const EVP_MD *evp_md, void *dst, size_t *size)
140+
{
141+
uint8_t buf[CRAPI_IO_BUFSZ];
142+
ssize_t ret;
143+
144+
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
145+
if (ctx == NULL)
146+
return -1;
147+
if (EVP_DigestInit_ex(ctx, evp_md, NULL) != 1) {
148+
EVP_MD_CTX_free(ctx);
149+
return -1;
150+
}
151+
while ((ret = read(fd, buf, sizeof buf)) == sizeof buf)
152+
EVP_DigestUpdate(ctx, (const void *)buf, sizeof buf);
153+
switch (ret) {
154+
case 0:
155+
break;
156+
case -1:
157+
EVP_MD_CTX_free(ctx);
158+
return -1;
159+
default:
160+
if (ret <= 0) {
161+
EVP_MD_CTX_free(ctx);
162+
return -1;
163+
}
164+
EVP_DigestUpdate(ctx, (const void *)buf, (size_t)ret);
165+
}
166+
unsigned int md_len = (unsigned int)*size;
167+
if (EVP_DigestFinal_ex(ctx, (unsigned char *)dst, &md_len) != 1) {
168+
EVP_MD_CTX_free(ctx);
169+
return -1;
170+
}
171+
*size = (size_t)md_len;
172+
EVP_MD_CTX_free(ctx);
173+
return 0;
174+
}
175+
#endif /* HAVE_OPENSSL_CRYPTO */
176+
100177
int crapi_digest_fd(int fd, crapi_alg_t alg, void *dst, size_t *size)
101178
{
102179
struct stat st;
@@ -107,6 +184,22 @@ int crapi_digest_fd(int fd, crapi_alg_t alg, void *dst, size_t *size)
107184
errno = EFAULT;
108185
return -1;
109186
}
187+
188+
/*
189+
* Resolve the algorithm and verify the output buffer is large enough
190+
* to hold the digest.
191+
*/
192+
#if defined(HAVE_OPENSSL_CRYPTO)
193+
const EVP_MD *evp_md = crapi_alg_t_to_evp_md(alg);
194+
if (evp_md == NULL) {
195+
errno = EINVAL;
196+
return -1;
197+
}
198+
if (*size < (size_t)EVP_MD_size(evp_md)) {
199+
errno = ENOBUFS;
200+
return -1;
201+
}
202+
#else
110203
int lib_alg = crapi_alg_t_to_lib_arg(alg);
111204
#if defined(HAVE_NSS3)
112205
if (*size < HASH_ResultLen(lib_alg)) {
@@ -116,6 +209,7 @@ int crapi_digest_fd(int fd, crapi_alg_t alg, void *dst, size_t *size)
116209
errno = ENOBUFS;
117210
return -1;
118211
}
212+
#endif /* HAVE_OPENSSL_CRYPTO */
119213

120214
if (fstat (fd, &st) != 0)
121215
return (-1);
@@ -129,6 +223,10 @@ int crapi_digest_fd(int fd, crapi_alg_t alg, void *dst, size_t *size)
129223
# endif
130224
if (buffer == NULL) {
131225
#endif /* _FILE_OFFSET_BITS == 32 */
226+
#if defined(HAVE_OPENSSL_CRYPTO)
227+
if (crapi_digest_fd_stream(fd, evp_md, dst, size) != 0)
228+
return -1;
229+
#else
132230
uint8_t _buffer[CRAPI_IO_BUFSZ];
133231
ssize_t ret;
134232

@@ -181,10 +279,18 @@ int crapi_digest_fd(int fd, crapi_alg_t alg, void *dst, size_t *size)
181279
memcpy (dst, buffer, gcry_md_get_algo_dlen(lib_alg));
182280
gcry_md_close (hd);
183281
#endif
282+
#endif /* !HAVE_OPENSSL_CRYPTO */
184283

185284
#if _FILE_OFFSET_BITS == 32
186285
} else {
187-
#if defined(HAVE_NSS3)
286+
#if defined(HAVE_OPENSSL_CRYPTO)
287+
unsigned int md_len = (unsigned int)*size;
288+
if (EVP_Digest(buffer, buflen, (unsigned char *)dst, &md_len, evp_md, NULL) != 1) {
289+
munmap(buffer, buflen);
290+
return -1;
291+
}
292+
*size = (size_t)md_len;
293+
#elif defined(HAVE_NSS3)
188294
HASH_HashBuf(lib_alg, (unsigned char *)dst, (unsigned char *)buffer, (unsigned int)buflen);
189295
#elif defined(HAVE_GCRYPT)
190296
gcry_md_hash_buffer(lib_alg, dst, (const void *)buffer, buflen);
@@ -201,6 +307,8 @@ struct crapi_digest_ctx {
201307
HASHContext *ctx;
202308
#elif defined(HAVE_GCRYPT)
203309
gcry_md_hd_t ctx;
310+
#elif defined(HAVE_OPENSSL_CRYPTO)
311+
EVP_MD_CTX *ctx;
204312
#endif
205313
void *dst;
206314
size_t *size;
@@ -215,14 +323,35 @@ static void *crapi_digest_init (void *dst, void *size, crapi_alg_t alg)
215323
{
216324
struct crapi_digest_ctx *ctx = malloc(sizeof(struct crapi_digest_ctx));
217325

326+
#if defined(HAVE_NSS3) || defined(HAVE_GCRYPT)
218327
int lib_alg = crapi_alg_t_to_lib_arg(alg);
328+
#endif
219329
#if defined(HAVE_NSS3)
220330
ctx->ctx = HASH_Create(lib_alg);
221331
#elif defined(HAVE_GCRYPT)
222332
if (gcry_md_open(&ctx->ctx, lib_alg, 0) != 0) {
223333
free(ctx);
224334
return NULL;
225335
}
336+
#elif defined(HAVE_OPENSSL_CRYPTO)
337+
if (ctx == NULL)
338+
return NULL;
339+
const EVP_MD *evp_md = crapi_alg_t_to_evp_md(alg);
340+
if (evp_md == NULL) {
341+
free(ctx);
342+
errno = EINVAL;
343+
return NULL;
344+
}
345+
ctx->ctx = EVP_MD_CTX_new();
346+
if (ctx->ctx == NULL) {
347+
free(ctx);
348+
return NULL;
349+
}
350+
if (EVP_DigestInit_ex(ctx->ctx, evp_md, NULL) != 1) {
351+
EVP_MD_CTX_free(ctx->ctx);
352+
free(ctx);
353+
return NULL;
354+
}
226355
#endif
227356
ctx->dst = dst;
228357
ctx->size = size;
@@ -245,6 +374,9 @@ static int crapi_digest_update(struct crapi_digest_ctx *ctx, void *bptr, size_t
245374
HASH_Update(ctx->ctx, (const unsigned char *)bptr, (unsigned int)blen);
246375
#elif defined(HAVE_GCRYPT)
247376
gcry_md_write(ctx->ctx, (const void *)bptr, blen);
377+
#elif defined(HAVE_OPENSSL_CRYPTO)
378+
if (EVP_DigestUpdate(ctx->ctx, (const void *)bptr, blen) != 1)
379+
return -1;
248380
#endif
249381
return (0);
250382
}
@@ -264,6 +396,15 @@ static int crapi_digest_fini(struct crapi_digest_ctx *ctx, crapi_alg_t alg)
264396
buffer = (void *)gcry_md_read(ctx->ctx, lib_alg);
265397
memcpy(ctx->dst, buffer, gcry_md_get_algo_dlen(lib_alg));
266398
gcry_md_close(ctx->ctx);
399+
#elif defined(HAVE_OPENSSL_CRYPTO)
400+
unsigned int md_len = (unsigned int)*ctx->size;
401+
if (EVP_DigestFinal_ex(ctx->ctx, (unsigned char *)ctx->dst, &md_len) != 1) {
402+
EVP_MD_CTX_free(ctx->ctx);
403+
free(ctx);
404+
return -1;
405+
}
406+
*ctx->size = (size_t)md_len;
407+
EVP_MD_CTX_free(ctx->ctx);
267408
#endif
268409
free (ctx);
269410

@@ -275,6 +416,9 @@ static void crapi_digest_free(struct crapi_digest_ctx *ctx)
275416
#if defined(HAVE_NSS3)
276417
HASH_Destroy(ctx->ctx);
277418
free(ctx);
419+
#elif defined(HAVE_OPENSSL_CRYPTO)
420+
EVP_MD_CTX_free(ctx->ctx);
421+
free(ctx);
278422
#endif
279423
return;
280424
}

0 commit comments

Comments
 (0)