diff options
-rw-r--r-- | libar2_decode_params.c | 10 | ||||
-rw-r--r-- | libar2_erase.c | 29 | ||||
-rw-r--r-- | test.c | 204 |
3 files changed, 221 insertions, 22 deletions
diff --git a/libar2_decode_params.c b/libar2_decode_params.c index fa59ab2..7707ce4 100644 --- a/libar2_decode_params.c +++ b/libar2_decode_params.c @@ -103,6 +103,8 @@ libar2_decode_params(const char *str, struct libar2_argon2_parameters *params, c if (*str != ',') goto einval; str++; + if (*str == '$') + goto einval; } if (have_t + have_m + have_p != 3) @@ -132,12 +134,12 @@ libar2_decode_params(const char *str, struct libar2_argon2_parameters *params, c return (size_t)(str - start); -einval: - errno = EINVAL; - goto fail; - erange: errno = ERANGE; + goto fail; + +einval: + errno = EINVAL; fail: if (*bufp) { ctx->deallocate(*bufp, ctx); diff --git a/libar2_erase.c b/libar2_erase.c index f4fa2d3..0e3174e 100644 --- a/libar2_erase.c +++ b/libar2_erase.c @@ -14,6 +14,11 @@ void *(*const volatile libar2_internal_explicit_memset__)(void *, int, size_t) = #endif +/* libar2_internal_erase__ is intended for the test code to use, because it replaces `libar2_erase` */ +# if defined(__GNUC__) +__attribute__((visibility("hidden"))) +# endif +void libar2_internal_erase__(volatile void *mem, size_t size); #if defined(__clang__) /* before __GNUC__ because that is also set in clang */ # if __has_attribute(optnone) __attribute__((optnone)) @@ -27,7 +32,7 @@ __attribute__((optimize("O0"))) LIBAR2_WEAKLY_LINKED__ #endif void -libar2_erase(volatile void *mem_, size_t size) +libar2_internal_erase__(volatile void *mem_, size_t size) { void *mem = *(void **)(void *)&mem_; #if defined(memset_s) @@ -41,15 +46,29 @@ libar2_erase(volatile void *mem_, size_t size) #endif } + +#if defined(__GNUC__) +LIBAR2_PUBLIC__ LIBAR2_WEAKLY_LINKED__ +extern void libar2_erase(volatile void *, size_t) __attribute__((__alias__("libar2_internal_erase__"))); +#else +void +libar2_erase(volatile void *mem, size_t size) +{ + libar2_internal_erase__(mem, size); +} +#endif + + /* Typo in version 1.0 */ #if defined(__GNUC__) -LIBAR2_PUBLIC__ -extern __typeof(libar2_erase) libar2_earse __attribute__((__weak__, __alias__("libar2_erase"))); +LIBAR2_PUBLIC__ LIBAR2_WEAKLY_LINKED__ +extern void libar2_earse(volatile void *, size_t) __attribute__((__alias__("libar2_internal_erase__"))); #else -LIBAR2_PUBLIC__ void libar2_earse(volatile void *mem, size_t size); +LIBAR2_PUBLIC__ LIBAR2_WEAKLY_LINKED__ +void libar2_earse(volatile void *mem, size_t size); void libar2_earse(volatile void *mem, size_t size) { - libar2_erase(mem, size); + libar2_internal_erase__(mem, size); } #endif @@ -22,36 +22,54 @@ static int from_lineno = 0; +struct context_user_data { + size_t allocate_fail_in; + int init_thread_pool_error; +}; + static void * allocate(size_t num, size_t size, size_t alignment, struct libar2_context *ctx) { #ifndef _POSIX_C_SOURCE # define _POSIX_C_SOURCE 0 #endif -#if _POSIX_C_SOURCE >= 200112L void *ptr; +#if _POSIX_C_SOURCE >= 200112L int err; #endif - (void) ctx; + if (ctx->user_data) { + struct context_user_data *user_data = ctx->user_data; + if (user_data->allocate_fail_in) { + if (!--user_data->allocate_fail_in) { + errno = ENOMEM; + return NULL; + } + } + } if (num > SIZE_MAX / size) { - errno = ENOMEM; - return NULL; + errno = ENOMEM; /* $covered$ */ + goto enomem; /* $covered$ */ } #if _POSIX_C_SOURCE >= 200112L if (alignment < sizeof(void *)) alignment = sizeof(void *); err = posix_memalign(&ptr, alignment, num * size); if (err) { - errno = err; - return NULL; + enomem: /* $covered$ */ + fprintf(stderr, "Internal test failure: %s\n", strerror(errno)); /* $covered$ */ + exit(2); /* $covered$ */ } else { return ptr; } #elif defined(_ISOC11_SOURCE) - return aligned_alloc(alignment, num * size); + ptr = aligned_alloc(alignment, num * size); + if (!ptr) { + fprintf(stderr, "Internal test failure: %s\n", strerror(errno)); /* $covered$ */ + exit(2); /* $covered$ */ + } + return ptr; #else - (void) alignment; - return malloc(num * size); +# error No implementation for aligned memory allocation available #endif } @@ -67,6 +85,13 @@ st_init_thread_pool(size_t desired, size_t *createdp, struct libar2_context *ctx { (void) desired; (void) ctx; + if (ctx->user_data) { + struct context_user_data *user_data = ctx->user_data; + if (user_data->init_thread_pool_error) { + errno = user_data->init_thread_pool_error; + return -1; + } + } *createdp = 0; return 0; } @@ -94,6 +119,8 @@ nulstrcmp(const char *a, const char *b) } +/* $covered{$ */ + static void assert_(int truth, const char *truthstr, int lineno) { @@ -141,6 +168,8 @@ assert_zueq_(size_t result, size_t expect, const char *code, int lineno) } } +/* $covered}$ */ + static void check_libar2_type_to_string(void) @@ -744,6 +773,40 @@ check_hash(const char *pwd_, size_t pwdlen, const char *hash, struct libar2_cont } +static int +memis(char *mem, int ch, size_t n) +{ + size_t i; + int ok = 1; + for (i = 0; i < n; i++) + if (mem[i] != (char)ch) + return 0; /* $covered$ */ + return ok; +} + +/* Typo in version 1.0 */ +extern void libar2_earse(volatile void *mem, size_t size); + +/* libar2_erase has been replaced by this test, so we test this instead */ +extern void libar2_internal_erase__(volatile void *mem, size_t size); + +static void +check_libar2_erase(void) +{ + char buf[1024]; + + memset(buf, 1, sizeof(buf)); + libar2_earse(&buf[0], 512); + assert(memis(&buf[512], 1, 512)); + assert(memis(&buf[0], 0, 512)); + + memset(buf, 1, sizeof(buf)); + libar2_internal_erase__(&buf[0], 512); + assert(memis(&buf[512], 1, 512)); + assert(memis(&buf[0], 0, 512)); +} + + static void check_libar2_hash(void) { @@ -780,8 +843,8 @@ check_libar2_hash(void) CHECK("password", "$argon2id$v=19$m=262144,t=2,p=1$c29tZXNhbHQ$eP4eyR+zqlZX1y5xCFTkw9m5GYx0L5YWwvCFvtlbLow"); CHECK("password", "$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4"); CHECK("password", "$argon2id$v=19$m=256,t=2,p=2$c29tZXNhbHQ$bQk8UB/VmZZF4Oo79iDXuL5/0ttZwg2f/5U52iv1cDc"); - CHECK("password", "$argon2id$v=19$m=65536,t=1,p=1$c29tZXNhbHQ$9qWtwbpyPd3vm1rB1GThgPzZ3/ydHL92zKL+15XZypg"); - CHECK("password", "$argon2id$v=19$m=65536,t=4,p=1$c29tZXNhbHQ$kCXUjmjvc5XMqQedpMTsOv+zyJEf5PhtGiUghW9jFyw"); + CHECK("password", "$argon2id$v=19$m=65536,p=1,t=1$c29tZXNhbHQ$9qWtwbpyPd3vm1rB1GThgPzZ3/ydHL92zKL+15XZypg"); + CHECK("password", "$argon2id$v=19$t=4,p=1,m=65536$c29tZXNhbHQ$kCXUjmjvc5XMqQedpMTsOv+zyJEf5PhtGiUghW9jFyw"); CHECK("differentpassword", "$argon2id$v=19$m=65536,t=2,p=1$c29tZXNhbHQ$C4TWUs9rDEvq7w3+J4umqA32aWKB1+DSiRuBfYxFj94"); CHECK("password", "$argon2id$v=19$m=65536,t=2,p=1$ZGlmZnNhbHQ$vfMrBczELrFdWP0ZsfhWsRPaHppYdP3MVEMIVlqoFBw"); @@ -835,7 +898,7 @@ check_libar2_hash_buf_size(void) size = MAX(size0, size1); if (libar2_hash_buf_size(¶ms) != size || size > params.hashlen + 63) - fprintf(stderr, "At hashlen = %zu (expect %zu)\n", params.hashlen, size); + fprintf(stderr, "At hashlen = %zu (expect %zu)\n", params.hashlen, size); /* $covered$ */ assert(size <= params.hashlen + 63); assert_zueq(libar2_hash_buf_size(¶ms), size); @@ -851,6 +914,117 @@ check_libar2_hash_buf_size(void) #endif +static void +check_failures(void) +{ + struct context_user_data user_data; + struct libar2_argon2_parameters params; + char *buf, sbuf[3 * sizeof(unsigned int) + 512]; + + params.hashlen = SIZE_MAX; + errno = 0; + assert(libar2_hash_buf_size(¶ms) == 0 && errno == EOVERFLOW); + + buf = NULL; +#define CHECKE(STR, ERR)\ + do {\ + errno = 0;\ + assert(libar2_decode_params(STR, ¶ms, &buf, &ctx_st) == 0 && errno == (ERR));\ + assert(!buf);\ + } while (0) +#define CHECK(STR) CHECKE(STR, EINVAL) + CHECK(""); + CHECK("x"); + CHECK("$"); + CHECK("$argon2id"); + CHECK("$argon2idX"); + CHECK("$argon2idX$"); + CHECK("$argon2id$"); + CHECK("$argon2id$$"); + CHECK("$argon2id$x"); + CHECK("$argon2id$v"); + CHECK("$argon2id$v="); + CHECK("$argon2id$v=$"); + CHECK("$argon2id$v=x$"); + CHECKE("$argon2id$v=9999999999999999999999999999999999999999999999999999999999999999999999999$", ERANGE); + sprintf(sbuf, "$argon2id$v=%u$", (unsigned int)INT_MAX + 1U); + CHECKE(sbuf, ERANGE); + CHECK("$argon2id$v=-1$"); + CHECK("$argon2id$v=16"); + CHECK("$argon2id$v=16,"); + CHECK("$argon2id$$m=128,t=128,p=128$AAAABBBBCCCC$"); + CHECK("$argon2id$v=19$m=-128,t=128,p=128$AAAABBBBCCCC$"); + CHECK("$argon2id$v=19$m=128,t=-128,p=128$AAAABBBBCCCC$"); + CHECK("$argon2id$v=19$m=128,t=128,p=-128$AAAABBBBCCCC$"); + CHECK("$argon2id$v=19$m=x,t=128,p=128$AAAABBBBCCCC$"); + CHECK("$argon2id$v=19$m=128,t=x,p=128$AAAABBBBCCCC$"); + CHECK("$argon2id$v=19$m=128,t=128,p=x$AAAABBBBCCCC$"); + CHECK("$argon2id$v=19$t=128,p=128$AAAABBBBCCCC$"); + CHECK("$argon2id$v=19$m=128,p=128$AAAABBBBCCCC$"); + CHECK("$argon2id$v=19$m=128,t=128$AAAABBBBCCCC$"); + CHECK("$argon2id$v=19$m=128,t=128,p=128,m=128$AAAABBBBCCCC$"); + CHECK("$argon2id$v=19$m=128,t=128,p=128,t=128$AAAABBBBCCCC$"); + CHECK("$argon2id$v=19$m=128,t=128,p=128,p=128$AAAABBBBCCCC$"); + CHECK("$argon2id$v=19$m=128$AAAABBBBCCCC$"); + CHECK("$argon2id$v=19$t=128$AAAABBBBCCCC$"); + CHECK("$argon2id$v=19$p=128$AAAABBBBCCCC$"); + CHECKE("$argon2id$v=19$m=999999999999999999999999999999999999999999999999999999999999,t=128,p=128$AAAABBBBCCCC$", ERANGE); + CHECKE("$argon2id$v=19$t=999999999999999999999999999999999999999999999999999999999999,p=128,m=128$AAAABBBBCCCC$", ERANGE); + CHECKE("$argon2id$v=19$p=999999999999999999999999999999999999999999999999999999999999,m=128,t=128$AAAABBBBCCCC$", ERANGE); + CHECK("$argon2id$m=128;t=128;p=128$AAAABBBBCCCC$"); + CHECK("$argon2id$m=128t=128,p=128$AAAABBBBCCCC$"); + CHECK("$argon2id$v=19,m=128,t=128,p=128$AAAABBBBCCCC$"); + CHECK("$argon2id$m=128,t=128,p=128,v=19$AAAABBBBCCCC$"); + CHECK("$argon2id$m=128,t=128,p=128,$AAAABBBBCCCC$"); + CHECK("$argon2id$m=128,t=128,p=128"); + CHECK("$argon2id$m=128,t=128,,p=128"); + CHECK("$argon2id$m=128,t=128,p=128$"); + CHECK("$argon2id$m=128,t=128,p=128,"); + CHECK("$argon2id$m=128,t=128,p=128,$AAAABBBBCCCC"); + CHECK("$argon2id$m=128,t=128,p=128$AAAABBBBCCCC"); + CHECK("$argon2id$m=128,t=128,p=128$AAAAB-BBCCCC$"); + CHECK("$argon2id$m=128,t=128,p=128$AAAABBBBC$"); + errno = 0; + ctx_st.user_data = &user_data; + user_data.allocate_fail_in = 1; + assert(libar2_decode_params("$argon2id$m=8,t=1,p=1$AAAABBBBCCC$", ¶ms, &buf, &ctx_st) == 0 && errno == ENOMEM); + assert(!buf); + ctx_st.user_data = NULL; +#undef CHECK +#undef CHECKE + + memset(¶ms, 0, sizeof(params)); + errno = 0; + assert(libar2_hash(sbuf, NULL, 0, ¶ms, &ctx_st) == -1 && errno == EINVAL); + params.m_cost = 32; + params.t_cost = 32; + params.lanes = 32; + params.salt = (unsigned char []){"\0\0\0\0\0\0\0\0"}; + params.saltlen = 8; + params.hashlen = 32; +#if SIZE_MAX >> 31 > 1 + errno = 0; + assert(libar2_hash(sbuf, NULL, (size_t)1 << 32, ¶ms, &ctx_st) == -1 && errno == EINVAL); +#endif + ctx_st.user_data = &user_data; + memset(&user_data, 0, sizeof(user_data)); + errno = 0; + user_data.allocate_fail_in = 1; + assert(libar2_hash(sbuf, NULL, 0, ¶ms, &ctx_st) == -1 && errno == ENOMEM); + errno = 0; + params.type = LIBAR2_ARGON2DS; + user_data.allocate_fail_in = 2; + assert(libar2_hash(sbuf, NULL, 0, ¶ms, &ctx_st) == -1 && errno == ENOMEM); + user_data.allocate_fail_in = 0; + user_data.init_thread_pool_error = EDOM; + assert(libar2_hash(sbuf, NULL, 0, ¶ms, &ctx_st) == -1 && errno == EDOM); + user_data.init_thread_pool_error = 0; + ctx_st.user_data = NULL; + + errno = 0; +} + + int main(void) { @@ -864,13 +1038,17 @@ main(void) check_libar2_decode_base64(); check_libar2_encode_params_libar2_decode_params(); check_libar2_validate_params(); + check_libar2_erase(); check_libar2_hash(); - # ifdef LIBAR2_WEAKLY_LINKED__ check_libar2_hash_buf_size(); # endif #endif +#if 1 + check_failures(); +#endif + #if MEASURE_TIME { struct libar2_argon2_parameters params; |