summaryrefslogtreecommitdiffstats
path: root/test/evp_test.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/evp_test.c')
-rw-r--r--test/evp_test.c288
1 files changed, 228 insertions, 60 deletions
diff --git a/test/evp_test.c b/test/evp_test.c
index 5634631703..71fea6f47f 100644
--- a/test/evp_test.c
+++ b/test/evp_test.c
@@ -75,6 +75,7 @@ typedef enum OPTION_choice {
OPT_IN_PLACE,
OPT_PROVIDER_NAME,
OPT_PROV_PROPQUERY,
+ OPT_DATA_CHUNK,
OPT_TEST_ENUM
} OPTION_CHOICE;
@@ -88,6 +89,8 @@ static KEY_LIST *public_keys;
static int find_key(EVP_PKEY **ppk, const char *name, KEY_LIST *lst);
static int parse_bin(const char *value, unsigned char **buf, size_t *buflen);
+static int parse_bin_chunk(const char *value, size_t offset, size_t max,
+ unsigned char **buf, size_t *buflen, size_t *out_offset);
static int is_digest_disabled(const char *name);
static int is_pkey_disabled(const char *name);
static int is_mac_disabled(const char *name);
@@ -118,6 +121,7 @@ static int memory_err_compare(EVP_TEST *t, const char *err,
/* Option specific for evp test */
static int process_mode_in_place;
static const char *propquery = NULL;
+static int data_chunk_size;
static int evp_test_process_mode(char *mode)
{
@@ -148,23 +152,42 @@ static void evp_test_buffer_free(EVP_TEST_BUFFER *db)
}
/* append buffer to a list */
-static int evp_test_buffer_append(const char *value,
+static int evp_test_buffer_append(const char *value, size_t max_len,
STACK_OF(EVP_TEST_BUFFER) **sk)
{
EVP_TEST_BUFFER *db = NULL;
+ int rv = 0;
+ size_t offset = 0;
- if (!TEST_ptr(db = OPENSSL_malloc(sizeof(*db))))
+ if (*sk == NULL && !TEST_ptr(*sk = sk_EVP_TEST_BUFFER_new_null()))
goto err;
- if (!parse_bin(value, &db->buf, &db->buflen))
- goto err;
- db->count = 1;
- db->count_set = 0;
+ do {
+ if (!TEST_ptr(db = OPENSSL_zalloc(sizeof(*db))))
+ goto err;
+ if (max_len == 0) {
+ /* parse all in one shot */
+ if ((rv = parse_bin(value, &db->buf, &db->buflen)) != 1)
+ goto err;
+ } else {
+ /* parse in chunks */
+ size_t new_offset = 0;
- if (*sk == NULL && !TEST_ptr(*sk = sk_EVP_TEST_BUFFER_new_null()))
- goto err;
- if (!sk_EVP_TEST_BUFFER_push(*sk, db))
- goto err;
+ if ((rv = parse_bin_chunk(value, offset, max_len, &db->buf,
+ &db->buflen, &new_offset)) == -1)
+ goto err;
+ offset = new_offset;
+ }
+
+ db->count = 1;
+ db->count_set = 0;
+
+ if (db->buf == NULL)
+ evp_test_buffer_free(db);
+ else if (db->buf != NULL && !sk_EVP_TEST_BUFFER_push(*sk, db))
+ goto err;
+ /* if processing by chunks, continue until the whole value is parsed */
+ } while (rv == 1 && max_len != 0);
return 1;
@@ -338,6 +361,66 @@ static int parse_bin(const char *value, unsigned char **buf, size_t *buflen)
return 1;
}
+/*
+ * Convert at maximum "max" bytes to a binary allocated buffer.
+ * Return 1 on success, -1 on failure or 0 for end of value string.
+ */
+static int parse_bin_chunk(const char *value, size_t offset, size_t max,
+ unsigned char **buf, size_t *buflen, size_t *out_offset)
+{
+ size_t vlen;
+ size_t chunk_len;
+ const char *value_str = value[0] == '"' ? value + offset + 1 : value + offset;
+
+ if (max < 1)
+ return -1;
+
+ if (*value == '\0' || strcmp(value, "\"\"") == 0) {
+ *buf = OPENSSL_malloc(1);
+ if (*buf == NULL)
+ return 0;
+ **buf = 0;
+ *buflen = 0;
+ return 0;
+ }
+
+ if (*value_str == '\0')
+ return 0;
+
+ vlen = strlen(value_str);
+ if (value[0] == '"') {
+ /* Parse string literal */
+ if (vlen == 1 && value_str[0] != '"')
+ /* Missing ending quotation mark */
+ return -1;
+ if (vlen == 1 && value_str[0] == '"')
+ /* End of value */
+ return 0;
+ vlen--;
+ chunk_len = max > vlen ? vlen : max;
+ if ((*buf = unescape(value_str, chunk_len, buflen)) == NULL)
+ return -1;
+ } else {
+ /* Parse hex string chunk */
+ long len;
+ char *chunk = NULL;
+
+ chunk_len = 2 * max > vlen ? vlen : 2 * max;
+ chunk = OPENSSL_strndup(value_str, chunk_len);
+ if (chunk == NULL)
+ return -1;
+ if (!TEST_ptr(*buf = OPENSSL_hexstr2buf(chunk, &len))) {
+ OPENSSL_free(chunk);
+ TEST_openssl_errors();
+ return -1;
+ }
+ OPENSSL_free(chunk);
+ *buflen = len;
+ }
+ *out_offset = value[0] == '"' ? offset + (*buflen) : offset + 2 * (*buflen);
+ return 1;
+}
+
/**
** MESSAGE DIGEST TESTS
**/
@@ -401,7 +484,7 @@ static int digest_test_parse(EVP_TEST *t,
DIGEST_DATA *mdata = t->data;
if (strcmp(keyword, "Input") == 0)
- return evp_test_buffer_append(value, &mdata->input);
+ return evp_test_buffer_append(value, data_chunk_size, &mdata->input);
if (strcmp(keyword, "Output") == 0)
return parse_bin(value, &mdata->output, &mdata->output_len);
if (strcmp(keyword, "Count") == 0)
@@ -599,6 +682,24 @@ typedef struct cipher_data_st {
const char *xts_standard;
} CIPHER_DATA;
+
+/*
+ * XTS, SIV, CCM, stitched ciphers and Wrap modes have special
+ * requirements about input lengths so we don't fragment for those
+ */
+static int cipher_test_valid_fragmentation(CIPHER_DATA *cdat)
+{
+ return (cdat->aead == EVP_CIPH_CCM_MODE
+ || cdat->aead == EVP_CIPH_CBC_MODE
+ || (cdat->aead == -1
+ && EVP_CIPHER_get_mode(cdat->cipher) == EVP_CIPH_STREAM_CIPHER)
+ || ((EVP_CIPHER_get_flags(cdat->cipher) & EVP_CIPH_FLAG_CTS) != 0)
+ || EVP_CIPHER_get_mode(cdat->cipher) == EVP_CIPH_SIV_MODE
+ || EVP_CIPHER_get_mode(cdat->cipher) == EVP_CIPH_GCM_SIV_MODE
+ || EVP_CIPHER_get_mode(cdat->cipher) == EVP_CIPH_XTS_MODE
+ || EVP_CIPHER_get_mode(cdat->cipher) == EVP_CIPH_WRAP_MODE) ? 0 : 1;
+}
+
static int cipher_test_init(EVP_TEST *t, const char *alg)
{
const EVP_CIPHER *cipher;
@@ -639,6 +740,15 @@ static int cipher_test_init(EVP_TEST *t, const char *alg)
else
cdat->aead = 0;
+ if (data_chunk_size != 0 && !cipher_test_valid_fragmentation(cdat)) {
+ ERR_pop_to_mark();
+ EVP_CIPHER_free(fetched_cipher);
+ OPENSSL_free(cdat);
+ t->skip = 1;
+ TEST_info("skipping, '%s' does not support fragmentation", alg);
+ return 1;
+ }
+
t->data = cdat;
if (fetched_cipher != NULL)
TEST_info("%s is fetched", alg);
@@ -946,15 +1056,26 @@ static int cipher_test_enc(EVP_TEST *t, int enc, size_t out_misalign,
if (expected->aad[0] != NULL && !expected->tls_aad) {
t->err = "AAD_SET_ERROR";
if (!frag) {
+ /* Supply the data all in one go or according to data_chunk_size */
for (i = 0; expected->aad[i] != NULL; i++) {
- if (!EVP_CipherUpdate(ctx, NULL, &chunklen, expected->aad[i],
- expected->aad_len[i]))
- goto err;
+ size_t aad_len = expected->aad_len[i];
+ donelen = 0;
+
+ do {
+ size_t current_aad_len = (size_t) data_chunk_size;
+
+ if (data_chunk_size == 0 || (size_t) data_chunk_size > aad_len)
+ current_aad_len = aad_len;
+ if (!EVP_CipherUpdate(ctx, NULL, &chunklen,
+ expected->aad[i] + donelen,
+ current_aad_len))
+ goto err;
+ donelen += current_aad_len;
+ aad_len -= current_aad_len;
+ } while (aad_len > 0);
}
} else {
- /*
- * Supply the AAD in chunks less than the block size where possible
- */
+ /* Supply the AAD in chunks less than the block size where possible */
for (i = 0; expected->aad[i] != NULL; i++) {
if (expected->aad_len[i] > 0) {
if (!EVP_CipherUpdate(ctx, NULL, &chunklen, expected->aad[i], 1))
@@ -1018,9 +1139,19 @@ static int cipher_test_enc(EVP_TEST *t, int enc, size_t out_misalign,
t->err = "CIPHERUPDATE_ERROR";
tmplen = 0;
if (!frag) {
- /* We supply the data all in one go */
- if (!EVP_CipherUpdate(ctx, tmp + out_misalign, &tmplen, in, in_len))
- goto err;
+ do {
+ /* Supply the data all in one go or according to data_chunk_size */
+ size_t current_in_len = (size_t) data_chunk_size;
+
+ if (data_chunk_size == 0 || (size_t) data_chunk_size > in_len)
+ current_in_len = in_len;
+ if (!EVP_CipherUpdate(ctx, tmp + out_misalign + tmplen, &chunklen,
+ in, current_in_len))
+ goto err;
+ tmplen += chunklen;
+ in += current_in_len;
+ in_len -= current_in_len;
+ } while (in_len > 0);
} else {
/* Supply the data in chunks less than the block size where possible */
if (in_len > 0) {
@@ -1064,7 +1195,7 @@ static int cipher_test_enc(EVP_TEST *t, int enc, size_t out_misalign,
tmp + out_misalign, tmplen + tmpflen))
goto err;
if (enc && expected->aead && !expected->tls_aad) {
- unsigned char rtag[16];
+ unsigned char rtag[48]; /* longest known for TLS_SHA384_SHA384 */
if (!TEST_size_t_le(expected->tag_len, sizeof(rtag))) {
t->err = "TAG_LENGTH_INTERNAL_ERROR";
@@ -1103,23 +1234,6 @@ static int cipher_test_enc(EVP_TEST *t, int enc, size_t out_misalign,
return ok;
}
-/*
- * XTS, SIV, CCM, stitched ciphers and Wrap modes have special
- * requirements about input lengths so we don't fragment for those
- */
-static int cipher_test_valid_fragmentation(CIPHER_DATA *cdat)
-{
- return (cdat->aead == EVP_CIPH_CCM_MODE
- || cdat->aead == EVP_CIPH_CBC_MODE
- || (cdat->aead == -1
- && EVP_CIPHER_get_mode(cdat->cipher) == EVP_CIPH_STREAM_CIPHER)
- || ((EVP_CIPHER_get_flags(cdat->cipher) & EVP_CIPH_FLAG_CTS) != 0)
- || EVP_CIPHER_get_mode(cdat->cipher) == EVP_CIPH_SIV_MODE
- || EVP_CIPHER_get_mode(cdat->cipher) == EVP_CIPH_GCM_SIV_MODE
- || EVP_CIPHER_get_mode(cdat->cipher) == EVP_CIPH_XTS_MODE
- || EVP_CIPHER_get_mode(cdat->cipher) == EVP_CIPH_WRAP_MODE) ? 0 : 1;
-}
-
static int cipher_test_run(EVP_TEST *t)
{
CIPHER_DATA *cdat = t->data;
@@ -1153,6 +1267,8 @@ static int cipher_test_run(EVP_TEST *t)
break;
for (frag = 0; frag <= fragmax; frag++) {
+ if (frag == 1 && data_chunk_size != 0)
+ break;
for (out_misalign = 0; out_misalign <= 1; out_misalign++) {
for (inp_misalign = 0; inp_misalign <= 1; inp_misalign++) {
/* Skip input misalign tests for in-place processing */
@@ -1410,6 +1526,7 @@ static int mac_test_run_pkey(EVP_TEST *t)
unsigned char *got = NULL;
size_t got_len;
int i;
+ size_t input_len, donelen;
/* We don't do XOF mode via PKEY */
if (expected->xof)
@@ -1479,10 +1596,21 @@ static int mac_test_run_pkey(EVP_TEST *t)
t->err = "EVPPKEYCTXCTRL_ERROR";
goto err;
}
- if (!EVP_DigestSignUpdate(mctx, expected->input, expected->input_len)) {
- t->err = "DIGESTSIGNUPDATE_ERROR";
- goto err;
- }
+ input_len = expected->input_len;
+ donelen = 0;
+ do {
+ size_t current_len = (size_t) data_chunk_size;
+
+ if (data_chunk_size == 0 || (size_t) data_chunk_size > input_len)
+ current_len = input_len;
+ if (!EVP_DigestSignUpdate(mctx, expected->input + donelen, current_len)) {
+ t->err = "DIGESTSIGNUPDATE_ERROR";
+ goto err;
+ }
+ donelen += current_len;
+ input_len -= current_len;
+ } while (input_len > 0);
+
if (!EVP_DigestSignFinal(mctx, NULL, &got_len)) {
t->err = "DIGESTSIGNFINAL_LENGTH_ERROR";
goto err;
@@ -1523,6 +1651,7 @@ static int mac_test_run_mac(EVP_TEST *t)
EVP_MAC_settable_ctx_params(expected->mac);
int xof;
int reinit = 1;
+ size_t input_len, donelen ;
if (expected->alg == NULL)
TEST_info("Trying the EVP_MAC %s test", expected->mac_name);
@@ -1669,10 +1798,21 @@ static int mac_test_run_mac(EVP_TEST *t)
}
}
retry:
- if (!EVP_MAC_update(ctx, expected->input, expected->input_len)) {
- t->err = "MAC_UPDATE_ERROR";
- goto err;
- }
+ input_len = expected->input_len;
+ donelen = 0;
+ do {
+ size_t current_len = (size_t) data_chunk_size;
+
+ if (data_chunk_size == 0 || (size_t) data_chunk_size > input_len)
+ current_len = input_len;
+ if (!EVP_MAC_update(ctx, expected->input + donelen, current_len)) {
+ t->err = "MAC_UPDATE_ERROR";
+ goto err;
+ }
+ donelen += current_len;
+ input_len -= current_len;
+ } while (input_len > 0);
+
xof = expected->xof;
if (xof) {
if (!TEST_ptr(got = OPENSSL_malloc(expected->output_len))) {
@@ -2438,6 +2578,7 @@ static int encode_test_run(EVP_TEST *t)
unsigned char *encode_out = NULL, *decode_out = NULL;
int output_len, chunk_len;
EVP_ENCODE_CTX *decode_ctx = NULL, *encode_ctx = NULL;
+ size_t input_len, donelen;
if (!TEST_ptr(decode_ctx = EVP_ENCODE_CTX_new())) {
t->err = "INTERNAL_ERROR";
@@ -2452,13 +2593,25 @@ static int encode_test_run(EVP_TEST *t)
goto err;
EVP_EncodeInit(encode_ctx);
- if (!TEST_true(EVP_EncodeUpdate(encode_ctx, encode_out, &chunk_len,
- expected->input, expected->input_len)))
- goto err;
- output_len = chunk_len;
+ input_len = expected->input_len;
+ donelen = 0;
+ output_len = 0;
+ do {
+ size_t current_len = (size_t) data_chunk_size;
+
+ if (data_chunk_size == 0 || (size_t) data_chunk_size > input_len)
+ current_len = input_len;
+ if (!TEST_true(EVP_EncodeUpdate(encode_ctx, encode_out, &chunk_len,
+ expected->input + donelen,
+ current_len)))
+ goto err;
+ donelen += current_len;
+ input_len -= current_len;
+ output_len += chunk_len;
+ } while (input_len > 0);
- EVP_EncodeFinal(encode_ctx, encode_out + chunk_len, &chunk_len);
+ EVP_EncodeFinal(encode_ctx, encode_out + output_len, &chunk_len);
output_len += chunk_len;
if (!memory_err_compare(t, "BAD_ENCODING",
@@ -2471,15 +2624,27 @@ static int encode_test_run(EVP_TEST *t)
OPENSSL_malloc(EVP_DECODE_LENGTH(expected->output_len))))
goto err;
+ output_len = 0;
EVP_DecodeInit(decode_ctx);
- if (EVP_DecodeUpdate(decode_ctx, decode_out, &chunk_len, expected->output,
- expected->output_len) < 0) {
- t->err = "DECODE_ERROR";
- goto err;
- }
- output_len = chunk_len;
- if (EVP_DecodeFinal(decode_ctx, decode_out + chunk_len, &chunk_len) != 1) {
+ input_len = expected->output_len;
+ donelen = 0;
+ do {
+ size_t current_len = (size_t) data_chunk_size;
+
+ if (data_chunk_size == 0 || (size_t) data_chunk_size > input_len)
+ current_len = input_len;
+ if (EVP_DecodeUpdate(decode_ctx, decode_out + output_len, &chunk_len,
+ expected->output + donelen, current_len) < 0) {
+ t->err = "DECODE_ERROR";
+ goto err;
+ }
+ donelen += current_len;
+ input_len -= current_len;
+ output_len += chunk_len;
+ } while (input_len > 0);
+
+ if (EVP_DecodeFinal(decode_ctx, decode_out + output_len, &chunk_len) != 1) {
t->err = "DECODE_ERROR";
goto err;
}
@@ -3449,12 +3614,12 @@ static int digestsigver_test_parse(EVP_TEST *t,
if (strcmp(keyword, "Input") == 0) {
if (mdata->is_oneshot)
return parse_bin(value, &mdata->osin, &mdata->osin_len);
- return evp_test_buffer_append(value, &mdata->input);
+ return evp_test_buffer_append(value, data_chunk_size, &mdata->input);
}
if (strcmp(keyword, "Output") == 0)
return parse_bin(value, &mdata->output, &mdata->output_len);
- if (!mdata->is_oneshot) {
+ if (!mdata->is_oneshot && data_chunk_size == 0) {
if (strcmp(keyword, "Count") == 0)
return evp_test_buffer_set_count(value, mdata->input);
if (strcmp(keyword, "Ncopy") == 0)
@@ -4161,6 +4326,7 @@ const OPTIONS *test_get_options(void)
"The provider to load (when no configuration file, the default value is 'default')" },
{ "propquery", OPT_PROV_PROPQUERY, 's',
"Property query used when fetching algorithms" },
+ { "chunk", OPT_DATA_CHUNK, 'N', "Size of data chunks to be processed, 0 for default size"},
{ OPT_HELP_STR, 1, '-', "file\tFile to run tests on.\n" },
{ NULL }
};
@@ -4182,6 +4348,8 @@ int setup_tests(void)
break;
case OPT_IN_PLACE:
if ((process_mode_in_place = evp_test_process_mode(opt_arg())) == -1)
+ case OPT_DATA_CHUNK:
+ if (!opt_int(opt_arg(), &data_chunk_size))
return 0;
break;
case OPT_PROVIDER_NAME: