changeset 24290:8d61a8fe510c

11965 crypto tests only test multi-part operations a byte at a time Reviewed by: Dan McDonald <danmcd@joyent.com> Approved by: Gordon Ross <gordon.w.ross@gmail.com>
author Jason King <jason.king@joyent.com>
date Thu, 15 Aug 2019 18:55:18 +0000
parents a99db9af9639
children b99fdd27bfbc
files usr/src/test/crypto-tests/tests/common/cryptotest.h usr/src/test/crypto-tests/tests/common/cryptotest_kcf.c usr/src/test/crypto-tests/tests/common/cryptotest_pkcs.c usr/src/test/crypto-tests/tests/common/testfuncs.c usr/src/test/crypto-tests/tests/digest/main.c usr/src/test/crypto-tests/tests/hmac/main.c usr/src/test/crypto-tests/tests/modes/aes/cbc/aes_cbc.c usr/src/test/crypto-tests/tests/modes/aes/cbc_pad/aes_cbc_pad.c usr/src/test/crypto-tests/tests/modes/aes/ccm/aes_ccm.c usr/src/test/crypto-tests/tests/modes/aes/cmac/aes_cmac.c usr/src/test/crypto-tests/tests/modes/aes/ctr/aes_ctr.c usr/src/test/crypto-tests/tests/modes/aes/ecb/aes_ecb.c usr/src/test/crypto-tests/tests/modes/aes/gcm/aes_gcm.c
diffstat 13 files changed, 767 insertions(+), 421 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/test/crypto-tests/tests/common/cryptotest.h	Sun Oct 21 22:14:02 2018 +0300
+++ b/usr/src/test/crypto-tests/tests/common/cryptotest.h	Thu Aug 15 18:55:18 2019 +0000
@@ -11,7 +11,7 @@
 
 /*
  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
- * Copyright 2018, Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
  */
 
 #ifndef _CRYPTOTEST_H
@@ -21,12 +21,16 @@
 extern "C" {
 #endif
 
+#include <inttypes.h>
 #include <sys/crypto/ioctl.h>
 
 #define	CTEST_INIT_FAILED (-1)
 #define	CTEST_NAME_RESOLVE_FAILED (-2)
 #define	CTEST_MECH_NO_PROVIDER (-3)
 
+#define	CTEST_UPDATELEN_WHOLE	SIZE_MAX
+#define	CTEST_UPDATELEN_END	0
+
 typedef struct cryptotest {
 	uint8_t *in;
 	uint8_t *out;
@@ -39,63 +43,56 @@
 	size_t plen;
 
 	char *mechname;
-	size_t updatelen;
+	size_t *updatelens;
 } cryptotest_t;
 
-typedef int (*testfunc_t)(cryptotest_t *);
+typedef struct crypto_op crypto_op_t;
 
 typedef struct test_fg {
-	testfunc_t single;
-	testfunc_t update;
+	crypto_func_group_t tf_fg;
+	int (*tf_init)(crypto_op_t *);
+	int (*tf_single)(crypto_op_t *);
+	int (*tf_update)(crypto_op_t *, size_t, size_t, size_t *);
+	int (*tf_final)(crypto_op_t *, size_t);
 } test_fg_t;
 
 #define	CRYPTO_INVALID_SESSION ((crypto_session_id_t)-1)
-typedef struct crypto_op crypto_op_t;
 
 int run_test(cryptotest_t *args, uint8_t *cmp, size_t cmplen, test_fg_t *funcs);
 
+const char *cryptotest_errstr(int e, char *buf, size_t buflen);
+
 /* utils */
 crypto_op_t *cryptotest_init(cryptotest_t *args, crypto_func_group_t fg);
-int cryptotest_close(crypto_op_t *op);
+void cryptotest_close(crypto_op_t *op);
 int get_mech_info(crypto_op_t *op);
 int get_hsession_by_mech(crypto_op_t *op);
 
 /* CRYPTO_MAC */
 int mac_init(crypto_op_t *op);
 int mac_single(crypto_op_t *op);
-int mac_update(crypto_op_t *op, int offset);
-int mac_final(crypto_op_t *op);
+int mac_update(crypto_op_t *op, size_t offset, size_t len, size_t *dummy);
+int mac_final(crypto_op_t *op, size_t dummy);
 
 /* CRYPTO_ENCRYPT */
 int encrypt_init(crypto_op_t *op);
 int encrypt_single(crypto_op_t *op);
-int encrypt_update(crypto_op_t *op, int offset, size_t *encrlen);
+int encrypt_update(crypto_op_t *op, size_t offset, size_t plainlen,
+    size_t *encrlen);
 int encrypt_final(crypto_op_t *op, size_t encrlen);
 
 /* CRYPTO_DECRYPT */
 int decrypt_init(crypto_op_t *op);
 int decrypt_single(crypto_op_t *op);
-int decrypt_update(crypto_op_t *op, int offset, size_t *encrlen);
+int decrypt_update(crypto_op_t *op, size_t offset, size_t cipherlen,
+    size_t *encrlen);
 int decrypt_final(crypto_op_t *op, size_t encrlen);
 
 /* CRYPTO_DIGEST */
 int digest_init(crypto_op_t *op);
 int digest_single(crypto_op_t *op);
-int digest_update(crypto_op_t *op, int);
-int digest_final(crypto_op_t *op);
-
-/* wrappers */
-int test_mac_single(cryptotest_t *args);
-int test_mac(cryptotest_t *args);
-
-int test_encrypt_single(cryptotest_t *args);
-int test_encrypt(cryptotest_t *args);
-
-int test_decrypt_single(cryptotest_t *args);
-int test_decrypt(cryptotest_t *args);
-
-int test_digest_single(cryptotest_t *args);
-int test_digest(cryptotest_t *args);
+int digest_update(crypto_op_t *op, size_t offset, size_t len, size_t *dummy);
+int digest_final(crypto_op_t *op, size_t dummy);
 
 extern test_fg_t cryptotest_decr_fg;
 extern test_fg_t cryptotest_encr_fg;
--- a/usr/src/test/crypto-tests/tests/common/cryptotest_kcf.c	Sun Oct 21 22:14:02 2018 +0300
+++ b/usr/src/test/crypto-tests/tests/common/cryptotest_kcf.c	Thu Aug 15 18:55:18 2019 +0000
@@ -11,7 +11,7 @@
 
 /*
  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
- * Copyright 2018, Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
  */
 
 #include <fcntl.h>
@@ -20,6 +20,7 @@
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/debug.h>
 
 #include "cryptotest.h"
 
@@ -33,7 +34,7 @@
 	size_t outlen;
 	size_t keylen;
 	size_t paramlen;
-	size_t updatelen;
+	const size_t *updatelens;
 
 	char *mechname;
 
@@ -43,7 +44,7 @@
 	crypto_func_group_t fg;
 };
 
-static int fd;
+static int fd = -1;
 static const char CRYPTO_DEVICE[] = "/dev/crypto";
 
 int
@@ -56,13 +57,21 @@
 			break;
 	}
 
-	if (ret < 0 || *arg != CRYPTO_SUCCESS)
-		(void) fprintf(stderr, "%s: Error = %d %d 0x%02x\n",
+	if (ret < 0 || *arg != CRYPTO_SUCCESS) {
+		(void) fprintf(stderr,
+		    "%s: Error = %d errno=%d (%s) 0x%02x\n",
 		    (opstr == NULL) ? "ioctl" : opstr,
-		    ret, errno, *arg);
+		    ret, errno, strerror(errno), *arg);
+
+	}
 
+	/*
+	 * The callers all expect CRYPTO_xx errors.  We've displayed the
+	 * errno value (see above), so just return a generic CRYPTO_xxx
+	 * error to signal failure.
+	 */
 	if (ret < 0)
-		return (errno);
+		return (CRYPTO_GENERAL_ERROR);
 
 	return (*arg);
 }
@@ -72,11 +81,15 @@
 {
 	crypto_op_t *op = malloc(sizeof (*op));
 
-	if (op == NULL)
+	if (op == NULL) {
+		(void) fprintf(stderr, "malloc failed: %s\n", strerror(errno));
 		return (NULL);
+	}
 
 	while ((fd = open(CRYPTO_DEVICE, O_RDWR)) < 0) {
 		if (errno != EINTR) {
+			(void) fprintf(stderr, "open of %s failed: %s",
+			    CRYPTO_DEVICE, strerror(errno));
 			free(op);
 			return (NULL);
 		}
@@ -91,7 +104,7 @@
 	op->outlen = arg->outlen;
 	op->keylen = arg->keylen * 8; /* kcf uses keylen in bits */
 	op->paramlen = arg->plen;
-	op->updatelen = arg->updatelen;
+	op->updatelens = arg->updatelens;
 
 	op->mechname = arg->mechname;
 
@@ -112,15 +125,15 @@
 	return (kcf_do_ioctl(CRYPTO_CLOSE_SESSION, (uint_t *)&cs, "session"));
 }
 
-int
+void
 cryptotest_close(crypto_op_t *op)
 {
 	if (op->hsession != CRYPTO_INVALID_SESSION)
 		(void) cryptotest_close_session(op->hsession);
 	free(op);
 	if (fd >= 0)
-		return (close(fd));
-	return (0);
+		VERIFY0(close(fd));
+	fd = -1;
 }
 
 int
@@ -207,7 +220,7 @@
 }
 
 int
-mac_update(crypto_op_t *op, int offset)
+mac_update(crypto_op_t *op, size_t offset, size_t len, size_t *dummy __unused)
 {
 	crypto_mac_update_t update;
 
@@ -215,13 +228,13 @@
 
 	update.mu_session = op->hsession;
 	update.mu_databuf = op->in + offset;
-	update.mu_datalen = op->updatelen;
+	update.mu_datalen = len;
 
 	return (kcf_do_ioctl(CRYPTO_MAC_UPDATE, (uint_t *)&update, "update"));
 }
 
 int
-mac_final(crypto_op_t *op)
+mac_final(crypto_op_t *op, size_t dummy __unused)
 {
 	crypto_mac_final_t final;
 
@@ -275,7 +288,7 @@
 }
 
 int
-encrypt_update(crypto_op_t *op, int offset, size_t *encrlen)
+encrypt_update(crypto_op_t *op, size_t offset, size_t plainlen, size_t *encrlen)
 {
 	crypto_encrypt_update_t update;
 	int ret;
@@ -283,7 +296,7 @@
 
 	update.eu_session = op->hsession;
 	update.eu_databuf = op->in + offset;
-	update.eu_datalen = op->updatelen;
+	update.eu_datalen = plainlen;
 	update.eu_encrlen = op->outlen - *encrlen;
 	update.eu_encrbuf = op->out + *encrlen;
 
@@ -346,7 +359,7 @@
 }
 
 int
-decrypt_update(crypto_op_t *op, int offset, size_t *encrlen)
+decrypt_update(crypto_op_t *op, size_t offset, size_t len, size_t *encrlen)
 {
 	crypto_decrypt_update_t update;
 	int ret;
@@ -356,7 +369,7 @@
 	update.du_session = op->hsession;
 	update.du_databuf = op->out + *encrlen;
 	update.du_datalen = op->outlen - *encrlen;
-	update.du_encrlen = op->updatelen;
+	update.du_encrlen = len;
 	update.du_encrbuf = op->in + offset;
 
 	ret = kcf_do_ioctl(CRYPTO_DECRYPT_UPDATE, (uint_t *)&update, "update");
@@ -412,7 +425,8 @@
 }
 
 int
-digest_update(crypto_op_t *op, int offset)
+digest_update(crypto_op_t *op, size_t offset, size_t len,
+    size_t *dummy __unused)
 {
 	crypto_digest_update_t update;
 
@@ -420,7 +434,7 @@
 
 	update.du_session = op->hsession;
 
-	update.du_datalen = op->updatelen;
+	update.du_datalen = len;
 	update.du_databuf = op->in + offset;
 
 	return (kcf_do_ioctl(CRYPTO_DIGEST_UPDATE, (uint_t *)&update,
@@ -428,7 +442,7 @@
 }
 
 int
-digest_final(crypto_op_t *op)
+digest_final(crypto_op_t *op, size_t dummy __unused)
 {
 	crypto_digest_final_t final;
 
@@ -441,6 +455,7 @@
 
 	return (kcf_do_ioctl(CRYPTO_DIGEST_FINAL, (uint_t *)&final, "final"));
 }
+
 void
 ccm_init_params(void *buf, ulong_t ulDataLen, uchar_t *pNonce,
     ulong_t ulNonceLen, uchar_t *pAAD, ulong_t ulAADLen, ulong_t ulMACLen)
@@ -460,3 +475,270 @@
 {
 	return (sizeof (CK_AES_CCM_PARAMS));
 }
+
+const char *
+cryptotest_errstr(int e, char *buf, size_t buflen)
+{
+	const char *valstr = NULL;
+
+	switch (e) {
+	case CRYPTO_SUCCESS:
+		valstr = "CRYPTO_SUCCESS";
+		break;
+	case CRYPTO_CANCEL:
+		valstr = "CRYPTO_CANCEL";
+		break;
+	case CRYPTO_HOST_MEMORY:
+		valstr = "CRYPTO_HOST_MEMORY";
+		break;
+	case CRYPTO_GENERAL_ERROR:
+		valstr = "CRYPTO_GENERAL_ERROR";
+		break;
+	case CRYPTO_FAILED:
+		valstr = "CRYPTO_FAILED";
+		break;
+	case CRYPTO_ARGUMENTS_BAD:
+		valstr = "CRYPTO_ARGUMENTS_BAD";
+		break;
+	case CRYPTO_ATTRIBUTE_READ_ONLY:
+		valstr = "CRYPTO_ATTRIBUTE_READ_ONLY";
+		break;
+	case CRYPTO_ATTRIBUTE_SENSITIVE:
+		valstr = "CRYPTO_ATTRIBUTE_SENSITIVE";
+		break;
+	case CRYPTO_ATTRIBUTE_TYPE_INVALID:
+		valstr = "CRYPTO_ATTRIBUTE_TYPE_INVALID";
+		break;
+	case CRYPTO_ATTRIBUTE_VALUE_INVALID:
+		valstr = "CRYPTO_ATTRIBUTE_VALUE_INVALID";
+		break;
+	case CRYPTO_CANCELED:
+		valstr = "CRYPTO_CANCELED";
+		break;
+	case CRYPTO_DATA_INVALID:
+		valstr = "CRYPTO_DATA_INVALID";
+		break;
+	case CRYPTO_DATA_LEN_RANGE:
+		valstr = "CRYPTO_DATA_LEN_RANGE";
+		break;
+	case CRYPTO_DEVICE_ERROR:
+		valstr = "CRYPTO_DEVICE_ERROR";
+		break;
+	case CRYPTO_DEVICE_MEMORY:
+		valstr = "CRYPTO_DEVICE_MEMORY";
+		break;
+	case CRYPTO_DEVICE_REMOVED:
+		valstr = "CRYPTO_DEVICE_REMOVED";
+		break;
+	case CRYPTO_ENCRYPTED_DATA_INVALID:
+		valstr = "CRYPTO_ENCRYPTED_DATA_INVALID";
+		break;
+	case CRYPTO_ENCRYPTED_DATA_LEN_RANGE:
+		valstr = "CRYPTO_ENCRYPTED_DATA_LEN_RANGE";
+		break;
+	case CRYPTO_KEY_HANDLE_INVALID:
+		valstr = "CRYPTO_KEY_HANDLE_INVALID";
+		break;
+	case CRYPTO_KEY_SIZE_RANGE:
+		valstr = "CRYPTO_KEY_SIZE_RANGE";
+		break;
+	case CRYPTO_KEY_TYPE_INCONSISTENT:
+		valstr = "CRYPTO_KEY_TYPE_INCONSISTENT";
+		break;
+	case CRYPTO_KEY_NOT_NEEDED:
+		valstr = "CRYPTO_KEY_NOT_NEEDED";
+		break;
+	case CRYPTO_KEY_CHANGED:
+		valstr = "CRYPTO_KEY_CHANGED";
+		break;
+	case CRYPTO_KEY_NEEDED:
+		valstr = "CRYPTO_KEY_NEEDED";
+		break;
+	case CRYPTO_KEY_INDIGESTIBLE:
+		valstr = "CRYPTO_KEY_INDIGESTIBLE";
+		break;
+	case CRYPTO_KEY_FUNCTION_NOT_PERMITTED:
+		valstr = "CRYPTO_KEY_FUNCTION_NOT_PERMITTED";
+		break;
+	case CRYPTO_KEY_NOT_WRAPPABLE:
+		valstr = "CRYPTO_KEY_NOT_WRAPPABLE";
+		break;
+	case CRYPTO_KEY_UNEXTRACTABLE:
+		valstr = "CRYPTO_KEY_UNEXTRACTABLE";
+		break;
+	case CRYPTO_MECHANISM_INVALID:
+		valstr = "CRYPTO_MECHANISM_INVALID";
+		break;
+	case CRYPTO_MECHANISM_PARAM_INVALID:
+		valstr = "CRYPTO_MECHANISM_PARAM_INVALID";
+		break;
+	case CRYPTO_OBJECT_HANDLE_INVALID:
+		valstr = "CRYPTO_OBJECT_HANDLE_INVALID";
+		break;
+	case CRYPTO_OPERATION_IS_ACTIVE:
+		valstr = "CRYPTO_OPERATION_IS_ACTIVE";
+		break;
+	case CRYPTO_OPERATION_NOT_INITIALIZED:
+		valstr = "CRYPTO_OPERATION_NOT_INITIALIZED";
+		break;
+	case CRYPTO_PIN_INCORRECT:
+		valstr = "CRYPTO_PIN_INCORRECT";
+		break;
+	case CRYPTO_PIN_INVALID:
+		valstr = "CRYPTO_PIN_INVALID";
+		break;
+	case CRYPTO_PIN_LEN_RANGE:
+		valstr = "CRYPTO_PIN_LEN_RANGE";
+		break;
+	case CRYPTO_PIN_EXPIRED:
+		valstr = "CRYPTO_PIN_EXPIRED";
+		break;
+	case CRYPTO_PIN_LOCKED:
+		valstr = "CRYPTO_PIN_LOCKED";
+		break;
+	case CRYPTO_SESSION_CLOSED:
+		valstr = "CRYPTO_SESSION_CLOSED";
+		break;
+	case CRYPTO_SESSION_COUNT:
+		valstr = "CRYPTO_SESSION_COUNT";
+		break;
+	case CRYPTO_SESSION_HANDLE_INVALID:
+		valstr = "CRYPTO_SESSION_HANDLE_INVALID";
+		break;
+	case CRYPTO_SESSION_READ_ONLY:
+		valstr = "CRYPTO_SESSION_READ_ONLY";
+		break;
+	case CRYPTO_SESSION_EXISTS:
+		valstr = "CRYPTO_SESSION_EXISTS";
+		break;
+	case CRYPTO_SESSION_READ_ONLY_EXISTS:
+		valstr = "CRYPTO_SESSION_READ_ONLY_EXISTS";
+		break;
+	case CRYPTO_SESSION_READ_WRITE_SO_EXISTS:
+		valstr = "CRYPTO_SESSION_READ_WRITE_SO_EXISTS";
+		break;
+	case CRYPTO_SIGNATURE_INVALID:
+		valstr = "CRYPTO_SIGNATURE_INVALID";
+		break;
+	case CRYPTO_SIGNATURE_LEN_RANGE:
+		valstr = "CRYPTO_SIGNATURE_LEN_RANGE";
+		break;
+	case CRYPTO_TEMPLATE_INCOMPLETE:
+		valstr = "CRYPTO_TEMPLATE_INCOMPLETE";
+		break;
+	case CRYPTO_TEMPLATE_INCONSISTENT:
+		valstr = "CRYPTO_TEMPLATE_INCONSISTENT";
+		break;
+	case CRYPTO_UNWRAPPING_KEY_HANDLE_INVALID:
+		valstr = "CRYPTO_UNWRAPPING_KEY_HANDLE_INVALID";
+		break;
+	case CRYPTO_UNWRAPPING_KEY_SIZE_RANGE:
+		valstr = "CRYPTO_UNWRAPPING_KEY_SIZE_RANGE";
+		break;
+	case CRYPTO_UNWRAPPING_KEY_TYPE_INCONSISTENT:
+		valstr = "CRYPTO_UNWRAPPING_KEY_TYPE_INCONSISTENT";
+		break;
+	case CRYPTO_USER_ALREADY_LOGGED_IN:
+		valstr = "CRYPTO_USER_ALREADY_LOGGED_IN";
+		break;
+	case CRYPTO_USER_NOT_LOGGED_IN:
+		valstr = "CRYPTO_USER_NOT_LOGGED_IN";
+		break;
+	case CRYPTO_USER_PIN_NOT_INITIALIZED:
+		valstr = "CRYPTO_USER_PIN_NOT_INITIALIZED";
+		break;
+	case CRYPTO_USER_TYPE_INVALID:
+		valstr = "CRYPTO_USER_TYPE_INVALID";
+		break;
+	case CRYPTO_USER_ANOTHER_ALREADY_LOGGED_IN:
+		valstr = "CRYPTO_USER_ANOTHER_ALREADY_LOGGED_IN";
+		break;
+	case CRYPTO_USER_TOO_MANY_TYPES:
+		valstr = "CRYPTO_USER_TOO_MANY_TYPES";
+		break;
+	case CRYPTO_WRAPPED_KEY_INVALID:
+		valstr = "CRYPTO_WRAPPED_KEY_INVALID";
+		break;
+	case CRYPTO_WRAPPED_KEY_LEN_RANGE:
+		valstr = "CRYPTO_WRAPPED_KEY_LEN_RANGE";
+		break;
+	case CRYPTO_WRAPPING_KEY_HANDLE_INVALID:
+		valstr = "CRYPTO_WRAPPING_KEY_HANDLE_INVALID";
+		break;
+	case CRYPTO_WRAPPING_KEY_SIZE_RANGE:
+		valstr = "CRYPTO_WRAPPING_KEY_SIZE_RANGE";
+		break;
+	case CRYPTO_WRAPPING_KEY_TYPE_INCONSISTENT:
+		valstr = "CRYPTO_WRAPPING_KEY_TYPE_INCONSISTENT";
+		break;
+	case CRYPTO_RANDOM_SEED_NOT_SUPPORTED:
+		valstr = "CRYPTO_RANDOM_SEED_NOT_SUPPORTED";
+		break;
+	case CRYPTO_RANDOM_NO_RNG:
+		valstr = "CRYPTO_RANDOM_NO_RNG";
+		break;
+	case CRYPTO_DOMAIN_PARAMS_INVALID:
+		valstr = "CRYPTO_DOMAIN_PARAMS_INVALID";
+		break;
+	case CRYPTO_BUFFER_TOO_SMALL:
+		valstr = "CRYPTO_BUFFER_TOO_SMALL";
+		break;
+	case CRYPTO_INFORMATION_SENSITIVE:
+		valstr = "CRYPTO_INFORMATION_SENSITIVE";
+		break;
+	case CRYPTO_NOT_SUPPORTED:
+		valstr = "CRYPTO_NOT_SUPPORTED";
+		break;
+	case CRYPTO_QUEUED:
+		valstr = "CRYPTO_QUEUED";
+		break;
+	case CRYPTO_BUFFER_TOO_BIG:
+		valstr = "CRYPTO_BUFFER_TOO_BIG";
+		break;
+	case CRYPTO_INVALID_CONTEXT:
+		valstr = "CRYPTO_INVALID_CONTEXT";
+		break;
+	case CRYPTO_INVALID_MAC:
+		valstr = "CRYPTO_INVALID_MAC";
+		break;
+	case CRYPTO_MECH_NOT_SUPPORTED:
+		valstr = "CRYPTO_MECH_NOT_SUPPORTED";
+		break;
+	case CRYPTO_INCONSISTENT_ATTRIBUTE:
+		valstr = "CRYPTO_INCONSISTENT_ATTRIBUTE";
+		break;
+	case CRYPTO_NO_PERMISSION:
+		valstr = "CRYPTO_NO_PERMISSION";
+		break;
+	case CRYPTO_INVALID_PROVIDER_ID:
+		valstr = "CRYPTO_INVALID_PROVIDER_ID";
+		break;
+	case CRYPTO_VERSION_MISMATCH:
+		valstr = "CRYPTO_VERSION_MISMATCH";
+		break;
+	case CRYPTO_BUSY:
+		valstr = "CRYPTO_BUSY";
+		break;
+	case CRYPTO_UNKNOWN_PROVIDER:
+		valstr = "CRYPTO_UNKNOWN_PROVIDER";
+		break;
+	case CRYPTO_MODVERIFICATION_FAILED:
+		valstr = "CRYPTO_MODVERIFICATION_FAILED";
+		break;
+	case CRYPTO_OLD_CTX_TEMPLATE:
+		valstr = "CRYPTO_OLD_CTX_TEMPLATE";
+		break;
+	case CRYPTO_WEAK_KEY:
+		valstr = "CRYPTO_WEAK_KEY";
+		break;
+	case CRYPTO_FIPS140_ERROR:
+		valstr = "CRYPTO_FIPS140_ERROR";
+		break;
+	default:
+		valstr = "Unknown KCF error";
+		break;
+	}
+
+	(void) snprintf(buf, buflen, "%s (0x%08x)", valstr, e);
+	return (buf);
+}
--- a/usr/src/test/crypto-tests/tests/common/cryptotest_pkcs.c	Sun Oct 21 22:14:02 2018 +0300
+++ b/usr/src/test/crypto-tests/tests/common/cryptotest_pkcs.c	Thu Aug 15 18:55:18 2019 +0000
@@ -11,12 +11,15 @@
 
 /*
  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
- * Copyright 2018, Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
  */
 
+#include <errno.h>
 #include <stdio.h>
+#include <string.h>
 #include <cryptoutil.h>
 #include <security/cryptoki.h>
+#include <sys/debug.h>
 
 #include "cryptotest.h"
 
@@ -30,7 +33,7 @@
 	size_t outlen;
 	size_t keylen;
 	size_t paramlen;
-	size_t updatelen;
+	const size_t *updatelens;
 
 	char *mechname;
 
@@ -53,6 +56,11 @@
 {
 	crypto_op_t *op = malloc(sizeof (*op));
 
+	if (op == NULL) {
+		(void) fprintf(stderr, "malloc failed: %s\n", strerror(errno));
+		return (NULL);
+	}
+
 	op->in = (CK_BYTE_PTR)arg->in;
 	op->out = (CK_BYTE_PTR)arg->out;
 	op->key = (CK_BYTE_PTR)arg->key;
@@ -62,7 +70,7 @@
 	op->outlen = arg->outlen;
 	op->keylen = arg->keylen;
 	op->paramlen = arg->plen;
-	op->updatelen = arg->updatelen;
+	op->updatelens = arg->updatelens;
 
 	op->mechname = arg->mechname;
 
@@ -86,7 +94,7 @@
 	return (rv);
 }
 
-int
+void
 cryptotest_close(crypto_op_t *op)
 {
 	if (op->keyt != CK_INVALID_HANDLE)
@@ -95,7 +103,7 @@
 	if (op->hsession != CK_INVALID_HANDLE)
 		(void) cryptotest_close_session(op->hsession);
 	free(op);
-	return (C_Finalize(NULL));
+	VERIFY0(C_Finalize(NULL));
 }
 
 int
@@ -168,10 +176,10 @@
 }
 
 int
-sign_update(crypto_op_t *op, int offset)
+sign_update(crypto_op_t *op, size_t offset, size_t len)
 {
 	CK_RV rv;
-	rv = C_SignUpdate(op->hsession, op->in + offset, op->updatelen);
+	rv = C_SignUpdate(op->hsession, op->in + offset, len);
 	if (rv != CKR_OK)
 		cryptotest_error("C_SignUpdate", rv);
 
@@ -204,13 +212,13 @@
 }
 
 int
-mac_update(crypto_op_t *op, int offset)
+mac_update(crypto_op_t *op, size_t offset, size_t len, size_t *dummy __unused)
 {
-	return (sign_update(op, offset));
+	return (sign_update(op, offset, len));
 }
 
 int
-mac_final(crypto_op_t *op)
+mac_final(crypto_op_t *op, size_t dummy __unused)
 {
 	return (sign_final(op));
 }
@@ -255,10 +263,10 @@
 }
 
 int
-verify_update(crypto_op_t *op, int offset)
+verify_update(crypto_op_t *op, size_t offset, size_t len)
 {
 	CK_RV rv;
-	rv = C_VerifyUpdate(op->hsession, op->in + offset, op->updatelen);
+	rv = C_VerifyUpdate(op->hsession, op->in + offset, len);
 	if (rv != CKR_OK)
 		cryptotest_error("C_VerifyUpdate", rv);
 	return (rv);
@@ -315,11 +323,11 @@
 }
 
 int
-encrypt_update(crypto_op_t *op, int offset, size_t *encrlen)
+encrypt_update(crypto_op_t *op, size_t offset, size_t plainlen, size_t *encrlen)
 {
 	CK_RV rv;
 	CK_ULONG outlen = op->outlen - *encrlen;
-	rv = C_EncryptUpdate(op->hsession, op->in + offset, op->updatelen,
+	rv = C_EncryptUpdate(op->hsession, op->in + offset, plainlen,
 	    op->out + *encrlen, &outlen);
 	if (rv != CKR_OK)
 		cryptotest_error("C_EncryptUpdate", rv);
@@ -379,11 +387,11 @@
 }
 
 int
-decrypt_update(crypto_op_t *op, int offset, size_t *encrlen)
+decrypt_update(crypto_op_t *op, size_t offset, size_t len, size_t *encrlen)
 {
 	CK_RV rv;
 	CK_ULONG outlen = op->outlen - *encrlen;
-	rv = C_DecryptUpdate(op->hsession, op->in + offset, op->updatelen,
+	rv = C_DecryptUpdate(op->hsession, op->in + offset, len,
 	    op->out + *encrlen, &outlen);
 	if (rv != CKR_OK)
 		cryptotest_error("C_DecryptUpdate", rv);
@@ -435,18 +443,19 @@
 }
 
 int
-digest_update(crypto_op_t *op, int offset)
+digest_update(crypto_op_t *op, size_t offset, size_t len,
+    size_t *dummy __unused)
 {
 	CK_RV rv;
 
-	rv = C_DigestUpdate(op->hsession, op->in + offset, op->updatelen);
+	rv = C_DigestUpdate(op->hsession, op->in + offset, len);
 	if (rv != CKR_OK)
 		cryptotest_error("C_DigestUpdate", rv);
 	return (rv);
 }
 
 int
-digest_final(crypto_op_t *op)
+digest_final(crypto_op_t *op, size_t dummy __unused)
 {
 	CK_RV rv;
 
@@ -475,3 +484,26 @@
 {
 	return (sizeof (CK_CCM_PARAMS));
 }
+
+const char *
+cryptotest_errstr(int e, char *buf, size_t buflen)
+{
+	char *valstr = NULL;
+
+	valstr = pkcs11_strerror(e);
+
+	/*
+	 * We'd like both the symbolic and numeric value for every error
+	 * value.  pkcs11_strerror() already includes the numeric value
+	 * for unknown error values (but not for known values), so we take
+	 * advantage of all known PKCS#11 error values starting with 'CKR_'
+	 * to determine if we need to include the numeric value or not.
+	 */
+	if (strcmp(valstr, "CKR_") == 0) {
+		(void) snprintf(buf, buflen, "%s (%08x)", valstr, e);
+	} else {
+		(void) strlcpy(buf, valstr, buflen);
+	}
+
+	return (buf);
+}
--- a/usr/src/test/crypto-tests/tests/common/testfuncs.c	Sun Oct 21 22:14:02 2018 +0300
+++ b/usr/src/test/crypto-tests/tests/common/testfuncs.c	Thu Aug 15 18:55:18 2019 +0000
@@ -11,26 +11,86 @@
 
 /*
  * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
- * Copyright 2018, Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
  */
 
 #define	__EXTENSIONS__
+#include <limits.h>
 #include <strings.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <sys/debug.h>
 #include "cryptotest.h"
 
+/*
+ * A somewhat arbitrary size that should be large enough to hold the printed
+ * error and size messages.
+ */
+#define	BUFSZ 128
 
+#define	EXIT_FAILURE_MULTIPART	1
+#define	EXIT_FAILURE_SINGLEPART	2
+
+test_fg_t cryptotest_decr_fg = {
+	.tf_fg = CRYPTO_FG_DECRYPT,
+	.tf_init = decrypt_init,
+	.tf_single = decrypt_single,
+	.tf_update = decrypt_update,
+	.tf_final = decrypt_final
+};
 
-test_fg_t cryptotest_decr_fg = {test_decrypt_single, test_decrypt};
-test_fg_t cryptotest_encr_fg = {test_encrypt_single, test_encrypt};
-test_fg_t cryptotest_mac_fg = {test_mac_single, test_mac};
-test_fg_t cryptotest_digest_fg = {test_digest_single, test_digest};
+test_fg_t cryptotest_encr_fg = {
+	.tf_fg = CRYPTO_FG_ENCRYPT,
+	.tf_init = encrypt_init,
+	.tf_single = encrypt_single,
+	.tf_update = encrypt_update,
+	.tf_final = encrypt_final
+};
+
+test_fg_t cryptotest_mac_fg = {
+	.tf_fg = CRYPTO_FG_MAC,
+	.tf_init = mac_init,
+	.tf_single = mac_single,
+	.tf_update = mac_update,
+	.tf_final = mac_final
+};
+
+test_fg_t cryptotest_digest_fg = {
+	.tf_fg = CRYPTO_FG_DIGEST,
+	.tf_init = digest_init,
+	.tf_single = digest_single,
+	.tf_update = digest_update,
+	.tf_final = digest_final
+};
 
 /*
  * Utils
  */
 
+static const char *
+ctest_errstr(int e, char *buf, size_t buflen)
+{
+	const char *name = NULL;
+	;
+	switch (e) {
+	case CTEST_INIT_FAILED:
+		name = "CTEST_INIT_FAILED";
+		break;
+	case CTEST_NAME_RESOLVE_FAILED:
+		name = "CTEST_MECH_NO_PROVIDER";
+		break;
+	case CTEST_MECH_NO_PROVIDER:
+		name = "CTEST_MECH_NO_PROVIDER";
+		break;
+	default:
+		name = "Unknown fatal error";
+		break;
+	}
+
+	(void) snprintf(buf, buflen, "%s (%d)", name, e);
+	return (buf);
+}
+
 void
 printbuf(uint8_t *buf, char *name, size_t size)
 {
@@ -48,16 +108,206 @@
 bufcmp(uint8_t *auth, uint8_t *cmp, size_t size)
 {
 	if (memcmp(cmp, auth, size) != 0) {
-		(void) fprintf(stderr, "mismatched result\n\n");
+		(void) fprintf(stderr, "        mismatched result\n\n");
 		printbuf(cmp, "calc", size);
 		printbuf(auth, "orig", size);
 		return (1);
 	} else {
-		(void) fprintf(stderr, "result matches\n\n");
+		(void) fprintf(stderr, "        result matches\n\n");
 		return (0);
 	}
 }
 
+static int
+test_setup(cryptotest_t *args, test_fg_t *funcs, crypto_op_t **opp)
+{
+	crypto_op_t *crypto_op = NULL;
+	int ret;
+
+	switch (funcs->tf_fg) {
+	case CRYPTO_FG_DECRYPT:
+	case CRYPTO_FG_ENCRYPT:
+		if (args->key == NULL)
+			return (CRYPTO_FAILED);
+		break;
+	case CRYPTO_FG_MAC:
+		if (args->in == NULL || args->key == NULL)
+			return (CRYPTO_FAILED);
+		break;
+	case CRYPTO_FG_DIGEST:
+		break;
+	default:
+		(void) fprintf(stderr,
+		    "Unexpected function group value %" PRIu32 "\n",
+		    funcs->tf_fg);
+		abort();
+	}
+
+	if ((crypto_op = cryptotest_init(args, funcs->tf_fg)) == NULL) {
+		/* cryptotest_init() will prints out a specific error msg  */
+		cryptotest_close(NULL);
+		return (CTEST_INIT_FAILED);
+	}
+
+	if ((ret = get_mech_info(crypto_op)) != CRYPTO_SUCCESS) {
+		cryptotest_close(crypto_op);
+		return (ret);
+	}
+
+	if ((ret = get_hsession_by_mech(crypto_op)) != CRYPTO_SUCCESS) {
+		cryptotest_close(crypto_op);
+		return (ret);
+	}
+
+	*opp = crypto_op;
+	return (CRYPTO_SUCCESS);
+}
+
+static int
+test_multi(cryptotest_t *args, test_fg_t *funcs, uint8_t *cmp, size_t cmplen)
+{
+	crypto_op_t *crypto_op = NULL;
+	size_t errs = 0;
+	size_t n;
+	int ret;
+
+	(void) fprintf(stderr, "multi-part:\n");
+
+	if ((ret = test_setup(args, funcs, &crypto_op)) != CRYPTO_SUCCESS) {
+		(void) fprintf(stderr, "        fatal error %d\n", ret);
+		exit(EXIT_FAILURE_MULTIPART);
+	}
+
+	for (n = 0; args->updatelens[n] != CTEST_UPDATELEN_END; n++) {
+		char errbuf[BUFSZ] = { 0 };
+		char sizebuf[BUFSZ] = { 0 };
+		size_t updatelen = args->updatelens[n];
+		size_t offset = 0;
+		size_t outlen = 0;
+
+		bzero(args->out, args->outlen);
+
+		if (updatelen == CTEST_UPDATELEN_WHOLE) {
+			updatelen = args->inlen;
+			(void) snprintf(sizebuf, sizeof (sizebuf),
+			    "%zu (whole buffer)", updatelen);
+		} else if (updatelen > args->inlen) {
+			/*
+			 * This can sometimes cause the same update size to
+			 * be used twice if one is specified larger than the
+			 * input and one also specifies a test using the
+			 * entire input as the update size.  It doesn't
+			 * hurt anything other than adding a little extra
+			 * time.
+			 */
+			updatelen = args->inlen;
+			(void) snprintf(sizebuf, sizeof (sizebuf),
+			    "%zu (was %zu but capped at input size)",
+			    updatelen, args->updatelens[n]);
+		} else {
+			(void) snprintf(sizebuf, sizeof (sizebuf), "%zu",
+			    updatelen);
+		}
+		(void) fprintf(stderr, "    update size: %s\n", sizebuf);
+		(void) fflush(stderr);
+
+		if ((ret = funcs->tf_init(crypto_op)) != CRYPTO_SUCCESS) {
+			(void) fprintf(stderr, "        fatal error %d\n", ret);
+			exit(EXIT_FAILURE_MULTIPART);
+		}
+
+		while (offset < args->inlen) {
+			size_t len = updatelen;
+
+			if (offset + updatelen > args->inlen) {
+				len = args->inlen - offset;
+			}
+
+			ret = funcs->tf_update(crypto_op, offset, len, &outlen);
+			if (ret != CRYPTO_SUCCESS) {
+				/*
+				 * The update functions will print out their
+				 * own error messages, so we don't need to.
+				 */
+				errs += 1;
+				break;
+			}
+
+			offset += len;
+		}
+
+		if (ret != CRYPTO_SUCCESS)
+			continue;
+
+		ret = funcs->tf_final(crypto_op, outlen);
+
+		/*
+		 * Errors from the crypto frameworks (KCF, PKCS#11) are all
+		 * positive (and 0 == success).  Negative values are used by
+		 * the test framework to signal fatal errors (CTEST_xxx).
+		 */
+		if (ret > 0) {
+			(void) fprintf(stderr, "        failure %s\n",
+			    cryptotest_errstr(ret, errbuf, sizeof (errbuf)));
+			errs += 1;
+		} else if (ret < 0) {
+			(void) fprintf(stderr, "        fatal error %s\n",
+			    ctest_errstr(ret, errbuf, sizeof (errbuf)));
+			exit(EXIT_FAILURE_MULTIPART);
+		} else {
+			errs += bufcmp(cmp, args->out, cmplen);
+		}
+	}
+
+	VERIFY3U(errs, <=, INT_MAX);
+	cryptotest_close(crypto_op);
+	return (errs);
+}
+
+static int
+test_single(cryptotest_t *args, test_fg_t *funcs, uint8_t *cmp, size_t cmplen)
+{
+	crypto_op_t *crypto_op = NULL;
+	char errbuf[BUFSZ] = { 0 };
+	int ret;
+
+	(void) fprintf(stderr, "single part:\n");
+
+	if ((ret = test_setup(args, funcs, &crypto_op)) != CRYPTO_SUCCESS) {
+		(void) fprintf(stderr, "        fatal error %d\n", ret);
+		exit(EXIT_FAILURE_SINGLEPART);
+	}
+
+	if ((ret = funcs->tf_init(crypto_op)) != CRYPTO_SUCCESS) {
+		(void) fprintf(stderr, "        fatal error %d\n", ret);
+		exit(EXIT_FAILURE_SINGLEPART);
+	}
+
+	if ((ret = funcs->tf_single(crypto_op)) != CRYPTO_SUCCESS)
+		goto out;
+
+	/*
+	 * Errors from the crypto frameworks (KCF, PKCS#11) are all
+	 * positive (and 0 == success).  Negative values are used by
+	 * the test framework to signal fatal errors (CTEST_xxx).
+	 */
+	if (ret > 0) {
+		(void) fprintf(stderr, "        failure %s\n",
+		    cryptotest_errstr(ret, errbuf, sizeof (errbuf)));
+		return (1);
+	} else if (ret < 0) {
+		(void) fprintf(stderr, "        fatal error %s\n",
+		    ctest_errstr(ret, errbuf, sizeof (errbuf)));
+		exit(EXIT_FAILURE_SINGLEPART);
+	} else {
+		ret = bufcmp(cmp, args->out, cmplen);
+	}
+
+out:
+	(void) cryptotest_close(crypto_op);
+	return ((ret == CRYPTO_SUCCESS) ? 0 : 1);
+}
+
 /*
  * Wrapper functions
  */
@@ -66,258 +316,17 @@
 run_test(cryptotest_t *args, uint8_t *cmp, size_t cmplen,
     test_fg_t *funcs)
 {
-	int ret, errs = 0;
+	size_t errs = 0;
 	static int i = 0;
 
 	(void) fprintf(stderr, "%s: run %d\n", args->mechname, ++i);
-	bzero(args->out, args->outlen);
-	ret = funcs->update(args);
-	if (ret > 0) {
-		(void) fprintf(stderr, "failure %x\n", ret);
-		errs += 1;
-	} else if (ret < 0) {
-		(void) fprintf(stderr, "fatal error %d\n", ret);
-		exit(1);
-	} else
-		errs += bufcmp(cmp, args->out, cmplen);
+
+	errs += test_multi(args, funcs, cmp, cmplen);
 
 	bzero(args->out, args->outlen);
-	ret = funcs->single(args);
-	if (ret > 0) {
-		(void) fprintf(stderr, "failure %x\n", ret);
-		errs += 1;
-	} else if (ret < 0) {
-		(void) fprintf(stderr, "fatal error %d\n", ret);
-		exit(2);
-	} else
-		errs += bufcmp(cmp, args->out, cmplen);
 
+	errs += test_single(args, funcs, cmp, cmplen);
+
+	VERIFY3U(errs, <=, INT_MAX);
 	return (errs);
 }
-
-static int
-test_mac_common(cryptotest_t *args, boolean_t AIO)
-{
-	int ret, i;
-	crypto_op_t *crypto_op;
-
-	if (args->in == NULL || args->key == NULL)
-		return (CRYPTO_FAILED);
-
-	if ((crypto_op = cryptotest_init(args, CRYPTO_FG_MAC)) == NULL) {
-		(void) fprintf(stderr, "Error occured during initialization\n");
-		(void) cryptotest_close(NULL);
-		return (CTEST_INIT_FAILED);
-	}
-
-	if ((ret = get_mech_info(crypto_op)) != CRYPTO_SUCCESS)
-		goto out;
-
-	if ((ret = get_hsession_by_mech(crypto_op)) != CRYPTO_SUCCESS)
-		goto out;
-
-	if ((ret = mac_init(crypto_op)) != CRYPTO_SUCCESS)
-		goto out;
-
-	if (AIO) {
-		if ((ret = mac_single(crypto_op)) != CRYPTO_SUCCESS)
-			goto out;
-	} else {
-		for (i = 0; i < args->inlen; i += args->updatelen) {
-
-			if ((ret = mac_update(crypto_op, i)) != CRYPTO_SUCCESS)
-				goto out;
-		}
-
-		if ((ret = mac_final(crypto_op)) != CRYPTO_SUCCESS)
-			goto out;
-
-	}
-
-out:
-	(void) cryptotest_close(crypto_op);
-	return (ret);
-}
-
-int
-test_mac_single(cryptotest_t *args)
-{
-	return (test_mac_common(args, B_TRUE));
-}
-
-int
-test_mac(cryptotest_t *args)
-{
-	return (test_mac_common(args, B_FALSE));
-}
-
-static int
-test_encrypt_common(cryptotest_t *args, boolean_t AIO)
-{
-	int ret, i;
-	size_t encrlen = 0;
-	crypto_op_t *crypto_op;
-
-	if (args->key == NULL)
-		return (CRYPTO_FAILED);
-
-	if ((crypto_op = cryptotest_init(args, CRYPTO_FG_ENCRYPT)) == NULL) {
-		(void) fprintf(stderr, "Error occured during initialization\n");
-		(void) cryptotest_close(NULL);
-		return (CTEST_INIT_FAILED);
-	}
-
-	if ((ret = get_mech_info(crypto_op)) != CRYPTO_SUCCESS)
-		goto out;
-
-	if ((ret = get_hsession_by_mech(crypto_op)) != CRYPTO_SUCCESS)
-		goto out;
-
-	if ((ret = encrypt_init(crypto_op)) != CRYPTO_SUCCESS)
-		goto out;
-
-	if (AIO) {
-		if ((ret = encrypt_single(crypto_op)) != CRYPTO_SUCCESS)
-			goto out;
-	} else {
-		for (i = 0; i < args->inlen; i += args->updatelen) {
-
-			if ((ret = encrypt_update(crypto_op, i,
-			    &encrlen)) != CRYPTO_SUCCESS)
-				goto out;
-		}
-
-		if ((ret = encrypt_final(crypto_op, encrlen)) != CRYPTO_SUCCESS)
-			goto out;
-
-	}
-
-out:
-	(void) cryptotest_close(crypto_op);
-	return (ret);
-}
-
-int
-test_encrypt_single(cryptotest_t *args)
-{
-	return (test_encrypt_common(args, B_TRUE));
-}
-
-
-int
-test_encrypt(cryptotest_t *args)
-{
-	return (test_encrypt_common(args, B_FALSE));
-}
-
-static int
-test_decrypt_common(cryptotest_t *args, boolean_t AIO)
-{
-	int ret, i;
-	size_t encrlen = 0;
-	crypto_op_t *crypto_op;
-
-	if (args->key == NULL)
-		return (CRYPTO_FAILED);
-
-	if ((crypto_op = cryptotest_init(args, CRYPTO_FG_DECRYPT)) == NULL) {
-		(void) fprintf(stderr, "Error occured during initialization\n");
-		(void) cryptotest_close(NULL);
-		return (CTEST_INIT_FAILED);
-	}
-
-	if ((ret = get_mech_info(crypto_op)) != CRYPTO_SUCCESS)
-		goto out;
-
-	if ((ret = get_hsession_by_mech(crypto_op)) != CRYPTO_SUCCESS)
-		goto out;
-
-	if ((ret = decrypt_init(crypto_op)) != CRYPTO_SUCCESS)
-		goto out;
-
-	if (AIO) {
-		if ((ret = decrypt_single(crypto_op)) != CRYPTO_SUCCESS)
-			goto out;
-	} else {
-		for (i = 0; i < args->inlen; i += args->updatelen) {
-
-			if ((ret = decrypt_update(crypto_op, i,
-			    &encrlen)) != CRYPTO_SUCCESS)
-				goto out;
-		}
-
-		if ((ret = decrypt_final(crypto_op, encrlen)) != CRYPTO_SUCCESS)
-			goto out;
-
-	}
-
-out:
-	(void) cryptotest_close(crypto_op);
-	return (ret);
-}
-
-int
-test_decrypt_single(cryptotest_t *args)
-{
-	return (test_decrypt_common(args, B_TRUE));
-}
-
-
-int
-test_decrypt(cryptotest_t *args)
-{
-	return (test_decrypt_common(args, B_FALSE));
-}
-
-static int
-test_digest_common(cryptotest_t *args, boolean_t AIO)
-{
-	int ret, i;
-	crypto_op_t *crypto_op;
-
-	if ((crypto_op = cryptotest_init(args, CRYPTO_FG_DIGEST)) == NULL) {
-		(void) fprintf(stderr, "Error occured during initalization\n");
-		(void) cryptotest_close(NULL);
-		return (CTEST_INIT_FAILED);
-	}
-
-	if ((ret = get_mech_info(crypto_op)) != CRYPTO_SUCCESS)
-		goto out;
-
-	if ((ret = get_hsession_by_mech(crypto_op)) != CRYPTO_SUCCESS)
-		goto out;
-
-	if ((ret = digest_init(crypto_op)) != CRYPTO_SUCCESS)
-		goto out;
-
-	if (AIO) {
-		if ((ret = digest_single(crypto_op)) != CRYPTO_SUCCESS)
-			goto out;
-	} else {
-		for (i = 0; i < args->inlen; i += args->updatelen) {
-
-			if ((ret = digest_update(crypto_op, i)) !=
-			    CRYPTO_SUCCESS)
-				goto out;
-		}
-
-		if ((ret = digest_final(crypto_op)) != CRYPTO_SUCCESS)
-			goto out;
-	}
-
-out:
-	(void) cryptotest_close(crypto_op);
-	return (ret);
-}
-
-int
-test_digest_single(cryptotest_t *args)
-{
-	return (test_digest_common(args, B_TRUE));
-}
-
-int
-test_digest(cryptotest_t *args)
-{
-	return (test_digest_common(args, B_FALSE));
-}
--- a/usr/src/test/crypto-tests/tests/digest/main.c	Sun Oct 21 22:14:02 2018 +0300
+++ b/usr/src/test/crypto-tests/tests/digest/main.c	Thu Aug 15 18:55:18 2019 +0000
@@ -10,7 +10,7 @@
  */
 
 /*
- * Copyright 2018, Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
  */
 
 #include <stdio.h>
@@ -24,18 +24,21 @@
 extern size_t mdlen;
 extern char *mechname;
 
+static size_t updatelens[] = {
+	1, 8, 33, 67, CTEST_UPDATELEN_WHOLE, CTEST_UPDATELEN_END
+};
+
 int
 main(void)
 {
 	int i, errs = 0;
 	uint8_t N[1024];
-	cryptotest_t args = { 0 };
-
-	args.out = N;
-	args.outlen = sizeof (N);
-
-	args.mechname = mechname;
-	args.updatelen = 1;
+	cryptotest_t args = {
+		.out = N,
+		.outlen = sizeof (N),
+		.mechname = mechname,
+		.updatelens = updatelens
+	};
 
 	for (i = 0; i < msgcount; i++) {
 		args.in = MSG[i];
--- a/usr/src/test/crypto-tests/tests/hmac/main.c	Sun Oct 21 22:14:02 2018 +0300
+++ b/usr/src/test/crypto-tests/tests/hmac/main.c	Thu Aug 15 18:55:18 2019 +0000
@@ -27,6 +27,10 @@
 extern size_t hmac_len;
 extern size_t msgcount;
 
+static size_t updatelens[] = {
+	1, 8, 33, 67, CTEST_UPDATELEN_WHOLE, CTEST_UPDATELEN_END
+};
+
 int
 main(void)
 {
@@ -38,7 +42,7 @@
 		.outlen = sizeof (N),
 		.plen = 0,
 		.mechname = mechname,
-		.updatelen = 1
+		.updatelens = updatelens
 	};
 
 	for (i = 0; i < msgcount; i++) {
--- a/usr/src/test/crypto-tests/tests/modes/aes/cbc/aes_cbc.c	Sun Oct 21 22:14:02 2018 +0300
+++ b/usr/src/test/crypto-tests/tests/modes/aes/cbc/aes_cbc.c	Thu Aug 15 18:55:18 2019 +0000
@@ -11,6 +11,7 @@
 
 /*
  * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2019 Joyent, Inc.
  */
 
 #include <aes/aes_impl.h>
@@ -19,22 +20,24 @@
 #include "cryptotest.h"
 #include "aes_cbc.h"
 
+static size_t updatelens[] = {
+	1, AES_BLOCK_LEN, AES_BLOCK_LEN + 1, 2*AES_BLOCK_LEN,
+	CTEST_UPDATELEN_WHOLE, CTEST_UPDATELEN_END
+};
+
 int
 main(void)
 {
 	int errs = 0;
 	int i;
 	uint8_t N[1024];
-	cryptotest_t args;
-
-	args.out = N;
-
-	args.outlen = sizeof (N);
-	args.plen = AES_BLOCK_LEN;
-
-	args.mechname = SUN_CKM_AES_CBC;
-	args.updatelen = 1;
-
+	cryptotest_t args = {
+		.out = N,
+		.outlen = sizeof (N),
+		.plen = AES_BLOCK_LEN,
+		.mechname = SUN_CKM_AES_CBC,
+		.updatelens = updatelens
+	};
 
 	for (i = 0; i < sizeof (RES) / sizeof (RES[0]); i++) {
 		args.in = DATA[i];
--- a/usr/src/test/crypto-tests/tests/modes/aes/cbc_pad/aes_cbc_pad.c	Sun Oct 21 22:14:02 2018 +0300
+++ b/usr/src/test/crypto-tests/tests/modes/aes/cbc_pad/aes_cbc_pad.c	Thu Aug 15 18:55:18 2019 +0000
@@ -23,28 +23,31 @@
 
 #include <aes/aes_impl.h>
 #include <stdio.h>
+#include <sys/sysmacros.h>
 
 #include "cryptotest.h"
 #include "aes_cbc_pad.h"
 
+static size_t updatelens[] = {
+	1, AES_BLOCK_LEN, AES_BLOCK_LEN + 1, 2*AES_BLOCK_LEN,
+	CTEST_UPDATELEN_WHOLE, CTEST_UPDATELEN_END
+};
+
 int
 main(void)
 {
 	int errs = 0;
 	int i;
 	uint8_t N[1024];
-	cryptotest_t args;
-
-	args.out = N;
+	cryptotest_t args = {
+		.out = N,
+		.outlen = sizeof (N),
+		.plen = AES_BLOCK_LEN,
+		.mechname = CBC_PAD,
+		.updatelens = updatelens
+	};
 
-	args.outlen = sizeof (N);
-	args.plen = AES_BLOCK_LEN;
-
-	args.mechname = CBC_PAD;
-	args.updatelen = 1;
-
-
-	for (i = 0; i < sizeof (RES) / sizeof (RES[0]); i++) {
+	for (i = 0; i < ARRAY_SIZE(RES); i++) {
 		args.in = DATA[i];
 		args.key = KEY[i];
 		args.param = IV[i];
@@ -58,7 +61,7 @@
 
 	(void) fprintf(stderr, "\t\t\t=== decrypt ===\n----------\n\n");
 
-	for (i = 0; i < sizeof (RES) / sizeof (RES[0]); i++) {
+	for (i = 0; i < ARRAY_SIZE(RES); i++) {
 		args.in = RES[i];
 		args.key = KEY[i];
 		args.param = IV[i];
--- a/usr/src/test/crypto-tests/tests/modes/aes/ccm/aes_ccm.c	Sun Oct 21 22:14:02 2018 +0300
+++ b/usr/src/test/crypto-tests/tests/modes/aes/ccm/aes_ccm.c	Thu Aug 15 18:55:18 2019 +0000
@@ -11,9 +11,10 @@
 
 /*
  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
- * Copyright 2018, Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
  */
 
+#include <aes/aes_impl.h>
 #include <strings.h>
 #include <stdio.h>
 #include <sys/debug.h>
@@ -26,6 +27,11 @@
  */
 #define	PARAM_SIZE_64 8
 
+static size_t updatelens[] = {
+	1, AES_BLOCK_LEN, AES_BLOCK_LEN + 1, 2*AES_BLOCK_LEN,
+	CTEST_UPDATELEN_WHOLE, CTEST_UPDATELEN_END
+};
+
 int
 main(void)
 {
@@ -34,14 +40,12 @@
 	uint8_t N[1024];
 	uint64_t param[PARAM_SIZE_64];
 
-	cryptotest_t args;
-
-	args.out = N;
-
-	args.outlen = sizeof (N);
-
-	args.mechname = SUN_CKM_AES_CCM;
-	args.updatelen = 1;
+	cryptotest_t args = {
+		.out = N,
+		.outlen = sizeof (N),
+		.mechname = SUN_CKM_AES_CCM,
+		.updatelens = updatelens
+	};
 
 	args.key = CCM_KEY1;
 	args.keylen = sizeof (CCM_KEY1);
--- a/usr/src/test/crypto-tests/tests/modes/aes/cmac/aes_cmac.c	Sun Oct 21 22:14:02 2018 +0300
+++ b/usr/src/test/crypto-tests/tests/modes/aes/cmac/aes_cmac.c	Thu Aug 15 18:55:18 2019 +0000
@@ -11,6 +11,7 @@
 
 /*
  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2019 Joyent, Inc.
  */
 
 #include <aes/aes_impl.h>
@@ -19,25 +20,26 @@
 #include "cryptotest.h"
 #include "aes_cmac.h"
 
+static size_t updatelens[] = {
+	1, AES_BLOCK_LEN, AES_BLOCK_LEN + 1, 2*AES_BLOCK_LEN,
+	CTEST_UPDATELEN_WHOLE, CTEST_UPDATELEN_END
+};
+
 int
 main(void)
 {
 	int errs = 0;
 	int i;
 	uint8_t N[AES_BLOCK_LEN];
-	cryptotest_t args;
-
-	args.in = M;
-	args.out = N;
-	args.key = keytest;
-	args.param = NULL;
-
-	args.outlen = sizeof (N);
-	args.keylen = sizeof (keytest);
-	args.plen = 0;
-
-	args.mechname = SUN_CKM_AES_CMAC;
-	args.updatelen = 1;
+	cryptotest_t args = {
+		.in = M,
+		.out = N,
+		.outlen = sizeof (N),
+		.key = keytest,
+		.keylen = sizeof (keytest),
+		.mechname = SUN_CKM_AES_CMAC,
+		.updatelens = updatelens
+	};
 
 	for (i = 0; i < sizeof (RES) / sizeof (RES[0]); i++) {
 		args.inlen = DATALEN[i];
--- a/usr/src/test/crypto-tests/tests/modes/aes/ctr/aes_ctr.c	Sun Oct 21 22:14:02 2018 +0300
+++ b/usr/src/test/crypto-tests/tests/modes/aes/ctr/aes_ctr.c	Thu Aug 15 18:55:18 2019 +0000
@@ -11,6 +11,7 @@
 
 /*
  * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2019 Joyent, Inc.
  */
 
 #include <strings.h>
@@ -21,34 +22,32 @@
 #include "cryptotest.h"
 #include "aes_ctr.h"
 
+/*
+ * CTR is a stream cipher, and it runs ctr_mode_final every time
+ * it has a remainder, so the result is different
+ * if len == 0 mod block_size vs len != 0 mod block_size
+ */
+static size_t updatelens[] = { 16, CTEST_UPDATELEN_END };
+
 int
 main(void)
 {
 	int errs = 0;
 	int i;
 	uint8_t N[1024];
-	CK_AES_CTR_PARAMS param;
-	cryptotest_t args;
 	size_t cblen = sizeof (CTR_CB0);
-
-	bzero(&param, sizeof (param));
-	param.ulCounterBits = 128 - cblen*8;
-	param.cb[15] = 0x01;
-
-	args.out = N;
-	args.param = &param;
-
-	args.outlen = sizeof (N);
-	args.plen = sizeof (param);
-
-	/*
-	 * CTR is a stream cipher, and it runs ctr_mode_final every time
-	 * it has a remainder, so the result is different
-	 * if len == 0 mod block_size vs len != 0 mod block_size
-	 */
-
-	args.mechname = SUN_CKM_AES_CTR;
-	args.updatelen = 16;
+	CK_AES_CTR_PARAMS param = {
+		.ulCounterBits = 128 - cblen * 8,
+		.cb[15] = 0x01
+	};
+	cryptotest_t args = {
+		.out = N,
+		.outlen = sizeof (N),
+		.param = &param,
+		.plen = sizeof (param),
+		.mechname = SUN_CKM_AES_CTR,
+		.updatelens = updatelens
+	};
 
 	for (i = 0; i < sizeof (DATA) / sizeof (DATA[0]); i++) {
 		bcopy(CB[i], param.cb, cblen);
--- a/usr/src/test/crypto-tests/tests/modes/aes/ecb/aes_ecb.c	Sun Oct 21 22:14:02 2018 +0300
+++ b/usr/src/test/crypto-tests/tests/modes/aes/ecb/aes_ecb.c	Thu Aug 15 18:55:18 2019 +0000
@@ -11,30 +11,33 @@
 
 /*
  * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2019 Joyent, Inc.
  */
 
+#include <aes/aes_impl.h>
 #include <stdio.h>
 #include "cryptotest.h"
 #include "aes_ecb.h"
 
+static size_t updatelens[] = {
+	1, AES_BLOCK_LEN, AES_BLOCK_LEN + 1, 2*AES_BLOCK_LEN,
+	CTEST_UPDATELEN_WHOLE, CTEST_UPDATELEN_END
+};
+
 int
 main(void)
 {
 	int errs = 0;
 	int i;
 	uint8_t N[1024];
-	cryptotest_t args;
-
-	args.in = ECB_DATA;
-	args.out = N;
-	args.param = NULL;
-
-	args.inlen = sizeof (ECB_DATA);
-	args.outlen = sizeof (N);
-	args.plen = 0;
-
-	args.mechname = SUN_CKM_AES_ECB;
-	args.updatelen = 1;
+	cryptotest_t args = {
+		.in = ECB_DATA,
+		.inlen = sizeof (ECB_DATA),
+		.out = N,
+		.outlen = sizeof (N),
+		.updatelens = updatelens,
+		.mechname = SUN_CKM_AES_ECB
+	};
 
 	for (i = 0; i < sizeof (RES) / sizeof (RES[0]); i++) {
 		args.key = KEY[i];
--- a/usr/src/test/crypto-tests/tests/modes/aes/gcm/aes_gcm.c	Sun Oct 21 22:14:02 2018 +0300
+++ b/usr/src/test/crypto-tests/tests/modes/aes/gcm/aes_gcm.c	Thu Aug 15 18:55:18 2019 +0000
@@ -11,14 +11,22 @@
 
 /*
  * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2019 Joyent, Inc.
  */
 
+#include <aes/aes_impl.h>
 #include <strings.h>
 #include <stdio.h>
 #include "cryptotest.h"
 #include "aes_gcm.h"
 
+static size_t updatelens[] = {
+	1, AES_BLOCK_LEN, AES_BLOCK_LEN + 1, 2*AES_BLOCK_LEN,
+	CTEST_UPDATELEN_WHOLE, CTEST_UPDATELEN_END
+};
+
 const size_t GCM_SPEC_TAG_LEN = 16;
+
 int
 main(void)
 {
@@ -27,20 +35,17 @@
 	uint8_t N[1024];
 	size_t taglen = GCM_SPEC_TAG_LEN;
 
-	CK_AES_GCM_PARAMS param;
-	cryptotest_t args;
-
-	bzero(&param, sizeof (param));
-	param.ulTagBits = taglen*8;
-
-	args.out = N;
-	args.param = &param;
-
-	args.outlen = sizeof (N);
-	args.plen = sizeof (param);
-
-	args.mechname = SUN_CKM_AES_GCM;
-	args.updatelen = 1;
+	CK_AES_GCM_PARAMS param = {
+		.ulTagBits = taglen * 8
+	};
+	cryptotest_t args = {
+		.out = N,
+		.outlen = sizeof (N),
+		.param = &param,
+		.plen = sizeof (param),
+		.mechname = SUN_CKM_AES_GCM,
+		.updatelens = updatelens
+	};
 
 	for (i = 0; i < sizeof (DATA) / sizeof (DATA[0]); i++) {
 		args.in = DATA[i];