From 066007029b3dd250305d7fac0bfd53aa1e4543cf Mon Sep 17 00:00:00 2001 From: Ondrej Mosnacek Date: Thu, 3 Feb 2022 17:53:23 +0100 Subject: [PATCH] semodule,libsemanage: move module hashing into libsemanage The main goal of this move is to have the SHA-256 implementation under libsemanage, since upcoming patches will make use of SHA-256 for a different (but similar) purpose in libsemanage. Having the hashing code in libsemanage will reduce code duplication and allow for easier hash algorithm upgrade in the future. Note that libselinux currently also contains a hash function implementation (for yet another different purpose). This patch doesn't make any effort to address that duplicity yet. This patch also changes the format of the hash string printed by semodule to include the name of the hash. The intent is to avoid ambiguity and potential collisions when the algorithm is potentially changed in the future. Signed-off-by: Ondrej Mosnacek --- libsemanage/include/semanage/modules.h | 26 +++ libsemanage/src/libsemanage.map | 4 + libsemanage/src/modules.c | 59 +++++ libsemanage/src/sha256.c | 294 +++++++++++++++++++++++++ libsemanage/src/sha256.h | 89 ++++++++ 5 files changed, 472 insertions(+) create mode 100644 libsemanage/src/sha256.c create mode 100644 libsemanage/src/sha256.h diff --git a/libsemanage/include/semanage/modules.h b/libsemanage/include/semanage/modules.h index 4b93e54e..26ac40b2 100644 --- a/libsemanage/include/semanage/modules.h +++ b/libsemanage/include/semanage/modules.h @@ -282,4 +282,30 @@ int semanage_module_get_enabled(semanage_handle_t *sh, const semanage_module_key_t *modkey, int *enabled); +/* Compute checksum for @modkey module contents. + * + * If @checksum is NULL, the function will just return the length of the + * checksum string in @checksum_len (checksum strings are guaranteed to + * have a fixed length for a given libsemanage binary). @modkey and @cil + * are ignored in this case and should be set to NULL and 0 (respectively). + * + * If @checksum is non-NULL, on success, @checksum will point to a buffer + * containing the checksum string and @checksum_len will point to the + * length of the string (without the null terminator). The semantics of + * @cil are the same as for @extract_cil in semanage_module_extract(). + * + * The caller is responsible to free the buffer returned in @checksum (using + * free(3)). + * + * Callers may assume that if the checksum strings for two modules match, + * the module content is the same (collisions are theoretically possible, + * yet extremely unlikely). + * + * Returns 0 on success and -1 on error. + */ +extern int semanage_module_compute_checksum(semanage_handle_t *sh, + semanage_module_key_t *modkey, + int cil, char **checksum, + size_t *checksum_len); + #endif diff --git a/libsemanage/src/libsemanage.map b/libsemanage/src/libsemanage.map index 02036696..a986b2d2 100644 --- a/libsemanage/src/libsemanage.map +++ b/libsemanage/src/libsemanage.map @@ -63,3 +63,7 @@ LIBSEMANAGE_1.1 { semanage_module_remove_key; semanage_set_store_root; } LIBSEMANAGE_1.0; + +LIBSEMANAGE_3.4 { + semanage_module_compute_checksum; +} LIBSEMANAGE_1.1; diff --git a/libsemanage/src/modules.c b/libsemanage/src/modules.c index fa84d33e..3a82d275 100644 --- a/libsemanage/src/modules.c +++ b/libsemanage/src/modules.c @@ -34,11 +34,13 @@ #include #include #include +#include #include #include #include "handle.h" #include "modules.h" +#include "sha256.h" #include "debug.h" asm(".symver semanage_module_get_enabled_1_1,semanage_module_get_enabled@@LIBSEMANAGE_1.1"); @@ -1146,3 +1148,60 @@ int semanage_module_remove_key(semanage_handle_t *sh, return sh->funcs->remove_key(sh, modkey); } +static const char CHECKSUM_TYPE[] = "sha256"; +static const size_t CHECKSUM_CONTENT_SIZE = sizeof(CHECKSUM_TYPE) + 1 + 2 * SHA256_HASH_SIZE; + +static void semanage_hash_to_checksum_string(const uint8_t *hash, char *checksum) +{ + size_t i; + + checksum += sprintf(checksum, "%s:", CHECKSUM_TYPE); + for (i = 0; i < SHA256_HASH_SIZE; i++) { + checksum += sprintf(checksum, "%02x", (unsigned)hash[i]); + } +} + +int semanage_module_compute_checksum(semanage_handle_t *sh, + semanage_module_key_t *modkey, + int cil, char **checksum, + size_t *checksum_len) +{ + semanage_module_info_t *extract_info = NULL; + Sha256Context context; + SHA256_HASH sha256_hash; + char *checksum_str; + void *data; + size_t data_len = 0; + int result; + + if (!checksum_len) + return -1; + + if (!checksum) { + *checksum_len = CHECKSUM_CONTENT_SIZE; + return 0; + } + + result = semanage_module_extract(sh, modkey, cil, &data, &data_len, &extract_info); + if (result != 0) + return -1; + + semanage_module_info_destroy(sh, extract_info); + free(extract_info); + + Sha256Initialise(&context); + Sha256Update(&context, data, data_len); + Sha256Finalise(&context, &sha256_hash); + + munmap(data, data_len); + + checksum_str = malloc(CHECKSUM_CONTENT_SIZE + 1 /* '\0' */); + if (!checksum_str) + return -1; + + semanage_hash_to_checksum_string(sha256_hash.bytes, checksum_str); + + *checksum = checksum_str; + *checksum_len = CHECKSUM_CONTENT_SIZE; + return 0; +} diff --git a/libsemanage/src/sha256.c b/libsemanage/src/sha256.c new file mode 100644 index 00000000..fe2aeef0 --- /dev/null +++ b/libsemanage/src/sha256.c @@ -0,0 +1,294 @@ +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// WjCryptLib_Sha256 +// +// Implementation of SHA256 hash function. +// Original author: Tom St Denis, tomstdenis@gmail.com, http://libtom.org +// Modified by WaterJuice retaining Public Domain license. +// +// This is free and unencumbered software released into the public domain - June 2013 waterjuice.org +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// IMPORTS +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#include "sha256.h" +#include + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// MACROS +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#define ror(value, bits) (((value) >> (bits)) | ((value) << (32 - (bits)))) + +#define MIN(x, y) ( ((x)<(y))?(x):(y) ) + +#define STORE32H(x, y) \ + { (y)[0] = (uint8_t)(((x)>>24)&255); (y)[1] = (uint8_t)(((x)>>16)&255); \ + (y)[2] = (uint8_t)(((x)>>8)&255); (y)[3] = (uint8_t)((x)&255); } + +#define LOAD32H(x, y) \ + { x = ((uint32_t)((y)[0] & 255)<<24) | \ + ((uint32_t)((y)[1] & 255)<<16) | \ + ((uint32_t)((y)[2] & 255)<<8) | \ + ((uint32_t)((y)[3] & 255)); } + +#define STORE64H(x, y) \ + { (y)[0] = (uint8_t)(((x)>>56)&255); (y)[1] = (uint8_t)(((x)>>48)&255); \ + (y)[2] = (uint8_t)(((x)>>40)&255); (y)[3] = (uint8_t)(((x)>>32)&255); \ + (y)[4] = (uint8_t)(((x)>>24)&255); (y)[5] = (uint8_t)(((x)>>16)&255); \ + (y)[6] = (uint8_t)(((x)>>8)&255); (y)[7] = (uint8_t)((x)&255); } + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// CONSTANTS +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// The K array +static const uint32_t K[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, + 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, + 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, + 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, + 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, + 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, + 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, + 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, + 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, + 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL +}; + +#define BLOCK_SIZE 64 + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// INTERNAL FUNCTIONS +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Various logical functions +#define Ch( x, y, z ) (z ^ (x & (y ^ z))) +#define Maj( x, y, z ) (((x | y) & z) | (x & y)) +#define S( x, n ) ror((x),(n)) +#define R( x, n ) (((x)&0xFFFFFFFFUL)>>(n)) +#define Sigma0( x ) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) +#define Sigma1( x ) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) +#define Gamma0( x ) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) +#define Gamma1( x ) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) + +#define Sha256Round( a, b, c, d, e, f, g, h, i ) \ + t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ + t1 = Sigma0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// TransformFunction +// +// Compress 512-bits +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static +void + TransformFunction + ( + Sha256Context* Context, + uint8_t const* Buffer + ) +{ + uint32_t S[8]; + uint32_t W[64]; + uint32_t t0; + uint32_t t1; + uint32_t t; + int i; + + // Copy state into S + for( i=0; i<8; i++ ) + { + S[i] = Context->state[i]; + } + + // Copy the state into 512-bits into W[0..15] + for( i=0; i<16; i++ ) + { + LOAD32H( W[i], Buffer + (4*i) ); + } + + // Fill W[16..63] + for( i=16; i<64; i++ ) + { + W[i] = Gamma1( W[i-2]) + W[i-7] + Gamma0( W[i-15] ) + W[i-16]; + } + + // Compress + for( i=0; i<64; i++ ) + { + Sha256Round( S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i ); + t = S[7]; + S[7] = S[6]; + S[6] = S[5]; + S[5] = S[4]; + S[4] = S[3]; + S[3] = S[2]; + S[2] = S[1]; + S[1] = S[0]; + S[0] = t; + } + + // Feedback + for( i=0; i<8; i++ ) + { + Context->state[i] = Context->state[i] + S[i]; + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// PUBLIC FUNCTIONS +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Sha256Initialise +// +// Initialises a SHA256 Context. Use this to initialise/reset a context. +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void + Sha256Initialise + ( + Sha256Context* Context // [out] + ) +{ + Context->curlen = 0; + Context->length = 0; + Context->state[0] = 0x6A09E667UL; + Context->state[1] = 0xBB67AE85UL; + Context->state[2] = 0x3C6EF372UL; + Context->state[3] = 0xA54FF53AUL; + Context->state[4] = 0x510E527FUL; + Context->state[5] = 0x9B05688CUL; + Context->state[6] = 0x1F83D9ABUL; + Context->state[7] = 0x5BE0CD19UL; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Sha256Update +// +// Adds data to the SHA256 context. This will process the data and update the internal state of the context. Keep on +// calling this function until all the data has been added. Then call Sha256Finalise to calculate the hash. +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void + Sha256Update + ( + Sha256Context* Context, // [in out] + void const* Buffer, // [in] + uint32_t BufferSize // [in] + ) +{ + uint32_t n; + + if( Context->curlen > sizeof(Context->buf) ) + { + return; + } + + while( BufferSize > 0 ) + { + if( Context->curlen == 0 && BufferSize >= BLOCK_SIZE ) + { + TransformFunction( Context, (uint8_t*)Buffer ); + Context->length += BLOCK_SIZE * 8; + Buffer = (uint8_t*)Buffer + BLOCK_SIZE; + BufferSize -= BLOCK_SIZE; + } + else + { + n = MIN( BufferSize, (BLOCK_SIZE - Context->curlen) ); + memcpy( Context->buf + Context->curlen, Buffer, (size_t)n ); + Context->curlen += n; + Buffer = (uint8_t*)Buffer + n; + BufferSize -= n; + if( Context->curlen == BLOCK_SIZE ) + { + TransformFunction( Context, Context->buf ); + Context->length += 8*BLOCK_SIZE; + Context->curlen = 0; + } + } + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Sha256Finalise +// +// Performs the final calculation of the hash and returns the digest (32 byte buffer containing 256bit hash). After +// calling this, Sha256Initialised must be used to reuse the context. +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void + Sha256Finalise + ( + Sha256Context* Context, // [in out] + SHA256_HASH* Digest // [out] + ) +{ + int i; + + if( Context->curlen >= sizeof(Context->buf) ) + { + return; + } + + // Increase the length of the message + Context->length += Context->curlen * 8; + + // Append the '1' bit + Context->buf[Context->curlen++] = (uint8_t)0x80; + + // if the length is currently above 56 bytes we append zeros + // then compress. Then we can fall back to padding zeros and length + // encoding like normal. + if( Context->curlen > 56 ) + { + while( Context->curlen < 64 ) + { + Context->buf[Context->curlen++] = (uint8_t)0; + } + TransformFunction(Context, Context->buf); + Context->curlen = 0; + } + + // Pad up to 56 bytes of zeroes + while( Context->curlen < 56 ) + { + Context->buf[Context->curlen++] = (uint8_t)0; + } + + // Store length + STORE64H( Context->length, Context->buf+56 ); + TransformFunction( Context, Context->buf ); + + // Copy output + for( i=0; i<8; i++ ) + { + STORE32H( Context->state[i], Digest->bytes+(4*i) ); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Sha256Calculate +// +// Combines Sha256Initialise, Sha256Update, and Sha256Finalise into one function. Calculates the SHA256 hash of the +// buffer. +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void + Sha256Calculate + ( + void const* Buffer, // [in] + uint32_t BufferSize, // [in] + SHA256_HASH* Digest // [in] + ) +{ + Sha256Context context; + + Sha256Initialise( &context ); + Sha256Update( &context, Buffer, BufferSize ); + Sha256Finalise( &context, Digest ); +} diff --git a/libsemanage/src/sha256.h b/libsemanage/src/sha256.h new file mode 100644 index 00000000..406ed869 --- /dev/null +++ b/libsemanage/src/sha256.h @@ -0,0 +1,89 @@ +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// WjCryptLib_Sha256 +// +// Implementation of SHA256 hash function. +// Original author: Tom St Denis, tomstdenis@gmail.com, http://libtom.org +// Modified by WaterJuice retaining Public Domain license. +// +// This is free and unencumbered software released into the public domain - June 2013 waterjuice.org +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#pragma once + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// IMPORTS +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#include +#include + +typedef struct +{ + uint64_t length; + uint32_t state[8]; + uint32_t curlen; + uint8_t buf[64]; +} Sha256Context; + +#define SHA256_HASH_SIZE ( 256 / 8 ) + +typedef struct +{ + uint8_t bytes [SHA256_HASH_SIZE]; +} SHA256_HASH; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// PUBLIC FUNCTIONS +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Sha256Initialise +// +// Initialises a SHA256 Context. Use this to initialise/reset a context. +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void + Sha256Initialise + ( + Sha256Context* Context // [out] + ); + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Sha256Update +// +// Adds data to the SHA256 context. This will process the data and update the internal state of the context. Keep on +// calling this function until all the data has been added. Then call Sha256Finalise to calculate the hash. +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void + Sha256Update + ( + Sha256Context* Context, // [in out] + void const* Buffer, // [in] + uint32_t BufferSize // [in] + ); + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Sha256Finalise +// +// Performs the final calculation of the hash and returns the digest (32 byte buffer containing 256bit hash). After +// calling this, Sha256Initialised must be used to reuse the context. +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void + Sha256Finalise + ( + Sha256Context* Context, // [in out] + SHA256_HASH* Digest // [out] + ); + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Sha256Calculate +// +// Combines Sha256Initialise, Sha256Update, and Sha256Finalise into one function. Calculates the SHA256 hash of the +// buffer. +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void + Sha256Calculate + ( + void const* Buffer, // [in] + uint32_t BufferSize, // [in] + SHA256_HASH* Digest // [in] + ); -- 2.30.2