diff --git a/KAEOpensslProvider/.gitignore b/KAEOpensslProvider/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..7b7335e7f4639fa53b5dccc7ac32df33779d1299 --- /dev/null +++ b/KAEOpensslProvider/.gitignore @@ -0,0 +1,15 @@ +build-aux +autom4te.cache +.deps +.libs +*.m4 +*.lo +*.la +*.o +*.tar.gz +Makefile.in +config.status +config.log +configure +libtool +cscope.* diff --git a/KAEOpensslProvider/AUTHORS b/KAEOpensslProvider/AUTHORS new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/KAEOpensslProvider/ChangeLog b/KAEOpensslProvider/ChangeLog new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/KAEOpensslProvider/Makefile.am b/KAEOpensslProvider/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..6d4ebf025cc058dc6777f4aaaf1813ca116ee2ce --- /dev/null +++ b/KAEOpensslProvider/Makefile.am @@ -0,0 +1,5 @@ +ACLOCAL_AMFLAGS = -I m4 + +if HAVE_WD +SUBDIRS = src +endif \ No newline at end of file diff --git a/KAEOpensslProvider/NEWS b/KAEOpensslProvider/NEWS new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/KAEOpensslProvider/README b/KAEOpensslProvider/README new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/KAEOpensslProvider/configure.ac b/KAEOpensslProvider/configure.ac new file mode 100644 index 0000000000000000000000000000000000000000..f0b0b99f235b18b604669881a4f7b592e1db5848 --- /dev/null +++ b/KAEOpensslProvider/configure.ac @@ -0,0 +1,47 @@ +AC_PREREQ([2.69]) +AC_INIT([uadk_engine], [1.1]) +AC_CONFIG_SRCDIR([src/Makefile.am]) +AM_INIT_AUTOMAKE([1.10 no-define]) +AM_PROG_AS([AS]) + + +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_HEADERS([config.h]) + +AC_PROG_CC +AC_PROG_LIBTOOL +AM_PROG_LIBTOOL + +# 定义命令行参数 +AC_ARG_ENABLE([kae], [AS_HELP_STRING([--enable-kae], [Enable kae support])], [enable_kae="yes"], [enable_kae="no"]) + +# 设置条件变量 +AM_CONDITIONAL([WD_KAE], [test "$enable_kae" = "yes"]) +AM_CONDITIONAL([WD_ENGINE], [test "$enable_provider" = "yes"]) + +# 通过命令传入openssl的安装路径,不然就用默认的 +AC_ARG_WITH(openssl_install_dir, + AS_HELP_STRING([--with-openssl_install_dir], + [Path to where the OpenSSL3.0 are installed to.])) +AC_SUBST(with_openssl_install_dir) + + +AC_SUBST([includes_openssl], ["-I\$(with_openssl_install_dir)/include"]) +AC_SUBST([includes_openssl], ["-I`pkg-config --variable=includedir libcrypto`"]) + + +PKG_CHECK_MODULES(WD, libwd libwd_crypto, [-L/usr/local/lib -L$(AM_LDFLAGS)], [with_wd=yes], [with_wd=no]) +AM_CONDITIONAL(HAVE_WD, [test "$with_wd" != "no"]) + +PKG_CHECK_MODULES(libcrypto, libcrypto < 3.0 libcrypto >= 1.1, + [with_crypto=yes], [with_crypto=no]) +AM_CONDITIONAL(HAVE_CRYPTO, test "$with_crypto" != "no") + +PKG_CHECK_MODULES(libcrypto, libcrypto >= 3.0, + [with_crypto3=yes], [with_crypto3=no]) +AM_CONDITIONAL(HAVE_CRYPTO3, test "$with_crypto3" != "no") + +AC_CONFIG_FILES([ + Makefile + src/Makefile]) +AC_OUTPUT diff --git a/KAEOpensslProvider/src/Makefile.am b/KAEOpensslProvider/src/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..376945d15880d0034bf83787a17dcb88d7d41cb4 --- /dev/null +++ b/KAEOpensslProvider/src/Makefile.am @@ -0,0 +1,48 @@ +VERSION = 2:0:3 +ACLOCAL_AMFLAGS = -I m4 +AUTOMAKE_OPTIONS = subdir-objects +CFLAGS =-ftrapv -fPIC -fPIE -pie -fstack-protector-strong -D_FORTIFY_SOURCE=2 -O2 +CFLAGS +=-Wl,-z,now -Wl,-z,relro -Wl,--disable-new-dtags -Wl,-s + +lib_LTLIBRARIES=kae_provider.la +kae_provider_la_SOURCES=adapter/common/kae_config.c \ + adapter/common/kae_log.c \ + adapter/common/kae_opensslerr.c \ + adapter/common/kae_utils.c \ + adapter/nosva/async/async_callback.c \ + adapter/nosva/async/async_event.c \ + adapter/nosva/async/async_poll.c \ + adapter/nosva/async/async_task_queue.c \ + adapter/nosva/async/async_check.c \ + adapter/nosva/async/async_fork.c \ + adapter/nosva/wdwarp/wd_alg_queue.c \ + adapter/nosva/wdwarp/wd_queue_memory.c \ + adapter/nosva/algorithm/cipher/sec_ciphers_aead.c \ + adapter/nosva/algorithm/cipher/sec_ciphers_soft.c \ + adapter/nosva/algorithm/cipher/sec_ciphers_utils.c \ + adapter/nosva/algorithm/cipher/sec_ciphers_wd.c \ + adapter/nosva/algorithm/cipher/sec_ciphers.c \ + adapter/nosva/algorithm/digest/sec_digests_wd.c \ + adapter/nosva/algorithm/digest/sec_digests.c \ + adapter/nosva/algorithm/pkey/hpre_rsa_utils.c \ + adapter/nosva/algorithm/pkey/hpre_rsa_wd.c \ + adapter/nosva/algorithm/pkey/hpre_rsa.c \ + adapter/nosva/algorithm/pkey/hpre_sm2.c \ + adapter/nosva/algorithm/pkey/hpre_dh_soft.c \ + adapter/nosva/algorithm/pkey/hpre_dh_wd.c \ + adapter/nosva/algorithm/pkey/hpre_dh.c \ + provider/prov_nosva.c \ + provider/prov_nosva/prov_rsa.c \ + provider/prov_nosva/prov_sm2.c \ + provider/prov_nosva/prov_digest.c \ + provider/prov_nosva/prov_cipher.c \ + provider/prov_nosva/prov_dh.c \ + provider/prov_nosva/internal/prov_bio.c \ + provider/prov_nosva/internal/prov_der_writer.c \ + provider/prov_nosva/internal/prov_packet.c \ + provider/prov_nosva/internal/prov_ffc.c + +kae_provider_la_LDFLAGS=-module -version-number $(VERSION) +kae_provider_la_LIBADD=$(WD_LIBS) -lpthread +kae_provider_la_CFLAGS=$(includes_openssl) $(libcrypto_CFLAGS) +kae_provider_la_CFLAGS+=-DOPENSSL_SUPPRESS_DEPRECATED \ No newline at end of file diff --git a/KAEOpensslProvider/src/adapter/common/kae_config.c b/KAEOpensslProvider/src/adapter/common/kae_config.c new file mode 100644 index 0000000000000000000000000000000000000000..59eb24634b3a11e1fe40321b09ccc88d8bdb78ca --- /dev/null +++ b/KAEOpensslProvider/src/adapter/common/kae_config.c @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides implementation of configuration file reading for the KAE engine + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "kae_config.h" + +int kae_drv_findsection(FILE *stream, const char *v_pszSection) +{ + char line[256]; // array length:256 + char *pos = NULL; + size_t section_len = strlen(v_pszSection); + + while (!feof(stream)) { + if (fgets(line, sizeof(line), stream) == NULL) + return -1; + + pos = line; + if (*(pos++) != '[') + continue; + + if (memcmp(pos, v_pszSection, section_len) == 0) { + pos += section_len; + if (*pos == ']') + return 0; + } + } + + return -1; +} + +void kae_drv_get_value(char *pos, char *v_pszValue) +{ + while (*pos != '\0') { + if (*pos == ' ') { + pos++; + continue; + } + + if (*pos == ';') { + *(v_pszValue++) = '\0'; + return; + } + + *(v_pszValue++) = *(pos++); + } +} + +int kae_drv_find_item(FILE *stream, const char *v_pszItem, char *v_pszValue) +{ + char line[256]; // array length:256 + char *pos = NULL; + + while (!feof(stream)) { + if (fgets(line, sizeof(line), stream) == NULL) + return -1; + + if (strstr(line, v_pszItem) != NULL) { + pos = strstr(line, "="); + if (pos != NULL) { + pos++; + kae_drv_get_value(pos, v_pszValue); + return 0; + } + } + + if ('[' == line[0]) + break; + } + + return -1; +} + +int kae_drv_get_item(const char *config_file, const char *v_pszSection, const char *v_pszItem, char *v_pszValue) +{ + FILE *stream; + int retvalue = -1; + + stream = fopen(config_file, "r"); + if (stream == NULL) + return -1; + + if (kae_drv_findsection(stream, v_pszSection) == 0) + retvalue = kae_drv_find_item(stream, v_pszItem, v_pszValue); + + fclose(stream); + + return retvalue; +} diff --git a/KAEOpensslProvider/src/adapter/common/kae_config.h b/KAEOpensslProvider/src/adapter/common/kae_config.h new file mode 100644 index 0000000000000000000000000000000000000000..504b83004f0b4faf62a6cbb1e3ac7f530403e595 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/common/kae_config.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides interface of configuration file reading for the KAE engine + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef KAE_CONFIG_H +#define KAE_CONFIG_H + +#include +#include +#include + +int kae_drv_get_item(const char *config_file, const char *v_pszSection, + const char *v_pszItem, char *v_pszValue); + +#endif // HISI_ACC_OPENSSL_CONFIG_H diff --git a/KAEOpensslProvider/src/adapter/common/kae_log.c b/KAEOpensslProvider/src/adapter/common/kae_log.c new file mode 100644 index 0000000000000000000000000000000000000000..38f5e416b6768b6dc48f51a30f7b256bcac1ac32 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/common/kae_log.c @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the implementation for log module + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include "kae_log.h" +#include "kae_config.h" +#include "kae_utils.h" + +#define KAE_CONFIG_FILE_NAME "/kae.cnf" +#define MAX_LEVEL_LEN 10 +#define MAX_CONFIG_LEN 512 + +static const char *g_kae_conf_env = "KAE_CONF_ENV"; + +FILE *g_kae_debug_log_file = (FILE *)NULL; +pthread_mutex_t g_debug_file_mutex = PTHREAD_MUTEX_INITIALIZER; +int g_debug_file_ref_count; +int g_log_init_times; +int g_kae_log_level; + +const char *g_log_level[] = { + "none", + "error", + "warning", + "info", + "debug", +}; + +static char *kae_getenv(const char *name) +{ + return getenv(name); +} + +static void kae_set_conf_debuglevel(void) +{ + char *conf_path = kae_getenv(g_kae_conf_env); + unsigned int i = 0; + const char *filename = KAE_CONFIG_FILE_NAME; + char *file_path = (char *)NULL; + char *debuglev = (char *)NULL; + int ret; + + if (conf_path == NULL || strlen(conf_path) > MAX_CONFIG_LEN) + goto err; + file_path = (char *)kae_malloc(strlen(conf_path) + strlen(filename) + 1); + debuglev = (char *)kae_malloc(MAX_LEVEL_LEN); + if (!file_path || !debuglev) + goto err; + memset(debuglev, 0, MAX_LEVEL_LEN); + memset(file_path, 0, strlen(conf_path) + strlen(filename) + 1); + strcat(file_path, conf_path); + strcat(file_path, filename); + ret = kae_drv_get_item(file_path, "LogSection", "debug_level", debuglev); + if (ret != 0) + goto err; + + for (i = 0; i < sizeof(g_log_level) / sizeof(g_log_level[0]); i++) { + if (strncmp(g_log_level[i], debuglev, strlen(debuglev) - 1) == 0) { + g_kae_log_level = i; + kae_free(file_path); + kae_free(debuglev); + return; + } + } + +err: + g_kae_log_level = KAE_ERROR; + if (debuglev != NULL) { + kae_free(debuglev); + debuglev = (char *)NULL; + } + if (file_path != NULL) { + kae_free(file_path); + file_path = (char *)NULL; + } +} + +void kae_debug_init_log(void) +{ + pthread_mutex_lock(&g_debug_file_mutex); + kae_set_conf_debuglevel(); + if (!g_debug_file_ref_count && g_kae_log_level != KAE_NONE) { + g_kae_debug_log_file = fopen(KAE_DEBUG_FILE_PATH, "a+"); + if (g_kae_debug_log_file == NULL) { + g_kae_debug_log_file = stderr; + fprintf(stderr, "unable to open %s, %s\n", KAE_DEBUG_FILE_PATH, strerror(errno)); + } else { + g_debug_file_ref_count++; + } + } + g_log_init_times++; + pthread_mutex_unlock(&g_debug_file_mutex); +} + +void kae_debug_close_log(void) +{ + pthread_mutex_lock(&g_debug_file_mutex); + g_log_init_times--; + if (g_debug_file_ref_count && (g_log_init_times == 0)) { + if (g_kae_debug_log_file != NULL) { + fclose(g_kae_debug_log_file); + g_debug_file_ref_count--; + g_kae_debug_log_file = stderr; + } + } + pthread_mutex_unlock(&g_debug_file_mutex); +} + +void ENGINE_LOG_LIMIT(int level, int times, int limit, const char *fmt, ...) +{ + struct tm *log_tm_p = (struct tm *)NULL; + static unsigned long ulpre; + static int is_should_print; + va_list args1 = {0}; + + if (level > g_kae_log_level) + return; + + // cppcheck-suppress * + va_start(args1, fmt); + time_t curr = time((time_t *)NULL); + + if (difftime(curr, ulpre) > limit) + is_should_print = times; + if (is_should_print <= 0) + is_should_print = 0; + if (is_should_print-- > 0) { + log_tm_p = (struct tm *)localtime(&curr); + flock(g_kae_debug_log_file->_fileno, LOCK_EX); + pthread_mutex_lock(&g_debug_file_mutex); + fseek(g_kae_debug_log_file, 0, SEEK_END); + if (log_tm_p != NULL) { + fprintf(g_kae_debug_log_file, + "[%4d-%02d-%02d %02d:%02d:%02d][%s][%s:%d:%s()] ", + (1900 + log_tm_p->tm_year), + (1 + log_tm_p->tm_mon), + log_tm_p->tm_mday, // base time 1900 year + log_tm_p->tm_hour, + log_tm_p->tm_min, + log_tm_p->tm_sec, + g_log_level[level], + __FILE__, + __LINE__, + __func__); + } else { + fprintf(g_kae_debug_log_file, "[%s][%s:%d:%s()] ", g_log_level[level], __FILE__, __LINE__, __func__); + } + vfprintf(g_kae_debug_log_file, fmt, args1); + fprintf(g_kae_debug_log_file, "\n"); + if (ftell(g_kae_debug_log_file) > KAE_LOG_MAX_SIZE) { + kae_save_log(g_kae_debug_log_file); + if (ftruncate(g_kae_debug_log_file->_fileno, 0)) + ; + fseek(g_kae_debug_log_file, 0, SEEK_SET); + } + pthread_mutex_unlock(&g_debug_file_mutex); + flock(g_kae_debug_log_file->_fileno, LOCK_UN); + ulpre = time((time_t *)NULL); + } + + va_end(args1); +} + +static int need_debug(void) +{ + if (g_kae_log_level >= KAE_DEBUG) + return 1; + else + return 0; +} + +/* + * desc: print data for debug + * @param name the name of buf + * @param buf the buf msg when input + * @param len bd len + */ +void dump_data(const char *name, unsigned char *buf, unsigned int len) +{ + unsigned int i; + + if (need_debug()) { + US_DEBUG("DUMP ==> %s", name); + for (i = 0; i + 8 <= len; i += 8) { // buf length:8 + US_DEBUG("0x%llx: \t%02x %02x %02x %02x %02x %02x %02x %02x", + (unsigned long long)(buf + i), + *(buf + i), + (*(buf + i + 1)), + *(buf + i + 2), + *(buf + i + 3), // buf offset:0,1,2,3 + *(buf + i + 4), + *(buf + i + 5), + *(buf + i + 6), + *(buf + i + 7)); // buf offset:4,5,6,7 + } + + if (len % 8) { // remainder:divide by 8 + US_DEBUG("0x%llx: \t", (unsigned long long)(buf + i)); + for (; i < len; i++) + US_DEBUG("%02x ", buf[i]); + } + } +} + +/* + * desc: print bd for debug + * @param bd the buf msg when input + * @param len bd len + */ +void dump_bd(unsigned int *bd, unsigned int len) +{ + unsigned int i; + + if (need_debug()) { + for (i = 0; i < len; i++) + US_DEBUG("Word[%d] 0x%08x", i, bd[i]); + } +} + +void kae_save_log(FILE *src) +{ + int size = 0; + char buf[1024] = {0}; // buf length:1024 + + if (src == NULL) + return; + + FILE *dst = fopen(KAE_DEBUG_FILE_PATH_OLD, "w"); + + if (dst == NULL) + return; + + fseek(src, 0, SEEK_SET); + while (1) { + size = fread(buf, sizeof(char), 1024, src); // buf length:1024 + fwrite(buf, sizeof(char), size, dst); + if (!size) + break; + } + + fclose(dst); +} diff --git a/KAEOpensslProvider/src/adapter/common/kae_log.h b/KAEOpensslProvider/src/adapter/common/kae_log.h new file mode 100644 index 0000000000000000000000000000000000000000..ca3db8343e0739b9acff30dde7fbe8d2dc3d00f9 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/common/kae_log.h @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the interface for log module + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef KAE_LOG_H +#define KAE_LOG_H +#include +#include +#include +#include +#include + +#define LOG_LEVEL_CONFIG KAE_NONE +#define KAE_DEBUG_FILE_PATH "/var/log/kae.log" +#define KAE_DEBUG_FILE_PATH_OLD "/var/log/kae.log.old" +#define KAE_DEBUG_FILE_PATH_LOCK "/var/log/.kae.log.lock" +#define KAE_LOG_MAX_SIZE 209715200 + +#define LOG_PRINT_NUM 20 + +extern FILE *g_kae_debug_log_file; +extern pthread_mutex_t g_debug_file_mutex; +extern const char *g_log_level[]; +extern int g_kae_log_level; + +enum KAE_LOG_LEVEL { + KAE_NONE = 0, + KAE_ERROR, + KAE_WARNING, + KAE_INFO, + KAE_DEBUG, +}; + +#define KAEOpensslEngine_CRYPTO(LEVEL, fmt, args...) \ + do { \ + if (LEVEL > g_kae_log_level) { \ + break; \ + } \ + struct tm *log_tm_p = NULL; \ + time_t timep = time((time_t *)NULL); \ + log_tm_p = localtime(&timep); \ + int log_lock_fd = open(KAE_DEBUG_FILE_PATH_LOCK, O_CREAT | O_RDWR, 0666); \ + if (log_lock_fd < 0) { \ + perror("[kae]:open log lock file error"); \ + break; \ + } \ + if (flock(log_lock_fd, LOCK_EX) != 0) { \ + perror("[kae]:flock error, check /var/log/.kae.log.lock"); \ + close(log_lock_fd); \ + break; \ + } \ + pthread_mutex_lock(&g_debug_file_mutex); \ + fseek(g_kae_debug_log_file, 0, SEEK_END); \ + if (log_tm_p != NULL) { \ + fprintf(g_kae_debug_log_file, \ + "[%4d-%02d-%02d %02d:%02d:%02d][%s][%s:%d:%s()] " fmt "\n", \ + (1900 + log_tm_p->tm_year), \ + (1 + log_tm_p->tm_mon), \ + log_tm_p->tm_mday, \ + log_tm_p->tm_hour, \ + log_tm_p->tm_min, \ + log_tm_p->tm_sec, \ + g_log_level[LEVEL], \ + __FILE__, \ + __LINE__, \ + __func__, \ + ##args); \ + } else { \ + fprintf(g_kae_debug_log_file, \ + "[%s][%s:%d:%s()] " fmt "\n", \ + g_log_level[LEVEL], \ + __FILE__, \ + __LINE__, \ + __func__, \ + ##args); \ + } \ + if (ftell(g_kae_debug_log_file) > KAE_LOG_MAX_SIZE) { \ + kae_save_log(g_kae_debug_log_file); \ + if (ftruncate(g_kae_debug_log_file->_fileno, 0)) \ + ; \ + fseek(g_kae_debug_log_file, 0, SEEK_SET); \ + } \ + pthread_mutex_unlock(&g_debug_file_mutex); \ + flock(log_lock_fd, LOCK_UN); \ + close(log_lock_fd); \ + } while (0) + +#define US_ERR(fmt, args...) KAEOpensslEngine_CRYPTO(KAE_ERROR, fmt, ##args) +#define US_WARN(fmt, args...) KAEOpensslEngine_CRYPTO(KAE_WARNING, fmt, ##args) +#define US_INFO(fmt, args...) KAEOpensslEngine_CRYPTO(KAE_INFO, fmt, ##args) +#define US_DEBUG(fmt, args...) KAEOpensslEngine_CRYPTO(KAE_DEBUG, fmt, ##args) + +void ENGINE_LOG_LIMIT(int level, int times, int limit, const char *fmt, ...); + +// #define US_WARN(fmt, args...) ENGINE_LOG_LIMIT(KAE_WARNING, LOG_PRINT_NUM, 1, fmt, ##args) +// #define US_ERR(fmt, args...) ENGINE_LOG_LIMIT(KAE_ERROR, LOG_PRINT_NUM, 1, fmt, ##args) +// #define US_INFO(fmt, args...) ENGINE_LOG_LIMIT(KAE_INFO, LOG_PRINT_NUM, 1, fmt, ##args) +// #define US_DEBUG(fmt, args...) ENGINE_LOG_LIMIT(KAE_DEBUG, LOG_PRINT_NUM, 1, fmt, ##args) + +#define US_WARN_LIMIT(fmt, args...) ENGINE_LOG_LIMIT(KAE_WARNING, 3, 1, fmt, ##args) +#define US_ERR_LIMIT(fmt, args...) ENGINE_LOG_LIMIT(KAE_ERROR, 3, 1, fmt, ##args) +#define US_INFO_LIMIT(fmt, args...) ENGINE_LOG_LIMIT(KAE_INFO, 3, 1, fmt, ##args) +#define US_DEBUG_LIMIT(fmt, args...) ENGINE_LOG_LIMIT(KAE_DEBUG, 3, 1, fmt, ##args) + +void kae_debug_init_log(void); +void kae_debug_close_log(void); +void kae_save_log(FILE *src); + +/* + * desc: print data for debug + * @param name the name of buf + * @param buf the buf msg when input + * @param len bd len + */ +void dump_data(const char *name, unsigned char *buf, unsigned int len); + +/* + * desc: print bd for debug + * @param bd the buf msg when input + * @param len bd len + */ +void dump_bd(unsigned int *bd, unsigned int len); + +#endif diff --git a/KAEOpensslProvider/src/adapter/common/kae_opensslerr.c b/KAEOpensslProvider/src/adapter/common/kae_opensslerr.c new file mode 100644 index 0000000000000000000000000000000000000000..4544aa8382a96e611e1c048ec875b7e6a2dd5dae --- /dev/null +++ b/KAEOpensslProvider/src/adapter/common/kae_opensslerr.c @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the implementation for error module + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "kae_opensslerr.h" + +#define ERR_FUNC(func) ERR_PACK(0, func, 0) +#define ERR_REASON(reason) ERR_PACK(0, 0, reason) + +static int g_kae_lib_error_code; +static int g_kae_error_init = 1; + +static ERR_STRING_DATA g_kae_str_functs[] = { + {ERR_FUNC(KAE_F_HPRE_GET_RSA_METHODS), "hpre_get_RSA_methods"}, + {ERR_FUNC(KAE_F_CHANGRSAMETHOD), "changRsaMethod"}, + {ERR_FUNC(KAE_F_HPRE_PKEY_METHS), "hpre_pkey_meths"}, + {ERR_FUNC(KAE_F_BIND_HELPER), "bind_helper"}, + {ERR_FUNC(KAE_F_RSA_FILL_KENGEN_PARAM), "rsa_fill_keygen_param"}, + {ERR_FUNC(KAE_F_HPRE_RSA_PUBENC), "hpre_rsa_public_encrypt"}, + {ERR_FUNC(KAE_F_HPRE_RSA_PRIENC), "hpre_rsa_private_encrypt"}, + {ERR_FUNC(KAE_F_HPRE_RSA_PUBDEC), "hpre_rsa_public_decrypt"}, + {ERR_FUNC(KAE_F_HPRE_RSA_PRIDEC), "hpre_rsa_private_decrypt"}, + {ERR_FUNC(KAE_F_HPRE_RSA_PRIMEGEN), "hpre_rsa_primegen"}, + {ERR_FUNC(KAE_F_HPRE_RSA_KEYGEN), "hpre_rsa_keygen"}, + {ERR_FUNC(KAE_F_CHECK_PUBKEY_PARAM), "check_pubkey_param"}, + {ERR_FUNC(KAE_F_HPRE_PUBENC_PADDING), "hpre_pubenc_padding"}, + {ERR_FUNC(KAE_F_HPRE_PRIENC_PADDING), "hpre_prienc_padding"}, + {ERR_FUNC(KAE_F_CHECK_HPRE_PUBDEC_PADDING), "hpre_check_pubdec_padding"}, + {ERR_FUNC(KAE_F_CHECK_HPRE_PRIDEC_PADDING), "hpre_check_pridec_padding"}, + {ERR_FUNC(KAE_F_DIGEST_SOFT_INIT), "sec_digest_soft_init"}, + {0, (const char *)NULL}}; + +static ERR_STRING_DATA g_kae_str_reasons[] = { + {ERR_REASON(KAE_R_NO_MATCH_DEVICE), "get no match device.check the hw resource"}, + {ERR_REASON(KAE_R_MALLOC_FAILURE), "no system memory to alloc"}, + {ERR_REASON(KAE_R_HWMEM_MALLOC_FAILURE), "no hardware memory to alloc"}, + {ERR_REASON(KAE_R_INPUT_PARAM_ERR), "input param is invalid"}, + {ERR_REASON(KAE_R_SET_ID_FAILURE), "kae set id failure"}, + {ERR_REASON(KAE_R_SET_NAME_FAILURE), "kae set name failure"}, + {ERR_REASON(KAE_R_SET_PKEYMETH_FAILURE), "kae set pkeymeth function failure"}, + {ERR_REASON(KAE_R_SET_RSA_FAILURE), "kae set rsa failure"}, + {ERR_REASON(KAE_R_SET_DESTORY_FAILURE), "kae set destroy function failure"}, + {ERR_REASON(KAE_R_SET_INIT_FAILURE), "kae set init function failure"}, + {ERR_REASON(KAE_R_SET_CTRL_FAILURE), "kae set ctrl function failure"}, + {ERR_REASON(KAE_R_SET_CMDDEF_FAILURE), "kae set cmd define failure"}, + {ERR_REASON(KAE_R_SET_FINISH_FAILURE), "kae set finish function failure"}, + {ERR_REASON(KAE_R_UNSUPPORT_HARDWARE_TYPE), "unsupported hardware type"}, + {ERR_REASON(KAE_R_TIMEOUT), "Operation timeout"}, + {ERR_REASON(KAE_R_RSARECV_FAILURE), "RSA receive failure"}, + {ERR_REASON(KAE_R_RSARECV_STATE_FAILURE), "RSA received but status is failure"}, + {ERR_REASON(KAE_R_RSASEND_FAILURE), "RSA send failure"}, + {ERR_REASON(KAE_R_GET_ALLOCED_HWMEM_FAILURE), "get memory from reserve memory failure"}, + {ERR_REASON(KAE_R_FREE_ALLOCED_HWMEM_FAILURE), "free memory to reserve memory failure"}, + {ERR_REASON(KAE_R_RSA_KEY_NOT_COMPELET), "rsa key param is not compeleted"}, + {ERR_REASON(KAE_R_RSA_PADDING_FAILURE), "rsa padding failed"}, + {ERR_REASON(KAE_R_DATA_TOO_LARGE_FOR_MODULUS), "data too large for modules"}, + {ERR_REASON(KAE_R_DATA_GREATER_THEN_MOD_LEN), "data greater than mod len"}, + {ERR_REASON(KAE_R_CHECKPADDING_FAILURE), "check rsa padding failure"}, + {ERR_REASON(KAE_R_ERR_LIB_BN), "err in BN operation"}, + {ERR_REASON(KAE_R_RSA_KEY_SIZE_TOO_SMALL), "data too small"}, + {ERR_REASON(KAE_R_MODULE_TOO_LARGE), "data too large"}, + {ERR_REASON(KAE_R_INVAILED_E_VALUE), "invailed e value"}, + {ERR_REASON(KAE_R_UNKNOW_PADDING_TYPE), "unknown padding type"}, + {ERR_REASON(KAE_R_INPUT_FIKE_LENGTH_ZERO), "input file length zero"}, + {ERR_REASON(KAE_R_NEW_ENGINE_FAILURE), "get new engine failure"}, + {ERR_REASON(KAE_R_BIND_ENGINE_FAILURE), "kae engine bind failure"}, + {ERR_REASON(KAE_R_RSA_SET_METHODS_FAILURE), "rsa set kae methods failure"}, + {ERR_REASON(KAE_R_PUBLIC_KEY_INVALID), "invalid public key"}, + {ERR_REASON(KAE_R_PUBLIC_ENCRYPTO_FAILURE), "rsa public key encrypto failure"}, + {ERR_REASON(KAE_R_PUBLIC_DECRYPTO_FAILURE), "rsa public key decrypto failure"}, + {ERR_REASON(KAE_R_GET_PRIMEKEY_FAILURE), "rsa prime key generate failure"}, + {ERR_REASON(KAE_R_ENGINE_ALREADY_DEFINED), "kae engine already defined, try to use engine id 'kae' instead."}, + {0, (const char *)NULL}}; + +int err_load_kae_strings(void) +{ + if (g_kae_lib_error_code == 0) + g_kae_lib_error_code = ERR_get_next_error_library(); + + if (g_kae_error_init) { + g_kae_error_init = 0; + ERR_load_strings(g_kae_lib_error_code, g_kae_str_functs); + ERR_load_strings(g_kae_lib_error_code, g_kae_str_reasons); + } + return 1; +} + +void err_unload_kae_strings(void) +{ + if (g_kae_error_init == 0) { + ERR_unload_strings(g_kae_lib_error_code, g_kae_str_functs); + ERR_unload_strings(g_kae_lib_error_code, g_kae_str_reasons); + g_kae_error_init = 1; + } +} + +void err_kae_error(int function, int reason, char *kae_err_file, int line) +{ + if (g_kae_lib_error_code == 0) + g_kae_lib_error_code = ERR_get_next_error_library(); + ERR_PUT_error(g_kae_lib_error_code, function, reason, kae_err_file, line); +} diff --git a/KAEOpensslProvider/src/adapter/common/kae_opensslerr.h b/KAEOpensslProvider/src/adapter/common/kae_opensslerr.h new file mode 100644 index 0000000000000000000000000000000000000000..9f735d59d21fb904ff9ac2f6d6aac43701fe3633 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/common/kae_opensslerr.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the interface for error module + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HISI_ACC_ENGINE_OPENSSLERR_H +#define HISI_ACC_ENGINE_OPENSSLERR_H + +int err_load_kae_strings(void); +void err_unload_kae_strings(void); +void err_kae_error(int function, int reason, char *kae_err_file, int line); +#define KAEerr(f, r) err_kae_error((f), (r), OPENSSL_FILE, OPENSSL_LINE) + +/* Function codes. */ +enum HISI_FUNC_CODE { + KAE_F_HPRE_GET_RSA_METHODS = 100, + KAE_F_CHANGRSAMETHOD, + KAE_F_HPRE_PKEY_METHS, + KAE_F_BIND_HELPER, + KAE_F_RSA_FILL_KENGEN_PARAM, + KAE_F_HPRE_RSA_PUBENC, + KAE_F_HPRE_RSA_PRIENC, + KAE_F_HPRE_RSA_PUBDEC, + KAE_F_HPRE_RSA_PRIDEC, + KAE_F_HPRE_RSA_PRIMEGEN, + KAE_F_HPRE_RSA_KEYGEN, + KAE_F_CHECK_PUBKEY_PARAM, + KAE_F_HPRE_PUBENC_PADDING, + KAE_F_HPRE_PRIENC_PADDING, + KAE_F_CHECK_HPRE_PUBDEC_PADDING, + KAE_F_CHECK_HPRE_PRIDEC_PADDING, + KAE_F_SEC_SM3_INIT, + KAE_F_SEC_SM3_FINAL, + KAE_F_DIGEST_SOFT_INIT, + KAE_F_ENGINE_WD, + KAE_F_BIND_FN, + KAE_F_CHECK_DATA_VALID, + KAE_F_CHECK_MALLOC_SUCC, + KAE_F_HPRE_GET_DH_METHODS, + KAE_F_HPRE_DH_KEYGEN, + KAE_F_HPRE_DH_KEYCOMP, + KAE_F_CHANGDHMETHOD +}; + +enum HISI_RESON_CODE { + KAE_R_NO_MATCH_DEVICE = 100, + KAE_R_MALLOC_FAILURE, + KAE_R_HWMEM_MALLOC_FAILURE, + KAE_R_INPUT_PARAM_ERR, + KAE_R_SET_ID_FAILURE, + KAE_R_SET_NAME_FAILURE, + KAE_R_SET_PKEYMETH_FAILURE, + KAE_R_SET_RSA_FAILURE, + KAE_R_SET_DESTORY_FAILURE, + KAE_R_SET_INIT_FAILURE, + KAE_R_SET_CTRL_FAILURE, + KAE_R_SET_CMDDEF_FAILURE, + KAE_R_SET_FINISH_FAILURE, + KAE_R_UNSUPPORT_HARDWARE_TYPE, + KAE_R_TIMEOUT, + KAE_R_RSARECV_FAILURE, + KAE_R_RSARECV_STATE_FAILURE, + KAE_R_RSASEND_FAILURE, + KAE_R_GET_ALLOCED_HWMEM_FAILURE, + KAE_R_FREE_ALLOCED_HWMEM_FAILURE, + KAE_R_RSA_KEY_NOT_COMPELET, + KAE_R_RSA_PADDING_FAILURE, + KAE_R_DATA_TOO_LARGE_FOR_MODULUS, + KAE_R_DATA_GREATER_THEN_MOD_LEN, + KAE_R_CHECKPADDING_FAILURE, + KAE_R_ERR_LIB_BN, + KAE_R_RSA_KEY_SIZE_TOO_SMALL, + KAE_R_MODULE_TOO_LARGE, + KAE_R_INVAILED_E_VALUE, + KAE_R_UNKNOW_PADDING_TYPE, + KAE_R_INPUT_FIKE_LENGTH_ZERO, + KAE_R_SET_CIPHERS_FAILURE, + KAE_R_SET_DIGESTS_FAILURE, + KAE_R_NEW_ENGINE_FAILURE, + KAE_R_BIND_ENGINE_FAILURE, + KAE_R_RSA_SET_METHODS_FAILURE, + KAE_R_PUBLIC_KEY_INVALID, + KAE_R_PUBLIC_ENCRYPTO_FAILURE, + KAE_R_PUBLIC_DECRYPTO_FAILURE, + KAE_R_GET_PRIMEKEY_FAILURE, + KAE_R_DH_SET_METHODS_FAILURE, + KAE_R_SET_DH_FAILURE, + KAE_R_DH_KEY_SIZE_TOO_LARGE, + KAE_R_DH_INVALID_PARAMETER, + KAE_R_ENGINE_ALREADY_DEFINED, +}; + +#endif // HISI_ACC_ENGINE_OPENSSLERR_H diff --git a/KAEOpensslProvider/src/adapter/common/kae_types.h b/KAEOpensslProvider/src/adapter/common/kae_types.h new file mode 100644 index 0000000000000000000000000000000000000000..4f53b444bfec9f2a753e9b2f49f85a2e04cae804 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/common/kae_types.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the implementation for some base type or define for KAE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef KAE_TYPES_H +#define KAE_TYPES_H + +#define OPENSSL_SUCCESS (1) +#define OPENSSL_FAIL (0) + +#define KAE_SUCCESS (0) +#define KAE_FAIL (-1) + +#define KAE_CRYPTO_FAIL (-2) + +#endif + diff --git a/KAEOpensslProvider/src/adapter/common/kae_utils.c b/KAEOpensslProvider/src/adapter/common/kae_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..86819e4087bea4eebd0f39b41c5e79dd1cb89f0d --- /dev/null +++ b/KAEOpensslProvider/src/adapter/common/kae_utils.c @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the implementation for utis module + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "kae_utils.h" +#include "kae_log.h" + +#define KAE_MEM_IMPROVE_THRESHOLD 1024 + +int kae_create_thread(pthread_t *thread_id, const pthread_attr_t *attr, void *(*start_func)(void *), void *p_arg) +{ + (void)attr; + pthread_attr_t thread_attr; + + pthread_attr_init(&thread_attr); + pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); + if (pthread_create(thread_id, &thread_attr, start_func, p_arg) != 0) { + US_ERR("fail to create thread, reason:%s", strerror(errno)); // lint !e666 + return 0; + } + + return 1; +} + +int kae_create_thread_joinable( + pthread_t *thread_id, const pthread_attr_t *attr, void *(*start_func)(void *), void *p_arg) +{ + (void)attr; + pthread_attr_t thread_attr; + + pthread_attr_init(&thread_attr); + pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE); + if (pthread_create(thread_id, &thread_attr, start_func, p_arg) != 0) { + US_ERR("fail to create thread, reason:%s", strerror(errno)); // lint !e666 + return 0; + } + return 1; +} + +void *memcpy_large(void *dstpp, const void *srcpp, size_t len) +{ + __asm__ __volatile__( + "add x4, %[src], %[count] \n\t" + "add x5, %[res], %[count] \n\t" + "ldr q0, [%[src]] \n\t" + "str q0, [%[res]] \n\t" + "sub %[count], %[count], 80 \n\t" + "and x14, %[src], 15 \n\t" + "bic %[src], %[src], 15 \n\t" + "sub x3, %[res], x14 \n\t" + "add %[count], %[count], x14 \n\t" + + "1: \n\t" + "ldp q0, q1, [%[src], 16] \n\t" + "stp q0, q1, [x3, 16] \n\t" + "ldp q0, q1, [%[src], 48] \n\t" + "stp q0, q1, [x3, 48] \n\t" + "add %[src], %[src], 64 \n\t" + "add x3, x3, 64 \n\t" + "subs %[count], %[count], 64 \n\t" + "b.hi 1b \n\t" + + "ldp q0, q1, [x4, -64] \n\t" + "stp q0, q1, [x5, -64] \n\t" + "ldp q0, q1, [x4, -32] \n\t" + "stp q0, q1, [x5, -32] \n\t" + + : [res] "+r"(dstpp) + : [src] "r"(srcpp), [count] "r"(len) + : "x3", "x4", "x5", "x14", "q0", "q1" + ); + + return dstpp; +} + +void *kae_memcpy(void *dstpp, const void *srcpp, size_t len) +{ + if (len >= KAE_MEM_IMPROVE_THRESHOLD) + return memcpy_large(dstpp, srcpp, len); + else + return memcpy(dstpp, srcpp, len); +} diff --git a/KAEOpensslProvider/src/adapter/common/kae_utils.h b/KAEOpensslProvider/src/adapter/common/kae_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..dd23315a140a19bc9a17bc5f336a5bd681588a6a --- /dev/null +++ b/KAEOpensslProvider/src/adapter/common/kae_utils.h @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the interface for utils module + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef KAE_UTILS_H +#define KAE_UTILS_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define gettid() syscall(SYS_gettid) +#define PRINTPID US_DEBUG("pid=%d, ptid=%lu, tid=%d", getpid(), pthread_self(), gettid()) + +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) + +#ifndef true +#define true (0 == 0) +#endif + +#ifndef false +#define false (0 == 1) +#endif + +enum KAE_Q_INIT_FLAG { + NOT_INIT = 0, + INITED, +}; + +#define UNUSED(x) ((void)(x)) + +#define BLOCKSIZES_OF(data) (sizeof((data)) / sizeof(((data)[0]))) + +#define KAE_SPIN_INIT(q) kae_spinlock_init(&(q)) +#define KAE_SPIN_LOCK(q) kae_spinlock_lock(&(q)) +#define KAE_SPIN_TRYLOCK(q) kae_spinlock_trylock(&(q)) +#define KAE_SPIN_UNLOCK(q) kae_spinlock_unlock(&(q)) + +#define kae_free(addr) \ + do { \ + if (addr != NULL) { \ + free(addr); \ + addr = NULL; \ + } \ + } while (0) + +struct kae_spinlock { + int lock; +}; + +static inline void kae_spinlock_init(struct kae_spinlock *lock) +{ + lock->lock = 0; +} + +static inline void kae_spinlock_lock(struct kae_spinlock *lock) +{ + while (__sync_lock_test_and_set(&lock->lock, 1)) + ; +} + +static inline int kae_spinlock_trylock(struct kae_spinlock *lock) +{ + return __sync_lock_test_and_set(&lock->lock, 1) == 0; +} + +static inline void kae_spinlock_unlock(struct kae_spinlock *lock) +{ + __sync_lock_release(&lock->lock); +} + +static inline void *kae_malloc(unsigned int size) +{ + return malloc(size); +} + +static inline void *kae_realloc(void *mem_address, unsigned int newsize) +{ + return realloc(mem_address, newsize); +} + +static inline void *kae_calloc(unsigned int num, unsigned int size) +{ + return calloc(num, size); +} + +static inline int kae_strcmp(const char *src, const char *dst) +{ + return strcmp(src, dst); +} + +static inline void kae_memset(void *ptr, int value, int len) +{ + (void)memset(ptr, value, len); +} + +void *kae_memcpy(void *dstpp, const void *srcpp, size_t len); + +static inline void kae_pthread_yield(void) +{ + //(void)pthread_yield(); //lint !e1055 + sched_yield(); +} + +int kae_create_thread(pthread_t *thread_id, const pthread_attr_t *attr, void *(*start_func)(void *), void *p_arg); + +int kae_create_thread_joinable( + pthread_t *thread_id, const pthread_attr_t *attr, void *(*start_func)(void *), void *p_arg); + +#endif diff --git a/KAEOpensslProvider/src/adapter/nosva/algorithm/cipher/sec_ciphers.c b/KAEOpensslProvider/src/adapter/nosva/algorithm/cipher/sec_ciphers.c new file mode 100644 index 0000000000000000000000000000000000000000..b1a63686877f461da2e89e5f3e701f8ae533938d --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/algorithm/cipher/sec_ciphers.c @@ -0,0 +1,469 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the implementation for KAE engine ciphers + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/***************************************************************************** + * @file sec_ciphers.c + * + * This file provides the implementation for ciphers + * + *****************************************************************************/ +#include "sec_ciphers.h" +#include "sec_ciphers_soft.h" +#include "sec_ciphers_utils.h" +#include "sec_ciphers_wd.h" +#include "sec_ciphers_aead.h" + +#include "../../async/async_callback.h" +#include "../../async/async_event.h" +#include "../../async/async_task_queue.h" +#include "../../async/async_check.h" +#include "../../../common/kae_utils.h" +#include "../../../common/kae_types.h" +#include "../../../common/kae_log.h" + +#define SEC_CIPHERS_RETURN_FAIL_IF(cond, mesg, ret) \ + do { \ + if (unlikely(cond)) { \ + US_ERR(mesg); \ + return (ret); \ + } \ + } while (0) + +#define SEC_CIPHERS_GOTO_FAIL_IF(cond, mesg, tag) \ + do { \ + if (unlikely(cond)) { \ + US_ERR(mesg); \ + goto tag; \ + } \ + } while (0) + +int sec_ciphers_init_priv_ctx( + cipher_priv_ctx *priv_ctx, const unsigned char *key, size_t key_len, const unsigned char *iv, size_t iv_len) +{ + SEC_CIPHERS_RETURN_FAIL_IF(priv_ctx == NULL, "null ctx or priv ctx", KAE_FAIL); + + priv_ctx->offset = 0; + + if (key) { + kae_memcpy(priv_ctx->key, key, key_len); + priv_ctx->key_len = key_len; + } + + if (iv) { + kae_memcpy(priv_ctx->iv, iv, iv_len); + priv_ctx->iv_len = iv_len; + } + // else + // kae_memcpy(priv_ctx->iv, EVP_CIPHER_CTX_iv_noconst(ctx), iv_len); // todo ensure + + if (priv_ctx->next_iv == NULL) { + priv_ctx->next_iv = (uint8_t *)kae_malloc(priv_ctx->iv_len); + SEC_CIPHERS_GOTO_FAIL_IF(priv_ctx->next_iv == NULL, "malloc next iv failed.", ERR); + } + + priv_ctx->c_mode = sec_ciphers_get_cipher_mode(priv_ctx->nid); + priv_ctx->c_alg = sec_ciphers_get_cipher_alg(priv_ctx->nid); + SEC_CIPHERS_GOTO_FAIL_IF( + priv_ctx->c_mode == NO_C_MODE || priv_ctx->c_alg == NO_C_ALG, "unsupport the cipher nid", ERR); + + if (priv_ctx->ecb_encryto == NULL && priv_ctx->c_mode == XTS) { + priv_ctx->ecb_encryto = (xts_ecb_data *)kae_malloc(sizeof(xts_ecb_data)); + SEC_CIPHERS_GOTO_FAIL_IF(priv_ctx->ecb_encryto == NULL, "malloc ecb ctx", ERR); + + priv_ctx->ecb_encryto->ecb_ctx = EVP_CIPHER_CTX_new(); + priv_ctx->ecb_encryto->key2_len = priv_ctx->key_len >> 1; + priv_ctx->ecb_encryto->key2 = (uint8_t *)kae_malloc(priv_ctx->key_len >> 1); + priv_ctx->ecb_encryto->encryto_iv = (uint8_t *)kae_malloc(priv_ctx->iv_len); + priv_ctx->ecb_encryto->iv_out = (uint8_t *)kae_malloc(priv_ctx->iv_len); + if (priv_ctx->ecb_encryto->ecb_ctx == NULL || priv_ctx->ecb_encryto->key2 == NULL || + priv_ctx->ecb_encryto->encryto_iv == NULL || priv_ctx->ecb_encryto->iv_out == NULL) { + if (priv_ctx->ecb_encryto->ecb_ctx != NULL) { + EVP_CIPHER_CTX_free(priv_ctx->ecb_encryto->ecb_ctx); + priv_ctx->ecb_encryto->ecb_ctx = NULL; + } + + kae_free(priv_ctx->ecb_encryto->key2); + kae_free(priv_ctx->ecb_encryto->encryto_iv); + kae_free(priv_ctx->ecb_encryto->iv_out); + kae_free(priv_ctx->ecb_encryto); + goto ERR; + } + + if (priv_ctx->ecb_encryto->key2_len == 32) { // 256-xts key2len is 32 + priv_ctx->ecb_encryto->cipher_type = EVP_aes_256_ecb(); + } else { + priv_ctx->ecb_encryto->cipher_type = EVP_aes_128_ecb(); + } + priv_ctx->ecb_encryto->countNum = 0; + kae_memcpy(priv_ctx->ecb_encryto->key2, + priv_ctx->key + priv_ctx->ecb_encryto->key2_len, + priv_ctx->ecb_encryto->key2_len); + } + + priv_ctx->switch_threshold = (size_t)sec_ciphers_sw_get_threshold(priv_ctx->nid); + + return OPENSSL_SUCCESS; + +ERR: + US_ERR("sec_ciphers_sec_state_init failed. ctx=%p", priv_ctx); + (void)sec_ciphers_priv_ctx_cleanup(priv_ctx); + return OPENSSL_FAIL; +} + +static void sec_ciphers_update_priv_ctx(cipher_priv_ctx *priv_ctx) +{ + uint32_t do_cipher_len = priv_ctx->do_cipher_len; + uint32_t increase_counter = 0; + + if (do_cipher_len == 0) + return; + + int iv_bytes = priv_ctx->e_cipher_ctx->op_data.iv_bytes; // equels 16 + unsigned char K[iv_bytes]; // next iv in OFB c_mode + if (priv_ctx->c_mode == OFB) { + int ofb_offset = priv_ctx->do_cipher_len - iv_bytes; + int i; + for (i = 0; i < iv_bytes; i++) { + K[i] = + *((unsigned char *)priv_ctx->in + ofb_offset + i) ^ *((unsigned char *)priv_ctx->out + ofb_offset + i); + } + } + + priv_ctx->in += priv_ctx->do_cipher_len; + priv_ctx->out += priv_ctx->do_cipher_len; + priv_ctx->left_len -= priv_ctx->do_cipher_len; + + switch (priv_ctx->c_mode) { + case ECB: + break; + case CBC: + if (priv_ctx->encrypt == OPENSSL_ENCRYPTION) + kae_memcpy(priv_ctx->iv, priv_ctx->out - 16, 16); // hardware need 16-byte alignment + else + kae_memcpy(priv_ctx->iv, priv_ctx->next_iv, 16); // hardware need 16-byte alignment + break; + case CTR: + increase_counter = (do_cipher_len + priv_ctx->offset) >> 4; // right shift 4 + sec_ciphers_ctr_iv_inc(priv_ctx->iv, increase_counter); + priv_ctx->offset = (priv_ctx->offset + (do_cipher_len & 0xf)) % 16; // hardware need 16-byte alignment + break; + case XTS: + if (priv_ctx->c_alg == AES) { + priv_ctx->ecb_encryto->countNum = (priv_ctx->do_cipher_len + priv_ctx->offset) >> 4; // right shift 4 + sec_ciphers_xts_iv_inc(priv_ctx); + priv_ctx->offset = (priv_ctx->offset + (do_cipher_len & 0xf)) % 16; // hardware need 16-byte alignment + } + break; + case OFB: + kae_memcpy(priv_ctx->iv, K, priv_ctx->e_cipher_ctx->op_data.iv_bytes); + break; + default: + US_WARN("mode=%d don't support.", priv_ctx->c_mode); + break; + } + + US_DEBUG("update priv_ctx success."); +} + +static int sec_ciphers_before_dociphers_cb(cipher_priv_ctx *priv_ctx) +{ + // store IV for next cbc decryption operation + if (priv_ctx->encrypt == OPENSSL_DECRYPTION && priv_ctx->c_mode == CBC) + kae_memcpy(priv_ctx->next_iv, priv_ctx->in + priv_ctx->do_cipher_len - priv_ctx->iv_len, priv_ctx->iv_len); + + if (priv_ctx->c_mode == XTS && priv_ctx->c_alg == AES) { + sec_ciphers_ecb_encryt( + priv_ctx->ecb_encryto, priv_ctx->ecb_encryto->encryto_iv, priv_ctx->iv, priv_ctx->iv_len); + } + + return KAE_SUCCESS; +} + +static int sec_ciphers_after_dociphers_cb(EVP_CIPHER_CTX *ctx) +{ + // sync priv ctx to next cipher, in case next cipher may be soft cipher + return sec_ciphers_sw_hw_ctx_sync(ctx, SEC_CIHPER_SYNC_H2S); +} + +int sec_ciphers_sync_do_crypto(cipher_engine_ctx_t *e_cipher_ctx, cipher_priv_ctx *priv_ctx) +{ + int ret = KAE_FAIL; + int leftlen = priv_ctx->left_len; + + while (leftlen != 0) { + priv_ctx->do_cipher_len = wd_ciphers_get_do_cipher_len(priv_ctx->offset, leftlen); + + (void)sec_ciphers_before_dociphers_cb(e_cipher_ctx->priv_ctx); + + wd_ciphers_set_input_data(e_cipher_ctx); + + ret = wd_ciphers_do_crypto_impl(e_cipher_ctx); + if (ret != KAE_SUCCESS) + return ret; + + wd_ciphers_get_output_data(e_cipher_ctx); + + // after cipher cycle should update: in, out, iv, key, length. + sec_ciphers_update_priv_ctx(priv_ctx); + + (void)sec_ciphers_after_dociphers_cb(priv_ctx->sw_ctx); // todo how? + + leftlen -= priv_ctx->do_cipher_len; + } + + US_DEBUG("sec state update success."); + + return KAE_SUCCESS; +} + +int sec_ciphers_async_do_crypto(cipher_engine_ctx_t *e_cipher_ctx, op_done_t *op_done) +{ + int ret = 0; + int cnt = 0; + cipher_priv_ctx *priv_ctx = e_cipher_ctx->priv_ctx; + enum task_type_wd type = ASYNC_TASK_WD_CIPHER; + void *tag = e_cipher_ctx; + + priv_ctx->do_cipher_len = wd_ciphers_get_do_cipher_len(priv_ctx->offset, priv_ctx->left_len); + + (void)sec_ciphers_before_dociphers_cb(e_cipher_ctx->priv_ctx); + + wd_ciphers_set_input_data(e_cipher_ctx); + + do { + if (cnt > MAX_SEND_TRY_CNTS) + break; + + ret = wcrypto_do_cipher(e_cipher_ctx->wd_ctx, &e_cipher_ctx->op_data, tag); + if (ret == -WD_EBUSY) { + if ((async_wake_job_v1(op_done->job, ASYNC_STATUS_EAGAIN) == 0 || + async_pause_job_v1(op_done->job, ASYNC_STATUS_EAGAIN) == 0)) { + US_ERR("sec wake job or sec pause job fail!\n"); + ret = 0; + break; + } + cnt++; + } + } while (ret == -WD_EBUSY); + + if (ret != WD_SUCCESS) { + US_ERR("sec async wcryto do cipher failed"); + return KAE_FAIL; + } + + if (async_add_poll_task_v1(e_cipher_ctx, op_done, type) == 0) { + US_ERR("sec add task failed "); + return KAE_FAIL; + } + + return KAE_SUCCESS; +} + +static int sec_ciphers_do_crypto(cipher_priv_ctx *priv_ctx) +{ + int ret = KAE_FAIL; + + // add async parm + int job_ret; + op_done_t op_done; + + SEC_CIPHERS_RETURN_FAIL_IF(priv_ctx == NULL, "priv_ctx is NULL.", KAE_FAIL); + cipher_engine_ctx_t *e_cipher_ctx = priv_ctx->e_cipher_ctx; + + SEC_CIPHERS_RETURN_FAIL_IF(e_cipher_ctx == NULL, "e_cipher_ctx is NULL", KAE_FAIL); + + SEC_CIPHERS_RETURN_FAIL_IF(priv_ctx->inl <= 0, "in length less than or equal to zero.", KAE_FAIL); + // packageSize>input_cache_size + if (priv_ctx->left_len > CIPHER_INPUT_CACHE_SIZE - priv_ctx->offset) { + ret = sec_ciphers_sync_do_crypto(e_cipher_ctx, priv_ctx); + if (ret != 0) { + US_ERR("sec sync crypto fail"); + return ret; + } + return KAE_SUCCESS; + } + + // async + async_init_op_done_v1(&op_done); + + if (op_done.job != NULL && kae_is_async_enabled()) { + if (async_setup_async_event_notification_v1(0) == 0) { + US_ERR("sec async event notifying failed"); + async_cleanup_op_done_v1(&op_done); + return KAE_FAIL; + } + } else { + US_DEBUG("NO ASYNC Job or async disable, back to SYNC!"); + async_cleanup_op_done_v1(&op_done); + return sec_ciphers_sync_do_crypto(e_cipher_ctx, priv_ctx); + } + + if (sec_ciphers_async_do_crypto(e_cipher_ctx, &op_done) == KAE_FAIL) + goto err; + + do { + job_ret = async_pause_job_v1(op_done.job, ASYNC_STATUS_OK); + if ((job_ret == 0)) { + US_DEBUG("- pthread_yidle -"); + kae_pthread_yield(); + } + } while (!op_done.flag || ASYNC_CHK_JOB_RESUMED_UNEXPECTEDLY(job_ret)); + + if (op_done.verifyRst < 0) { + US_ERR("verify result failed with %d", op_done.verifyRst); + async_cleanup_op_done_v1(&op_done); + return KAE_FAIL; + } + + async_cleanup_op_done_v1(&op_done); + + US_DEBUG(" Cipher Async Job Finish! priv_ctx = %p\n", priv_ctx); + + // after cipher cycle should update: in, out, iv, key, length. + sec_ciphers_update_priv_ctx(priv_ctx); + (void)sec_ciphers_after_dociphers_cb(priv_ctx->sw_ctx); + + return KAE_SUCCESS; +err: + US_ERR("async job err"); + (void)async_clear_async_event_notification_v1(); + async_cleanup_op_done_v1(&op_done); + return KAE_FAIL; +} + +static int sec_ciphers_is_check_valid(cipher_priv_ctx *priv_ctx) +{ + if (priv_ctx->switch_threshold > (size_t)priv_ctx->inl) { + US_WARN_LIMIT("small packet cipher offload, switch to soft cipher, inl %d", (int)priv_ctx->inl); + return KAE_FAIL; + } + + if (sec_ciphers_is_iv_may_overflow(priv_ctx)) { + US_WARN("sec do cipher, the iv will overflow"); + return KAE_FAIL; + } + + return KAE_SUCCESS; +} + +int sec_ciphers_do_cipher( + cipher_priv_ctx *priv_ctx, unsigned char *out, size_t outsize, const unsigned char *in, size_t inl) +{ + int ret; + + if (outsize < priv_ctx->blk_size) { + // ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return OPENSSL_FAIL; + } + + SEC_CIPHERS_RETURN_FAIL_IF(in == NULL, "in is NULL", OPENSSL_FAIL); + SEC_CIPHERS_RETURN_FAIL_IF(out == NULL, "out is NULL", OPENSSL_FAIL); + + priv_ctx->inl = inl; + priv_ctx->in = in; + priv_ctx->out = out; + priv_ctx->left_len = inl; + + ret = sec_ciphers_is_check_valid(priv_ctx); + if (ret != KAE_SUCCESS) { + US_WARN_LIMIT("sec cipher check invalid, switch to soft cipher"); + goto do_soft_cipher; + } + + if (priv_ctx->e_cipher_ctx == NULL) { + priv_ctx->e_cipher_ctx = wd_ciphers_get_engine_ctx(priv_ctx); + if (priv_ctx->e_cipher_ctx == NULL) { + US_WARN("failed to get engine ctx, switch to soft cipher"); + goto do_soft_cipher; + } + } + + ret = sec_ciphers_do_crypto(priv_ctx); + if (ret != KAE_SUCCESS) { + US_WARN("sec cipher do ciphers failed, switch to soft cipher"); + goto do_soft_cipher; + } + + US_DEBUG("do cipher success. priv_ctx=%p, inl=%d", priv_ctx, (int)inl); + + return OPENSSL_SUCCESS; + +do_soft_cipher: + if (priv_ctx->e_cipher_ctx != NULL) { + wd_ciphers_put_engine_ctx(priv_ctx->e_cipher_ctx); + priv_ctx->e_cipher_ctx = NULL; + } + + return KAE_CRYPTO_FAIL; +} + +int sec_ciphers_priv_ctx_cleanup(cipher_priv_ctx *priv_ctx) +{ + if (unlikely(priv_ctx == NULL)) { + US_WARN("ctx cipher data is NULL."); + return KAE_FAIL; + } + + kae_free(priv_ctx->next_iv); + if (priv_ctx->ecb_encryto) { + if (priv_ctx->ecb_encryto->ecb_ctx != NULL) { + EVP_CIPHER_CTX_free(priv_ctx->ecb_encryto->ecb_ctx); + priv_ctx->ecb_encryto->ecb_ctx = NULL; + } + + kae_free(priv_ctx->ecb_encryto->key2); + kae_free(priv_ctx->ecb_encryto->encryto_iv); + kae_free(priv_ctx->ecb_encryto->iv_out); + kae_free(priv_ctx->ecb_encryto); + } + + (void)wd_ciphers_put_engine_ctx(priv_ctx->e_cipher_ctx); + priv_ctx->e_cipher_ctx = NULL; + + return KAE_SUCCESS; +} + +// async poll thread create +int sec_cipher_engine_ctx_poll(void *engnine_ctx) +{ + int ret = 0; + struct cipher_engine_ctx *eng_ctx = (struct cipher_engine_ctx *)engnine_ctx; + struct wd_queue *q = eng_ctx->q_node->kae_wd_queue; + +POLL_AGAIN: + ret = wcrypto_cipher_poll(q, 1); + if (!ret) { + goto POLL_AGAIN; + } else if (ret < 0) { + US_ERR("cipher poll failed\n"); + return ret; + } + return ret; +} + +int sec_cipher_module_init(void) +{ + wd_ciphers_init_qnode_pool(); + wd_aead_init_qnode_pool(); + + // reg async interface here + async_register_poll_fn_v1(ASYNC_TASK_WD_CIPHER, sec_cipher_engine_ctx_poll); + async_register_poll_fn_v1(ASYNC_TASK_WD_AEAD, sec_aead_engine_ctx_poll); + + return 1; +} diff --git a/KAEOpensslProvider/src/adapter/nosva/algorithm/cipher/sec_ciphers.h b/KAEOpensslProvider/src/adapter/nosva/algorithm/cipher/sec_ciphers.h new file mode 100644 index 0000000000000000000000000000000000000000..dbd5cde0b9cb6654d2edf54ec2e54bc0ac6e5474 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/algorithm/cipher/sec_ciphers.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the interface for KAE engine dealing with wrapdrive + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/***************************************************************************** + * @file sec_cipher.h + * + * This file provides the interface for SEC engine dealing with wrapdrive + * + *****************************************************************************/ + +#ifndef SEC_CIPHERS_H +#define SEC_CIPHERS_H +#include +#include +#include "../../wdwarp/wd_queue_memory.h" +#include "../../../common/kae_types.h" + +#define MAX_SEND_TRY_CNTS 50 +#define GENERIC_BLOCK_SIZE 16 +#define CIPHER_INPUT_CACHE_SIZE (256 * 1024) +#define CIPHER_OUTPUT_CACHE_SIZE (256 * 1024) +#define ALG_NAME_SIZE 128 +#define IV_LEN 16 +#define MAX_KEY_LEN 64 + +enum openssl_cipher_enc_t { OPENSSL_DECRYPTION = 0, OPENSSL_ENCRYPTION = 1 }; + +enum sec_cipher_priv_ctx_syncto { + SEC_CIHPER_SYNC_S2W = 1, // software priv ctx sync to hareware priv ctx + SEC_CIHPER_SYNC_H2S, // hareware priv ctx sync to software priv ctx +}; +typedef enum sec_cipher_priv_ctx_syncto sec_cipher_priv_ctx_syncto_t; + +typedef struct xts_ecb_data_strcut { + EVP_CIPHER_CTX *ecb_ctx; + const EVP_CIPHER *cipher_type; + uint8_t *key2; + uint8_t key2_len; + uint8_t *iv_out; + uint8_t *encryto_iv; + uint32_t countNum; +} xts_ecb_data; + +typedef struct cipher_engine_ctx cipher_engine_ctx_t; +/* + * | 16bytes * n length | offset | | + * | <---------first buf -----------><---next buf -->| + * the next buf send to warpdriv should start at hardaddr + first offset + */ +typedef struct { + int32_t encrypt; // encrypt or decryto DECRYPTION = 0, ENCRYPTION = 1 + uint32_t inl; // input length + uint32_t left_len; // left length for warpdrive to do + uint32_t offset; // prev buf offset, that indicate the next buf should start at hardware_addr+offset + uint32_t key_len; // key length + uint32_t iv_len; // iv length + uint8_t *next_iv; // store IV for next cbc operation in decryption + const uint8_t *in; + uint8_t *out; + uint32_t c_mode; + uint32_t c_alg; + uint32_t do_cipher_len; // do one cycle cipher length + size_t switch_threshold; // crypt small packet offload threshold + xts_ecb_data *ecb_encryto; + cipher_engine_ctx_t *e_cipher_ctx; + + int nid; + int blk_size; + /* Buffer of partial blocks processed via update calls */ + unsigned char buf[GENERIC_BLOCK_SIZE]; + size_t buf_size; /* Number of bytes in buf */ + char alg_name[ALG_NAME_SIZE]; + bool pad; + EVP_CIPHER_CTX *sw_ctx; + EVP_CIPHER *sw_cipher; + unsigned char key[MAX_KEY_LEN]; + unsigned char iv[IV_LEN]; +} cipher_priv_ctx; + +struct cipher_engine_ctx { + KAE_QUEUE_DATA_NODE_S *q_node; + struct wcrypto_cipher_op_data op_data; + struct wcrypto_cipher_ctx_setup setup; + void *wd_ctx; // one ctx or a list of ctx + + cipher_priv_ctx *priv_ctx; +}; + +int sec_cipher_module_init(void); + +int sec_ciphers_init_priv_ctx( + cipher_priv_ctx *priv_ctx, const unsigned char *key, size_t key_len, const unsigned char *iv, size_t iv_len); + +int sec_ciphers_do_cipher( + cipher_priv_ctx *priv_ctx, unsigned char *out, size_t outsize, const unsigned char *in, size_t inl); + +int sec_ciphers_priv_ctx_cleanup(cipher_priv_ctx *priv_ctx); + +#endif diff --git a/KAEOpensslProvider/src/adapter/nosva/algorithm/cipher/sec_ciphers_aead.c b/KAEOpensslProvider/src/adapter/nosva/algorithm/cipher/sec_ciphers_aead.c new file mode 100644 index 0000000000000000000000000000000000000000..393ecd91a5341aca4ce28df69213cd4f7dd0b902 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/algorithm/cipher/sec_ciphers_aead.c @@ -0,0 +1,706 @@ +/* + * Copyright 2023 Huawei Technologies Co.,Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include +#include +#include +#include +#include +#include +#include "sec_ciphers_aead.h" +#include "sec_ciphers_utils.h" + +#include "../../async/async_callback.h" +#include "../../async/async_event.h" +#include "../../async/async_task_queue.h" +#include "../../async/async_check.h" +#include "../../../common/kae_types.h" +#include "../../../common/kae_log.h" +#include "../../../common/kae_utils.h" + +#define MAX_KEY_SIZE 64 +#define MAX_IV_SIZE 16 + +#define SEC_AES_GCM_BLOCK_SIZE 16 +#define SEC_AES_GCM_IV_LEN 12 +#define AES_GCM_TAG_LEN 16 +#define GCM_FLAG \ + (EVP_CIPH_FLAG_DEFAULT_ASN1 | EVP_CIPH_GCM_MODE | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_AEAD_CIPHER | \ + EVP_CIPH_FLAG_CUSTOM_CIPHER | EVP_CIPH_ALWAYS_CALL_INIT) + +static EVP_CIPHER *sec_aes_128_gcm; +static EVP_CIPHER *sec_aes_192_gcm; +static EVP_CIPHER *sec_aes_256_gcm; + +KAE_QUEUE_POOL_HEAD_S *g_sec_aeads_qnode_pool; + +void wd_aead_free_engine_ctx(void *engine_ctx) +{ + aead_engine_ctx_t *e_aead_ctx = (aead_engine_ctx_t *)engine_ctx; + + if (e_aead_ctx == NULL) + return; + + // 我理解aead_engine_ctx_t并未申请内存,aead_priv_ctx_t申请的内存在aead_priv_ctx_t处理,后续看下cipher的逻辑 + if (e_aead_ctx->op_data.in && e_aead_ctx->setup.br.usr) { + e_aead_ctx->setup.br.free(e_aead_ctx->setup.br.usr, (void *)e_aead_ctx->op_data.in); + e_aead_ctx->op_data.in = NULL; + } + + if (e_aead_ctx->op_data.out && e_aead_ctx->setup.br.usr) { + e_aead_ctx->setup.br.free(e_aead_ctx->setup.br.usr, (void *)e_aead_ctx->op_data.out); + e_aead_ctx->op_data.out = NULL; + } + + if (e_aead_ctx->op_data.iv && e_aead_ctx->setup.br.usr) { + e_aead_ctx->setup.br.free(e_aead_ctx->setup.br.usr, (void *)e_aead_ctx->op_data.iv); + e_aead_ctx->op_data.iv = NULL; + } + + OPENSSL_free(e_aead_ctx); + e_aead_ctx = NULL; +} + +static aead_engine_ctx_t *wd_aeads_new_engine_ctx(KAE_QUEUE_DATA_NODE_S *q_node, aead_priv_ctx_t *priv_ctx) +{ + aead_engine_ctx_t *e_aead_ctx = NULL; + + e_aead_ctx = (aead_engine_ctx_t *)OPENSSL_malloc(sizeof(aead_engine_ctx_t)); + if (e_aead_ctx == NULL) { + US_ERR("OPENSSL_malloc ctx failed"); + return NULL; + } + kae_memset(e_aead_ctx, 0, sizeof(aead_engine_ctx_t)); + + e_aead_ctx->setup.br.alloc = kae_wd_alloc_blk; + e_aead_ctx->setup.br.free = kae_wd_free_blk; + e_aead_ctx->setup.br.iova_map = kae_dma_map; + e_aead_ctx->setup.br.iova_unmap = kae_dma_unmap; + e_aead_ctx->setup.br.usr = q_node->kae_queue_mem_pool; + + if (e_aead_ctx->op_data.in == NULL) { + e_aead_ctx->op_data.in = + e_aead_ctx->setup.br.alloc(e_aead_ctx->setup.br.usr, CIPHER_INPUT_CACHE_SIZE); // 一次性申请20M是不是太大了 + } + + if (e_aead_ctx->op_data.out == NULL) { + e_aead_ctx->op_data.out = e_aead_ctx->setup.br.alloc(e_aead_ctx->setup.br.usr, AEAD_OUTPUT_CACHE_SIZE); + } + + if (e_aead_ctx->op_data.iv == NULL) { + e_aead_ctx->op_data.iv = e_aead_ctx->setup.br.alloc(e_aead_ctx->setup.br.usr, 16); + } + + e_aead_ctx->priv_ctx = priv_ctx; + e_aead_ctx->q_node = q_node; + q_node->engine_ctx = e_aead_ctx; + + return e_aead_ctx; +} + +void sec_aead_cb(const void *msg, void *tag) +{ + if (!msg || !tag) { + US_ERR("sec cb params err!\n"); + return; + } + struct wcrypto_aead_msg *message = (struct wcrypto_aead_msg *)msg; + aead_engine_ctx_t *eng_ctx = (aead_engine_ctx_t *)tag; + + kae_memcpy(eng_ctx->priv_ctx->out_data_buf, message->out, message->out_bytes); +} + +static int wd_aeads_init_engine_ctx(aead_engine_ctx_t *e_aead_ctx) +{ + struct wd_queue *q = e_aead_ctx->q_node->kae_wd_queue; + aead_priv_ctx_t *priv_ctx = e_aead_ctx->priv_ctx; + + if (e_aead_ctx->wd_ctx != NULL) { + US_WARN("wd ctx is in used by other aeads"); + + return KAE_FAIL; + } + + e_aead_ctx->setup.calg = (enum wcrypto_cipher_alg)priv_ctx->c_alg; // for example: WD_aead_SM4; + e_aead_ctx->setup.cmode = (enum wcrypto_cipher_mode)priv_ctx->c_mode; // for example: WD_aead_CBC; + e_aead_ctx->setup.cb = (wcrypto_cb)sec_aead_cb; // 异步使用 + e_aead_ctx->wd_ctx = wcrypto_create_aead_ctx(q, &e_aead_ctx->setup); + + if (e_aead_ctx->wd_ctx == NULL) { + US_ERR("wd create sec aead ctx fail!"); + return KAE_FAIL; + } + + return KAE_SUCCESS; +} + +void wd_aeads_put_engine_ctx(aead_engine_ctx_t *e_aead_ctx) +{ + if (unlikely(e_aead_ctx == NULL)) { + US_WARN("sec cipher engine ctx NULL!"); + return; + } + // e_aead_ctx->wd_ctx + if (e_aead_ctx->wd_ctx != NULL) { + wcrypto_del_aead_ctx(e_aead_ctx->wd_ctx); + e_aead_ctx->wd_ctx = NULL; + } + + if (e_aead_ctx->q_node != NULL) { + (void)kae_put_node_to_pool(g_sec_aeads_qnode_pool, e_aead_ctx->q_node); + } + + e_aead_ctx = NULL; + return; +} + +aead_engine_ctx_t *wd_aead_get_engine_ctx(aead_priv_ctx_t *priv_ctx) +{ + KAE_QUEUE_DATA_NODE_S *q_node = NULL; + aead_engine_ctx_t *e_aead_ctx = NULL; + + if (unlikely(priv_ctx == NULL)) { + US_ERR("sec aead priv ctx NULL!"); + return NULL; + } + + // KAE_QUEUE_DATA_NODE_S + q_node = kae_get_node_from_pool(g_sec_aeads_qnode_pool); + if (q_node == NULL) { + US_ERR("failed to get hardware queue"); + return NULL; + } + + // wcrypto_aead_ctx_setup wcrypto_aead_op_data + e_aead_ctx = (aead_engine_ctx_t *)q_node->engine_ctx; + if (e_aead_ctx == NULL) { + e_aead_ctx = wd_aeads_new_engine_ctx(q_node, priv_ctx); + if (e_aead_ctx == NULL) { + US_WARN("sec new engine ctx fail!"); + (void)kae_put_node_to_pool(g_sec_aeads_qnode_pool, q_node); + return NULL; + } + } + + e_aead_ctx->priv_ctx = priv_ctx; + + if (wd_aeads_init_engine_ctx(e_aead_ctx) == KAE_FAIL) { + US_WARN("init engine ctx fail!"); + wd_aeads_put_engine_ctx(e_aead_ctx); + return NULL; + } + + return e_aead_ctx; +} + +static int sec_aead_engine_cleanup(aead_priv_ctx_t *priv_ctx) +{ + if (unlikely(priv_ctx == NULL)) { + US_WARN("ctx is NULL"); + return OPENSSL_FAIL; + } + + if (priv_ctx->e_aead_ctx != NULL) { + wd_aeads_put_engine_ctx(priv_ctx->e_aead_ctx); + priv_ctx->e_aead_ctx = NULL; + } + + if (priv_ctx->key != NULL) { + kae_free(priv_ctx->key); + } + + US_DEBUG("AEAD Cleanup success, ctx=%p", priv_ctx); + + return OPENSSL_SUCCESS; +} + +static int sec_aes_gcm_init(EVP_CIPHER_CTX *ctx, const unsigned char *ckey, const unsigned char *iv, int encrypt) +{ + int nid = 0; + int ret, ckey_len; + aead_priv_ctx_t *priv_ctx = NULL; + + if (unlikely((ctx == NULL))) { + US_ERR("ctx or key is NULL."); + return OPENSSL_FAIL; + } + + if (unlikely(!ckey)) + return OPENSSL_SUCCESS; + + if (encrypt != EVP_CIPHER_CTX_encrypting(ctx)) { + US_ERR("encrypt different, ctx=%p", ctx); + return OPENSSL_FAIL; + } + + priv_ctx = (aead_priv_ctx_t *)EVP_CIPHER_CTX_get_cipher_data(ctx); + if (unlikely(priv_ctx == NULL)) { + US_ERR("sec private ctx is NULL"); + return OPENSSL_FAIL; + } + + // init cipher mode and alg of private ctx + nid = EVP_CIPHER_CTX_nid(ctx); + priv_ctx->c_mode = sec_ciphers_get_cipher_mode(nid); + priv_ctx->c_alg = sec_ciphers_get_cipher_alg(nid); + priv_ctx->iv_len = 12; // AES_GCM_IV_LEN + + // engine_ctx + if (priv_ctx->e_aead_ctx == NULL) { + priv_ctx->e_aead_ctx = wd_aead_get_engine_ctx(priv_ctx); + if (priv_ctx->e_aead_ctx == NULL) { + US_WARN("failed to get engine ctx, switch to soft cipher"); + goto ERR; + } + } + + // encrypt ==> optype + if (encrypt) + priv_ctx->e_aead_ctx->op_data.op_type = WCRYPTO_CIPHER_ENCRYPTION_DIGEST; // aad + plen + authsize; + else + priv_ctx->e_aead_ctx->op_data.op_type = WCRYPTO_CIPHER_DECRYPTION_DIGEST; // aad + plen; + + // opdata + priv_ctx->data_buf = priv_ctx->e_aead_ctx->op_data.in; + priv_ctx->out_data_buf = priv_ctx->e_aead_ctx->op_data.out; + + // ckey akey + if (ckey) { + ckey_len = EVP_CIPHER_CTX_key_length(ctx); + priv_ctx->key = (uint8_t *)kae_malloc(ckey_len); + kae_memcpy(priv_ctx->key, ckey, ckey_len); + wcrypto_set_aead_ckey(priv_ctx->e_aead_ctx->wd_ctx, priv_ctx->key, ckey_len); + priv_ctx->key_len = ckey_len; // 感觉多余,考虑是否删除该成员变量 + } + + // iv + if (iv) { + memset(priv_ctx->e_aead_ctx->op_data.iv, 0, 16); + memcpy(priv_ctx->e_aead_ctx->op_data.iv, iv, 12); // AES_GCM_IV_LEN + priv_ctx->iv_len = 12; + } + + priv_ctx->mac_len = AES_GCM_TAG_LEN; + + ret = wcrypto_aead_setauthsize(priv_ctx->e_aead_ctx->wd_ctx, 16); + if (ret) { + US_WARN("wd set authsize fail!\n"); + goto ERR; + } + + US_DEBUG("init success, ctx=%p", ctx); +#ifdef KAE_DEBUG_KEY_ENABLE + dump_data("key", priv_ctx->key, priv_ctx->key_len); + dump_data("iv", priv_ctx->iv, priv_ctx->iv_len); +#endif + return OPENSSL_SUCCESS; +ERR: + sec_aead_engine_cleanup(priv_ctx); + // do soft? + return OPENSSL_FAIL; +} + +int wd_aead_do_crypto_impl(struct aead_priv_ctx *priv) +{ + int ret = -WD_EINVAL; + int trycount = 0; + + if (unlikely(priv == NULL) || unlikely(priv->e_aead_ctx == NULL)) { + US_ERR("do cipher priv or e_aead_ctx NULL!"); + return KAE_FAIL; + } + + aead_engine_ctx_t *e_aead_ctx = priv->e_aead_ctx; + + // 输入参数 + e_aead_ctx->op_data.out_buf_bytes = AEAD_OUTPUT_CACHE_SIZE; + e_aead_ctx->op_data.iv_bytes = priv->iv_len; + e_aead_ctx->op_data.assoc_size = AES_GCM_TAG_LEN; + +again: + ret = wcrypto_do_aead(e_aead_ctx->wd_ctx, &e_aead_ctx->op_data, NULL); + if (ret != WD_SUCCESS) { + if (ret == -WD_EBUSY && trycount <= 5) { // try 5 times + US_WARN("do cipher busy, retry again!"); + trycount++; + goto again; + } else { + US_ERR("do cipher failed! ret is %d.", ret); + return KAE_FAIL; + } + } + + return KAE_SUCCESS; +} + +// 当前支持同步,异步之后再说,只输出 +int wd_aead_do_crypto_impl_async(struct aead_priv_ctx *priv, op_done_t *op_done) +{ + int ret = -WD_EINVAL; + int cnt = 0; + enum task_type_wd type = ASYNC_TASK_WD_AEAD; + + if (unlikely(priv == NULL) || unlikely(priv->e_aead_ctx == NULL)) { + US_ERR("do cipher priv or e_aead_ctx NULL!"); + return KAE_FAIL; + } + + aead_engine_ctx_t *e_aead_ctx = priv->e_aead_ctx; + + // 输入参数 + e_aead_ctx->op_data.out_buf_bytes = AEAD_OUTPUT_CACHE_SIZE; + e_aead_ctx->op_data.iv_bytes = priv->iv_len; + + do { + if (cnt > MAX_SEND_TRY_CNTS) + break; + + ret = wcrypto_do_aead(e_aead_ctx->wd_ctx, &e_aead_ctx->op_data, e_aead_ctx); + if (ret == -WD_EBUSY) { + if ((async_wake_job_v1(op_done->job, ASYNC_STATUS_EAGAIN) == 0 || + async_pause_job_v1(op_done->job, ASYNC_STATUS_EAGAIN) == 0)) { + US_ERR("sec wake job or sec pause job fail!\n"); + ret = 0; + break; + } + cnt++; + } + } while (ret == -WD_EBUSY); + + if (ret != WD_SUCCESS) { + US_ERR("sec async wcryto do cipher failed"); + return KAE_FAIL; + } + + if (async_add_poll_task_v1(e_aead_ctx, op_done, type) == 0) { + US_ERR("sec add task failed "); + return KAE_FAIL; + } + + return KAE_SUCCESS; +} + +// 获取add头信息 +static int sec_aes_do_aes_gcm_first( + struct aead_priv_ctx *priv, unsigned char *out, const unsigned char *in, size_t inlen) +{ + memcpy(priv->data_buf, in, inlen); + priv->aad_len = inlen; + + return priv->aad_len; +} + +static int do_aes_aead_final(EVP_CIPHER_CTX *ctx, struct aead_priv_ctx *priv, unsigned char *out, + const unsigned char *in, size_t inlen, op_done_t *op_done) +{ + int enc; + enc = EVP_CIPHER_CTX_encrypting(ctx); + + if (!enc) { + unsigned char *ctx_buf = EVP_CIPHER_CTX_buf_noconst(ctx); + memcpy(priv->data_buf + priv->aad_len + priv->data_len, ctx_buf, AES_GCM_TAG_LEN); + priv->e_aead_ctx->op_data.in_bytes = priv->data_len; + priv->e_aead_ctx->op_data.out_bytes = priv->aad_len + priv->data_len; + } else { + priv->e_aead_ctx->op_data.in_bytes = priv->data_len; + priv->e_aead_ctx->op_data.out_bytes = priv->aad_len + priv->data_len + priv->mac_len; + } + + if (op_done) { + // async + if (wd_aead_do_crypto_impl_async(priv, op_done) != KAE_SUCCESS) + return KAE_FAIL; + } else { + // sync + if (wd_aead_do_crypto_impl(priv) != KAE_SUCCESS) + return KAE_FAIL; + } + + memcpy(out, priv->out_data_buf + priv->aad_len, priv->data_len); + + if (enc) { + unsigned char *ctx_buf = EVP_CIPHER_CTX_buf_noconst(ctx); + memcpy(ctx_buf, priv->out_data_buf + priv->aad_len + priv->data_len, priv->mac_len); + } + + return priv->data_len; +} + +static int sec_aes_do_aes_gcm_update( + EVP_CIPHER_CTX *ctx, struct aead_priv_ctx *priv, unsigned char *out, const unsigned char *in, size_t inlen) +{ + memcpy(priv->data_buf + priv->aad_len, in, inlen); + priv->data_len += inlen; + return 0; // 只囤包,不计算 +} + +static int sec_aes_do_aes_gcm_final( + EVP_CIPHER_CTX *ctx, struct aead_priv_ctx *priv, unsigned char *out, const unsigned char *in, size_t inlen) +{ + // add async parm + int job_ret; + op_done_t op_done; + + // async + async_init_op_done_v1(&op_done); + + if (op_done.job != NULL && kae_is_async_enabled()) { + if (async_setup_async_event_notification_v1(0) == 0) { + US_ERR("sec async event notifying failed"); + async_cleanup_op_done_v1(&op_done); + return KAE_FAIL; + } + } else { + US_DEBUG("NO ASYNC Job or async disable, back to SYNC!"); + async_cleanup_op_done_v1(&op_done); + return do_aes_aead_final(ctx, priv, out, in, inlen, NULL); // sync + } + + // async + if (do_aes_aead_final(ctx, priv, out, in, inlen, &op_done) == KAE_FAIL) + goto err; + + do { + job_ret = async_pause_job_v1(op_done.job, ASYNC_STATUS_OK); + if ((job_ret == 0)) { + US_DEBUG("- pthread_yidle -"); + kae_pthread_yield(); + } + } while (!op_done.flag || ASYNC_CHK_JOB_RESUMED_UNEXPECTEDLY(job_ret)); + + if (op_done.verifyRst < 0) { + US_ERR("verify result failed with %d", op_done.verifyRst); + async_cleanup_op_done_v1(&op_done); + return KAE_FAIL; + } + + async_cleanup_op_done_v1(&op_done); + + US_DEBUG(" Cipher Async Job Finish! priv_ctx = %p\n", priv); + return priv->data_len; +err: + US_ERR("async job err"); + (void)async_clear_async_event_notification_v1(); + async_cleanup_op_done_v1(&op_done); + return KAE_FAIL; +} + +static int sec_aes_do_aes_gcm(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, size_t inlen) +{ + struct aead_priv_ctx *priv; + + priv = (struct aead_priv_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx); + if (unlikely(!priv)) { + fprintf(stderr, "invalid: aead priv ctx is NULL.\n"); + return 0; + } + + if (in) { + if (out == NULL) + return sec_aes_do_aes_gcm_first(priv, NULL, in, inlen); + return sec_aes_do_aes_gcm_update(ctx, priv, out, in, inlen); + } + return sec_aes_do_aes_gcm_final(ctx, priv, out, NULL, 0); +} + +static int sec_aes_gcm_cleanup(EVP_CIPHER_CTX *ctx) +{ + struct aead_priv_ctx *priv; + + priv = (struct aead_priv_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx); + if (!priv) { + fprintf(stderr, "invalid: aead priv ctx is NULL.\n"); + return 0; + } + + sec_aead_engine_cleanup(priv); + + return 1; +} + +static int sec_aes_gcm_set_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr) +{ + void *ctx_buf = EVP_CIPHER_CTX_buf_noconst(ctx); + int enc = EVP_CIPHER_CTX_encrypting(ctx); + struct aead_priv_ctx *priv; + + priv = (struct aead_priv_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx); + if (!priv) { + fprintf(stderr, "invalid: aead priv ctx is NULL.\n"); + return 0; + } + + switch (type) { + case EVP_CTRL_INIT: + priv->e_aead_ctx->op_data.iv_bytes = 0; + return 1; +#if (OPENSSL_VERSION_NUMBER >= 0x1010106fL) + case EVP_CTRL_GET_IVLEN: + *(int *)ptr = priv->e_aead_ctx->op_data.iv_bytes; + return 1; +#endif + case EVP_CTRL_GCM_SET_IVLEN: + if (arg != AES_GCM_IV_LEN) { + fprintf(stderr, "invalid: aead gcm iv length only support 12B.\n"); + return 0; + } + return 1; + case EVP_CTRL_GCM_GET_TAG: + if (arg <= 0 || arg > AES_GCM_TAG_LEN || !enc) { + fprintf(stderr, "cannot get tag when decrypt or arg is invalid.\n"); + return 0; + } + + if (ctx_buf == NULL || ptr == NULL) { + fprintf(stderr, "failed to get tag, ctx memory pointer is invalid.\n"); + return 0; + } + + memcpy(ptr, ctx_buf, arg); + return 1; + case EVP_CTRL_GCM_SET_TAG: + if (arg <= 0 || arg > AES_GCM_TAG_LEN || enc) { + fprintf(stderr, "cannot set tag when encrypt or arg is invalid.\n"); + return 0; + } + + if (ctx_buf == NULL || ptr == NULL) { + fprintf(stderr, "failed to set tag, ctx memory pointer is invalid.\n"); + return 0; + } + + memcpy(ctx_buf, ptr, arg); + priv->mac_len = arg; + return 1; + default: + fprintf(stderr, "unsupported ctrl type: %d\n", type); + return 0; + } +} + +#define SEC_CIPHERS_AEAD_DESCR( \ + name, block_size, key_size, iv_len, flags, ctx_size, init, cipher, cleanup, set_params, get_params, ctrl) \ + do { \ + sec_##name = EVP_CIPHER_meth_new(NID_##name, block_size, key_size); \ + if (sec_##name == 0 || !EVP_CIPHER_meth_set_iv_length(sec_##name, iv_len) || \ + !EVP_CIPHER_meth_set_flags(sec_##name, flags) || \ + !EVP_CIPHER_meth_set_impl_ctx_size(sec_##name, ctx_size) || !EVP_CIPHER_meth_set_init(sec_##name, init) || \ + !EVP_CIPHER_meth_set_do_cipher(sec_##name, cipher) || !EVP_CIPHER_meth_set_cleanup(sec_##name, cleanup) || \ + !EVP_CIPHER_meth_set_set_asn1_params(sec_##name, set_params) || \ + !EVP_CIPHER_meth_set_get_asn1_params(sec_##name, get_params) || \ + !EVP_CIPHER_meth_set_ctrl(sec_##name, ctrl)) \ + return 0; \ + } while (0) + +EVP_CIPHER *sec_ciphers_set_gcm_method(int nid) +{ + EVP_CIPHER *aead = NULL; + + switch (nid) { + case NID_aes_128_gcm: + SEC_CIPHERS_AEAD_DESCR(aes_128_gcm, + SEC_AES_GCM_BLOCK_SIZE, + 16, + SEC_AES_GCM_IV_LEN, + GCM_FLAG, + sizeof(struct aead_priv_ctx), + sec_aes_gcm_init, + sec_aes_do_aes_gcm, + sec_aes_gcm_cleanup, + (EVP_CIPH_FLAG_DEFAULT_ASN1 ? NULL : EVP_CIPHER_set_asn1_iv), + (EVP_CIPH_FLAG_DEFAULT_ASN1 ? NULL : EVP_CIPHER_get_asn1_iv), + sec_aes_gcm_set_ctrl); + aead = sec_aes_128_gcm; + break; + case NID_aes_192_gcm: + SEC_CIPHERS_AEAD_DESCR(aes_192_gcm, + SEC_AES_GCM_BLOCK_SIZE, + 24, + SEC_AES_GCM_IV_LEN, + GCM_FLAG, + sizeof(struct aead_priv_ctx), + sec_aes_gcm_init, + sec_aes_do_aes_gcm, + sec_aes_gcm_cleanup, + (EVP_CIPH_FLAG_DEFAULT_ASN1 ? NULL : EVP_CIPHER_set_asn1_iv), + (EVP_CIPH_FLAG_DEFAULT_ASN1 ? NULL : EVP_CIPHER_get_asn1_iv), + sec_aes_gcm_set_ctrl); + aead = sec_aes_192_gcm; + break; + case NID_aes_256_gcm: + SEC_CIPHERS_AEAD_DESCR(aes_256_gcm, + SEC_AES_GCM_BLOCK_SIZE, + 32, + SEC_AES_GCM_IV_LEN, + GCM_FLAG, + sizeof(struct aead_priv_ctx), + sec_aes_gcm_init, + sec_aes_do_aes_gcm, + sec_aes_gcm_cleanup, + (EVP_CIPH_FLAG_DEFAULT_ASN1 ? NULL : EVP_CIPHER_set_asn1_iv), + (EVP_CIPH_FLAG_DEFAULT_ASN1 ? NULL : EVP_CIPHER_get_asn1_iv), + sec_aes_gcm_set_ctrl); + aead = sec_aes_256_gcm; + break; + default: + aead = NULL; + break; + } + + return aead; +} + +// async poll thread create +int sec_aead_engine_ctx_poll(void *engnine_ctx) +{ + int ret = 0; + struct aead_engine_ctx *eng_ctx = (struct aead_engine_ctx *)engnine_ctx; + struct wd_queue *q = eng_ctx->q_node->kae_wd_queue; + +POLL_AGAIN: + ret = wcrypto_aead_poll(q, 1); + if (!ret) { + goto POLL_AGAIN; + } else if (ret < 0) { + US_ERR("cipher poll failed\n"); + return ret; + } + return ret; +} + +KAE_QUEUE_POOL_HEAD_S *wd_aead_get_qnode_pool(void) +{ + return g_sec_aeads_qnode_pool; +} + +int wd_aead_init_qnode_pool(void) +{ + kae_queue_pool_destroy(g_sec_aeads_qnode_pool, wd_aead_free_engine_ctx); + + g_sec_aeads_qnode_pool = kae_init_queue_pool(WCRYPTO_AEAD); + if (g_sec_aeads_qnode_pool == NULL) { + US_ERR("do cipher ctx NULL!"); + return KAE_FAIL; + } + + return KAE_SUCCESS; +} + +void wd_aead_uninit_qnode_pool(void) +{ + kae_queue_pool_destroy(g_sec_aeads_qnode_pool, wd_aead_free_engine_ctx); + g_sec_aeads_qnode_pool = NULL; +} \ No newline at end of file diff --git a/KAEOpensslProvider/src/adapter/nosva/algorithm/cipher/sec_ciphers_aead.h b/KAEOpensslProvider/src/adapter/nosva/algorithm/cipher/sec_ciphers_aead.h new file mode 100644 index 0000000000000000000000000000000000000000..b37ef914c2ad6a98b9755fa68f4523bf432c947c --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/algorithm/cipher/sec_ciphers_aead.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the interface for KAE engine dealing with wrapdrive + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/***************************************************************************** + * @file sec_cipher.h + * + * This file provides the interface for SEC engine dealing with wrapdrive + * + *****************************************************************************/ + +#ifndef SEC_CIPHERS_AEAD_H +#define SEC_CIPHERS_AEAD_H +#include +#include +#include "../../wdwarp/wd_queue_memory.h" + +#define AEAD_OUTPUT_CACHE_SIZE (256*1024 + 64) +#define SEC_AEAD_OUTBUF_SIZE (20*1024*1024) +#define AES_GCM_TAG_LEN 16 +#define RET_FAIL (-1) + +#define OPENSSL_SUCCESS (1) +#define OPENSSL_FAIL (0) +#define KAE_SUCCESS (0) +#define KAE_FAIL (-1) + +#define AES_GCM_BLOCK_SIZE 16 +#define AES_GCM_IV_LEN 12 +#define AES_GCM_TAG_LEN 16 + +extern KAE_QUEUE_POOL_HEAD_S *g_sec_aeads_qnode_pool; + +#define SEC_AEAD_RETURN_FAIL_IF(cond, mesg, ret) \ + do { \ + if (unlikely(cond)) { \ + US_ERR(mesg); \ + return (ret); \ + } \ + } while (0) + +#define SEC_AEAD_GOTO_FAIL_IF(cond, mesg, tag) \ + do { \ + if (unlikely(cond)) { \ + US_ERR(mesg); \ + goto tag; \ + } \ + } while (0) + +typedef struct aead_engine_ctx aead_engine_ctx_t; + +struct aead_priv_ctx { + unsigned char *key; // key + uint32_t key_len; // key length + unsigned char *iv; + uint32_t iv_len; + + unsigned char mac[16]; + uint32_t mac_len; + + uint8_t *data_buf; + uint32_t data_len; + uint8_t *out_data_buf; + + uint32_t aad_len; + uint32_t plen; + + uint32_t c_mode; + uint32_t c_alg; + int encrypt; + //reserve + size_t switch_threshold; + void *sw_ctx_data; + aead_engine_ctx_t *e_aead_ctx; +}; + +typedef struct aead_priv_ctx aead_priv_ctx_t; + +struct aead_engine_ctx { + KAE_QUEUE_DATA_NODE_S *q_node; + struct wcrypto_aead_op_data op_data; + struct wcrypto_aead_ctx_setup setup; + void *wd_ctx; // one ctx or a list of ctx + + aead_priv_ctx_t *priv_ctx; +}; + +EVP_CIPHER *sec_ciphers_set_gcm_method(int nid); +int wd_aead_init_qnode_pool(void); +void wd_aead_uninit_qnode_pool(void); +int sec_aead_engine_ctx_poll(void *engnine_ctx); +KAE_QUEUE_POOL_HEAD_S *wd_aead_get_qnode_pool(void); +void wd_aead_free_engine_ctx(void *engine_ctx); + +#endif diff --git a/KAEOpensslProvider/src/adapter/nosva/algorithm/cipher/sec_ciphers_soft.c b/KAEOpensslProvider/src/adapter/nosva/algorithm/cipher/sec_ciphers_soft.c new file mode 100644 index 0000000000000000000000000000000000000000..7a1e4eb7e023c83e61a8981a59e31dd3cd5288ee --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/algorithm/cipher/sec_ciphers_soft.c @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the implementation for switch to soft ciphers + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/***************************************************************************** + * @file sec_ciphers_soft.c + * + * This file provides the implementation for switch to soft ciphers + * + *****************************************************************************/ +#include "../../../common/kae_types.h" +#include "../../../common/kae_log.h" +#include "sec_ciphers_soft.h" +#include "sec_ciphers.h" +#include "sec_ciphers_utils.h" + +#define CRYPTO_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT 192 + +static cipher_threshold_table_t g_sec_ciphers_pkt_threshold_table[] = { + {NID_aes_128_ecb, CRYPTO_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT}, + {NID_aes_192_ecb, CRYPTO_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT}, + {NID_aes_256_ecb, CRYPTO_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT}, + {NID_aes_128_cbc, CRYPTO_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT}, + {NID_aes_192_cbc, CRYPTO_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT}, + {NID_aes_256_cbc, CRYPTO_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT}, + {NID_aes_128_ctr, CRYPTO_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT}, + {NID_aes_192_ctr, CRYPTO_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT}, + {NID_aes_256_ctr, CRYPTO_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT}, + {NID_aes_128_xts, CRYPTO_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT}, + {NID_aes_256_xts, CRYPTO_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT}, + {NID_aes_128_cfb128, CRYPTO_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT}, + {NID_aes_192_cfb128, CRYPTO_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT}, + {NID_aes_256_cfb128, CRYPTO_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT}, + {NID_aes_128_ofb128, CRYPTO_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT}, + {NID_aes_192_ofb128, CRYPTO_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT}, + {NID_aes_256_ofb128, CRYPTO_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT}, + {NID_sm4_cbc, CRYPTO_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT}, + {NID_sm4_ctr, CRYPTO_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT}, + {NID_sm4_ofb128, CRYPTO_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT}, + {NID_sm4_cfb128, CRYPTO_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT}, + {NID_sm4_ecb, CRYPTO_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT}, +}; +static int g_sec_ciphers_pkt_threshold_table_size = BLOCKSIZES_OF(g_sec_ciphers_pkt_threshold_table); + +int sec_ciphers_sw_get_threshold(int nid) +{ + int i = 0; + + do { + if (g_sec_ciphers_pkt_threshold_table[i].nid == nid) + return g_sec_ciphers_pkt_threshold_table[i].threshold; + } while (++i < g_sec_ciphers_pkt_threshold_table_size); + + US_ERR("nid %d not found in threshold table", nid); + + return KAE_FAIL; +} + +int sec_ciphers_sw_hw_ctx_sync(EVP_CIPHER_CTX *ctx, sec_cipher_priv_ctx_syncto_t direction) +{ + cipher_priv_ctx *priv_ctx = NULL; + unsigned int num = 0; + unsigned int offset = 0; + + US_DEBUG("sw hw state sync start. ctx=%p", ctx); + + priv_ctx = (cipher_priv_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx); + if (unlikely(priv_ctx == NULL)) { + US_ERR("cipher priv ctx data is NULL."); + return KAE_FAIL; + } + + if (direction == SEC_CIHPER_SYNC_S2W) { + kae_memcpy(priv_ctx->iv, EVP_CIPHER_CTX_iv_noconst(ctx), EVP_CIPHER_CTX_iv_length(ctx)); + num = EVP_CIPHER_CTX_num(ctx); + if (num) + sec_ciphers_ctr_iv_sub(priv_ctx->iv); + priv_ctx->offset = num; + priv_ctx->left_len = 0; + } else { + if (priv_ctx->do_cipher_len != 0) { + offset = priv_ctx->offset; + kae_memcpy(EVP_CIPHER_CTX_iv_noconst(ctx), priv_ctx->iv, EVP_CIPHER_CTX_iv_length(ctx)); + EVP_CIPHER_CTX_set_num(ctx, offset); + } + } + + US_DEBUG("state sync success, direct=%d[1:SW_TO_HW, 2:HW_TO_SW], offset=%d", direction, num); + + return KAE_SUCCESS; +} + +int sec_ciphers_ecb_encryt(xts_ecb_data *ecb_encryto, uint8_t *buf_out, uint8_t *buf_in, int buf_len) +{ + int out_len1, tmplen; + /* Encrypt */ + if (!EVP_EncryptInit_ex(ecb_encryto->ecb_ctx, ecb_encryto->cipher_type, NULL, ecb_encryto->key2, NULL)) { + US_ERR("EVP_EncryptInit failed.\n"); + return KAE_FAIL; + } + EVP_CIPHER_CTX_set_padding(ecb_encryto->ecb_ctx, 0); + + if (!EVP_EncryptUpdate(ecb_encryto->ecb_ctx, buf_out, &out_len1, buf_in, buf_len)) { + US_ERR("EVP_EncryptUpdate failed.\n"); + return KAE_FAIL; + } + + if (!EVP_EncryptFinal_ex(ecb_encryto->ecb_ctx, buf_out + out_len1, &tmplen)) { + /* Error */ + return KAE_FAIL; + } + out_len1 += tmplen; + + return KAE_SUCCESS; +} + +int sec_ciphers_ecb_decrypt(xts_ecb_data *ecb_encryto, uint8_t *buf_out, uint8_t *buf_in, int buf_len) +{ + int out_len1, tmplen; + + /* decrypt */ + if (!EVP_DecryptInit_ex(ecb_encryto->ecb_ctx, ecb_encryto->cipher_type, NULL, ecb_encryto->key2, NULL)) { + US_ERR("EVP_EncryptInit failed.\n"); + return KAE_FAIL; + } + + EVP_CIPHER_CTX_set_padding(ecb_encryto->ecb_ctx, 0); + + if (!EVP_DecryptUpdate(ecb_encryto->ecb_ctx, buf_out, &out_len1, buf_in, buf_len)) { + US_ERR("EVP_EncryptUpdate failed.\n"); + return KAE_FAIL; + } + + if (!EVP_DecryptFinal_ex(ecb_encryto->ecb_ctx, buf_out + out_len1, &tmplen)) { + /* Error */ + return KAE_FAIL; + } + out_len1 += tmplen; + + return KAE_SUCCESS; +} diff --git a/KAEOpensslProvider/src/adapter/nosva/algorithm/cipher/sec_ciphers_soft.h b/KAEOpensslProvider/src/adapter/nosva/algorithm/cipher/sec_ciphers_soft.h new file mode 100644 index 0000000000000000000000000000000000000000..bdb7858eedc79604a74dc2fa837f73a9cbca29c6 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/algorithm/cipher/sec_ciphers_soft.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the cipher interface for soft ciphers + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/***************************************************************************** + * @file sec_ciphers_soft.h + * + * This file provides the cipher interface for soft ciphers + * + *****************************************************************************/ + +#ifndef SEC_CIPHERS_SOFT_H +#define SEC_CIPHERS_SOFT_H + +#include "sec_ciphers.h" + +typedef struct cipher_threshold_table_s { + int nid; + const int threshold; +} cipher_threshold_table_t; + +typedef struct sw_cipher_s { + int nid; + const EVP_CIPHER *(*get_cipher)(void); +} sw_cipher_t; + +int sec_ciphers_sw_get_threshold(int nid); +int sec_ciphers_sw_hw_ctx_sync(EVP_CIPHER_CTX *ctx, sec_cipher_priv_ctx_syncto_t direction); +int sec_ciphers_ecb_encryt(xts_ecb_data *ecb_encryto, uint8_t *buf_out, uint8_t *buf_in, int buf_len); +int sec_ciphers_ecb_decrypt(xts_ecb_data *ecb_encryto, uint8_t *buf_out, uint8_t *buf_in, int buf_len); + +#endif diff --git a/KAEOpensslProvider/src/adapter/nosva/algorithm/cipher/sec_ciphers_utils.c b/KAEOpensslProvider/src/adapter/nosva/algorithm/cipher/sec_ciphers_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..1dd03c194c7b7755111de4c2736aae435dca8557 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/algorithm/cipher/sec_ciphers_utils.c @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the implementation for KAE engine utils dealing with wrapdrive + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/***************************************************************************** + * @file sec_ciphers_utils.c + * + * This file provides the interface for SEC engine dealing with wrapdrive + * + *****************************************************************************/ + +#include "sec_ciphers_utils.h" +#include "sec_ciphers_soft.h" +#include "../../../common/kae_log.h" +#include "../../../common/kae_types.h" + +int sec_ciphers_get_cipher_mode(int nid) +{ + uint32_t c_mode = NO_C_MODE; + + switch (nid) { + case NID_aes_128_ecb: + case NID_aes_192_ecb: + case NID_aes_256_ecb: + case NID_sm4_ecb: + c_mode = ECB; + break; + case NID_aes_128_cbc: + case NID_aes_192_cbc: + case NID_aes_256_cbc: + case NID_sm4_cbc: + c_mode = CBC; + break; + case NID_aes_128_ctr: + case NID_aes_192_ctr: + case NID_aes_256_ctr: + case NID_sm4_ctr: + c_mode = CTR; + break; + case NID_aes_128_xts: + case NID_aes_256_xts: + c_mode = XTS; + break; + case NID_sm4_ofb128: + case NID_aes_128_ofb128: + case NID_aes_192_ofb128: + case NID_aes_256_ofb128: + c_mode = OFB; + break; + case NID_aes_128_cfb128: + case NID_aes_192_cfb128: + case NID_aes_256_cfb128: + case NID_sm4_cfb128: + c_mode = CFB; + break; + case NID_aes_128_gcm: + case NID_aes_192_gcm: + case NID_aes_256_gcm: + c_mode = GCM; + break; + default: + US_WARN("nid=%d don't support by sec engine.", nid); + break; + } + + return c_mode; +} + +int sec_ciphers_get_cipher_alg(int nid) +{ + uint32_t c_alg = NO_C_ALG; + + switch (nid) { + case NID_sm4_ctr: + case NID_sm4_cbc: + case NID_sm4_ofb128: + case NID_sm4_cfb128: + case NID_sm4_ecb: + c_alg = SM4; + break; + case NID_aes_128_ecb: + case NID_aes_192_ecb: + case NID_aes_256_ecb: + case NID_aes_128_cbc: + case NID_aes_192_cbc: + case NID_aes_256_cbc: + case NID_aes_128_ctr: + case NID_aes_192_ctr: + case NID_aes_256_ctr: + case NID_aes_128_xts: + case NID_aes_256_xts: + case NID_aes_128_gcm: + case NID_aes_192_gcm: + case NID_aes_256_gcm: + case NID_aes_128_ofb128: + case NID_aes_192_ofb128: + case NID_aes_256_ofb128: + case NID_aes_128_cfb128: + case NID_aes_192_cfb128: + case NID_aes_256_cfb128: + c_alg = AES; + break; + default: + US_WARN("nid=%d don't support by sec engine.", nid); + break; + } + + return c_alg; +} + +/* + * SEC ENGINE IV: {Flag, Random, Counter} + * | <--4--> <--8--> | <---4bytes ---> | + * | Flag, Random | counter | + */ +static unsigned int __iv_to_engine_counter(const uint8_t *iv) +{ + unsigned int counter = 0; + const unsigned int SEC_IV_COUNTER_POSTION = 12; + + counter |= iv[SEC_IV_COUNTER_POSTION]; + counter <<= 8; // left shift 8 + counter |= iv[(unsigned int)(SEC_IV_COUNTER_POSTION + 1)]; // count num 1 + counter <<= 8; // left shift 8 + counter |= iv[(unsigned int)(SEC_IV_COUNTER_POSTION + 2)]; // count num 2 + counter <<= 8; // left shift 8 + counter |= iv[(unsigned int)(SEC_IV_COUNTER_POSTION + 3)]; // count num 3 + + return counter; +} + +/* increment counter (128-bit int) by c */ +void sec_ciphers_ctr_iv_inc(uint8_t *counter, uint32_t c) +{ + uint32_t n = 16; + + do { + --n; + c += counter[n]; + counter[n] = (uint8_t)c; + c >>= 8; // right shift 8 + } while (n); +} + +void sec_ciphers_xts_iv_inc(cipher_priv_ctx *priv_ctx) +{ + uint32_t i = 0; + unsigned int carry; + unsigned int res; + + union { + uint64_t u[2]; // union length 2 + uint32_t d[4]; // union length 4 + uint8_t c[16]; // union length 16 + } tweak; + + kae_memcpy(tweak.c, priv_ctx->ecb_encryto->encryto_iv, 16); // encrypto iv length 16 + + for (i = 0; i < priv_ctx->ecb_encryto->countNum; i++) { + // cppcheck-suppress * + res = 0x87 & (((int)tweak.d[3]) >> 31); // algorithm para 31 + carry = (unsigned int)(tweak.u[0] >> 63); // algorithm para 63 + tweak.u[0] = (tweak.u[0] << 1) ^ res; + tweak.u[1] = (tweak.u[1] << 1) | carry; + } + + sec_ciphers_ecb_decrypt(priv_ctx->ecb_encryto, priv_ctx->ecb_encryto->iv_out, tweak.c, 16); // iv len 16 + kae_memcpy(priv_ctx->iv, priv_ctx->ecb_encryto->iv_out, 16); // update iv len 16 +} + +void sec_ciphers_ctr_iv_sub(uint8_t *counter) +{ + unsigned int n = 16; + int c = 0; + + do { + --n; + c = counter[n] < 1 ? 1 : 0; + counter[n] = (unsigned char)(counter[n] + c * 256 - 1); // algorithm para 256 + if (c == 0) + break; + } while (n); +} + +void sec_ciphers_update_iv(cipher_priv_ctx *tmp_docipher_ctx, int cipher_length) +{ + unsigned int inc_counter = 0; + + switch (tmp_docipher_ctx->c_mode) { + case CBC: + if (tmp_docipher_ctx->encrypt == OPENSSL_ENCRYPTION) + kae_memcpy(tmp_docipher_ctx->iv, tmp_docipher_ctx->out + cipher_length - IV_SIZE, IV_SIZE); + break; + case CTR: + inc_counter = cipher_length >> 4; // right shift 4 + sec_ciphers_ctr_iv_inc(tmp_docipher_ctx->iv, inc_counter); + break; + case XTS: + // update iv here + break; + default: + break; + } +} + +int sec_ciphers_is_iv_may_overflow(cipher_priv_ctx *priv_ctx) +{ + unsigned int will_inc_counter = 0; + unsigned int current_counter = 0; + + if (sec_ciphers_get_cipher_mode(priv_ctx->nid) == CTR) { + // (input length + prev offset)/ 16 = will_inc_counter + will_inc_counter = (priv_ctx->inl + priv_ctx->offset) >> 4; // right shift 4 + current_counter = __iv_to_engine_counter(priv_ctx->iv); + if ((0xFFFFFFFFU - current_counter < will_inc_counter)) { + US_DEBUG("ciphers increase iv overflow 0xFFFFFFFF."); + return 1; + } + } + + return 0; +} \ No newline at end of file diff --git a/KAEOpensslProvider/src/adapter/nosva/algorithm/cipher/sec_ciphers_utils.h b/KAEOpensslProvider/src/adapter/nosva/algorithm/cipher/sec_ciphers_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..99439800e9c052c2d7521ae00c8141b1ff9fe22c --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/algorithm/cipher/sec_ciphers_utils.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the cipher interface for KAE engine utils dealing + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/***************************************************************************** + * @file sec_ciphers_utils.h + * + * This file provides the implementation for SEC engine utils dealing + * + *****************************************************************************/ + +#ifndef SEC_CIPHERS_CHECKER_H +#define SEC_CIPHERS_CHECKER_H + +#include "sec_ciphers.h" + +#define IV_SIZE 16 + +#define NO_C_MODE (UINT_MAX) +#define NO_C_ALG (UINT_MAX) + +enum CIPHERS_MODE { + ECB, + CBC, + CTR, + XTS, + OFB, + CFB, + CCM, + GCM, +}; + +enum CIPHERS_ALG { + SM4, + AES, + DES, + M_3DES, +}; + +int sec_ciphers_is_iv_may_overflow(cipher_priv_ctx *priv_ctx); +int sec_ciphers_get_cipher_mode(int nid); +int sec_ciphers_get_cipher_alg(int nid); + +void sec_ciphers_ctr_iv_inc(uint8_t *counter, uint32_t c); +void sec_ciphers_ctr_iv_sub(uint8_t *counter); +void sec_ciphers_xts_iv_inc(cipher_priv_ctx *priv_ctx); + +void sec_ciphers_update_iv(cipher_priv_ctx *tmp_docipher_ctx, int cipher_length); + +#endif diff --git a/KAEOpensslProvider/src/adapter/nosva/algorithm/cipher/sec_ciphers_wd.c b/KAEOpensslProvider/src/adapter/nosva/algorithm/cipher/sec_ciphers_wd.c new file mode 100644 index 0000000000000000000000000000000000000000..f90be37c7ba66c07567348359604bc88fc7d0bd7 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/algorithm/cipher/sec_ciphers_wd.c @@ -0,0 +1,308 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the implementation for KAE ciphers using wd interface + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/***************************************************************************** + * @file sec_cipher_wd.c + * + * This file provides the implementation for SEC ciphers using wd interface + * + *****************************************************************************/ +#include "sec_ciphers_wd.h" +#include "sec_ciphers_utils.h" +#include "../../wdwarp/wd_queue_memory.h" +#include "../../../common/kae_utils.h" +#include "../../../common/kae_types.h" +#include "../../../common/kae_log.h" + +#define MAX_KEY_SIZE 64 +#define MAX_IV_SIZE 16 + +KAE_QUEUE_POOL_HEAD_S *g_sec_ciphers_qnode_pool; +static cipher_engine_ctx_t *wd_ciphers_new_engine_ctx(KAE_QUEUE_DATA_NODE_S *q_node, cipher_priv_ctx *priv_ctx); + +void wd_ciphers_free_engine_ctx(void *engine_ctx) +{ + cipher_engine_ctx_t *e_cipher_ctx = (cipher_engine_ctx_t *)engine_ctx; + + if (e_cipher_ctx == NULL) + return; + + if (e_cipher_ctx->op_data.in && e_cipher_ctx->setup.br.usr) { + e_cipher_ctx->setup.br.free(e_cipher_ctx->setup.br.usr, (void *)e_cipher_ctx->op_data.in); + e_cipher_ctx->op_data.in = NULL; + } + + if (e_cipher_ctx->op_data.out && e_cipher_ctx->setup.br.usr) { + e_cipher_ctx->setup.br.free(e_cipher_ctx->setup.br.usr, (void *)e_cipher_ctx->op_data.out); + e_cipher_ctx->op_data.out = NULL; + } + + if (e_cipher_ctx->op_data.iv && e_cipher_ctx->setup.br.usr) { + e_cipher_ctx->setup.br.free(e_cipher_ctx->setup.br.usr, (void *)e_cipher_ctx->op_data.iv); + e_cipher_ctx->op_data.iv = NULL; + } + + OPENSSL_free(e_cipher_ctx); + e_cipher_ctx = NULL; +} + +static cipher_engine_ctx_t *wd_ciphers_new_engine_ctx(KAE_QUEUE_DATA_NODE_S *q_node, cipher_priv_ctx *priv_ctx) +{ + cipher_engine_ctx_t *e_cipher_ctx = NULL; + + e_cipher_ctx = (cipher_engine_ctx_t *)OPENSSL_malloc(sizeof(cipher_engine_ctx_t)); + if (e_cipher_ctx == NULL) { + US_ERR("OPENSSL_malloc ctx failed"); + return NULL; + } + kae_memset(e_cipher_ctx, 0, sizeof(cipher_engine_ctx_t)); + + e_cipher_ctx->setup.br.alloc = kae_wd_alloc_blk; + e_cipher_ctx->setup.br.free = kae_wd_free_blk; + e_cipher_ctx->setup.br.iova_map = kae_dma_map; + e_cipher_ctx->setup.br.iova_unmap = kae_dma_unmap; + e_cipher_ctx->setup.br.usr = q_node->kae_queue_mem_pool; + + e_cipher_ctx->op_data.in = e_cipher_ctx->setup.br.alloc(e_cipher_ctx->setup.br.usr, CIPHER_INPUT_CACHE_SIZE); + if (e_cipher_ctx->op_data.in == NULL) { + US_ERR("alloc opdata in buf failed"); + goto err; + } + + e_cipher_ctx->op_data.out = e_cipher_ctx->setup.br.alloc(e_cipher_ctx->setup.br.usr, CIPHER_OUTPUT_CACHE_SIZE); + if (e_cipher_ctx->op_data.out == NULL) { + US_ERR("alloc opdata out buf failed"); + goto err; + } + + e_cipher_ctx->op_data.iv = e_cipher_ctx->setup.br.alloc(e_cipher_ctx->setup.br.usr, priv_ctx->iv_len); + if (e_cipher_ctx->op_data.iv == NULL) { + US_ERR("alloc opdata iv buf failed"); + goto err; + } + + e_cipher_ctx->priv_ctx = priv_ctx; + e_cipher_ctx->q_node = q_node; + q_node->engine_ctx = e_cipher_ctx; + + return e_cipher_ctx; + +err: + (void)wd_ciphers_free_engine_ctx(e_cipher_ctx); + + return NULL; +} + +void sec_ciphers_cb(const void *msg, void *tag) +{ + if (!msg || !tag) { + US_ERR("sec cb params err!\n"); + return; + } + struct wcrypto_cipher_msg *message = (struct wcrypto_cipher_msg *)msg; + cipher_engine_ctx_t *eng_ctx = (cipher_engine_ctx_t *)tag; + + kae_memcpy(eng_ctx->priv_ctx->out, message->out, message->out_bytes); +} + +static int wd_ciphers_init_engine_ctx(cipher_engine_ctx_t *e_cipher_ctx) +{ + struct wd_queue *q = e_cipher_ctx->q_node->kae_wd_queue; + cipher_priv_ctx *priv_ctx = e_cipher_ctx->priv_ctx; + + if (e_cipher_ctx->wd_ctx != NULL) { + US_WARN("wd ctx is in used by other ciphers"); + + return KAE_FAIL; + } + + e_cipher_ctx->setup.alg = (enum wcrypto_cipher_alg)priv_ctx->c_alg; // for example: WD_CIPHER_SM4; + e_cipher_ctx->setup.mode = (enum wcrypto_cipher_mode)priv_ctx->c_mode; // for example: WD_CIPHER_CBC; + e_cipher_ctx->setup.cb = (wcrypto_cb)sec_ciphers_cb; + e_cipher_ctx->wd_ctx = wcrypto_create_cipher_ctx(q, &e_cipher_ctx->setup); + + if (e_cipher_ctx->wd_ctx == NULL) { + US_ERR("wd create sec cipher ctx fail!"); + return KAE_FAIL; + } + + wcrypto_set_cipher_key(e_cipher_ctx->wd_ctx, priv_ctx->key, priv_ctx->key_len); + + return KAE_SUCCESS; +} + +cipher_engine_ctx_t *wd_ciphers_get_engine_ctx(cipher_priv_ctx *priv_ctx) +{ + KAE_QUEUE_DATA_NODE_S *q_node = NULL; + cipher_engine_ctx_t *e_cipher_ctx = NULL; + + if (unlikely(priv_ctx == NULL)) { + US_ERR("sec cipher priv ctx NULL!"); + return NULL; + } + + q_node = kae_get_node_from_pool(g_sec_ciphers_qnode_pool); + if (q_node == NULL) { + US_ERR_LIMIT("failed to get hardware queue"); + return NULL; + } + + e_cipher_ctx = (cipher_engine_ctx_t *)q_node->engine_ctx; + if (e_cipher_ctx == NULL) { + e_cipher_ctx = wd_ciphers_new_engine_ctx(q_node, priv_ctx); + if (e_cipher_ctx == NULL) { + US_WARN("sec new engine ctx fail!"); + (void)kae_put_node_to_pool(g_sec_ciphers_qnode_pool, q_node); + return NULL; + } + } + + e_cipher_ctx->priv_ctx = priv_ctx; + + if (wd_ciphers_init_engine_ctx(e_cipher_ctx) == KAE_FAIL) { + US_WARN("init engine ctx fail!"); + wd_ciphers_put_engine_ctx(e_cipher_ctx); + return NULL; + } + + return e_cipher_ctx; +} + +void wd_ciphers_put_engine_ctx(cipher_engine_ctx_t *e_cipher_ctx) +{ + if (unlikely(e_cipher_ctx == NULL)) { + US_WARN("sec cipher engine ctx NULL!"); + return; + } + + if (e_cipher_ctx->wd_ctx != NULL) { + wcrypto_del_cipher_ctx(e_cipher_ctx->wd_ctx); + e_cipher_ctx->wd_ctx = NULL; + } + + if (e_cipher_ctx->priv_ctx && e_cipher_ctx->priv_ctx->ecb_encryto) { + if (e_cipher_ctx->priv_ctx->ecb_encryto->ecb_ctx != NULL) { + EVP_CIPHER_CTX_free(e_cipher_ctx->priv_ctx->ecb_encryto->ecb_ctx); + e_cipher_ctx->priv_ctx->ecb_encryto->ecb_ctx = NULL; + } + + kae_free(e_cipher_ctx->priv_ctx->ecb_encryto->key2); + kae_free(e_cipher_ctx->priv_ctx->ecb_encryto->encryto_iv); + kae_free(e_cipher_ctx->priv_ctx->ecb_encryto->iv_out); + kae_free(e_cipher_ctx->priv_ctx->ecb_encryto); + } + + if (e_cipher_ctx->q_node != NULL) + (void)kae_put_node_to_pool(g_sec_ciphers_qnode_pool, e_cipher_ctx->q_node); + + e_cipher_ctx = NULL; +} + +int wd_ciphers_do_crypto_impl(cipher_engine_ctx_t *e_cipher_ctx) +{ + int ret = -WD_EINVAL; + int trycount = 0; + + if (unlikely(e_cipher_ctx == NULL)) { + US_ERR("do cipher ctx NULL!"); + return KAE_FAIL; + } + +again: + ret = wcrypto_do_cipher(e_cipher_ctx->wd_ctx, &e_cipher_ctx->op_data, NULL); + if (ret != WD_SUCCESS) { + if (ret == -WD_EBUSY && trycount <= 5) { // try 5 times + US_WARN("do cipher busy, retry again!"); + trycount++; + goto again; + } else { + US_ERR("do cipher failed!"); + return KAE_FAIL; + } + } + + return KAE_SUCCESS; +} + +void wd_ciphers_set_input_data(cipher_engine_ctx_t *e_cipher_ctx) +{ + // fill engine ctx opdata + cipher_priv_ctx *priv_ctx = e_cipher_ctx->priv_ctx; + + kae_memcpy(((uint8_t *)e_cipher_ctx->op_data.in + priv_ctx->offset), priv_ctx->in, priv_ctx->do_cipher_len); + + if (priv_ctx->encrypt == OPENSSL_ENCRYPTION) + e_cipher_ctx->op_data.op_type = WCRYPTO_CIPHER_ENCRYPTION; + else + e_cipher_ctx->op_data.op_type = WCRYPTO_CIPHER_DECRYPTION; + + e_cipher_ctx->op_data.in_bytes = priv_ctx->do_cipher_len + priv_ctx->offset; + + // the real out data start at opdata.out + offset + e_cipher_ctx->op_data.out_bytes = priv_ctx->offset + priv_ctx->do_cipher_len; + kae_memcpy(e_cipher_ctx->op_data.iv, priv_ctx->iv, priv_ctx->iv_len); + e_cipher_ctx->op_data.iv_bytes = priv_ctx->iv_len; +} + +void wd_ciphers_get_output_data(cipher_engine_ctx_t *e_cipher_ctx) +{ + cipher_priv_ctx *priv_ctx = e_cipher_ctx->priv_ctx; + + // the real out data start at opdata.out + offset + kae_memcpy(priv_ctx->out, (uint8_t *)e_cipher_ctx->op_data.out + priv_ctx->offset, priv_ctx->do_cipher_len); +} + +uint32_t wd_ciphers_get_do_cipher_len(uint32_t offset, int leftlen) +{ + uint32_t do_cipher_len = 0; + int max_input_datalen = CIPHER_INPUT_CACHE_SIZE - offset; + /* + * Note: Small encrypted block can be encrypted once. + * or the last encrypted slice of a large encrypted block + */ + if (leftlen <= max_input_datalen) + do_cipher_len = leftlen; + else + do_cipher_len = max_input_datalen; + + return do_cipher_len; +} + +KAE_QUEUE_POOL_HEAD_S *wd_ciphers_get_qnode_pool(void) +{ + return g_sec_ciphers_qnode_pool; +} + +int wd_ciphers_init_qnode_pool(void) +{ + kae_queue_pool_destroy(g_sec_ciphers_qnode_pool, wd_ciphers_free_engine_ctx); + + g_sec_ciphers_qnode_pool = kae_init_queue_pool(WCRYPTO_CIPHER); + if (g_sec_ciphers_qnode_pool == NULL) { + US_ERR("do cipher ctx NULL!"); + return KAE_FAIL; + } + + return KAE_SUCCESS; +} + +void wd_ciphers_uninit_qnode_pool(void) +{ + kae_queue_pool_destroy(g_sec_ciphers_qnode_pool, wd_ciphers_free_engine_ctx); + g_sec_ciphers_qnode_pool = NULL; +} diff --git a/KAEOpensslProvider/src/adapter/nosva/algorithm/cipher/sec_ciphers_wd.h b/KAEOpensslProvider/src/adapter/nosva/algorithm/cipher/sec_ciphers_wd.h new file mode 100644 index 0000000000000000000000000000000000000000..73053c3d265f394317a8922282521a1ab3d798b5 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/algorithm/cipher/sec_ciphers_wd.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the cipher interface for KAE ciphers using wd interface + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/***************************************************************************** + * @file sec_cipher_wd.h + * + * This file provides the interface for SEC ciphers using wd interface + * + *****************************************************************************/ + +#ifndef SEC_CIPHERS_WD_H +#define SEC_CIPHERS_WD_H + +#include "sec_ciphers.h" + +extern KAE_QUEUE_POOL_HEAD_S *g_sec_ciphers_qnode_pool; + +cipher_engine_ctx_t *wd_ciphers_get_engine_ctx(cipher_priv_ctx *priv_ctx); +void wd_ciphers_put_engine_ctx(cipher_engine_ctx_t *e_cipher_ctx); +int wd_ciphers_do_crypto_impl(cipher_engine_ctx_t *e_cipher_ctx); + +void wd_ciphers_set_input_data(cipher_engine_ctx_t *e_cipher_ctx); +void wd_ciphers_get_output_data(cipher_engine_ctx_t *e_cipher_ctx); +uint32_t wd_ciphers_get_do_cipher_len(uint32_t offset, int leftlen); + +int wd_ciphers_init_qnode_pool(void); +void wd_ciphers_uninit_qnode_pool(void); + +KAE_QUEUE_POOL_HEAD_S *wd_ciphers_get_qnode_pool(void); +void wd_ciphers_free_engine_ctx(void *engine_ctx); + +void sec_ciphers_cb(const void *msg, void *tag); + +#endif diff --git a/KAEOpensslProvider/src/adapter/nosva/algorithm/digest/sec_digests.c b/KAEOpensslProvider/src/adapter/nosva/algorithm/digest/sec_digests.c new file mode 100644 index 0000000000000000000000000000000000000000..8a1a260ce046283ab555b335ef7a25bb7bb807bb --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/algorithm/digest/sec_digests.c @@ -0,0 +1,504 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the implementation for KAE engine digests + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "sec_digests.h" +#include "sec_digests_wd.h" + +#include "../../../common/kae_utils.h" +#include "../../../common/kae_types.h" +#include "../../../common/kae_log.h" +#include "../../async/async_callback.h" +#include "../../async/async_event.h" +#include "../../async/async_task_queue.h" +#include "../../async/async_check.h" + +#define DIGEST_SM3_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT (512) +#define DIGEST_MD5_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT (8 * 1024) + +struct digest_info { + int nid; + int is_enabled; + EVP_MD *digest; +}; + +static struct digest_threshold_table g_digest_pkt_threshold_table[] = { + {NID_sm3, DIGEST_SM3_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT}, + {NID_md5, DIGEST_MD5_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT}, +}; + +#define SEC_DIGESTS_RETURN_FAIL_IF(cond, mesg, ret) \ + do { \ + if (unlikely(cond)) { \ + US_ERR(mesg); \ + return (ret); \ + } \ + } while (0) + +static int sec_digests_dowork(sec_digest_priv *md_ctx); +static int sec_digests_sync_dowork(sec_digest_priv *md_ctx); +static int sec_digests_async_dowork(sec_digest_priv *md_ctx, op_done_t *op_done); +static uint32_t sec_digests_sw_get_threshold(int nid); + +static uint32_t sec_digests_sw_get_threshold(int nid) +{ + int threshold_table_sz = BLOCKSIZES_OF(g_digest_pkt_threshold_table); + int i = 0; + + do { + if (g_digest_pkt_threshold_table[i].nid == nid) + return g_digest_pkt_threshold_table[i].threshold; + } while (++i < threshold_table_sz); + + US_ERR("nid %d not found in digest threshold table", nid); + return UINT_MAX; +} + +static void sec_digests_get_alg(sec_digest_priv *md_ctx) +{ + switch (md_ctx->e_nid) { + case NID_sm3: + md_ctx->d_alg = WCRYPTO_SM3; + md_ctx->out_len = SM3_LEN; + break; + case NID_md5: + md_ctx->d_alg = WCRYPTO_MD5; + md_ctx->out_len = MD5_HASH_LEN; + break; + default: + US_WARN("nid=%d don't support by sec engine.", md_ctx->e_nid); + break; + } +} + +int sec_digests_init(sec_digest_priv *md_ctx) +{ + + if (unlikely(md_ctx == NULL)) { + return OPENSSL_FAIL; + } + if (md_ctx->e_digest_ctx) { + (void)wd_digests_put_engine_ctx(md_ctx->e_digest_ctx); + md_ctx->e_digest_ctx = NULL; + } + + sec_digests_get_alg(md_ctx); + md_ctx->state = SEC_DIGEST_INIT; + return OPENSSL_SUCCESS; +} + +static void sec_digests_set_msg_state(sec_digest_priv *md_ctx, bool is_end) +{ + if (unlikely(md_ctx->is_stream_copy)) { + md_ctx->e_digest_ctx->op_data.has_next = is_end ? WCRYPTO_DIGEST_STREAM_END : WCRYPTO_DIGEST_STREAM_DOING; + md_ctx->is_stream_copy = false; + } else { + md_ctx->e_digest_ctx->op_data.has_next = is_end ? WCRYPTO_DIGEST_END : WCRYPTO_DIGEST_DOING; + } +} + +static int sec_digests_update_inner(sec_digest_priv *md_ctx, size_t data_len, const void *data) +{ + int ret = OPENSSL_FAIL; + size_t left_len = data_len; + const unsigned char *tmpdata = (const unsigned char *)data; + sec_digests_set_msg_state(md_ctx, false); + + while (md_ctx->last_update_bufflen + left_len > DIGEST_INPUT_CACHE_SIZE) { + int copy_to_bufflen = DIGEST_INPUT_CACHE_SIZE - md_ctx->last_update_bufflen; + + kae_memcpy(md_ctx->last_update_buff + md_ctx->last_update_bufflen, tmpdata, copy_to_bufflen); + md_ctx->last_update_bufflen = DIGEST_INPUT_CACHE_SIZE; + left_len -= copy_to_bufflen; + tmpdata += copy_to_bufflen; + + if (md_ctx->state == SEC_DIGEST_INIT) + md_ctx->state = SEC_DIGEST_FIRST_UPDATING; + else if (md_ctx->state == SEC_DIGEST_FIRST_UPDATING) + md_ctx->state = SEC_DIGEST_DOING; + else + (void)md_ctx->state; + + ret = sec_digests_sync_dowork(md_ctx); + if (ret != KAE_SUCCESS) { + US_WARN("do sec digest failed, switch to soft digest"); + return KAE_CRYPTO_FAIL; + } + + md_ctx->last_update_bufflen = 0; + if (left_len <= DIGEST_INPUT_CACHE_SIZE) { + md_ctx->last_update_bufflen = left_len; + kae_memcpy(md_ctx->last_update_buff, tmpdata, md_ctx->last_update_bufflen); + break; + } + } + + return OPENSSL_SUCCESS; +} + +int sec_digests_update(sec_digest_priv *md_ctx, const void *data, size_t data_len) +{ + // SEC_DIGESTS_RETURN_FAIL_IF(unlikely(!ctx || !data), "ctx is NULL.", OPENSSL_FAIL); + // sec_digest_priv *md_ctx = (sec_digest_priv *)EVP_MD_CTX_md_data(ctx); + // sec_digest_priv *md_ctx = ctx->priv; + SEC_DIGESTS_RETURN_FAIL_IF(unlikely(md_ctx == NULL), "md_ctx is NULL.", OPENSSL_FAIL); + if (md_ctx->e_digest_ctx == NULL && md_ctx->switch_flag != 1) { + md_ctx->e_digest_ctx = wd_digests_get_engine_ctx(md_ctx); + if (md_ctx->e_digest_ctx == NULL) { + US_WARN("failed to get engine ctx"); + md_ctx->switch_flag = 1; + return KAE_CRYPTO_FAIL; + // 如果硬件申请不行就走软算 + // if (sec_digests_soft_init(md_ctx) != OPENSSL_SUCCESS) { + // US_ERR("do sec digest soft init failed"); + // return OPENSSL_FAIL; + // } + // md_ctx->switch_flag = 1; + } + } + + // if (md_ctx->switch_flag == 1) { + // return sec_digests_soft_update(md_ctx, data, data_len); + // } + + if (md_ctx->e_digest_ctx == NULL) { + US_ERR("digest_ctx is null"); + return OPENSSL_FAIL; + } + digest_engine_ctx_t *e_digest_ctx = md_ctx->e_digest_ctx; + if (md_ctx->last_update_buff == NULL) { + md_ctx->last_update_buff = e_digest_ctx->op_data.in; + } + + // int nid = EVP_MD_nid(EVP_MD_CTX_md(ctx)); + // md_ctx->e_nid = nid; + md_ctx->total_data_len += data_len; + sec_digests_get_alg(md_ctx); + unsigned char digest[MAX_OUTLEN] = {0}; + md_ctx->out = digest; + + if (md_ctx->last_update_bufflen + data_len <= DIGEST_INPUT_CACHE_SIZE) { + kae_memcpy(md_ctx->last_update_buff + md_ctx->last_update_bufflen, data, data_len); + md_ctx->last_update_bufflen += data_len; + return OPENSSL_SUCCESS; + } + + return sec_digests_update_inner(md_ctx, data_len, data); +} + +int sec_digests_final(sec_digest_priv *md_ctx, unsigned char *digest) +{ + int ret = KAE_FAIL; + + // SEC_DIGESTS_RETURN_FAIL_IF(!ctx || !digest, "ctx is NULL.", OPENSSL_FAIL); + // sec_digest_priv *md_ctx = ctx->priv; + SEC_DIGESTS_RETURN_FAIL_IF(unlikely(md_ctx == NULL), "md_ctx is NULL.", OPENSSL_FAIL); + + if (md_ctx->switch_flag == 1) { + // ret = sec_digests_soft_final(md_ctx, digest); + // sec_digests_soft_cleanup(md_ctx); + return KAE_CRYPTO_FAIL; + } + + if (md_ctx->last_update_bufflen == 0) { + US_WARN("no data input, swich to soft digest"); + return KAE_CRYPTO_FAIL; + // goto do_soft_digest; + } + + if (md_ctx->last_update_buff && md_ctx->last_update_bufflen != 0) { + if (md_ctx->state == SEC_DIGEST_INIT && + md_ctx->last_update_bufflen < sec_digests_sw_get_threshold(md_ctx->e_nid)) { + US_WARN_LIMIT("small package offload, switch to soft digest"); + // goto do_soft_digest; + return KAE_CRYPTO_FAIL; + } + + uint32_t tmp = md_ctx->state; + md_ctx->state = SEC_DIGEST_FINAL; + + md_ctx->out = digest; + sec_digests_set_msg_state(md_ctx, true); + ret = sec_digests_dowork(md_ctx); + if (ret != KAE_SUCCESS) { + US_WARN("do sec digest failed, switch to soft digest"); + md_ctx->state = tmp; + // goto do_soft_digest; + return KAE_CRYPTO_FAIL; + } + ret = OPENSSL_SUCCESS; + } + + US_DEBUG("do digest success. ctx=%p", md_ctx); + + // end: + return ret; + + // do_soft_digest: + // if (md_ctx->state == SEC_DIGEST_INIT) { + // ret = sec_digests_soft_work(md_ctx, md_ctx->last_update_bufflen, digest); + // } else { + // US_ERR("do sec digest failed"); + // ret = OPENSSL_FAIL; + // } + + // return ret; +} +static void sec_digests_update_md_ctx(sec_digest_priv *md_ctx) +{ + if (md_ctx->do_digest_len == 0) + return; + + md_ctx->in += md_ctx->do_digest_len; +} + +static int sec_digests_dowork(sec_digest_priv *md_ctx) +{ + int ret = KAE_FAIL; + + // add async parm + int job_ret; + op_done_t op_done; + + SEC_DIGESTS_RETURN_FAIL_IF(md_ctx->last_update_bufflen <= 0, "in length less than or equal to zero.", KAE_FAIL); + // packageSize>input_cache_size + if (md_ctx->last_update_bufflen > DIGEST_INPUT_CACHE_SIZE) { + ret = sec_digests_sync_dowork(md_ctx); + if (ret != 0) { + US_ERR("sec digest sync fail"); + return ret; + } + return KAE_SUCCESS; + } + + // async + async_init_op_done_v1(&op_done); + + if (op_done.job != NULL && kae_is_async_enabled()) { + if (async_setup_async_event_notification_v1(0) == 0) { + US_ERR("sec async event notifying failed"); + async_cleanup_op_done_v1(&op_done); + return KAE_FAIL; + } + } else { + US_DEBUG("NO ASYNC Job or async disable, back to SYNC!"); + async_cleanup_op_done_v1(&op_done); + return sec_digests_sync_dowork(md_ctx); + } + + if (sec_digests_async_dowork(md_ctx, &op_done) == KAE_FAIL) + goto err; + + do { + job_ret = async_pause_job_v1(op_done.job, ASYNC_STATUS_OK); + if ((job_ret == 0)) { + US_DEBUG("- pthread_yidle -"); + kae_pthread_yield(); + } + } while (!op_done.flag || ASYNC_CHK_JOB_RESUMED_UNEXPECTEDLY(job_ret)); + + if (op_done.verifyRst < 0) { + US_ERR("verify result failed with %d", op_done.verifyRst); + async_cleanup_op_done_v1(&op_done); + return KAE_FAIL; + } + + async_cleanup_op_done_v1(&op_done); + + US_DEBUG(" Digest Async Job Finish! md_ctx = %p\n", md_ctx); + return KAE_SUCCESS; +err: + US_ERR("async job err"); + (void)async_clear_async_event_notification_v1(); + async_cleanup_op_done_v1(&op_done); + return KAE_FAIL; +} + +static int sec_digests_sync_dowork(sec_digest_priv *md_ctx) +{ + SEC_DIGESTS_RETURN_FAIL_IF(md_ctx == NULL, "md_ctx is NULL.", KAE_FAIL); + digest_engine_ctx_t *e_digest_ctx = md_ctx->e_digest_ctx; + uint32_t leftlen = md_ctx->last_update_bufflen; + int ret; + + md_ctx->in = md_ctx->last_update_buff; + + while (leftlen != 0) { + md_ctx->do_digest_len = wd_digests_get_do_digest_len(e_digest_ctx, leftlen); + + wd_digests_set_input_data(e_digest_ctx); + + ret = wd_digests_doimpl(e_digest_ctx); + if (ret != KAE_SUCCESS) + return ret; + + wd_digests_get_output_data(e_digest_ctx); + sec_digests_update_md_ctx(md_ctx); + leftlen -= md_ctx->do_digest_len; + } + + US_DEBUG("sec do digest success."); + + return KAE_SUCCESS; +} + +static int sec_digests_async_dowork(sec_digest_priv *md_ctx, op_done_t *op_done) +{ + int ret = 0; + int cnt = 0; + enum task_type_wd type = ASYNC_TASK_WD_DIGEST; + + SEC_DIGESTS_RETURN_FAIL_IF(md_ctx == NULL, "md_ctx is NULL.", KAE_FAIL); + digest_engine_ctx_t *e_digest_ctx = md_ctx->e_digest_ctx; + + SEC_DIGESTS_RETURN_FAIL_IF(e_digest_ctx == NULL, "e_digest_ctx is NULL", KAE_FAIL); + void *tag = e_digest_ctx; + uint32_t leftlen = md_ctx->last_update_bufflen; + + md_ctx->in = md_ctx->last_update_buff; + md_ctx->do_digest_len = wd_digests_get_do_digest_len(e_digest_ctx, leftlen); + e_digest_ctx->op_data.has_next = (md_ctx->state == SEC_DIGEST_FINAL) ? false : true; + wd_digests_set_input_data(e_digest_ctx); + + do { + if (cnt > MAX_SEND_TRY_CNTS) + break; + ret = wcrypto_do_digest(e_digest_ctx->wd_ctx, &e_digest_ctx->op_data, tag); + if (ret == -WD_EBUSY) { + if ((async_wake_job_v1(op_done->job, ASYNC_STATUS_EAGAIN) == 0 || + async_pause_job_v1(op_done->job, ASYNC_STATUS_EAGAIN) == 0)) { + US_ERR("sec wake job or sec pause job fail!\n"); + ret = 0; + break; + } + cnt++; + } + } while (ret == -WD_EBUSY); + + if (ret != WD_SUCCESS) { + US_ERR("sec async wcryto do cipher failed"); + return KAE_FAIL; + } + + if (async_add_poll_task_v1(e_digest_ctx, op_done, type) == 0) { + US_ERR("sec add task failed "); + return KAE_FAIL; + } + + return KAE_SUCCESS; +} + +int sec_digests_cleanup(sec_digest_priv *md_ctx) +{ + // SEC_DIGESTS_RETURN_FAIL_IF(!ctx, "ctx is NULL.", OPENSSL_FAIL); + // sec_digest_priv *md_ctx = (sec_digest_priv *)EVP_MD_CTX_md_data(ctx); + + /* Prevent double-free after the copy is used */ + if (!md_ctx) + return OPENSSL_SUCCESS; + // if (md_ctx->switch_flag == 1) { + // sec_digests_soft_cleanup(md_ctx); + // } + + if (md_ctx->e_digest_ctx != NULL) { + (void)wd_digests_put_engine_ctx(md_ctx->e_digest_ctx); + md_ctx->e_digest_ctx = NULL; + } + + return OPENSSL_SUCCESS; +} + +int sec_digests_copy(sec_digest_priv *to_ctx, const sec_digest_priv *from_ctx) +{ + // sec_digest_priv *to_ctx = to->priv; + // sec_digest_priv *from_ctx = from->priv; + struct wcrypto_digest_op_data *tp; + struct wcrypto_digest_op_data *fp; + + if (!to_ctx) + return 1; + + if (!from_ctx) { + US_ERR("priv get from digest ctx is NULL.\n"); + return OPENSSL_FAIL; + } + + if (from_ctx->e_digest_ctx) { + to_ctx->e_digest_ctx = NULL; + to_ctx->e_digest_ctx = wd_digests_get_engine_ctx(to_ctx); + + if (to_ctx->e_digest_ctx == NULL) { + US_WARN("failed to get engine ctx"); + return OPENSSL_FAIL; + } + + tp = &to_ctx->e_digest_ctx->op_data; + fp = &from_ctx->e_digest_ctx->op_data; + memcpy(tp->in, fp->in, from_ctx->last_update_bufflen); + memcpy(tp->out, fp->out, fp->out_bytes); + memcpy(tp->iv, fp->iv, fp->iv_bytes); + tp->in_bytes = from_ctx->last_update_bufflen; + tp->out_bytes = fp->out_bytes; + tp->status = fp->status; + tp->has_next = fp->has_next; + tp->iv_bytes = fp->iv_bytes; + + to_ctx->last_update_buff = tp->in; + to_ctx->is_copy = true; + + if (to_ctx->state != SEC_DIGEST_INIT) { + to_ctx->is_stream_copy = true; + /* Length that the hardware has processed should be equal to + * total input data length minus software cache data length. + */ + + to_ctx->long_data_len = to_ctx->total_data_len - to_ctx->last_update_bufflen; + tp->priv = (void *)&to_ctx->long_data_len; + } + } + + return 1; +} + +// async poll thread create +int sec_digest_engine_ctx_poll(void *engnine_ctx) +{ + int ret = 0; + digest_engine_ctx_t *e_digest_ctx = (digest_engine_ctx_t *)engnine_ctx; + struct wd_queue *q = e_digest_ctx->q_node->kae_wd_queue; + +POLL_AGAIN: + ret = wcrypto_digest_poll(q, 1); + if (!ret) { + goto POLL_AGAIN; + } else if (ret < 0) { + US_ERR("digest poll failed\n"); + return ret; + } + return ret; +} + +int sec_digest_module_init(void) +{ + wd_digests_init_qnode_pool(); + async_register_poll_fn_v1(ASYNC_TASK_WD_DIGEST, sec_digest_engine_ctx_poll); + + return 1; +} diff --git a/KAEOpensslProvider/src/adapter/nosva/algorithm/digest/sec_digests.h b/KAEOpensslProvider/src/adapter/nosva/algorithm/digest/sec_digests.h new file mode 100644 index 0000000000000000000000000000000000000000..eb353b868687f3b8033f873a3b1dbaceb118ee75 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/algorithm/digest/sec_digests.h @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the digest interface for KAE engine + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SEC_DIGESTS_H +#define SEC_DIGESTS_H + +#include +#include +#include "../../wdwarp/wd_queue_memory.h" +#include "../../../common/kae_utils.h" +#include "../../../common/kae_types.h" + +#define MAX_SEND_TRY_CNTS 50 + +#define MIN_DIGEST_LEN 512 +#define DIGEST_INPUT_CACHE_SIZE (512 * 1024) +#define SM3_LEN 32 +#define MAX_OUTLEN 64 +#define MD5_HASH_LEN 16 + +struct evp_md_st { + int type; + int pkey_type; + int md_size; + unsigned long flags; + int (*init) (EVP_MD_CTX *ctx); + int (*update) (EVP_MD_CTX *ctx, const void *data, size_t count); + int (*final) (EVP_MD_CTX *ctx, unsigned char *md); + int (*copy) (EVP_MD_CTX *to, const EVP_MD_CTX *from); + int (*cleanup) (EVP_MD_CTX *ctx); + int block_size; + int ctx_size; /* how big does the ctx->md_data need to be */ + /* control function */ + int (*md_ctrl) (EVP_MD_CTX *ctx, int cmd, int p1, void *p2); +} /* EVP_MD */ ; +typedef struct evp_md_st EVP_MD; + +typedef struct evp_md_ctx_st EVP_MD_CTX; + +enum sec_digest_state { + SEC_DIGEST_INIT = 0, + SEC_DIGEST_FIRST_UPDATING, + SEC_DIGEST_DOING, + SEC_DIGEST_FINAL +}; + +typedef struct digest_engine_ctx digest_engine_ctx_t; + +typedef struct { + uint8_t *last_update_buff; + uint8_t *in; + uint8_t *out; + uint32_t d_mode; // haven't used + uint32_t d_alg; + uint32_t state; + uint32_t last_update_bufflen; + uint32_t do_digest_len; // do one cycle digest length + uint32_t out_len; // digest out length + uint32_t e_nid; // digest nid + digest_engine_ctx_t *e_digest_ctx; + EVP_MD_CTX *soft_ctx; + EVP_MD *soft_md; + uint32_t switch_flag; + uint32_t app_datasize; + bool is_stream_copy; + bool is_copy; + uint32_t total_data_len; + __u64 long_data_len; + size_t md_size; + size_t blk_size; +} sec_digest_priv; + +struct digest_engine_ctx { + KAE_QUEUE_DATA_NODE_S *q_node; + struct wcrypto_digest_op_data op_data; + struct wcrypto_digest_ctx_setup setup; + void *wd_ctx; // one ctx or a list of ctx + sec_digest_priv *md_ctx; +}; + +struct digest_threshold_table { + int nid; + int threshold; +}; + +struct evp_md_ctx_st { + const EVP_MD *reqdigest; /* The original requested digest */ + const EVP_MD *digest; + ENGINE *engine; /* functional reference if 'digest' is + * ENGINE-provided */ + unsigned long flags; + void *md_data; + /* Public key context for sign/verify */ + EVP_PKEY_CTX *pctx; + /* Update function: usually copied from EVP_MD */ + int (*update) (EVP_MD_CTX *ctx, const void *data, size_t count); + + /* + * Opaque ctx returned from a providers digest algorithm implementation + * OSSL_FUNC_digest_newctx() + */ + void *algctx; + EVP_MD *fetched_digest; +} /* EVP_MD_CTX */ ; + +int sec_digest_module_init(void); + +int sec_digests_init(sec_digest_priv *md_ctx); +int sec_digests_update(sec_digest_priv *md_ctx, const void *data, size_t data_len); +int sec_digests_final(sec_digest_priv *md_ctx, unsigned char *digest); +int sec_digests_cleanup(sec_digest_priv *md_ctx); +int sec_digests_copy(sec_digest_priv *to_ctx, const sec_digest_priv *from_ctx); + +#endif + diff --git a/KAEOpensslProvider/src/adapter/nosva/algorithm/digest/sec_digests_wd.c b/KAEOpensslProvider/src/adapter/nosva/algorithm/digest/sec_digests_wd.c new file mode 100644 index 0000000000000000000000000000000000000000..294e06eecdefeb44a2d8a76a03968db651b03ac6 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/algorithm/digest/sec_digests_wd.c @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the implementation for KAE engine utils dealing with wrapdrive + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sec_digests_wd.h" +#include "../../wdwarp/wd_queue_memory.h" +#include "../../../common/kae_utils.h" +#include "../../../common/kae_types.h" +#include "../../../common/kae_log.h" + +KAE_QUEUE_POOL_HEAD_S *g_sec_digests_qnode_pool; +static digest_engine_ctx_t *wd_digests_new_engine_ctx(KAE_QUEUE_DATA_NODE_S *q_node, sec_digest_priv *md_ctx); +static int wd_digests_init_engine_ctx(digest_engine_ctx_t *e_digest_ctx); + +void wd_digests_free_engine_ctx(void *digest_ctx) +{ + digest_engine_ctx_t *e_digest_ctx = (digest_engine_ctx_t *)digest_ctx; + + if (e_digest_ctx == NULL) + return; + + if (e_digest_ctx->op_data.in && e_digest_ctx->setup.br.usr) { + e_digest_ctx->setup.br.free(e_digest_ctx->setup.br.usr, (void *)e_digest_ctx->op_data.in); + e_digest_ctx->op_data.in = NULL; + } + + if (e_digest_ctx->op_data.out && e_digest_ctx->setup.br.usr) { + e_digest_ctx->setup.br.free(e_digest_ctx->setup.br.usr, (void *)e_digest_ctx->op_data.out); + e_digest_ctx->op_data.out = NULL; + } + + OPENSSL_free(e_digest_ctx); + e_digest_ctx = NULL; +} + +static digest_engine_ctx_t *wd_digests_new_engine_ctx(KAE_QUEUE_DATA_NODE_S *q_node, sec_digest_priv *md_ctx) +{ + digest_engine_ctx_t *e_digest_ctx = NULL; + + e_digest_ctx = (digest_engine_ctx_t *)OPENSSL_malloc(sizeof(digest_engine_ctx_t)); + if (e_digest_ctx == NULL) { + US_ERR("digest engine_ctx malloc fail."); + return NULL; + } + kae_memset(e_digest_ctx, 0, sizeof(digest_engine_ctx_t)); + + e_digest_ctx->setup.br.alloc = kae_wd_alloc_blk; + e_digest_ctx->setup.br.free = kae_wd_free_blk; + e_digest_ctx->setup.br.iova_map = kae_dma_map; + e_digest_ctx->setup.br.iova_unmap = kae_dma_unmap; + e_digest_ctx->setup.br.usr = q_node->kae_queue_mem_pool; + + e_digest_ctx->op_data.in = e_digest_ctx->setup.br.alloc(e_digest_ctx->setup.br.usr, DIGEST_BLOCK_SIZE); + if (e_digest_ctx->op_data.in == NULL) { + US_ERR("alloc opdata in buf failed"); + goto err; + } + + e_digest_ctx->op_data.out = e_digest_ctx->setup.br.alloc(e_digest_ctx->setup.br.usr, DIGEST_BLOCK_SIZE); + if (e_digest_ctx->op_data.out == NULL) { + US_ERR("alloc opdata out buf failed"); + goto err; + } + + e_digest_ctx->md_ctx = md_ctx; // point to each other + e_digest_ctx->q_node = q_node; // point to each other + q_node->engine_ctx = e_digest_ctx; // point to each other + + return e_digest_ctx; + +err: + wd_digests_free_engine_ctx(e_digest_ctx); + return NULL; +} + +void wd_digests_cb(const void *msg, void *tag) +{ + if (!msg || !tag) { + US_ERR("sec cb params err!\n"); + return; + } + struct wcrypto_digest_msg *message = (struct wcrypto_digest_msg *)msg; + digest_engine_ctx_t *e_digest_ctx = (digest_engine_ctx_t *)tag; + + kae_memcpy(e_digest_ctx->md_ctx->out, message->out, message->out_bytes); +} + +static int wd_digests_init_engine_ctx(digest_engine_ctx_t *e_digest_ctx) +{ + struct wd_queue *q = e_digest_ctx->q_node->kae_wd_queue; + sec_digest_priv *md_ctx = e_digest_ctx->md_ctx; + + if (e_digest_ctx->wd_ctx != NULL) { + US_WARN("wd ctx is in used by other digests"); + return KAE_FAIL; + } + + e_digest_ctx->setup.alg = (enum wcrypto_digest_alg)md_ctx->d_alg; // for example: WD_SM3; + e_digest_ctx->setup.mode = WCRYPTO_DIGEST_NORMAL; + e_digest_ctx->setup.cb = (wcrypto_cb)wd_digests_cb; + e_digest_ctx->wd_ctx = wcrypto_create_digest_ctx(q, &e_digest_ctx->setup); + if (e_digest_ctx->wd_ctx == NULL) { + US_ERR("wd create sec digest ctx fail!"); + return KAE_FAIL; + } + + return KAE_SUCCESS; +} + +digest_engine_ctx_t *wd_digests_get_engine_ctx(sec_digest_priv *md_ctx) +{ + KAE_QUEUE_DATA_NODE_S *q_node = NULL; + digest_engine_ctx_t *e_digest_ctx = NULL; + + if (unlikely(md_ctx == NULL)) { + US_WARN("sec digest priv ctx NULL!"); + return NULL; + } + + q_node = kae_get_node_from_pool(g_sec_digests_qnode_pool); + if (q_node == NULL) { + US_ERR_LIMIT("failed to get hardware queue"); + return NULL; + } + + e_digest_ctx = (digest_engine_ctx_t *)q_node->engine_ctx; + if (e_digest_ctx == NULL) { + e_digest_ctx = wd_digests_new_engine_ctx(q_node, md_ctx); + if (e_digest_ctx == NULL) { + US_WARN("sec new engine ctx fail!"); + (void)kae_put_node_to_pool(g_sec_digests_qnode_pool, q_node); + return NULL; + } + } + + e_digest_ctx->md_ctx = md_ctx; + md_ctx->e_digest_ctx = e_digest_ctx; + + if (wd_digests_init_engine_ctx(e_digest_ctx) == KAE_FAIL) { + US_WARN("init engine ctx fail!"); + wd_digests_put_engine_ctx(e_digest_ctx); + return NULL; + } + + return e_digest_ctx; +} + +void wd_digests_put_engine_ctx(digest_engine_ctx_t *e_digest_ctx) +{ + if (unlikely(e_digest_ctx == NULL)) { + US_WARN("sec digest engine ctx NULL!"); + return; + } + + if (e_digest_ctx->wd_ctx != NULL) { + wcrypto_del_digest_ctx(e_digest_ctx->wd_ctx); + e_digest_ctx->wd_ctx = NULL; + } + + if (e_digest_ctx->q_node != NULL) + (void)kae_put_node_to_pool(g_sec_digests_qnode_pool, e_digest_ctx->q_node); + + e_digest_ctx = NULL; +} + +int wd_digests_doimpl(digest_engine_ctx_t *e_digest_ctx) +{ + int ret; + int trycount = 0; + + if (unlikely(e_digest_ctx == NULL)) { + US_ERR("do digest ctx NULL!"); + return KAE_FAIL; + } + +again: + ret = wcrypto_do_digest(e_digest_ctx->wd_ctx, &e_digest_ctx->op_data, NULL); + if (ret != WD_SUCCESS) { + if (ret == -WD_EBUSY && trycount <= 5) { // try 5 times + US_WARN("do digest busy, retry again!"); + trycount++; + goto again; + } else { + US_ERR("do digest failed!"); + return KAE_FAIL; + } + } + + return KAE_SUCCESS; +} + +void wd_digests_set_input_data(digest_engine_ctx_t *e_digest_ctx) +{ + // fill engine ctx opdata + sec_digest_priv *md_ctx = e_digest_ctx->md_ctx; + + e_digest_ctx->op_data.in_bytes = md_ctx->do_digest_len; + e_digest_ctx->op_data.out_bytes = md_ctx->out_len; + + e_digest_ctx->op_data.has_next = (md_ctx->state == SEC_DIGEST_FINAL) ? false : true; +} + +void wd_digests_get_output_data(digest_engine_ctx_t *e_digest_ctx) +{ + sec_digest_priv *md_ctx = e_digest_ctx->md_ctx; + + // the real out data start at opdata.out + offset + if (e_digest_ctx->op_data.has_next == false) + kae_memcpy(md_ctx->out, (uint8_t *)e_digest_ctx->op_data.out, md_ctx->out_len); +} + +uint32_t wd_digests_get_do_digest_len(digest_engine_ctx_t *e_digest_ctx, int leftlen) +{ + uint32_t do_digest_len = 0; + int max_input_datalen = DIGEST_BLOCK_SIZE; + + /* + * Note: Small encrypted block can be encrypted once. + * or the last encrypted slice of a large encrypted block + */ + if (leftlen <= max_input_datalen) + do_digest_len = leftlen; + else + do_digest_len = max_input_datalen; + + return do_digest_len; +} + +KAE_QUEUE_POOL_HEAD_S *wd_digests_get_qnode_pool(void) +{ + return g_sec_digests_qnode_pool; +} + +int wd_digests_init_qnode_pool(void) +{ + kae_queue_pool_destroy(g_sec_digests_qnode_pool, wd_digests_free_engine_ctx); + + g_sec_digests_qnode_pool = kae_init_queue_pool(WCRYPTO_DIGEST); + if (g_sec_digests_qnode_pool == NULL) { + US_ERR("do digest ctx NULL!"); + return KAE_FAIL; + } + + return KAE_SUCCESS; +} + +void wd_digests_uninit_qnode_pool(void) +{ + kae_queue_pool_destroy(g_sec_digests_qnode_pool, wd_digests_free_engine_ctx); + g_sec_digests_qnode_pool = NULL; +} diff --git a/KAEOpensslProvider/src/adapter/nosva/algorithm/digest/sec_digests_wd.h b/KAEOpensslProvider/src/adapter/nosva/algorithm/digest/sec_digests_wd.h new file mode 100644 index 0000000000000000000000000000000000000000..2fbe712d6622b4aa964bdb2e130f54e78d4babaf --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/algorithm/digest/sec_digests_wd.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the digest interface for KAE digests using wd interface + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SEC_DIGESTS_WD_H +#define SEC_DIGESTS_WD_H + +#include "sec_digests.h" + +extern KAE_QUEUE_POOL_HEAD_S *g_sec_digests_qnode_pool; + +void wd_digests_cb(const void *msg, void *tag); + +digest_engine_ctx_t *wd_digests_get_engine_ctx(sec_digest_priv *md_ctx); +void wd_digests_put_engine_ctx(digest_engine_ctx_t *e_digest_ctx); +int wd_digests_doimpl(digest_engine_ctx_t *e_digest_ctx); + +void wd_digests_set_input_data(digest_engine_ctx_t *e_digest_ctx); +void wd_digests_get_output_data(digest_engine_ctx_t *e_digest_ctx); +uint32_t wd_digests_get_do_digest_len(digest_engine_ctx_t *e_digest_ctx, int leftlen); + +KAE_QUEUE_POOL_HEAD_S *wd_digests_get_qnode_pool(void); +int wd_digests_init_qnode_pool(void); +void wd_digests_uninit_qnode_pool(void); +void wd_digests_free_engine_ctx(void *digest_ctx); + +#endif diff --git a/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_dh.c b/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_dh.c new file mode 100644 index 0000000000000000000000000000000000000000..30199a26f59da83c95292a770d94722844e5cc14 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_dh.c @@ -0,0 +1,245 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the implementation for KAE engine DH. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "hpre_dh.h" +#include "hpre_dh_wd.h" +#include "hpre_dh_soft.h" +#include "../../../common/kae_types.h" +#include "../../../common/kae_opensslerr.h" +#include "../../../common/kae_log.h" +#include "../../async/async_task_queue.h" + +#define GENERATOR_2 2 + +#ifndef OPENSSL_NO_DH +const int DHPKEYMETH_IDX = 1; +#else +const int DHPKEYMETH_IDX = -1; +#endif + +const char *g_hpre_dh_device = "hisi_hpre"; + +#define CHECK_AND_GOTO(cond, goto_tag, log) \ + do { \ + if (cond) { \ + US_WARN(log); \ + goto goto_tag; \ + } \ + } while (0) + +static int check_dh_bit_useful(const int bit); + +static int prepare_dh_data(const int bits, const BIGNUM *g, DH *dh, hpre_dh_engine_ctx_t **eng_ctx, BIGNUM **priv_key); + +static int hpre_dh_ctx_poll(void *engine_ctx); + +int hpre_module_dh_init(void) +{ + wd_hpre_dh_init_qnode_pool(); + + /* register async poll func */ + async_register_poll_fn_v1(ASYNC_TASK_WD_DH, hpre_dh_ctx_poll); + + return OPENSSL_SUCCESS; +} + +EVP_PKEY_METHOD *get_dsa_pkey_meth(void) +{ + return (EVP_PKEY_METHOD *)EVP_PKEY_meth_get0(DHPKEYMETH_IDX); +} + +static int hpre_dh_ctx_poll(void *engine_ctx) +{ + int ret; + hpre_dh_engine_ctx_t *eng_ctx = (hpre_dh_engine_ctx_t *)engine_ctx; + struct wd_queue *q = eng_ctx->qlist->kae_wd_queue; + +poll_again: + ret = wcrypto_dh_poll(q, 1); + if (!ret) { + goto poll_again; + } else if (ret < 0) { + US_ERR("dh poll fail!\n"); + return ret; + } + return ret; +} + +int hpre_dh_generate_key(DH *dh) +{ + int bits = DH_bits(dh); + const BIGNUM *p = NULL; + const BIGNUM *g = NULL; + const BIGNUM *q = NULL; + BIGNUM *pub_key = NULL; + BIGNUM *priv_key = NULL; + hpre_dh_engine_ctx_t *eng_ctx = NULL; + int ret = OPENSSL_FAIL; + + if (dh == NULL) { + KAEerr(KAE_F_HPRE_DH_KEYGEN, KAE_R_DH_INVALID_PARAMETER); + US_ERR("DH_BUILTIN_KEYGEN KAE_R_DH_INVALID_PARAMETER"); + return OPENSSL_FAIL; + } + + hpre_dh_soft_get_pg(dh, &p, &g, &q); + if (p == NULL || g == NULL) { + KAEerr(KAE_F_HPRE_DH_KEYGEN, KAE_R_DH_INVALID_PARAMETER); + US_ERR("invalid g or p."); + return OPENSSL_FAIL; + } + + // check whether it is dsa parameter. + CHECK_AND_GOTO(q != NULL, end_soft, "q is not null, then switch to soft!"); + + // check whether bits exceeds the limit. + if (bits > OPENSSL_DH_MAX_MODULUS_BITS) { + KAEerr(KAE_F_HPRE_DH_KEYGEN, KAE_R_DH_KEY_SIZE_TOO_LARGE); + US_ERR("DH_BUILTIN_KEYGEN DH_KEY_SIZE_TOO_LARGE"); + return OPENSSL_FAIL; + } + + ret = prepare_dh_data(bits, g, dh, &eng_ctx, &priv_key); + CHECK_AND_GOTO(ret != OPENSSL_SUCCESS, end_soft, "prepare dh data failed!"); + + // construct opdata + ret = hpre_dh_fill_genkey_opdata(g, p, priv_key, eng_ctx); + CHECK_AND_GOTO(ret != OPENSSL_SUCCESS, end_soft, "fill opdata fail then switch to soft!"); + + // call wd api + ret = hpre_dh_genkey(eng_ctx); + CHECK_AND_GOTO(ret != OPENSSL_SUCCESS, end_soft, "hpre generate dh key failed.switch to soft!"); + + // get public key from opdata + ret = hpre_dh_get_pubkey(eng_ctx, &pub_key); + CHECK_AND_GOTO(ret != OPENSSL_SUCCESS, end_soft, "get pub key failed.switch to soft!"); + + // set public key and secret key to the DH. + hpre_dh_soft_set_pkeys(dh, pub_key, priv_key); + +end_soft: + if (pub_key != DH_get0_pub_key(dh)) { + BN_free(pub_key); + } + if (priv_key != DH_get0_priv_key(dh)) { + BN_free(priv_key); + } + + hpre_dh_free_eng_ctx(eng_ctx); + + if (ret != OPENSSL_SUCCESS) + return hpre_dh_soft_generate_key(dh); + + US_DEBUG("hpre dh generate key success!"); + return OPENSSL_SUCCESS; +} + +int hpre_dh_compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh) +{ + int bits = DH_bits(dh); + const BIGNUM *p = NULL; + const BIGNUM *g = NULL; + const BIGNUM *q = NULL; + BIGNUM *priv_key = NULL; + hpre_dh_engine_ctx_t *eng_ctx = NULL; + int ret = OPENSSL_FAIL; + int ret_size = 0; + + if (dh == NULL || key == NULL || pub_key == NULL || DH_get0_priv_key(dh) == NULL) { + KAEerr(KAE_F_HPRE_DH_KEYCOMP, KAE_R_DH_INVALID_PARAMETER); + US_ERR("KAE_F_HPRE_DH_KEYCOMP KAE_R_DH_INVALID_PARAMETER"); + return OPENSSL_FAIL; + } + + hpre_dh_soft_get_pg(dh, &p, &g, &q); + if (p == NULL || g == NULL) { + KAEerr(KAE_F_HPRE_DH_KEYCOMP, KAE_R_DH_INVALID_PARAMETER); + US_ERR("invalid g or p."); + return OPENSSL_FAIL; + } + + // check whether it is dsa parameter. + CHECK_AND_GOTO(q != NULL, end_soft, "q is not null, then switch to soft!"); + + // check whether bits exceeds the limit. + if (bits > OPENSSL_DH_MAX_MODULUS_BITS) { + KAEerr(KAE_F_HPRE_DH_KEYCOMP, KAE_R_DH_KEY_SIZE_TOO_LARGE); + US_ERR("DH_BUILTIN_KEYGEN DH_KEY_SIZE_TOO_LARGE"); + return OPENSSL_FAIL; + } + + ret = prepare_dh_data(bits, g, dh, &eng_ctx, &priv_key); + CHECK_AND_GOTO(ret != OPENSSL_SUCCESS, end_soft, "prepare dh data failed!"); + + // construct opdata + ret = hpre_dh_fill_compkey_opdata(g, p, priv_key, pub_key, eng_ctx); + CHECK_AND_GOTO(ret != OPENSSL_SUCCESS, end_soft, "fill opdata fail then switch to soft!"); + + // call wd api to generate shared secret key. + ret = hpre_dh_compkey(eng_ctx); + CHECK_AND_GOTO(ret != OPENSSL_SUCCESS, end_soft, "hpre compute dh key failed.switch to soft!"); + + ret_size = hpre_dh_get_output_chars(eng_ctx, key); + +end_soft: + + hpre_dh_free_eng_ctx(eng_ctx); + + if (ret != OPENSSL_SUCCESS) + return hpre_dh_soft_compute_key(key, pub_key, dh); + + US_DEBUG("hpre dh compute key success!"); + return ret_size; +} + +static int check_dh_bit_useful(const int bit) +{ + switch (bit) { + case DH768BITS: + case DH1024BITS: + case DH1536BITS: + case DH2048BITS: + case DH3072BITS: + case DH4096BITS: + return 1; + default: + break; + } + return 0; +} + +static int prepare_dh_data(const int bits, const BIGNUM *g, DH *dh, hpre_dh_engine_ctx_t **eng_ctx, BIGNUM **priv_key) +{ + int ret = OPENSSL_FAIL; + bool is_g2 = BN_is_word(g, GENERATOR_2); + // check whether the bits is supported by hpre. + CHECK_AND_GOTO(!check_dh_bit_useful(bits), err, "op sizes not supported by hpre engine then back to soft!"); + + // get ctx + *eng_ctx = hpre_dh_get_eng_ctx(dh, bits, is_g2); + CHECK_AND_GOTO(*eng_ctx == NULL, err, "get eng ctx fail then switch to soft!"); + + // get private key + ret = hpre_dh_soft_try_get_priv_key(dh, priv_key); + CHECK_AND_GOTO(ret != OPENSSL_SUCCESS, err, "get priv key fail then switch to soft!"); + + return OPENSSL_SUCCESS; +err: + return OPENSSL_FAIL; +} diff --git a/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_dh.h b/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_dh.h new file mode 100644 index 0000000000000000000000000000000000000000..e25a9ca9ad30844f054d839498d06cbe3c0a42cc --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_dh.h @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the implementation for KAE engine DH. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HPRE_DH_H +#define HPRE_DH_H + +#include + +#define DH768BITS 768 +#define DH1024BITS 1024 +#define DH1536BITS 1536 +#define DH2048BITS 2048 +#define DH3072BITS 3072 +#define DH4096BITS 4096 + +#define DH_MAX_PARAM_LEN 80 +#define IGNORE_Q 1 +#define USE_PAD 1 +#define KDF_PARAM_NUM 5 + +/* + * This type is only really used to handle some legacy related functionality. + * If you need to use other KDF's (such as SSKDF) just use PROV_DH_KDF_NONE + * here and then create and run a KDF after the key is derived. + * Note that X942 has 2 variants of key derivation: + * (1) DH_KDF_X9_42_ASN1 - which contains an ANS1 encoded object that has + * the counter embedded in it. + * (2) DH_KDF_X941_CONCAT - which is the same as ECDH_X963_KDF (which can be + * done by creating a "X963KDF". + */ +enum kdf_type { PROV_DH_KDF_NONE = 0, PROV_DH_KDF_X9_42_ASN1 }; + +/* + * Finite field cryptography (FFC) domain parameters are used by DH and DSA. + * Refer to FIPS186_4 Appendix A & B. + */ +typedef struct ffc_params_st { + /* Primes */ + BIGNUM *p; + BIGNUM *q; + /* Generator */ + BIGNUM *g; + /* DH X9.42 Optional Subgroup factor j >= 2 where p = j * q + 1 */ + BIGNUM *j; + + /* Required for FIPS186_4 validation of p, q and optionally canonical g */ + unsigned char *seed; + /* If this value is zero the hash size is used as the seed length */ + size_t seedlen; + /* Required for FIPS186_4 validation of p and q */ + int pcounter; + /* The identity of a named group */ + int nid; + + /* + * Required for FIPS186_4 generation & validation of canonical g. + * It uses unverifiable g if this value is -1. + */ + int gindex; + /* loop counter for unverifiable g */ + int h; + + unsigned int flags; + /* + * The digest to use for generation or validation. If this value is NULL, + * then the digest is chosen using the value of N. + */ + const char *mdname; + const char *mdprops; +#if OPENSSL_VERSION_NUMBER >= 0x30000060 + /* Default key length for known named groups according to RFC7919 */ + int keylength; +#endif +} FFC_PARAMS; + +struct dh_st { + /* + * This first argument is used to pick up errors when a DH is passed + * instead of a EVP_PKEY + */ + int pad; + int version; + FFC_PARAMS params; + /* max generated private key length (can be less than len(q)) */ + int32_t length; + BIGNUM *pub_key; /* g^x % p */ + BIGNUM *priv_key; /* x */ + int flags; + BN_MONT_CTX *method_mont_p; + int references; +#ifndef FIPS_MODULE + CRYPTO_EX_DATA ex_data; + ENGINE *engine; +#endif + OSSL_LIB_CTX *libctx; + const DH_METHOD *meth; + void *lock; + + /* Provider data */ + /* If any key material changes, increment this */ + size_t dirty_cnt; +}; /* DH */ + +typedef struct { + OSSL_LIB_CTX *libctx; + + FFC_PARAMS *ffc_params; + int selection; + /* All these parameters are used for parameter generation only */ + /* If there is a group name then the remaining parameters are not needed */ + int group_nid; + size_t pbits; + size_t qbits; + unsigned char *seed; /* optional FIPS186-4 param for testing */ + size_t seedlen; + int gindex; /* optional FIPS186-4 generator index (ignored if -1) */ + int gen_type; /* see dhtype2id */ + int generator; /* Used by DH_PARAMGEN_TYPE_GENERATOR in non fips mode only */ + int pcounter; + int hindex; + int priv_len; + + char *mdname; + char *mdprops; + OSSL_CALLBACK *cb; + void *cbarg; + int dh_type; +} PROV_DH_KEYMGMT_CTX; + +/* + * What's passed as an actual key is defined by the KEYMGMT interface. + * We happen to know that our KEYMGMT simply passes DH structures, so + * we use that here too. + */ +typedef struct { + OSSL_LIB_CTX *libctx; + DH *dh; + DH *dhpeer; + unsigned int pad : 1; + + /* DH KDF */ + /* KDF (if any) to use for DH */ + enum kdf_type kdf_type; + /* Message digest to use for key derivation */ + EVP_MD *kdf_md; + /* User key material */ + unsigned char *kdf_ukm; + size_t kdf_ukmlen; + /* KDF output length */ + size_t kdf_outlen; + char *kdf_cekalg; +} PROV_DH_KEYEXCH_CTX; + +const DH_METHOD *hpre_get_dh_methods(void); + +int hpre_module_dh_init(void); + +int hpre_dh_compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh); + +int hpre_dh_generate_key(DH *dh); + +EVP_PKEY_METHOD *get_dh_pkey_meth(void); + +EVP_PKEY_METHOD *get_dsa_pkey_meth(void); + +#endif diff --git a/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_dh_soft.c b/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_dh_soft.c new file mode 100644 index 0000000000000000000000000000000000000000..4c3674a62856e69acd7b49ce314d8e95b448b560 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_dh_soft.c @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the implementation for switch to soft dh. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hpre_dh_soft.h" +#include "../../../common/kae_types.h" +#include "../../../common/kae_log.h" + +static int generate_new_priv_key(const DH *dh, BIGNUM *new_priv_key); + +void hpre_dh_soft_get_pg(const DH *dh, const BIGNUM **p, const BIGNUM **g, const BIGNUM **q) +{ + DH_get0_pqg(dh, p, q, g); +} + +int hpre_dh_soft_try_get_priv_key(const DH *dh, BIGNUM **priv_key) +{ + int generate_new_key = 0; + BIGNUM *new_priv_key = NULL; + + // get the private key from dh. + *priv_key = (BIGNUM *)DH_get0_priv_key(dh); + + if (*priv_key == NULL) { + new_priv_key = BN_secure_new(); + if (new_priv_key == NULL) + goto err; + generate_new_key = 1; + } + + if (generate_new_key) { + // generate random private key,referencing function 'generate_key' in openssl + if (generate_new_priv_key(dh, new_priv_key) == OPENSSL_FAIL) + goto err; + else + *priv_key = new_priv_key; + } + return OPENSSL_SUCCESS; + +err: + BN_free(new_priv_key); + return OPENSSL_FAIL; +} + +void hpre_dh_soft_set_pkeys(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key) +{ + const BIGNUM *old_pub = DH_get0_pub_key(dh); + const BIGNUM *old_priv = DH_get0_priv_key(dh); + + if (old_pub != pub_key && old_priv != priv_key) + DH_set0_key(dh, pub_key, priv_key); + else if (old_pub != pub_key) + DH_set0_key(dh, pub_key, NULL); + else if (old_priv != priv_key) + DH_set0_key(dh, NULL, priv_key); +} + +int hpre_dh_soft_generate_key(DH *dh) +{ + int (*dh_soft_generate_key)(DH *dh); + + dh_soft_generate_key = DH_meth_get_generate_key(DH_OpenSSL()); + int ret = dh_soft_generate_key(dh); + + if (ret < 0) { + US_ERR("dh soft key generate fail: %d", ret); + return OPENSSL_FAIL; + } + + return OPENSSL_SUCCESS; +} + +int hpre_dh_soft_compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh) +{ + int (*dh_soft_compute_key)(unsigned char *key, const BIGNUM *pub_key, DH *dh); + + dh_soft_compute_key = DH_meth_get_compute_key(DH_OpenSSL()); + int ret = dh_soft_compute_key(key, pub_key, dh); + + if (ret < 0) { + US_ERR("dh soft key compute fail: %d", ret); + return OPENSSL_FAIL; + } + + return ret; +} + +static int generate_new_priv_key(const DH *dh, BIGNUM *new_priv_key) +{ + const BIGNUM *q = DH_get0_q(dh); + int l; + + if (q) { + do { + if (!BN_priv_rand_range(new_priv_key, q)) + return OPENSSL_FAIL; + } while (BN_is_zero(new_priv_key) || BN_is_one(new_priv_key)); + } else { + l = DH_get_length(dh) ? DH_get_length(dh) : BN_num_bits(DH_get0_p(dh)) - 1; + if (!BN_priv_rand(new_priv_key, l, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ANY)) + return OPENSSL_FAIL; + } + + return OPENSSL_SUCCESS; +} diff --git a/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_dh_soft.h b/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_dh_soft.h new file mode 100644 index 0000000000000000000000000000000000000000..f46d5f388b8259bd43483f0516f9e6d58fd03f99 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_dh_soft.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the implementation for switch to soft dh. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HPRE_DH_SOFT_H +#define HPRE_DH_SOFT_H + +#include + +/* + * get p, g, q in dh. + */ +void hpre_dh_soft_get_pg(const DH *dh, const BIGNUM **p, const BIGNUM **g, const BIGNUM **q); + +/* + * get private key in dh, if null, then generate a random one. + */ +int hpre_dh_soft_try_get_priv_key(const DH *dh, BIGNUM **priv_key); + +/* + * put private key and public key in the dh. + */ +void hpre_dh_soft_set_pkeys(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key); + +/* + * call openssl API to generate public key . + */ +int hpre_dh_soft_generate_key(DH *dh); + +/* + * call openssl API to generate secret key . + */ +int hpre_dh_soft_compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh); + +#endif diff --git a/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_dh_wd.c b/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_dh_wd.c new file mode 100644 index 0000000000000000000000000000000000000000..9257fc522d4acafb178d61c41d62fc0cd5dde27a --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_dh_wd.c @@ -0,0 +1,423 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides wd api for DH. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hpre_dh_wd.h" +#include "../../../common/kae_types.h" +#include "../../../common/kae_log.h" +#include "../../async/async_callback.h" +#include "../../async/async_task_queue.h" +#include "../../async/async_event.h" +#include "../../async/async_check.h" +#include + +#define DH_GENERATOR_2 2 +#define DH_GENERATOR_5 5 +#define CHAR_BIT_SIZE 3 +#define DH_PARAMS_CNT 4 +#define MAX_SEND_TRY_CNTS 50 +#define WD_STATUS_BUSY (-EBUSY) + +KAE_QUEUE_POOL_HEAD_S *g_hpre_dh_qnode_pool; + +static hpre_dh_engine_ctx_t *hpre_dh_new_eng_ctx(DH *alg); + +static int hpre_dh_init_eng_ctx(hpre_dh_engine_ctx_t *eng_ctx, int bits, bool is_g2); + +static int hpre_dh_set_g(const BIGNUM *g, const int key_size, unsigned char *ag_bin, hpre_dh_engine_ctx_t *engine_ctx); + +static int hpre_dh_fill_g_p_priv_key( + const BIGNUM *g, const BIGNUM *p, const BIGNUM *priv_key, hpre_dh_engine_ctx_t *engine_ctx, unsigned char *ag_bin); + +static int hpre_dh_internal_do(void *ctx, struct wcrypto_dh_op_data *opdata); + +static int hpre_dh_fill_pub_key(const BIGNUM *pub_key, hpre_dh_engine_ctx_t *engine_ctx, unsigned char *ag_bin); + +static void hpre_dh_free_opdata(hpre_dh_engine_ctx_t *eng_ctx); + +static int hpre_internal_do_dh(hpre_dh_engine_ctx_t *eng_ctx, enum wcrypto_dh_op_type op_type); + +static int hpre_dh_async(hpre_dh_engine_ctx_t *eng_ctx, struct wcrypto_dh_op_data *opdata, op_done_t *op_done); + +void wd_hpre_dh_uninit_qnode_pool(void) +{ + kae_queue_pool_destroy(g_hpre_dh_qnode_pool, NULL); + g_hpre_dh_qnode_pool = NULL; +} + +int wd_hpre_dh_init_qnode_pool(void) +{ + kae_queue_pool_destroy(g_hpre_dh_qnode_pool, NULL); + + g_hpre_dh_qnode_pool = kae_init_queue_pool(WCRYPTO_DH); + if (g_hpre_dh_qnode_pool == NULL) { + US_ERR("hpre dh qnode poll init fail!\n"); + return KAE_FAIL; + } + + return KAE_SUCCESS; +} + +KAE_QUEUE_POOL_HEAD_S *wd_hpre_dh_get_qnode_pool(void) +{ + return g_hpre_dh_qnode_pool; +} + +hpre_dh_engine_ctx_t *hpre_dh_get_eng_ctx(DH *dh, int bits, bool is_g2) +{ + hpre_dh_engine_ctx_t *eng_ctx = hpre_dh_new_eng_ctx(dh); + + if (eng_ctx == NULL) { + US_WARN("new eng ctx fail then switch to soft!"); + return NULL; + } + + if (hpre_dh_init_eng_ctx(eng_ctx, bits, is_g2) == 0) { + hpre_dh_free_eng_ctx(eng_ctx); + US_WARN("init eng ctx fail then switch to soft!"); + return NULL; + } + return eng_ctx; +} + +int hpre_dh_fill_genkey_opdata( + const BIGNUM *g, const BIGNUM *p, const BIGNUM *priv_key, hpre_dh_engine_ctx_t *engine_ctx) +{ + unsigned char *ag_bin = NULL; + int key_size = engine_ctx->priv_ctx.key_size; + + // allocate data block + ag_bin = (unsigned char *)kae_wd_alloc_blk(engine_ctx->qlist->kae_queue_mem_pool, key_size); + if (!ag_bin) { + US_ERR("pool alloc ag_bin fail!"); + return -ENOMEM; + } + int ret = hpre_dh_fill_g_p_priv_key(g, p, priv_key, engine_ctx, ag_bin); + + if (ret != OPENSSL_SUCCESS) { + kae_wd_free_blk(engine_ctx->qlist->kae_queue_mem_pool, ag_bin); + return ret; + } + engine_ctx->priv_ctx.block_addr = ag_bin; + + return OPENSSL_SUCCESS; +} + +int hpre_dh_fill_compkey_opdata( + const BIGNUM *g, const BIGNUM *p, const BIGNUM *priv_key, const BIGNUM *pub_key, hpre_dh_engine_ctx_t *engine_ctx) +{ + unsigned char *ag_bin = NULL; + int key_size = engine_ctx->priv_ctx.key_size; + + ag_bin = (unsigned char *)kae_wd_alloc_blk(engine_ctx->qlist->kae_queue_mem_pool, key_size); + if (!ag_bin) { + US_ERR("pool alloc ag_bin fail!"); + return -ENOMEM; + } + int ret = hpre_dh_fill_g_p_priv_key(g, p, priv_key, engine_ctx, ag_bin); + + if (ret != OPENSSL_SUCCESS) { + kae_wd_free_blk(engine_ctx->qlist->kae_queue_mem_pool, ag_bin); + return ret; + } + + ret = hpre_dh_fill_pub_key(pub_key, engine_ctx, ag_bin); + if (ret != OPENSSL_SUCCESS) + return ret; + engine_ctx->priv_ctx.block_addr = ag_bin; + + return OPENSSL_SUCCESS; +} + +int hpre_dh_genkey(hpre_dh_engine_ctx_t *engine_ctx) +{ + return hpre_internal_do_dh(engine_ctx, WCRYPTO_DH_PHASE1); +} + +int hpre_dh_compkey(hpre_dh_engine_ctx_t *engine_ctx) +{ + return hpre_internal_do_dh(engine_ctx, WCRYPTO_DH_PHASE2); +} + +int hpre_dh_get_output_chars(hpre_dh_engine_ctx_t *engine_ctx, unsigned char *out) +{ + kae_memcpy(out, engine_ctx->opdata.pri, engine_ctx->opdata.pri_bytes); + return engine_ctx->opdata.pri_bytes; +} + +int hpre_dh_get_pubkey(hpre_dh_engine_ctx_t *engine_ctx, BIGNUM **pubkey) +{ + const unsigned char *pubkey_str = (const unsigned char *)engine_ctx->opdata.pri; + + if (pubkey_str == NULL) + return OPENSSL_FAIL; + *pubkey = BN_bin2bn(pubkey_str, engine_ctx->opdata.pri_bytes, *pubkey); + if (*pubkey == NULL) + return OPENSSL_FAIL; + + return OPENSSL_SUCCESS; +} + +void hpre_dh_free_eng_ctx(hpre_dh_engine_ctx_t *eng_ctx) +{ + US_DEBUG("hpre dh free engine ctx start!"); + if (eng_ctx == NULL) { + US_DEBUG("no eng_ctx to free"); + return; + } + + if (eng_ctx->qlist != NULL) { + if (eng_ctx->ctx != NULL) + wcrypto_del_dh_ctx(eng_ctx->ctx); + kae_put_node_to_pool(g_hpre_dh_qnode_pool, eng_ctx->qlist); + } + + hpre_dh_free_opdata(eng_ctx); + + eng_ctx->priv_ctx.block_addr = NULL; + eng_ctx->priv_ctx.ssl_alg = NULL; + eng_ctx->qlist = NULL; + eng_ctx->ctx = NULL; + eng_ctx->opdata.pri = NULL; + eng_ctx->opdata.x_p = NULL; + eng_ctx->opdata.pv = NULL; + OPENSSL_free(eng_ctx); + eng_ctx = NULL; +} + +static int hpre_internal_do_dh(hpre_dh_engine_ctx_t *eng_ctx, enum wcrypto_dh_op_type op_type) +{ + int job_ret; + op_done_t op_done; + + async_init_op_done_v1(&op_done); + + eng_ctx->opdata.op_type = op_type; + if (op_done.job != NULL && kae_is_async_enabled()) { + if (async_setup_async_event_notification_v1(0) == 0) { + US_ERR("hpre async event notifying failed"); + async_cleanup_op_done_v1(&op_done); + return OPENSSL_FAIL; + } + } else { + US_DEBUG("hpre dh no async Job or async disable, back to sync!"); + async_cleanup_op_done_v1(&op_done); + return hpre_dh_internal_do(eng_ctx->ctx, &eng_ctx->opdata); + } + + if (hpre_dh_async(eng_ctx, &eng_ctx->opdata, &op_done) == OPENSSL_FAIL) + goto err; + + do { + job_ret = async_pause_job_v1(op_done.job, ASYNC_STATUS_OK); + if (job_ret == 0) { + US_DEBUG("- pthread_yidle -"); + kae_pthread_yield(); + } + } while (!op_done.flag || ASYNC_CHK_JOB_RESUMED_UNEXPECTEDLY(job_ret)); + + if (op_done.verifyRst <= 0) { + US_ERR("hpre dh verify result failed with %d", op_done.verifyRst); + async_cleanup_op_done_v1(&op_done); + return OPENSSL_FAIL; + } + + async_cleanup_op_done_v1(&op_done); + + US_DEBUG("hpre dh do async job success!"); + return OPENSSL_SUCCESS; + +err: + US_ERR("hpre dh do async job err"); + (void)async_clear_async_event_notification_v1(); + async_cleanup_op_done_v1(&op_done); + return OPENSSL_FAIL; +} + +static void hpre_dh_free_opdata(hpre_dh_engine_ctx_t *eng_ctx) +{ + if (eng_ctx->priv_ctx.block_addr != NULL) { + if (eng_ctx->qlist != NULL) + eng_ctx->dh_setup.br.free(eng_ctx->qlist->kae_queue_mem_pool, eng_ctx->priv_ctx.block_addr); + } +} + +static hpre_dh_engine_ctx_t *hpre_dh_new_eng_ctx(DH *alg) +{ + hpre_dh_engine_ctx_t *eng_ctx = NULL; + + eng_ctx = (hpre_dh_engine_ctx_t *)OPENSSL_malloc(sizeof(hpre_dh_engine_ctx_t)); + if (eng_ctx == NULL) { + US_ERR("hpre engine_ctx malloc fail"); + return NULL; + } + kae_memset(eng_ctx, 0, sizeof(hpre_dh_engine_ctx_t)); + + eng_ctx->priv_ctx.ssl_alg = alg; + eng_ctx->qlist = kae_get_node_from_pool(g_hpre_dh_qnode_pool); + if (eng_ctx->qlist == NULL) { + US_ERR_LIMIT("error. get hardware queue failed"); + OPENSSL_free(eng_ctx); + eng_ctx = NULL; + return NULL; + } + return eng_ctx; +} + +static void hpre_dh_cb(const void *message, void *tag) +{ + if (!message || !tag) { + US_ERR("hpre cb params err!\n"); + return; + } + struct wcrypto_dh_msg *msg = (struct wcrypto_dh_msg *)message; + hpre_dh_engine_ctx_t *eng_ctx = (hpre_dh_engine_ctx_t *)tag; + + eng_ctx->opdata.pri = msg->out; + eng_ctx->opdata.pri_bytes = msg->out_bytes; + eng_ctx->opdata.status = msg->result; +} + +static int hpre_dh_init_eng_ctx(hpre_dh_engine_ctx_t *eng_ctx, int bits, bool is_g2) +{ + struct wd_queue *q = eng_ctx->qlist->kae_wd_queue; + struct wd_queue_mempool *pool = eng_ctx->qlist->kae_queue_mem_pool; + + // this is for ctx is in use.we dont need to re create ctx->ctx again + if (eng_ctx->ctx) + return OPENSSL_SUCCESS; + if (eng_ctx->ctx == NULL) { + if (bits == 0) + eng_ctx->priv_ctx.key_size = DH_size(eng_ctx->priv_ctx.ssl_alg); + else + eng_ctx->priv_ctx.key_size = bits >> CHAR_BIT_SIZE; + eng_ctx->priv_ctx.block_addr = NULL; + eng_ctx->dh_setup.key_bits = eng_ctx->priv_ctx.key_size << CHAR_BIT_SIZE; + eng_ctx->dh_setup.cb = hpre_dh_cb; + eng_ctx->dh_setup.br.alloc = kae_wd_alloc_blk; + eng_ctx->dh_setup.br.free = kae_wd_free_blk; + eng_ctx->dh_setup.br.iova_map = kae_dma_map; + eng_ctx->dh_setup.br.iova_unmap = kae_dma_unmap; + eng_ctx->dh_setup.br.usr = pool; + eng_ctx->dh_setup.is_g2 = is_g2; + eng_ctx->ctx = wcrypto_create_dh_ctx(q, &eng_ctx->dh_setup); + if (eng_ctx->ctx == NULL) { + US_ERR("create dh ctx fail!"); + return OPENSSL_FAIL; + } + } + + return OPENSSL_SUCCESS; +} + +static int hpre_dh_set_g(const BIGNUM *g, const int key_size, unsigned char *ag_bin, hpre_dh_engine_ctx_t *engine_ctx) +{ + struct wd_dtb g_dtb; + int ret; + __u32 gbytes = BN_bn2bin(g, ag_bin); + + g_dtb.data = (char *)ag_bin; + g_dtb.bsize = key_size; + g_dtb.dsize = gbytes; + + ret = wcrypto_set_dh_g(engine_ctx->ctx, &g_dtb); + if (ret) { + US_ERR("wcrypto_set_dh_g fail: %d", ret); + return OPENSSL_FAIL; + } + return OPENSSL_SUCCESS; +} + +static int hpre_dh_fill_g_p_priv_key( + const BIGNUM *g, const BIGNUM *p, const BIGNUM *priv_key, hpre_dh_engine_ctx_t *engine_ctx, unsigned char *ag_bin) +{ + unsigned char *apriv_key_bin = NULL; + unsigned char *ap_bin = NULL; + int key_size = engine_ctx->priv_ctx.key_size; + int ret = 0; + + apriv_key_bin = ag_bin + key_size; + ap_bin = apriv_key_bin + key_size; + memset(ag_bin, 0, key_size * DH_PARAMS_CNT); + + // construct data block of g + ret = hpre_dh_set_g(g, key_size, ag_bin, engine_ctx); + if (ret != OPENSSL_SUCCESS) + return OPENSSL_FAIL; + + // construct data block of p and private key + engine_ctx->opdata.pbytes = BN_bn2bin(p, ap_bin); + engine_ctx->opdata.xbytes = BN_bn2bin(priv_key, apriv_key_bin); + + engine_ctx->opdata.x_p = apriv_key_bin; + engine_ctx->opdata.pri = ap_bin + key_size; + + return OPENSSL_SUCCESS; +} + +static int hpre_dh_internal_do(void *ctx, struct wcrypto_dh_op_data *opdata) +{ + int ret = wcrypto_do_dh(ctx, opdata, NULL); + + if (ret) { + US_ERR("wcrypto_do_dh fail: %d", ret); + return OPENSSL_FAIL; + } else if (opdata->pri == NULL) { + US_ERR("output is empty"); + return OPENSSL_FAIL; + } else { + return OPENSSL_SUCCESS; + } +} + +static int hpre_dh_fill_pub_key(const BIGNUM *pub_key, hpre_dh_engine_ctx_t *engine_ctx, unsigned char *ag_bin) +{ + engine_ctx->opdata.pvbytes = BN_bn2bin(pub_key, ag_bin); + engine_ctx->opdata.pv = ag_bin; /* bob's public key here */ + return OPENSSL_SUCCESS; +} + +static int hpre_dh_async(hpre_dh_engine_ctx_t *eng_ctx, struct wcrypto_dh_op_data *opdata, op_done_t *op_done) +{ + int ret = 0; + int cnt = 0; + enum task_type_wd type = ASYNC_TASK_WD_DH; + void *tag = eng_ctx; + + do { + if (cnt > MAX_SEND_TRY_CNTS) + break; + ret = wcrypto_do_dh(eng_ctx->ctx, opdata, tag); + if (ret == WD_STATUS_BUSY) { + if ((async_wake_job_v1(op_done->job, ASYNC_STATUS_EAGAIN) == 0 || + (async_pause_job_v1(op_done->job, ASYNC_STATUS_EAGAIN) == 0))) { + US_ERR("hpre wake job or hpre pause job fail!"); + ret = 0; + break; + } + cnt++; + } + } while (ret == WD_STATUS_BUSY); + + if (ret != WD_SUCCESS) + return OPENSSL_FAIL; + + if (async_add_poll_task_v1(eng_ctx, op_done, type) == 0) + return OPENSSL_FAIL; + + return OPENSSL_SUCCESS; +} diff --git a/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_dh_wd.h b/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_dh_wd.h new file mode 100644 index 0000000000000000000000000000000000000000..f4115381b151baa1bd101e943a130aa52ad50a32 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_dh_wd.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides wd api for DH. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HPRE_DH_WD_H +#define HPRE_DH_WD_H + +#include +#include +#include "../../wdwarp/wd_queue_memory.h" + +struct hpre_dh_priv_ctx { + DH *ssl_alg; + int key_size; + unsigned char *block_addr; +}; + +typedef struct hpre_dh_priv_ctx hpre_dh_priv_ctx_t; + +struct hpre_dh_engine_ctx { + void *ctx; + struct wcrypto_dh_op_data opdata; + struct wcrypto_dh_ctx_setup dh_setup; + struct KAE_QUEUE_DATA_NODE *qlist; + hpre_dh_priv_ctx_t priv_ctx; +}; + +typedef struct hpre_dh_engine_ctx hpre_dh_engine_ctx_t; + +extern KAE_QUEUE_POOL_HEAD_S *g_hpre_dh_qnode_pool; + +int wd_hpre_dh_init_qnode_pool(void); +void wd_hpre_dh_uninit_qnode_pool(void); + +KAE_QUEUE_POOL_HEAD_S *wd_hpre_dh_get_qnode_pool(void); + +void hpre_dh_free_eng_ctx(hpre_dh_engine_ctx_t *eng_ctx); + +hpre_dh_engine_ctx_t *hpre_dh_get_eng_ctx(DH *dh, int bits, bool is_g2); + +/* + * fill opdata for generate_key. + */ +int hpre_dh_fill_genkey_opdata( + const BIGNUM *g, const BIGNUM *p, const BIGNUM *priv_key, hpre_dh_engine_ctx_t *engine_ctx); + +/* + * fill opdata for compute_key. + */ +int hpre_dh_fill_compkey_opdata( + const BIGNUM *g, const BIGNUM *p, const BIGNUM *priv_key, const BIGNUM *pub_key, hpre_dh_engine_ctx_t *engine_ctx); + +/* + * call wd API for generating public key. + */ +int hpre_dh_genkey(hpre_dh_engine_ctx_t *engine_ctx); + +/* + * call wd API for generating secret key. + */ +int hpre_dh_compkey(hpre_dh_engine_ctx_t *engine_ctx); + +/* + * get public key from engine ctx. + */ +int hpre_dh_get_pubkey(hpre_dh_engine_ctx_t *engine_ctx, BIGNUM **pubkey); + +/* + * get secret key from engine ctx. + */ +int hpre_dh_get_output_chars(hpre_dh_engine_ctx_t *engine_ctx, unsigned char *out); + +#endif diff --git a/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_rsa.c b/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_rsa.c new file mode 100644 index 0000000000000000000000000000000000000000..420badce40622da73ab62204d5db2da4918777a3 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_rsa.c @@ -0,0 +1,527 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the implementation for KAE engine rsa + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "hpre_rsa.h" +#include "hpre_rsa_utils.h" +#include "hpre_rsa_wd.h" +#include "hpre_dh.h" +#include "hpre_sm2.h" +#include "../../async/async_poll.h" +#include "../../../common/kae_types.h" +#include "../../../common/kae_log.h" + +#ifndef OPENSSL_NO_RSA +const int RSAPKEYMETH_IDX; +#else +const int RSAPKEYMETH_IDX = -1; +#endif + +// lint -save -e506 +#undef GOTOEND_IF +#define GOTOEND_IF(cond, mesg, f, r) \ + do { \ + if (cond) { \ + KAEerr(f, r); \ + US_ERR(mesg); \ + ret = OPENSSL_FAIL; \ + goto end; \ + } \ + } while (0) + +int hpre_rsa_ctx_poll(void *engine_ctx) +{ + int ret; + hpre_rsa_ctx_t *eng_ctx = (hpre_rsa_ctx_t *)engine_ctx; + struct wd_queue *q = eng_ctx->qlist->kae_wd_queue; + +poll_again: + ret = wcrypto_rsa_poll(q, 1); + if (!ret) { + goto poll_again; + } else if (ret < 0) { + US_ERR("rsa poll fail!\n"); + return ret; + } + return ret; +} + +int hpre_module_rsa_init(void) +{ + wd_hpre_init_qnode_pool(); + /* register async poll func */ + async_register_poll_fn_v1(ASYNC_TASK_WD_RSA, hpre_rsa_ctx_poll); + + return 1; +} + +static int hpre_rsa_check(const int flen, const BIGNUM *n, const BIGNUM *e, int *num_bytes, RSA *rsa) +{ + int key_bits; + + if (n == NULL || e == NULL) + return OPENSSL_FAIL; + + if (check_pubkey_param(n, e) != OPENSSL_SUCCESS) + return OPENSSL_FAIL; + + *num_bytes = BN_num_bytes(n); + if (flen > *num_bytes) { + KAEerr(KAE_F_HPRE_RSA_PUBDEC, KAE_R_DATA_GREATER_THEN_MOD_LEN); + US_WARN("data length is large than num bytes of rsa->n"); + return OPENSSL_FAIL; + } + + key_bits = RSA_bits(rsa); + if (!check_bit_useful(key_bits)) { + US_WARN("op sizes not supported by hpre engine then back to soft!"); + return OPENSSL_FAIL; + } + + return OPENSSL_SUCCESS; +} + +static int hpre_rsa_new_bn( + const BIGNUM *n, int flen, const unsigned char *from, BN_CTX **bn_ctx, BIGNUM **bn_ret, BIGNUM **f) +{ + BN_CTX *bn_ctx_tmp; + BIGNUM *bn_ret_tmp = NULL; + BIGNUM *f_tmp = NULL; + + bn_ctx_tmp = BN_CTX_new(); + if (bn_ctx_tmp == NULL) { + US_ERR("fail to new BN_CTX."); + return OPENSSL_FAIL; + } + + BN_CTX_start(bn_ctx_tmp); + bn_ret_tmp = BN_CTX_get(bn_ctx_tmp); + f_tmp = BN_CTX_get(bn_ctx_tmp); + if (bn_ret_tmp == NULL || f_tmp == NULL) { + US_ERR("fail to get BN_CTX."); + return OPENSSL_FAIL; + } + + if (BN_bin2bn(from, flen, f_tmp) == NULL) { + US_ERR("fail to bin2bn"); + return OPENSSL_FAIL; + } + + if (BN_ucmp(f_tmp, n) >= 0) { + US_ERR("data is too large"); + return OPENSSL_FAIL; + } + *bn_ctx = bn_ctx_tmp; + *bn_ret = bn_ret_tmp; + *f = f_tmp; + return OPENSSL_SUCCESS; +} + +int hpre_rsa_keygen(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb) +{ + struct wcrypto_rsa_pubkey *pubkey = NULL; + struct wcrypto_rsa_prikey *prikey = NULL; + struct wd_dtb *wd_e = NULL; + struct wd_dtb *wd_p = NULL; + struct wd_dtb *wd_q = NULL; + BIGNUM *e_value = NULL; + BIGNUM *p = NULL; + BIGNUM *q = NULL; + hpre_rsa_ctx_t *eng_ctx; + int ret; + + if (bits < RSA_MIN_MODULUS_BITS) { + US_ERR("rsa key size too small"); + return OPENSSL_FAIL; + } + if (!check_bit_useful(bits)) { + US_WARN("op sizes not supported by hpre engine then back to soft!"); + return OPENSSL_FAIL; + } + if ((eng_ctx = hpre_get_rsa_eng_ctx(rsa, bits, 1)) == NULL) { + US_WARN("get eng ctx fail then switch to soft!"); + return KAE_CRYPTO_FAIL; + } + + e_value = BN_new(); + p = BN_new(); + q = BN_new(); + + GOTOEND_IF(e_value == NULL || p == NULL || q == NULL, + "e_value or p or q MALLOC FAILED.", + KAE_F_HPRE_RSA_KEYGEN, + KAE_R_ERR_LIB_BN); + GOTOEND_IF(hpre_rsa_primegen(bits, e, p, q, cb) == OPENSSL_FAIL, + "hisi_rsa_primegen failed", + KAE_F_HPRE_RSA_KEYGEN, + KAE_R_GET_PRIMEKEY_FAILURE); + GOTOEND_IF(BN_copy(e_value, e) == NULL, "copy e failed", KAE_F_HPRE_RSA_KEYGEN, KAE_R_ERR_LIB_BN); + + wcrypto_get_rsa_pubkey(eng_ctx->ctx, &pubkey); + wcrypto_get_rsa_pubkey_params(pubkey, &wd_e, NULL); + wd_e->dsize = BN_bn2bin(e_value, (unsigned char *)wd_e->data); + wcrypto_get_rsa_prikey(eng_ctx->ctx, &prikey); + wcrypto_get_rsa_crt_prikey_params(prikey, NULL, NULL, NULL, &wd_q, &wd_p); + wd_q->dsize = BN_bn2bin(q, (unsigned char *)wd_q->data); + wd_p->dsize = BN_bn2bin(p, (unsigned char *)wd_p->data); + + eng_ctx->opdata.in_bytes = eng_ctx->priv_ctx.key_size; + eng_ctx->opdata.op_type = WCRYPTO_RSA_GENKEY; + ret = hpre_fill_keygen_opdata(eng_ctx->ctx, &eng_ctx->opdata); + if (ret != KAE_SUCCESS) { + US_WARN("hpre fill keygen opdata failed"); + ret = KAE_CRYPTO_FAIL; + goto end; + } + ret = hpre_rsa_sync(eng_ctx->ctx, &eng_ctx->opdata); + if (ret == OPENSSL_FAIL) { + US_WARN("hpre generate rsa key failed.switch to soft"); + goto end; + } + ret = hpre_rsa_get_keygen_param(&eng_ctx->opdata, eng_ctx->ctx, rsa, e_value, p, q); + + US_DEBUG("hpre rsa keygen success!"); + +end: + hpre_free_rsa_eng_ctx(eng_ctx); + + return ret; +} + +int hpre_rsa_private_encrypt(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) +{ + hpre_rsa_ctx_t *eng_ctx = NULL; + BIGNUM *f = NULL; + BIGNUM *bn_ret = NULL; + BN_CTX *bn_ctx = NULL; + BIGNUM *res = (BIGNUM *)NULL; + const BIGNUM *n = (const BIGNUM *)NULL; + const BIGNUM *e = (const BIGNUM *)NULL; + const BIGNUM *d = (const BIGNUM *)NULL; + const BIGNUM *p = (const BIGNUM *)NULL; + const BIGNUM *q = (const BIGNUM *)NULL; + const BIGNUM *dmp1 = (const BIGNUM *)NULL; + const BIGNUM *dmq1 = (const BIGNUM *)NULL; + const BIGNUM *iqmp = (const BIGNUM *)NULL; + unsigned char *in_buf = (unsigned char *)NULL; + int num_bytes = 0; + int key_bits; + int version; + int ret; + + if (hpre_rsa_check_param(flen, from, to, rsa) != OPENSSL_SUCCESS) + return OPENSSL_FAIL; + + key_bits = RSA_bits(rsa); + if (!check_bit_useful(key_bits)) { + US_WARN("op sizes not supported by hpre engine then back to soft!"); + return OPENSSL_FAIL; + } + + if ((eng_ctx = hpre_get_rsa_eng_ctx(rsa, 0, 0)) == NULL) { + US_WARN("get eng ctx fail then switch to soft!"); + return KAE_CRYPTO_FAIL; + } + + bn_ctx = BN_CTX_new(); + + GOTOEND_IF(bn_ctx == NULL, "PRI_ENC MALLOC_FAILURE ", KAE_F_HPRE_RSA_PRIENC, KAE_R_MALLOC_FAILURE); + + BN_CTX_start(bn_ctx); + f = BN_CTX_get(bn_ctx); + bn_ret = BN_CTX_get(bn_ctx); + + RSA_get0_factors(rsa, &p, &q); + RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp); + RSA_get0_key(rsa, &n, &e, &d); + version = RSA_get_version(rsa); + num_bytes = BN_num_bytes(n); + + in_buf = (unsigned char *)OPENSSL_malloc(num_bytes); + GOTOEND_IF(bn_ret == NULL || in_buf == NULL, "OpenSSL malloc failure", KAE_F_HPRE_RSA_PRIENC, KAE_R_MALLOC_FAILURE); + + ret = hpre_rsa_padding(flen, from, in_buf, num_bytes, padding, PRI_ENC); + GOTOEND_IF(ret == OPENSSL_FAIL, "RSA PADDING FAILED!", KAE_F_HPRE_RSA_PRIENC, KAE_R_RSA_PADDING_FAILURE); + + hpre_rsa_fill_pubkey(e, n, eng_ctx); + hpre_rsa_fill_prikey(rsa, eng_ctx, version, p, q, dmp1, dmq1, iqmp); + + eng_ctx->opdata.in_bytes = eng_ctx->priv_ctx.key_size; + eng_ctx->opdata.op_type = WCRYPTO_RSA_SIGN; + eng_ctx->opdata.in = + eng_ctx->rsa_setup.br.alloc(eng_ctx->qlist->kae_queue_mem_pool, eng_ctx->qlist->kae_queue_mem_pool->block_size); + eng_ctx->opdata.out = + eng_ctx->rsa_setup.br.alloc(eng_ctx->qlist->kae_queue_mem_pool, eng_ctx->qlist->kae_queue_mem_pool->block_size); + kae_memcpy(eng_ctx->opdata.in, in_buf, eng_ctx->opdata.in_bytes); + + ret = hpre_rsa_crypto(eng_ctx, &eng_ctx->opdata); + if (ret == OPENSSL_FAIL) { + US_WARN("hpre rsa priv encrypt failed!"); + goto end; + } + + BN_bin2bn((const unsigned char *)eng_ctx->opdata.out, eng_ctx->opdata.out_bytes, bn_ret); + + if (hpre_get_prienc_res(padding, f, n, bn_ret, &res) == OPENSSL_FAIL) + goto end; + + ret = BN_bn2binpad(res, to, num_bytes); + + US_DEBUG("hpre rsa priv encrypt success!"); + +end: + hpre_free_bn_ctx_buf(bn_ctx, in_buf, num_bytes); + hpre_free_rsa_eng_ctx(eng_ctx); + + return ret; +} + +int hpre_rsa_public_encrypt(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) +{ + const BIGNUM *n = NULL; + const BIGNUM *e = NULL; + const BIGNUM *d = NULL; + BIGNUM *ret_bn = NULL; + hpre_rsa_ctx_t *eng_ctx = NULL; + unsigned char *in_buf = NULL; + BN_CTX *bn_ctx = NULL; + int num_bytes = 0; + int key_bits; + int ret; + + if (!to) + return RSA_size(rsa); + + if (hpre_rsa_check_param(flen, from, to, rsa) != OPENSSL_SUCCESS) + return OPENSSL_FAIL; + + key_bits = RSA_bits(rsa); + if (!check_bit_useful(key_bits)) { + US_WARN("op sizes not supported by hpre engine then back to soft!"); + return OPENSSL_FAIL; + } + + if ((eng_ctx = hpre_get_rsa_eng_ctx(rsa, 0, 0)) == NULL) { + US_WARN("get eng ctx fail then switch to soft!"); + return KAE_CRYPTO_FAIL; + } + + RSA_get0_key(rsa, &n, &e, &d); + ret = check_pubkey_param(n, e); + GOTOEND_IF(ret != OPENSSL_SUCCESS, "check public key fail", KAE_F_HPRE_RSA_PUBENC, KAE_R_PUBLIC_KEY_INVALID); + + bn_ctx = BN_CTX_new(); + + GOTOEND_IF(bn_ctx == NULL, "bn_ctx MALLOC FAILED!", KAE_F_HPRE_RSA_PUBENC, KAE_R_MALLOC_FAILURE); + BN_CTX_start(bn_ctx); + ret_bn = BN_CTX_get(bn_ctx); + num_bytes = BN_num_bytes(n); + in_buf = (unsigned char *)OPENSSL_malloc(num_bytes); + + GOTOEND_IF(ret_bn == NULL || in_buf == NULL, + "PUBLIC_ENCRYPT RSA MALLOC FAILED!", + KAE_F_HPRE_RSA_PUBENC, + KAE_R_MALLOC_FAILURE); + + ret = hpre_rsa_padding(flen, from, in_buf, num_bytes, padding, PUB_ENC); + GOTOEND_IF(ret == OPENSSL_FAIL, "RSA PADDING FAILED", KAE_F_HPRE_RSA_PUBENC, KAE_R_RSA_PADDING_FAILURE); + + hpre_rsa_fill_pubkey(e, n, eng_ctx); + eng_ctx->opdata.in_bytes = eng_ctx->priv_ctx.key_size; + eng_ctx->opdata.op_type = WCRYPTO_RSA_VERIFY; + eng_ctx->opdata.in = + eng_ctx->rsa_setup.br.alloc(eng_ctx->qlist->kae_queue_mem_pool, eng_ctx->qlist->kae_queue_mem_pool->block_size); + eng_ctx->opdata.out = + eng_ctx->rsa_setup.br.alloc(eng_ctx->qlist->kae_queue_mem_pool, eng_ctx->qlist->kae_queue_mem_pool->block_size); + kae_memcpy(eng_ctx->opdata.in, in_buf, eng_ctx->opdata.in_bytes); + + ret = hpre_rsa_crypto(eng_ctx, &eng_ctx->opdata); + GOTOEND_IF( + ret == OPENSSL_FAIL, "hpre rsa pub encrypt failed!", KAE_F_HPRE_RSA_PUBENC, KAE_R_PUBLIC_ENCRYPTO_FAILURE); + + BN_bin2bn((const unsigned char *)eng_ctx->opdata.out, eng_ctx->opdata.out_bytes, ret_bn); + ret = BN_bn2binpad(ret_bn, to, num_bytes); + + US_DEBUG("hpre rsa public encrypt success!"); + +end: + hpre_free_bn_ctx_buf(bn_ctx, in_buf, num_bytes); + hpre_free_rsa_eng_ctx(eng_ctx); + + return ret; +} + +int hpre_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) +{ + hpre_rsa_ctx_t *eng_ctx = NULL; + const BIGNUM *n = (const BIGNUM *)NULL; + const BIGNUM *e = (const BIGNUM *)NULL; + const BIGNUM *d = (const BIGNUM *)NULL; + const BIGNUM *p = (const BIGNUM *)NULL; + const BIGNUM *q = (const BIGNUM *)NULL; + const BIGNUM *dmp1 = (const BIGNUM *)NULL; + const BIGNUM *dmq1 = (const BIGNUM *)NULL; + const BIGNUM *iqmp = (const BIGNUM *)NULL; + BIGNUM *bn_ret = NULL; + BIGNUM *f = NULL; + BN_CTX *bn_ctx = NULL; + unsigned char *buf = (unsigned char *)NULL; + int num_bytes, key_bits, version; + int ret, len; + + if (hpre_rsa_check_param(flen, from, to, rsa) != OPENSSL_SUCCESS) + return OPENSSL_FAIL; + + RSA_get0_key(rsa, &n, &e, &d); + num_bytes = BN_num_bytes(n); + if (flen > num_bytes) { + US_ERR("flen is no equal to num_byte"); + return OPENSSL_FAIL; + } + + key_bits = RSA_bits(rsa); + if (!check_bit_useful(key_bits)) { + US_WARN("op sizes not supported by hpre engine then switch soft!"); + return KAE_CRYPTO_FAIL; + } + + if ((eng_ctx = hpre_get_rsa_eng_ctx(rsa, 0, 0)) == NULL) { + US_WARN("get eng ctx fail then switch to soft!"); + return KAE_CRYPTO_FAIL; + } + + ret = hpre_rsa_new_bn(n, flen, from, &bn_ctx, &bn_ret, &f); + if (ret == OPENSSL_FAIL) { + goto end; + } + + RSA_get0_factors(rsa, &p, &q); + RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp); + version = RSA_get_version(rsa); + buf = (unsigned char *)OPENSSL_malloc(num_bytes); + + hpre_rsa_fill_pubkey(e, n, eng_ctx); + hpre_rsa_fill_prikey(rsa, eng_ctx, version, p, q, dmp1, dmq1, iqmp); + + eng_ctx->opdata.in_bytes = eng_ctx->priv_ctx.key_size; + eng_ctx->opdata.op_type = WCRYPTO_RSA_SIGN; + eng_ctx->opdata.in = + eng_ctx->rsa_setup.br.alloc(eng_ctx->qlist->kae_queue_mem_pool, eng_ctx->qlist->kae_queue_mem_pool->block_size); + eng_ctx->opdata.out = + eng_ctx->rsa_setup.br.alloc(eng_ctx->qlist->kae_queue_mem_pool, eng_ctx->qlist->kae_queue_mem_pool->block_size); + kae_memcpy(eng_ctx->opdata.in, from, eng_ctx->opdata.in_bytes); + + ret = hpre_rsa_crypto(eng_ctx, &eng_ctx->opdata); + if (ret == OPENSSL_FAIL) { + US_WARN("hpre rsa priv decrypt failed."); + goto end; + } + + BN_bin2bn((const unsigned char *)eng_ctx->opdata.out, eng_ctx->opdata.out_bytes, bn_ret); + len = BN_bn2binpad(bn_ret, buf, num_bytes); + ret = check_rsa_padding(to, num_bytes, buf, len, padding, PRI_DEC); + if (ret == OPENSSL_FAIL) { + US_WARN("hpre rsa check padding failed."); + goto end; + } + + US_DEBUG("hpre rsa priv decrypt success!"); + +end: + hpre_free_bn_ctx_buf(bn_ctx, buf, num_bytes); + hpre_free_rsa_eng_ctx(eng_ctx); + + return ret; +} + +int hpre_rsa_public_decrypt(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) +{ + hpre_rsa_ctx_t *eng_ctx = NULL; + BN_CTX *bn_ctx = NULL; + BIGNUM *f = NULL; + BIGNUM *bn_ret = NULL; + const BIGNUM *n = NULL; + const BIGNUM *e = NULL; + const BIGNUM *d = NULL; + int num_bytes = 0; + unsigned char *buf = NULL; + int ret, len; + + if (!to) + return RSA_size(rsa); + + if (hpre_rsa_check_param(flen, from, to, rsa) != OPENSSL_SUCCESS) + return KAE_CRYPTO_FAIL; + + RSA_get0_key(rsa, &n, &e, &d); + ret = hpre_rsa_check(flen, n, e, &num_bytes, rsa); + if (ret == OPENSSL_FAIL) { + return ret; + } + + if ((eng_ctx = hpre_get_rsa_eng_ctx(rsa, 0, 0)) == NULL) { + US_WARN("get eng ctx fail then switch to soft!"); + return KAE_CRYPTO_FAIL; + } + + ret = hpre_rsa_new_bn(n, flen, from, &bn_ctx, &bn_ret, &f); + if (ret == OPENSSL_FAIL) { + goto end; + } + + buf = (unsigned char *)OPENSSL_malloc(num_bytes); + if (buf == NULL) { + ret = OPENSSL_FAIL; + goto end; + } + + hpre_rsa_fill_pubkey(e, n, eng_ctx); + eng_ctx->opdata.in_bytes = eng_ctx->priv_ctx.key_size; + eng_ctx->opdata.op_type = WCRYPTO_RSA_VERIFY; + eng_ctx->opdata.in = + eng_ctx->rsa_setup.br.alloc(eng_ctx->qlist->kae_queue_mem_pool, eng_ctx->qlist->kae_queue_mem_pool->block_size); + eng_ctx->opdata.out = + eng_ctx->rsa_setup.br.alloc(eng_ctx->qlist->kae_queue_mem_pool, eng_ctx->qlist->kae_queue_mem_pool->block_size); + kae_memcpy(eng_ctx->opdata.in, from, eng_ctx->opdata.in_bytes); + + ret = hpre_rsa_crypto(eng_ctx, &eng_ctx->opdata); + GOTOEND_IF( + ret == OPENSSL_FAIL, "hpre rsa pub decrypt failed!", KAE_F_HPRE_RSA_PUBDEC, KAE_R_PUBLIC_DECRYPTO_FAILURE); + + BN_bin2bn((const unsigned char *)eng_ctx->opdata.out, eng_ctx->opdata.out_bytes, bn_ret); + if ((padding == RSA_X931_PADDING) && ((bn_get_words(bn_ret)[0] & 0xf) != 12)) { // not 12 then BN_sub + GOTOEND_IF(!BN_sub(bn_ret, n, bn_ret), "BN_sub failed", KAE_F_HPRE_RSA_PUBDEC, KAE_R_ERR_LIB_BN); + } + len = BN_bn2binpad(bn_ret, buf, num_bytes); + ret = check_rsa_padding(to, num_bytes, buf, len, padding, PUB_DEC); + if (ret == OPENSSL_FAIL) { + US_WARN("hpre rsa check padding failed.switch to soft"); + goto end; + } + + US_DEBUG("hpre rsa public decrypt success!"); + +end: + hpre_free_bn_ctx_buf(bn_ctx, buf, num_bytes); + hpre_free_rsa_eng_ctx(eng_ctx); + + return ret; +} \ No newline at end of file diff --git a/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_rsa.h b/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_rsa.h new file mode 100644 index 0000000000000000000000000000000000000000..96b58b202beb68b479b6c9cc162f09fbe59d9c19 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_rsa.h @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the implementation for KAE rsa using wd interface + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HPRE_RSA_H +#define HPRE_RSA_H + +#include +#include + +#include +#include +#include +#include + +#include "../../../common/kae_opensslerr.h" +#include "../../../common/kae_utils.h" + +#define RSA_MIN_MODULUS_BITS 512 + +#define RSA1024BITS 1024 +#define RSA2048BITS 2048 +#define RSA3072BITS 3072 +#define RSA4096BITS 4096 + +enum { + INVALID = 0, + PUB_ENC, + PUB_DEC, + PRI_ENC, + PRI_DEC, + MAX_CODE, +}; + +struct bignum_st { + BN_ULONG *d; + int top; + int dmax; + int neg; + int flags; +}; + +typedef int CRYPTO_REF_COUNT; + +typedef struct rsa_pss_params_30_st { + int hash_algorithm_nid; + struct { + int algorithm_nid; /* Currently always NID_mgf1 */ + int hash_algorithm_nid; + } mask_gen; + int salt_len; + int trailer_field; +} RSA_PSS_PARAMS_30; + +struct rsa_st { + /* + * #legacy + * The first field is used to pickup errors where this is passed + * instead of an EVP_PKEY. It is always zero. + * THIS MUST REMAIN THE FIRST FIELD. + */ + int dummy_zero; + + OSSL_LIB_CTX *libctx; + int32_t version; + const RSA_METHOD *meth; + /* functional reference if 'meth' is ENGINE-provided */ + ENGINE *engine; + BIGNUM *n; + BIGNUM *e; + BIGNUM *d; + BIGNUM *p; + BIGNUM *q; + BIGNUM *dmp1; + BIGNUM *dmq1; + BIGNUM *iqmp; + + /* + * If a PSS only key this contains the parameter restrictions. + * There are two structures for the same thing, used in different cases. + */ + /* This is used uniquely by OpenSSL provider implementations. */ + RSA_PSS_PARAMS_30 pss_params; + + /* This is used uniquely by rsa_ameth.c and rsa_pmeth.c. */ + RSA_PSS_PARAMS *pss; + /* for multi-prime RSA, defined in RFC 8017 */ + STACK_OF(RSA_PRIME_INFO) * prime_infos; + /* Be careful using this if the RSA structure is shared */ + CRYPTO_EX_DATA ex_data; + + int references; + int flags; + /* Used to cache montgomery values */ + BN_MONT_CTX *_method_mod_n; + BN_MONT_CTX *_method_mod_p; + BN_MONT_CTX *_method_mod_q; + BN_BLINDING *blinding; + BN_BLINDING *mt_blinding; + CRYPTO_RWLOCK *lock; + + int dirty_cnt; +}; + +struct rsa_gen_ctx { + OSSL_LIB_CTX *libctx; + const char *propq; + + int rsa_type; + + size_t nbits; + BIGNUM *pub_exp; + size_t primes; + + /* For PSS */ + RSA_PSS_PARAMS_30 pss_params; + int pss_defaults_set; + + /* For generation callback */ + OSSL_CALLBACK *cb; + void *cbarg; +}; + +typedef struct { + OSSL_LIB_CTX *libctx; + RSA *rsa; + int pad_mode; + int operation; + /* OAEP message digest */ + EVP_MD *oaep_md; + /* message digest for MGF1 */ + EVP_MD *mgf1_md; + /* OAEP label */ + unsigned char *oaep_label; + size_t oaep_labellen; + /* TLS padding */ + unsigned int client_version; + unsigned int alt_version; + +} PROV_RSA_ASYM_CTX; + +typedef struct { + OSSL_LIB_CTX *libctx; + char *propq; + RSA *rsa; + int operation; + + /* + * Flag to determine if the hash function can be changed (1) or not (0) + * Because it's dangerous to change during a DigestSign or DigestVerify + * operation, this flag is cleared by their Init function, and set again + * by their Final function. + */ + unsigned int flag_allow_md : 1; + unsigned int mgf1_md_set : 1; + + /* main digest */ + EVP_MD *md; + EVP_MD_CTX *mdctx; + int mdnid; + char mdname[50]; /* Purely informational */ + + /* RSA padding mode */ + int pad_mode; + /* message digest for MGF1 */ + EVP_MD *mgf1_md; + int mgf1_mdnid; + char mgf1_mdname[50]; /* Purely informational */ + /* PSS salt length */ + int saltlen; + /* Minimum salt length or -1 if no PSS parameter restriction */ + int min_saltlen; + + /* Temp buffer */ + unsigned char *tbuf; + +} PROV_RSA_SIG_CTX; + +int hpre_module_rsa_init(void); + +int hpre_rsa_public_encrypt(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding); + +int hpre_rsa_private_encrypt(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding); + +int hpre_rsa_public_decrypt(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding); + +int hpre_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding); + +int hpre_rsa_keygen(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb); + +#endif diff --git a/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_rsa_utils.c b/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_rsa_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..a087daef6aa0156a40a646690277653974f11544 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_rsa_utils.c @@ -0,0 +1,535 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the implementation for KAE engine utils dealing with wrapdrive + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include "hpre_rsa.h" +#include "hpre_rsa_wd.h" +#include "../../../common/kae_types.h" +#include "../../../common/kae_log.h" +#include "../../../common/kae_utils.h" + +BN_ULONG *bn_get_words(const BIGNUM *a) +{ + return a->d; +} + +void hpre_free_bn_ctx_buf(BN_CTX *bn_ctx, unsigned char *in_buf, int num) +{ + if (bn_ctx != NULL) + BN_CTX_end(bn_ctx); + BN_CTX_free(bn_ctx); + if (in_buf != NULL) + OPENSSL_clear_free(in_buf, num); +} + +/* check parameter */ +int hpre_rsa_check_param(int flen, const unsigned char *from, unsigned char *to, RSA *rsa) +{ + if ((rsa == NULL || from == NULL || to == NULL || flen <= 0)) { + US_ERR("RSA key %p, input %p or output %p are NULL, or flen invalid length.\n", rsa, from, to); + return OPENSSL_FAIL; + } + return OPENSSL_SUCCESS; +} + +int hpre_get_prienc_res(int padding, BIGNUM *f, const BIGNUM *n, BIGNUM *bn_ret, BIGNUM **res) +{ + if (padding == RSA_X931_PADDING) { + if (!BN_sub(f, n, bn_ret)) + return OPENSSL_FAIL; + if (BN_cmp(bn_ret, f) > 0) + *res = f; + else + *res = bn_ret; + } else { + *res = bn_ret; + } + return OPENSSL_SUCCESS; +} + +/** + * func: + * desc: + * Check HPRE rsa bits + * + * @param bit :rsa bit + * @return + * succ: 1 + * fail: 0 + */ +int check_bit_useful(const int bit) +{ + switch (bit) { + case RSA1024BITS: + case RSA2048BITS: + case RSA3072BITS: + case RSA4096BITS: + return 1; + default: + break; + } + return 0; +} + +/** + * + * @param n + * @param e + * @return success 1 / failed 0 + */ +int check_pubkey_param(const BIGNUM *n, const BIGNUM *e) +{ + if (BN_num_bits(n) > OPENSSL_RSA_MAX_MODULUS_BITS) { + KAEerr(KAE_F_CHECK_PUBKEY_PARAM, KAE_R_MODULE_TOO_LARGE); + US_ERR("RSA MODULUS TOO LARGE!"); + return OPENSSL_FAIL; + } + + if (BN_ucmp(n, e) <= 0) { + KAEerr(KAE_F_CHECK_PUBKEY_PARAM, KAE_R_INVAILED_E_VALUE); + US_ERR("RSA E VALUE IS NOT VALID!"); + return OPENSSL_FAIL; + } + + /* for large moduli, enforce exponent limit */ + if (BN_num_bits(n) > OPENSSL_RSA_SMALL_MODULUS_BITS) { + if (BN_num_bits(e) > OPENSSL_RSA_MAX_PUBEXP_BITS) { + KAEerr(KAE_F_CHECK_PUBKEY_PARAM, KAE_R_INVAILED_E_VALUE); + US_ERR("RSA E VALUE IS NOT VALID!"); + return OPENSSL_FAIL; + } + } + return OPENSSL_SUCCESS; +} + +static int hpre_pubenc_padding(int flen, const unsigned char *from, unsigned char *buf, int num, int padding) +{ + int ret = OPENSSL_FAIL; + + switch (padding) { + case RSA_PKCS1_PADDING: + ret = RSA_padding_add_PKCS1_type_2(buf, num, from, flen); + break; + case RSA_PKCS1_OAEP_PADDING: + ret = RSA_padding_add_PKCS1_OAEP(buf, num, from, flen, NULL, 0); + break; +#if OPENSSL_VERSION_NUMBER < 0x30000000 + case RSA_SSLV23_PADDING: + ret = RSA_padding_add_SSLv23(buf, num, from, flen); + break; +#endif + case RSA_NO_PADDING: + ret = RSA_padding_add_none(buf, num, from, flen); + break; + default: + KAEerr(KAE_F_HPRE_PUBENC_PADDING, KAE_R_UNKNOW_PADDING_TYPE); + US_ERR("RSA UNKNOWN PADDING TYPE!"); + ret = OPENSSL_FAIL; + } + if (ret <= 0) { + US_ERR("padding error: ret = %d", ret); + ret = OPENSSL_FAIL; + } else { + ret = OPENSSL_SUCCESS; + } + return ret; +} + +static int hpre_prienc_padding(int flen, const unsigned char *from, unsigned char *buf, int num, int padding) +{ + int ret = OPENSSL_FAIL; + + switch (padding) { + case RSA_PKCS1_PADDING: + ret = RSA_padding_add_PKCS1_type_1(buf, num, from, flen); + break; + case RSA_X931_PADDING: + ret = RSA_padding_add_X931(buf, num, from, flen); + break; + case RSA_NO_PADDING: + ret = RSA_padding_add_none(buf, num, from, flen); + break; + default: + KAEerr(KAE_F_HPRE_PRIENC_PADDING, KAE_R_UNKNOW_PADDING_TYPE); + US_ERR("RSA UNKNOWN PADDING TYPE!"); + ret = OPENSSL_FAIL; + } + if (ret <= 0) { + US_DEBUG("padding error: ret = %d", ret); + ret = OPENSSL_FAIL; + } else { + ret = OPENSSL_SUCCESS; + } + return ret; +} + +/** + * func: + * + * @param flen [IN] - size in bytes of input + * @param from [IN] - pointer to the input + * @param buf [OUT] - pointer to output data + * @param num [IN] - pointer to public key structure + * @param padding [IN] - Padding scheme + * @param type [IN] - Padding type + * @return + * SUCCESS: 1 + * FAIL: 0 + * desc: + * rsa encrypt padding. + * + */ +int hpre_rsa_padding( + int flen, const unsigned char *from, unsigned char *buf, int num, int padding, int type, EVP_MD *md) +{ + int ret = OPENSSL_FAIL; + + if (type == PUB_ENC) + return hpre_pubenc_padding(flen, from, buf, num, padding); + else if (type == PRI_ENC) + return hpre_prienc_padding(flen, from, buf, num, padding); + + US_ERR("hpre rsa padding type error."); + return ret; +} + +static int hpre_check_pubdec_padding(unsigned char *to, int num, const unsigned char *buf, int len, int padding) +{ + int ret = OPENSSL_FAIL; + + switch (padding) { + case RSA_PKCS1_PADDING: + ret = RSA_padding_check_PKCS1_type_1(to, num, buf, len, num); + break; + case RSA_X931_PADDING: + ret = RSA_padding_check_X931(to, num, buf, len, num); + break; + case RSA_NO_PADDING: + kae_memcpy(to, buf, len); + ret = len; + break; + default: + KAEerr(KAE_F_CHECK_HPRE_PUBDEC_PADDING, KAE_R_UNKNOW_PADDING_TYPE); + US_ERR("RSA UNKNOWN PADDING TYPE!"); + ret = OPENSSL_FAIL; + } + + if (ret == -1) { + US_ERR("FAIL ret = %d.", ret); + ret = OPENSSL_FAIL; + } + return ret; +} + +static int hpre_check_pridec_padding(unsigned char *to, int num, const unsigned char *buf, int len, int padding) +{ + int ret = OPENSSL_FAIL; + + switch (padding) { + case RSA_PKCS1_PADDING: + ret = RSA_padding_check_PKCS1_type_2(to, num, buf, len, num); + break; + case RSA_PKCS1_OAEP_PADDING: + ret = RSA_padding_check_PKCS1_OAEP(to, num, buf, len, num, NULL, 0); + break; +#if OPENSSL_VERSION_NUMBER < 0x30000000 + case RSA_SSLV23_PADDING: + ret = RSA_padding_check_SSLv23(to, num, buf, len, num); + break; +#endif + case RSA_NO_PADDING: + kae_memcpy(to, buf, len); + ret = len; + break; + default: + KAEerr(KAE_F_CHECK_HPRE_PRIDEC_PADDING, KAE_R_UNKNOW_PADDING_TYPE); + US_ERR("RSA UNKNOWN PADDING TYPE!"); + ret = OPENSSL_FAIL; + } + + if (ret == -1) { + US_ERR("FAIL ret = %d.", ret); + ret = OPENSSL_FAIL; + } + return ret; +} + +/** + * func: + * + * @param len [IN] - size in bytes of output + * @param to [IN] - pointer to the output + * @param buf [OUT] - pointer to output data + * @param num [IN] - pointer to public key structure + * @param padding [IN] - Padding scheme + * @param type [IN] - Padding type + * @return + * SUCCESS: 1 + * FAIL: 0 + * desc: + * rsa decrypt padding. + * + */ +int check_rsa_padding(unsigned char *to, int num, const unsigned char *buf, int len, int padding, int type) +{ + int ret = OPENSSL_FAIL; + + if (type == PUB_DEC) + return hpre_check_pubdec_padding(to, num, buf, len, padding); + else if (type == PRI_DEC) + return hpre_check_pridec_padding(to, num, buf, len, padding); + + US_ERR("hpre rsa padding type error."); + return ret; +} + +static int check_primeequal(int i, BIGNUM *rsa_p, BIGNUM *rsa_q, BIGNUM *prime) +{ + int j; + + for (j = 0; j < i; j++) { + BIGNUM *prev_prime = NULL; + + if (j == 0) + prev_prime = rsa_p; + else + prev_prime = rsa_q; + + if (!BN_cmp(prime, prev_prime)) + return KAE_FAIL; + } + return KAE_SUCCESS; +} + +static int prime_mul_res(int i, BIGNUM *rsa_p, BIGNUM *rsa_q, BIGNUM *r1, BN_CTX *ctx, BN_GENCB *cb) +{ + if (i == 1) { + /* we get at least 2 primes */ + if (!BN_mul(r1, rsa_p, rsa_q, ctx)) + goto err; + } else { + /* i == 0, do nothing */ + if (!BN_GENCB_call(cb, 3, i)) // When a random p has been found, call BN_GENCB_call(cb, 3, *i) + goto err; + goto cont; + } + return KAE_SUCCESS; +err: + return -1; +cont: + return 1; +} +static int check_prime_sufficient(int *i, int *bitsr, int *bitse, int *n, BIGNUM *rsa_p, BIGNUM *rsa_q, BIGNUM *r1, + BIGNUM *r2, BN_CTX *ctx, BN_GENCB *cb) +{ + BN_ULONG bitst; + static int retries; + int ret; + + /* calculate n immediately to see if it's sufficient */ + ret = prime_mul_res(*i, rsa_p, rsa_q, r1, ctx, cb); + if (ret != KAE_SUCCESS) + return ret; + if (!BN_rshift(r2, r1, *bitse - 4)) // right shift *bitse - 4 + goto err; + bitst = BN_get_word(r2); + if (bitst < 0x9 || bitst > 0xF) { + *bitse -= bitsr[*i]; + if (!BN_GENCB_call(cb, 2, *n++)) // When the n-th is rejected, call BN_GENCB_call(cb, 2, n) + goto err; + if (retries == 4) { // retries max is 4 + *i = -1; + *bitse = 0; + retries = 0; + goto cont; + } + retries++; + goto redo; + } + + if (!BN_GENCB_call(cb, 3, *i)) // When a random p has been found, call BN_GENCB_call(cb, 3, *i) + goto err; + retries = 0; + return 0; +err: + return -1; +redo: + return -2; // if redo return -2 +cont: + return 1; +} + +static void set_primes(int i, BIGNUM *rsa_p, BIGNUM *rsa_q, BIGNUM **prime) +{ + if (i == 0) + *prime = rsa_p; + else + *prime = rsa_q; + BN_set_flags(*prime, BN_FLG_CONSTTIME); +} + +static int check_prime_useful(int *n, BIGNUM *prime, BIGNUM *r1, BIGNUM *r2, BIGNUM *e_value, BN_CTX *ctx, BN_GENCB *cb) +{ + unsigned long error = ERR_peek_last_error(); + + if (!BN_sub(r2, prime, BN_value_one())) + goto err; + ERR_set_mark(); + BN_set_flags(r2, BN_FLG_CONSTTIME); + if (BN_mod_inverse(r1, r2, e_value, ctx) != NULL) + goto br; + + if (ERR_GET_LIB(error) == ERR_LIB_BN && ERR_GET_REASON(error) == BN_R_NO_INVERSE) + ERR_pop_to_mark(); + else + goto err; + if (!BN_GENCB_call(cb, 2, *n++)) // When the n-th is rejected, call BN_GENCB_call(cb, 2, n) + goto err; + return 0; +err: + return -1; +br: + return 1; +} +static void switch_p_q(BIGNUM *rsa_p, BIGNUM *rsa_q, BIGNUM *p, BIGNUM *q) +{ + BIGNUM *tmp = (BIGNUM *)NULL; + + if (BN_cmp(rsa_p, rsa_q) < 0) { + tmp = rsa_p; + rsa_p = rsa_q; + rsa_q = tmp; + } + BN_copy(q, rsa_q); + BN_copy(p, rsa_p); +} + +static int hpre_get_prime_once(int i, const int *bitsr, int *n, BIGNUM *prime, BIGNUM *rsa_p, BIGNUM *rsa_q, BIGNUM *r1, + BIGNUM *r2, BIGNUM *e_value, BN_CTX *ctx, BN_GENCB *cb) +{ + int adj = 0; + int ret = KAE_FAIL; + + for (;;) { + redo: + if (!BN_generate_prime_ex(prime, bitsr[i] + adj, 0, (const BIGNUM *)NULL, (const BIGNUM *)NULL, cb)) + goto err; + /* + * prime should not be equal to p, q, r_3... + * (those primes prior to this one) + */ + if (check_primeequal(i, rsa_p, rsa_q, prime) == KAE_FAIL) + goto redo; + + ret = check_prime_useful(n, prime, r1, r2, e_value, ctx, cb); + if (ret == KAE_FAIL) + goto err; + else if (ret == 1) + break; + } + return ret; +err: + return KAE_FAIL; +} + +int hpre_rsa_primegen(int bits, BIGNUM *e_value, BIGNUM *p, BIGNUM *q, BN_GENCB *cb) +{ + int ok = -1; + int primes = 2; + int n = 0; + int bitse = 0; + int i = 0; + int bitsr[2]; // 2 bits + BN_CTX *ctx = (BN_CTX *)NULL; + BIGNUM *r1 = (BIGNUM *)NULL; + BIGNUM *r2 = (BIGNUM *)NULL; + BIGNUM *prime = (BIGNUM *)NULL; + BIGNUM *rsa_p, *rsa_q; + int ret, quo; + + ctx = BN_CTX_new(); + if (ctx == NULL) + goto err; + BN_CTX_start(ctx); + r1 = BN_CTX_get(ctx); + r2 = BN_CTX_get(ctx); + rsa_p = BN_CTX_get(ctx); + rsa_q = BN_CTX_get(ctx); + if (rsa_q == NULL) + goto err; + /* divide bits into 'primes' pieces evenly */ + quo = bits / primes; + bitsr[0] = quo; + bitsr[1] = quo; + /* generate p, q and other primes (if any) */ + for (i = 0; i < primes; i++) { + set_primes(i, rsa_p, rsa_q, &prime); + redo: + if (hpre_get_prime_once(i, bitsr, &n, prime, rsa_p, rsa_q, r1, r2, e_value, ctx, cb) == KAE_FAIL) + goto err; + + bitse += bitsr[i]; + ret = check_prime_sufficient(&i, bitsr, &bitse, &n, rsa_p, rsa_q, r1, r2, ctx, cb); + if (ret == -1) + goto err; + else if (ret == -2) // ret = -2 goto redo + goto redo; + else if (ret == 1) + continue; + } + switch_p_q(rsa_p, rsa_q, p, q); + ok = 1; +err: + if (ok == -1) { + KAEerr(KAE_F_HPRE_RSA_PRIMEGEN, KAE_R_ERR_LIB_BN); + US_ERR("rsa prime gen failed"); + ok = 0; + } + hpre_free_bn_ctx_buf(ctx, NULL, 0); + return ok; +} + +int hpre_rsa_iscrt(RSA *rsa) +{ + if (unlikely(rsa == NULL)) + return 0; + + if (RSA_test_flags(rsa, RSA_FLAG_EXT_PKEY)) + return 1; + + int version = RSA_get_version(rsa); + if (version == RSA_ASN1_VERSION_MULTI) + return 1; + + const BIGNUM *p = NULL; + const BIGNUM *q = NULL; + const BIGNUM *dmp1 = NULL; + const BIGNUM *dmq1 = NULL; + const BIGNUM *iqmp = NULL; + + RSA_get0_factors(rsa, &p, &q); + RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp); + if ((p != NULL) && (q != NULL) && (dmp1 != NULL) && (dmq1 != NULL) && (iqmp != NULL)) + return 1; + + return 0; +} diff --git a/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_rsa_utils.h b/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_rsa_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..ea2fa71e4b2651c63faf2abe66d5be614afd821c --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_rsa_utils.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the rsa interface for KAE engine utils dealing + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HPRE_RSA_UTILS_H +#define HPRE_RSA_UTILS_H + +BN_ULONG *bn_get_words(const BIGNUM *a); + +void hpre_free_bn_ctx_buf(BN_CTX *bn_ctx, unsigned char *in_buf, int num); + +int hpre_rsa_check_param(int flen, const unsigned char *from, unsigned char *to, RSA *rsa); + +int hpre_get_prienc_res(int padding, BIGNUM *f, const BIGNUM *n, BIGNUM *bn_ret, BIGNUM **res); + +int check_bit_useful(const int bit); + +int check_pubkey_param(const BIGNUM *n, const BIGNUM *e); + +int hpre_rsa_padding(int flen, const unsigned char *from, unsigned char *buf, int num, int padding, int type); + +int check_rsa_padding(unsigned char *to, int num, const unsigned char *buf, int len, int padding, int type); + +int hpre_rsa_primegen(int bits, BIGNUM *e_value, BIGNUM *p, BIGNUM *q, BN_GENCB *cb); + +int hpre_rsa_iscrt(RSA *rsa); + +#endif diff --git a/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_rsa_wd.c b/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_rsa_wd.c new file mode 100644 index 0000000000000000000000000000000000000000..3c58e28633e604e86bfa360dedaf91ef6c08bce5 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_rsa_wd.c @@ -0,0 +1,454 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the implementation for KAE rsa using wd interface + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hpre_rsa_wd.h" +#include "hpre_rsa_utils.h" +#include +#include "../../async/async_callback.h" +#include "../../async/async_task_queue.h" +#include "../../async/async_task_queue.h" +#include "../../async/async_event.h" +#include "../../async/async_check.h" +#include "../../wdwarp/wd_queue_memory.h" +#include "../../../common/kae_types.h" +#include "../../../common/kae_log.h" + +static void hpre_rsa_cb(const void *message, void *tag); + +KAE_QUEUE_POOL_HEAD_S *g_hpre_rsa_qnode_pool; + +void wd_hpre_uninit_qnode_pool(void) +{ + kae_queue_pool_destroy(g_hpre_rsa_qnode_pool, NULL); + g_hpre_rsa_qnode_pool = NULL; +} + +int wd_hpre_init_qnode_pool(void) +{ + kae_queue_pool_destroy(g_hpre_rsa_qnode_pool, NULL); + + g_hpre_rsa_qnode_pool = kae_init_queue_pool(WCRYPTO_RSA); + if (g_hpre_rsa_qnode_pool == NULL) { + US_ERR("hpre rsa qnode poll init fail!\n"); + return KAE_FAIL; + } + + return KAE_SUCCESS; +} + +KAE_QUEUE_POOL_HEAD_S *wd_hpre_get_qnode_pool(void) +{ + return g_hpre_rsa_qnode_pool; +} + +static hpre_rsa_ctx_t *hpre_new_eng_ctx(RSA *rsa_alg) +{ + hpre_rsa_ctx_t *eng_ctx = NULL; + + eng_ctx = (hpre_rsa_ctx_t *)OPENSSL_malloc(sizeof(hpre_rsa_ctx_t)); + if (eng_ctx == NULL) { + US_ERR("hpre engine_ctx malloc fail"); + return NULL; + } + kae_memset(eng_ctx, 0, sizeof(hpre_rsa_ctx_t)); + + eng_ctx->priv_ctx.ssl_alg = rsa_alg; + eng_ctx->qlist = kae_get_node_from_pool(g_hpre_rsa_qnode_pool); + if (eng_ctx->qlist == NULL) { + US_ERR_LIMIT("error. get hardware queue failed"); + OPENSSL_free(eng_ctx); + eng_ctx = NULL; + return NULL; + } + eng_ctx->priv_ctx.is_privkey_ready = UNSET; + eng_ctx->priv_ctx.is_pubkey_ready = UNSET; + return eng_ctx; +} + +static int hpre_init_eng_ctx(hpre_rsa_ctx_t *eng_ctx, int bits) +{ + struct wd_queue *q = eng_ctx->qlist->kae_wd_queue; + struct wd_queue_mempool *pool = eng_ctx->qlist->kae_queue_mem_pool; + + // this is for ctx is in use.we dont need to re create ctx->ctx again + if (eng_ctx->ctx && eng_ctx->opdata.in) { + kae_memset(eng_ctx->opdata.in, 0, eng_ctx->opdata.in_bytes); + return OPENSSL_SUCCESS; + } + if (eng_ctx->ctx == NULL) { + if (bits == 0) + eng_ctx->priv_ctx.key_size = RSA_size(eng_ctx->priv_ctx.ssl_alg); + else + eng_ctx->priv_ctx.key_size = bits >> BIT_BYTES_SHIFT; + + eng_ctx->rsa_setup.key_bits = eng_ctx->priv_ctx.key_size << BIT_BYTES_SHIFT; + eng_ctx->rsa_setup.cb = (wcrypto_cb)hpre_rsa_cb; + eng_ctx->rsa_setup.br.alloc = kae_wd_alloc_blk; + eng_ctx->rsa_setup.br.free = kae_wd_free_blk; + eng_ctx->rsa_setup.br.iova_map = kae_dma_map; + eng_ctx->rsa_setup.br.iova_unmap = kae_dma_unmap; + eng_ctx->rsa_setup.br.usr = pool; + eng_ctx->ctx = wcrypto_create_rsa_ctx(q, &eng_ctx->rsa_setup); + + if (eng_ctx->ctx == NULL) { + US_ERR("create rsa ctx fail!"); + return OPENSSL_FAIL; + } + } + + return OPENSSL_SUCCESS; +} + +hpre_rsa_ctx_t *hpre_get_rsa_eng_ctx(RSA *rsa, int bits, int type) +{ + hpre_rsa_ctx_t *eng_ctx = hpre_new_eng_ctx(rsa); + + if (eng_ctx == NULL) { + US_WARN("new eng ctx fail then switch to soft!"); + return NULL; + } + if (hpre_rsa_iscrt(rsa) || type == ISSET) + eng_ctx->rsa_setup.is_crt = ISSET; + else + eng_ctx->rsa_setup.is_crt = 0; + + if (hpre_init_eng_ctx(eng_ctx, bits) == 0) { + hpre_free_rsa_eng_ctx(eng_ctx); + US_WARN("init eng ctx fail then switch to soft!"); + return NULL; + } + return eng_ctx; +} + +void hpre_free_rsa_eng_ctx(hpre_rsa_ctx_t *eng_ctx) +{ + US_DEBUG("hpre rsa free engine ctx start!"); + if (eng_ctx == NULL) { + US_DEBUG("no eng_ctx to free"); + return; + } + + if (eng_ctx->opdata.op_type != WCRYPTO_RSA_GENKEY) { + if (eng_ctx->opdata.in) + eng_ctx->rsa_setup.br.free(eng_ctx->qlist->kae_queue_mem_pool, eng_ctx->opdata.in); + if (eng_ctx->opdata.out) { + if (eng_ctx->qlist != NULL) + eng_ctx->rsa_setup.br.free(eng_ctx->qlist->kae_queue_mem_pool, eng_ctx->opdata.out); + } + } else { + if (eng_ctx->opdata.in) + wcrypto_del_kg_in(eng_ctx->ctx, (struct wcrypto_rsa_kg_in *)eng_ctx->opdata.in); + if (eng_ctx->opdata.out) + wcrypto_del_kg_out(eng_ctx->ctx, (struct wcrypto_rsa_kg_out *)eng_ctx->opdata.out); + } + + if (eng_ctx->qlist != NULL) { + hpre_free_rsa_ctx(eng_ctx->ctx); + kae_put_node_to_pool(g_hpre_rsa_qnode_pool, eng_ctx->qlist); + } + + eng_ctx->priv_ctx.ssl_alg = NULL; + eng_ctx->qlist = NULL; + eng_ctx->ctx = NULL; + eng_ctx->opdata.in = NULL; + eng_ctx->opdata.out = NULL; + eng_ctx->priv_ctx.is_privkey_ready = UNSET; + eng_ctx->priv_ctx.is_pubkey_ready = UNSET; + OPENSSL_free(eng_ctx); + eng_ctx = NULL; +} + +void hpre_free_rsa_ctx(void *ctx) +{ + if (ctx != NULL) { + wcrypto_del_rsa_ctx(ctx); + ctx = NULL; + } +} + +void hpre_rsa_fill_pubkey(const BIGNUM *e, const BIGNUM *n, hpre_rsa_ctx_t *eng_ctx) +{ + struct wcrypto_rsa_pubkey *pubkey = NULL; + struct wd_dtb *wd_e = NULL; + struct wd_dtb *wd_n = NULL; + + wcrypto_get_rsa_pubkey(eng_ctx->ctx, &pubkey); + wcrypto_get_rsa_pubkey_params(pubkey, &wd_e, &wd_n); + if (!eng_ctx->priv_ctx.is_pubkey_ready) { + wd_e->dsize = BN_bn2bin(e, (unsigned char *)wd_e->data); + wd_n->dsize = BN_bn2bin(n, (unsigned char *)wd_n->data); + eng_ctx->priv_ctx.is_pubkey_ready = ISSET; + } +} + +/** + * FILL prikey to rsa_ctx in normal mode + * @param rsa get prikey from rsa + * @param rsa_ctx + */ +static void hpre_rsa_fill_prikey1(RSA *rsa, hpre_rsa_ctx_t *eng_ctx) +{ + struct wcrypto_rsa_prikey *prikey = NULL; + struct wd_dtb *wd_d = NULL; + struct wd_dtb *wd_n = NULL; + const BIGNUM *n = (const BIGNUM *)NULL; + const BIGNUM *e = (const BIGNUM *)NULL; + const BIGNUM *d = (const BIGNUM *)NULL; + + RSA_get0_key(rsa, &n, &e, &d); + wcrypto_get_rsa_prikey(eng_ctx->ctx, &prikey); + wcrypto_get_rsa_prikey_params(prikey, &wd_d, &wd_n); + + if (!eng_ctx->priv_ctx.is_privkey_ready) { + wd_d->dsize = BN_bn2bin(d, (unsigned char *)wd_d->data); + wd_n->dsize = BN_bn2bin(n, (unsigned char *)wd_n->data); + eng_ctx->priv_ctx.is_privkey_ready = ISSET; + } +} + +/** + * FILL prikey to rsa_ctx in crt mode + * @param rsa get prikey from rsa + * @param rsa_ctx + */ +static void hpre_rsa_fill_prikey2(RSA *rsa, hpre_rsa_ctx_t *eng_ctx) +{ + struct wcrypto_rsa_prikey *prikey = NULL; + struct wd_dtb *wd_dq, *wd_dp, *wd_q, *wd_p, *wd_qinv; + const BIGNUM *p = NULL; + const BIGNUM *q = NULL; + const BIGNUM *dmp1 = NULL; + const BIGNUM *dmq1 = NULL; + const BIGNUM *iqmp = NULL; + + RSA_get0_factors(rsa, &p, &q); + RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp); + wcrypto_get_rsa_prikey(eng_ctx->ctx, &prikey); + wcrypto_get_rsa_crt_prikey_params(prikey, &wd_dq, &wd_dp, &wd_qinv, &wd_q, &wd_p); + if (!eng_ctx->priv_ctx.is_privkey_ready) { + wd_dq->dsize = BN_bn2bin(dmq1, (unsigned char *)wd_dq->data); + wd_dp->dsize = BN_bn2bin(dmp1, (unsigned char *)wd_dp->data); + wd_q->dsize = BN_bn2bin(q, (unsigned char *)wd_q->data); + wd_p->dsize = BN_bn2bin(p, (unsigned char *)wd_p->data); + wd_qinv->dsize = BN_bn2bin(iqmp, (unsigned char *)wd_qinv->data); + eng_ctx->priv_ctx.is_privkey_ready = ISSET; + } +} + +void hpre_rsa_fill_prikey(RSA *rsa, hpre_rsa_ctx_t *eng_ctx, int version, const BIGNUM *p, const BIGNUM *q, + const BIGNUM *dmp1, const BIGNUM *dmq1, const BIGNUM *iqmp) +{ + if (hpre_rsa_iscrt(rsa)) + hpre_rsa_fill_prikey2(rsa, eng_ctx); + else + hpre_rsa_fill_prikey1(rsa, eng_ctx); +} + +int hpre_fill_keygen_opdata(void *ctx, struct wcrypto_rsa_op_data *opdata) +{ + struct wd_dtb *wd_e = NULL; + struct wd_dtb *wd_p = NULL; + struct wd_dtb *wd_q = NULL; + struct wcrypto_rsa_pubkey *pubkey = NULL; + struct wcrypto_rsa_prikey *prikey = NULL; + + wcrypto_get_rsa_pubkey(ctx, &pubkey); + wcrypto_get_rsa_pubkey_params(pubkey, &wd_e, NULL); + wcrypto_get_rsa_prikey(ctx, &prikey); + wcrypto_get_rsa_crt_prikey_params(prikey, NULL, NULL, NULL, &wd_q, &wd_p); + opdata->in = wcrypto_new_kg_in(ctx, wd_e, wd_p, wd_q); + if (!opdata->in) { + US_ERR("create rsa kgen in fail!\n"); + return -ENOMEM; + } + opdata->out = wcrypto_new_kg_out(ctx); + if (!opdata->out) { + wcrypto_del_kg_in(ctx, (struct wcrypto_rsa_kg_in *)opdata->in); + US_ERR("create rsa kgen out fail\n"); + return -ENOMEM; + } + + return 0; +} + +int hpre_rsa_get_keygen_param( + struct wcrypto_rsa_op_data *opdata, void *ctx, RSA *rsa, BIGNUM *e_value, BIGNUM *p, BIGNUM *q) +{ + BIGNUM *n = BN_new(); + BIGNUM *d = BN_new(); + BIGNUM *dmp1 = BN_new(); + BIGNUM *dmq1 = BN_new(); + BIGNUM *iqmp = BN_new(); + struct wd_dtb wd_d; + struct wd_dtb wd_n; + struct wd_dtb wd_qinv; + struct wd_dtb wd_dq; + struct wd_dtb wd_dp; + unsigned int key_bits, key_size; + struct wcrypto_rsa_kg_out *out = (struct wcrypto_rsa_kg_out *)opdata->out; + + key_bits = wcrypto_rsa_key_bits(ctx); + key_size = key_bits >> BIT_BYTES_SHIFT; + wcrypto_get_rsa_kg_out_params(out, &wd_d, &wd_n); + wcrypto_get_rsa_kg_out_crt_params(out, &wd_qinv, &wd_dq, &wd_dp); + + BN_bin2bn((unsigned char *)wd_d.data, key_size, d); + BN_bin2bn((unsigned char *)wd_n.data, key_size, n); + BN_bin2bn((unsigned char *)wd_qinv.data, wd_qinv.dsize, iqmp); + BN_bin2bn((unsigned char *)wd_dq.data, wd_dq.dsize, dmq1); + BN_bin2bn((unsigned char *)wd_dp.data, wd_dp.dsize, dmp1); + + if (!(RSA_set0_key(rsa, n, e_value, d) && RSA_set0_factors(rsa, p, q) && + RSA_set0_crt_params(rsa, dmp1, dmq1, iqmp))) { + KAEerr(KAE_F_RSA_FILL_KENGEN_PARAM, KAE_R_RSA_KEY_NOT_COMPELET); + US_ERR("set key failed!"); + return OPENSSL_FAIL; + } else { + return OPENSSL_SUCCESS; + } +} + +static void hpre_rsa_cb(const void *message, void *tag) +{ + if (!message || !tag) { + US_ERR("hpre cb params err!\n"); + return; + } + struct wcrypto_rsa_msg *msg = (struct wcrypto_rsa_msg *)message; + hpre_rsa_ctx_t *eng_ctx = (hpre_rsa_ctx_t *)tag; + + eng_ctx->opdata.out = msg->out; + eng_ctx->opdata.out_bytes = msg->out_bytes; + eng_ctx->opdata.status = msg->result; +} + +int hpre_rsa_sync(void *ctx, struct wcrypto_rsa_op_data *opdata) +{ + void *tag = NULL; + int ret; + + if (!ctx || !opdata) { + US_ERR("sync params err!"); + return OPENSSL_FAIL; + } + + ret = wcrypto_do_rsa(ctx, opdata, tag); + if (ret != WD_SUCCESS) { + US_ERR("hpre do rsa fail!"); + return OPENSSL_FAIL; + } + + return OPENSSL_SUCCESS; +} + +int hpre_rsa_async(hpre_rsa_ctx_t *eng_ctx, struct wcrypto_rsa_op_data *opdata, op_done_t *op_done) +{ + int ret = 0; + int cnt = 0; + enum task_type_wd type = ASYNC_TASK_WD_RSA; + void *tag = eng_ctx; + + do { + if (cnt > MAX_SEND_TRY_CNTS) + break; + ret = wcrypto_do_rsa(eng_ctx->ctx, opdata, tag); + if (ret == WD_STATUS_BUSY) { + if ((async_wake_job_v1(op_done->job, ASYNC_STATUS_EAGAIN) == 0 || + (async_pause_job_v1(op_done->job, ASYNC_STATUS_EAGAIN) == 0))) { + US_ERR("hpre wake job or hpre pause job fail!"); + ret = 0; + break; + } + cnt++; + } + } while (ret == WD_STATUS_BUSY); + + if (ret != WD_SUCCESS) + return OPENSSL_FAIL; + + if (async_add_poll_task_v1(eng_ctx, op_done, type) == 0) + return OPENSSL_FAIL; + + return OPENSSL_SUCCESS; +} + +int hpre_rsa_crypto(hpre_rsa_ctx_t *eng_ctx, struct wcrypto_rsa_op_data *opdata) +{ + int job_ret; + op_done_t op_done; + + async_init_op_done_v1(&op_done); + + if (op_done.job != NULL && kae_is_async_enabled()) { + if (async_setup_async_event_notification_v1(0) == 0) { + US_ERR("hpre async event notifying failed"); + async_cleanup_op_done_v1(&op_done); + return OPENSSL_FAIL; + } + } else { + US_DEBUG("hpre rsa no async Job or async disable, back to sync!"); + async_cleanup_op_done_v1(&op_done); + return hpre_rsa_sync(eng_ctx->ctx, opdata); + } + + if (hpre_rsa_async(eng_ctx, opdata, &op_done) == OPENSSL_FAIL) + goto err; + + do { + job_ret = async_pause_job_v1(op_done.job, ASYNC_STATUS_OK); + if (job_ret == 0) { + US_DEBUG("- pthread_yidle -"); + kae_pthread_yield(); + } + } + + while (!op_done.flag || ASYNC_CHK_JOB_RESUMED_UNEXPECTEDLY(job_ret)); + + if (op_done.verifyRst <= 0) { + US_ERR("hpre rsa verify result failed with %d", op_done.verifyRst); + async_cleanup_op_done_v1(&op_done); + return OPENSSL_FAIL; + } + + async_cleanup_op_done_v1(&op_done); + + US_DEBUG("hpre rsa do async job success!"); + return OPENSSL_SUCCESS; + +err: + US_ERR("hpre rsa do async job err"); + (void)async_clear_async_event_notification_v1(); + async_cleanup_op_done_v1(&op_done); + return OPENSSL_FAIL; +} diff --git a/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_rsa_wd.h b/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_rsa_wd.h new file mode 100644 index 0000000000000000000000000000000000000000..86c6ffe313ec64c2d3e9a31961f0f4fd8e8a981f --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_rsa_wd.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the rsa interface for KAE rsa using wd interface + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HPRE_WD_H +#define HPRE_WD_H + +#include + +#include "hpre_rsa.h" +#include +#include "../../wdwarp/wd_queue_memory.h" + +#define UNSET 0 +#define ISSET 1 +#define BIT_BYTES_SHIFT 3 + +#define BN_ULONG unsigned long +#define MAX_SEND_TRY_CNTS 50 +#define MAX_RECV_TRY_CNTS 3000 + +#define RSA_BALANCE_TIMES 1280 + +#define WD_STATUS_BUSY (-EBUSY) + +struct hpre_priv_ctx { + RSA *ssl_alg; + int is_pubkey_ready; + int is_privkey_ready; + int key_size; +}; + +typedef struct hpre_priv_ctx hpre_priv_ctx_t; + +struct hpre_rsa_ctx { + void *ctx; + struct wcrypto_rsa_op_data opdata; + struct wcrypto_rsa_ctx_setup rsa_setup; + struct KAE_QUEUE_DATA_NODE *qlist; + hpre_priv_ctx_t priv_ctx; +}; + +typedef struct hpre_rsa_ctx hpre_rsa_ctx_t; + +extern KAE_QUEUE_POOL_HEAD_S *g_hpre_rsa_qnode_pool; + +int wd_hpre_init_qnode_pool(void); +void wd_hpre_uninit_qnode_pool(void); + +KAE_QUEUE_POOL_HEAD_S *wd_hpre_get_qnode_pool(void); + +hpre_rsa_ctx_t *hpre_get_rsa_eng_ctx(RSA *rsa, int bits, int type); + +void hpre_free_rsa_eng_ctx(hpre_rsa_ctx_t *eng_ctx); + +void hpre_free_rsa_ctx(void *ctx); + +void hpre_rsa_fill_pubkey(const BIGNUM *e, const BIGNUM *n, hpre_rsa_ctx_t *rsa_ctx); + +void hpre_rsa_fill_prikey(RSA *rsa, hpre_rsa_ctx_t *eng_ctx, int version, const BIGNUM *p, const BIGNUM *q, + const BIGNUM *dmp1, const BIGNUM *dmq1, const BIGNUM *iqmp); + +int hpre_fill_keygen_opdata(void *ctx, struct wcrypto_rsa_op_data *opdata); + +int hpre_rsa_get_keygen_param( + struct wcrypto_rsa_op_data *opdata, void *ctx, RSA *rsa, BIGNUM *e_value, BIGNUM *p, BIGNUM *q); + +int hpre_rsa_sync(void *ctx, struct wcrypto_rsa_op_data *opdata); + +int hpre_rsa_crypto(hpre_rsa_ctx_t *eng_ctx, struct wcrypto_rsa_op_data *opdata); + +#endif diff --git a/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_sm2.c b/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_sm2.c new file mode 100644 index 0000000000000000000000000000000000000000..fce7e5f65f55b7a98a43f2079bba1b46f48ea1de --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_sm2.c @@ -0,0 +1,1629 @@ +/* + * Copyright 2020-2022 Huawei Technologies Co.,Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include +#include +#include +#include +#include +#include +#include + +#include "hpre_sm2.h" +#include "../../async/async_callback.h" +#include "../../async/async_task_queue.h" +#include "../../async/async_event.h" +#include "../../async/async_check.h" +#include "../../../common/kae_types.h" +#include "../../../common/kae_log.h" +#include "../../../common/kae_utils.h" +#include "../../wdwarp/wd_queue_memory.h" + +#define SM2_DEFAULT_USERID "1234567812345678" +#define SM2_DEFAULT_USERID_LEN 16 + +KAE_QUEUE_POOL_HEAD_S *g_hpre_sm2_qnode_pool; + +DECLARE_ASN1_FUNCTIONS(HPRE_SM2_Ciphertext) + +ASN1_SEQUENCE(HPRE_SM2_Ciphertext) = +{ + ASN1_SIMPLE(HPRE_SM2_Ciphertext, C1x, BIGNUM), + ASN1_SIMPLE(HPRE_SM2_Ciphertext, C1y, BIGNUM), + ASN1_SIMPLE(HPRE_SM2_Ciphertext, C3, ASN1_OCTET_STRING), + ASN1_SIMPLE(HPRE_SM2_Ciphertext, C2, ASN1_OCTET_STRING), +} ASN1_SEQUENCE_END(HPRE_SM2_Ciphertext) + +IMPLEMENT_ASN1_FUNCTIONS(HPRE_SM2_Ciphertext) + +// 回调函数,返回值不按OPENSSL规范 +static int hpre_sm2_get_rand(char *out, size_t out_len, void *usr) +{ + int count = SM2_GET_RAND_MAX_CNT; + BIGNUM *k; + int ret; + + if (!out) { + fprintf(stderr, "out is NULL\n"); + return -1; + } + + k = BN_new(); + if (!k) + return -ENOMEM; + + do { + ret = BN_priv_rand_range(k, usr); + if (!ret) { + fprintf(stderr, "failed to BN_priv_rand_range\n"); + ret = -ENOMEM; + goto err; + } + + ret = BN_bn2binpad(k, (void *)out, (int)out_len); + if (ret < 0) { + ret = -ENOMEM; + fprintf(stderr, "failed to BN_bn2binpad\n"); + goto err; + } + } while (--count >= 0 && BN_is_zero(k)); + + ret = 0; + if (count < 0) + ret = -1; +err: + BN_free(k); + + return ret; +} + +// 回调函数 +static int hpre_sm2_compute_hash(const char *in, size_t in_len, char *out, size_t out_len, void *usr) +{ + const EVP_MD *digest = (const EVP_MD *)usr; + EVP_MD_CTX *hash = EVP_MD_CTX_new(); + int ret = 0; + + digest = digest ? digest : EVP_sm3(); + if (EVP_DigestInit(hash, digest) == 0 || EVP_DigestUpdate(hash, in, in_len) == 0 || + EVP_DigestFinal(hash, (void *)out, NULL) == 0) { + fprintf(stderr, "compute hash failed\n"); + ret = -1; + } + + EVP_MD_CTX_free(hash); + + return ret; +} + +static hpre_sm2_engine_ctx_t *wd_sm2_new_engine_ctx(KAE_QUEUE_DATA_NODE_S *q_node, hpre_sm2_priv_ctx *priv_ctx) +{ + hpre_sm2_engine_ctx_t *e_sm2_ctx = NULL; + + e_sm2_ctx = (hpre_sm2_engine_ctx_t *)OPENSSL_malloc(sizeof(hpre_sm2_engine_ctx_t)); + if (e_sm2_ctx == NULL) { + US_ERR("OPENSSL_malloc ctx failed"); + return NULL; + } + kae_memset(e_sm2_ctx, 0, sizeof(hpre_sm2_engine_ctx_t)); + + // 配置setup参数 + e_sm2_ctx->setup.br.alloc = kae_wd_alloc_blk; + e_sm2_ctx->setup.br.free = kae_wd_free_blk; + e_sm2_ctx->setup.br.iova_map = kae_dma_map; + e_sm2_ctx->setup.br.iova_unmap = kae_dma_unmap; + // e_sm2_ctx->setup.br.get_bufsize = wd_blksize; + e_sm2_ctx->setup.br.usr = q_node->kae_queue_mem_pool; + + e_sm2_ctx->priv_ctx = priv_ctx; + e_sm2_ctx->qlist = q_node; + q_node->engine_ctx = e_sm2_ctx; + + return e_sm2_ctx; +} + +static int wd_sm2_init_engine_ctx(hpre_sm2_engine_ctx_t *e_sm2_ctx) +{ + + // 后续考虑放到update中? + e_sm2_ctx->setup.key_bits = 256; + // sm2算法在UADK的setup_curve_cfg函数中会填充cv信息 + // e_sm2_ctx->setup.cv.type = WCRYPTO_CV_CFG_ID; + // e_sm2_ctx->setup.cv.cfg.id = WCRYPTO_BRAINPOOLP320R1; + e_sm2_ctx->setup.rand.cb = hpre_sm2_get_rand; + e_sm2_ctx->setup.hash.cb = hpre_sm2_compute_hash; + e_sm2_ctx->setup.hash.type = WCRYPTO_HASH_SHA256; + return KAE_SUCCESS; +} + +void wd_sm2_put_engine_ctx(hpre_sm2_engine_ctx_t *e_hpre_sm2_ctx) +{ + if (unlikely(e_hpre_sm2_ctx == NULL)) { + US_WARN("sec cipher engine ctx NULL!"); + return; + } + + if (e_hpre_sm2_ctx->wd_ctx != NULL) { + wcrypto_del_ecc_ctx(e_hpre_sm2_ctx->wd_ctx); + e_hpre_sm2_ctx->wd_ctx = NULL; + } + + if (e_hpre_sm2_ctx->qlist != NULL) { + (void)kae_put_node_to_pool(g_hpre_sm2_qnode_pool, e_hpre_sm2_ctx->qlist); + e_hpre_sm2_ctx->qlist->engine_ctx = NULL; + } + + e_hpre_sm2_ctx = NULL; +} + +hpre_sm2_engine_ctx_t *wd_sm2_get_engine_ctx(hpre_sm2_priv_ctx *priv_ctx) +{ + KAE_QUEUE_DATA_NODE_S *q_node = NULL; + hpre_sm2_engine_ctx_t *e_hpre_sm2_ctx = NULL; + + if (unlikely(priv_ctx == NULL)) { + US_ERR("sm2 cipher priv ctx NULL!"); + return NULL; + } + US_DEBUG("kae hpre_sm2 get queue node from pool start."); + + q_node = kae_get_node_from_pool(g_hpre_sm2_qnode_pool); + if (q_node == NULL) { + US_ERR_LIMIT("failed to get hardware queue"); + return NULL; + } + + e_hpre_sm2_ctx = (hpre_sm2_engine_ctx_t *)q_node->engine_ctx; + if (e_hpre_sm2_ctx == NULL) { + e_hpre_sm2_ctx = wd_sm2_new_engine_ctx(q_node, priv_ctx); + if (e_hpre_sm2_ctx == NULL) { + US_WARN("sec new engine ctx fail!"); + (void)kae_put_node_to_pool(g_hpre_sm2_qnode_pool, q_node); + return NULL; + } + } + + e_hpre_sm2_ctx->priv_ctx = priv_ctx; + + // 初始化一次engine参数 + if (wd_sm2_init_engine_ctx(e_hpre_sm2_ctx) == KAE_FAIL) { // todo + US_WARN("init engine ctx fail!"); + OPENSSL_free(e_hpre_sm2_ctx); + wd_sm2_put_engine_ctx(e_hpre_sm2_ctx); + return NULL; + } + + return e_hpre_sm2_ctx; +} + +void hpre_free_sm2_eng_ctx(hpre_sm2_engine_ctx_t *eng_ctx, struct wcrypto_ecc_op_data opdata) +{ + if (!eng_ctx) { + return; + } + if (opdata.in) + wcrypto_del_ecc_in(eng_ctx->wd_ctx, opdata.in); + if (opdata.out) + wcrypto_del_ecc_out(eng_ctx->wd_ctx, opdata.out); + + wd_sm2_put_engine_ctx(eng_ctx); + + eng_ctx->wd_ctx = NULL; + eng_ctx->qlist = NULL; + eng_ctx->priv_ctx = NULL; + eng_ctx->opdata.in = NULL; + eng_ctx->opdata.out = NULL; + + OPENSSL_free(eng_ctx); +} + +static int hpre_sm2_get_hash_type(int nid_hash) +{ + switch (nid_hash) { + case NID_sha1: + return WCRYPTO_HASH_SHA1; + case NID_sha224: + return WCRYPTO_HASH_SHA224; + case NID_sha256: + return WCRYPTO_HASH_SHA256; + case NID_sha384: + return WCRYPTO_HASH_SHA384; + case NID_sha512: + return WCRYPTO_HASH_SHA512; +#ifndef KAE_TONGSUO + case NID_md4: + return WCRYPTO_HASH_MD4; +#endif + case NID_md5: + return WCRYPTO_HASH_MD5; + case NID_sm3: + return WCRYPTO_HASH_SM3; + default: + return -1; + } +} + +static void hpre_sm2_cb(const void *message, void *tag) +{ + if (!message || !tag) { + US_ERR("hpre sm2 params err!\n"); + return; + } + struct wcrypto_ecc_msg *msg = (struct wcrypto_ecc_msg *)message; + hpre_sm2_engine_ctx_t *eng_ctx = (hpre_sm2_engine_ctx_t *)tag; + + eng_ctx->opdata.out = msg->out; + eng_ctx->opdata.out_bytes = msg->out_bytes; + eng_ctx->opdata.status = msg->result; +} + +int hpre_sm2_update_sess(SM2_PROV_CTX *sm2_pctx) +{ + const unsigned char sm2_order[] = { + 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x72, 0x03, 0xdf, 0x6b, 0x21, 0xc6, 0x05, 0x2b, + 0x53, 0xbb, 0xf4, 0x09, 0x39, 0xd5, 0x41, 0x23 + }; + + if (!sm2_pctx->hsmctx) { + sm2_pctx->hsmctx = (hpre_sm2_priv_ctx *)OPENSSL_malloc(sizeof(hpre_sm2_priv_ctx)); + if (sm2_pctx->hsmctx == NULL) { + printf("hpre smctx malloc fail"); + return OPENSSL_FAIL; + } + kae_memset(sm2_pctx->hsmctx, 0, sizeof(hpre_sm2_priv_ctx)); + } + + hpre_sm2_priv_ctx *smctx = sm2_pctx->hsmctx; + + if (smctx->e_hpre_sm2_ctx == NULL) { + smctx->e_hpre_sm2_ctx = wd_sm2_get_engine_ctx(smctx); + if (smctx->e_hpre_sm2_ctx == NULL) { + US_WARN("hpre sm2 failed to get engine ctx, switch to soft cipher"); + return OPENSSL_FAIL; + } + } + + // struct wcrypto_ecc_ctx_setup setup; + hpre_sm2_engine_ctx_t *e_sm2_ctx = smctx->e_hpre_sm2_ctx; + void *sess; + BIGNUM *order; + int type; + + struct wd_queue *queue = smctx->e_hpre_sm2_ctx->qlist->kae_wd_queue; + + if (smctx->ctx.md) { + /* Set hash method */ + e_sm2_ctx->setup.hash.cb = hpre_sm2_compute_hash; + e_sm2_ctx->setup.hash.usr = (void *)smctx->ctx.md; + type = hpre_sm2_get_hash_type(smctx->md_nid); + if (type < 0) { + wd_sm2_put_engine_ctx(smctx->e_hpre_sm2_ctx); + fprintf(stderr, "uadk not support hash nid %d\n", smctx->md_nid); + return OPENSSL_FAIL; + } + e_sm2_ctx->setup.hash.type = type; + } + + order = BN_bin2bn((void *)sm2_order, sizeof(sm2_order), NULL); + e_sm2_ctx->setup.rand.cb = hpre_sm2_get_rand; + e_sm2_ctx->setup.rand.usr = (void *)order; + e_sm2_ctx->setup.cb = (wcrypto_cb)hpre_sm2_cb; + sess = wcrypto_create_ecc_ctx(queue, &e_sm2_ctx->setup); + if (!sess) { + fprintf(stderr, "failed to alloc sess\n"); + wd_sm2_put_engine_ctx(smctx->e_hpre_sm2_ctx); + BN_free(order); + smctx->init_status = HPRE_SM2_INIT_FAIL; + return OPENSSL_FAIL; + } + + /* Free old session before setting new session */ + if (smctx->e_hpre_sm2_ctx->wd_ctx) { + wcrypto_del_ecc_ctx(smctx->e_hpre_sm2_ctx->wd_ctx); + smctx->e_hpre_sm2_ctx->wd_ctx = NULL; + } + + smctx->e_hpre_sm2_ctx->wd_ctx = sess; + + smctx->prikey = NULL; + smctx->pubkey = NULL; + smctx->order = order; + + return OPENSSL_SUCCESS; +} + +static int get_hpre_sm2_param(struct hpre_sm2_param *sm2_param, BN_CTX *ctx) +{ + sm2_param->p = BN_CTX_get(ctx); + if (!sm2_param->p) + goto end; + + sm2_param->a = BN_CTX_get(ctx); + if (!sm2_param->a) + goto end; + + sm2_param->b = BN_CTX_get(ctx); + if (!sm2_param->b) + goto end; + + sm2_param->xG = BN_CTX_get(ctx); + if (!sm2_param->xG) + goto end; + + sm2_param->yG = BN_CTX_get(ctx); + if (!sm2_param->yG) + goto end; + + sm2_param->xA = BN_CTX_get(ctx); + if (!sm2_param->xA) + goto end; + + sm2_param->yA = BN_CTX_get(ctx); + if (!sm2_param->yA) + goto end; + + return OPENSSL_SUCCESS; + +end: + fprintf(stderr, "failed to malloc params\n"); + return OPENSSL_FAIL; +} + +static int hpre_sm2_check_digest_evp_lib(const EVP_MD *digest, EVP_MD_CTX *hash, const size_t id_len, const uint8_t *id) +{ + uint8_t e_byte; + uint16_t entl; + if (!EVP_DigestInit(hash, digest)) { + fprintf(stderr, "error evp lib\n"); + return OPENSSL_FAIL; + } + + /* Z = h(ENTL || ID || a || b || xG || yG || xA || yA) */ + if (id_len >= (UINT16_MAX >> TRANS_BITS_BYTES_SHIFT)) { + fprintf(stderr, "id too large\n"); + return OPENSSL_FAIL; + } + + entl = (uint16_t)(id_len << TRANS_BITS_BYTES_SHIFT); + + /* Update the most significant (first) byte of 'entl' */ + e_byte = GET_MS_BYTE(entl); + if (!EVP_DigestUpdate(hash, &e_byte, 1)) { + fprintf(stderr, "error evp lib\n"); + return OPENSSL_FAIL; + } + + /* Update the least significant (second) byte of 'entl' */ + e_byte = GET_LS_BYTE(entl); + if (!EVP_DigestUpdate(hash, &e_byte, 1)) { + fprintf(stderr, "error evp lib\n"); + return OPENSSL_FAIL; + } + + if (id_len > 0 && !EVP_DigestUpdate(hash, id, id_len)) { + fprintf(stderr, "error evp lib\n"); + return OPENSSL_FAIL; + } + + return OPENSSL_SUCCESS; +} + +static int check_equation_param(struct hpre_sm2_param *param, EVP_MD_CTX *hash, uint8_t *buf, int p_bytes) +{ + if (BN_bn2binpad(param->a, buf, p_bytes) < 0 || !EVP_DigestUpdate(hash, buf, p_bytes) || + BN_bn2binpad(param->b, buf, p_bytes) < 0 || !EVP_DigestUpdate(hash, buf, p_bytes)) { + fprintf(stderr, "failed to check equation param\n"); + return OPENSSL_FAIL; + } + + return OPENSSL_SUCCESS; +} + +static int check_base_point_group_param(struct hpre_sm2_param *param, BN_CTX *ctx, const EC_KEY *key) +{ + const EC_GROUP *group = EC_KEY_get0_group(key); + + if (!EC_POINT_get_affine_coordinates(group, EC_GROUP_get0_generator(group), param->xG, param->yG, ctx)) { + fprintf(stderr, "failed to check base point group param\n"); + return OPENSSL_FAIL; + } + + return OPENSSL_SUCCESS; +} + +static int check_base_point_param(struct hpre_sm2_param *param, EVP_MD_CTX *hash, uint8_t *buf, int p_bytes) +{ + if (BN_bn2binpad(param->xG, buf, p_bytes) < 0 || !EVP_DigestUpdate(hash, buf, p_bytes) || + BN_bn2binpad(param->yG, buf, p_bytes) < 0 || !EVP_DigestUpdate(hash, buf, p_bytes)) { + fprintf(stderr, "failed to check base point param\n"); + return OPENSSL_FAIL; + } + + return OPENSSL_SUCCESS; +} + +static int check_pkey_point_group_param(struct hpre_sm2_param *param, BN_CTX *ctx, const EC_KEY *key) +{ + const EC_GROUP *group = EC_KEY_get0_group(key); + + if (!EC_POINT_get_affine_coordinates(group, EC_KEY_get0_public_key(key), param->xA, param->yA, ctx)) { + fprintf(stderr, "failed to check pkey point group param\n"); + return OPENSSL_FAIL; + } + return OPENSSL_SUCCESS; +} + +static int check_pkey_point_param( + struct hpre_sm2_param *param, EVP_MD_CTX *hash, uint8_t *buf, int p_bytes, uint8_t *out) +{ + if (BN_bn2binpad(param->xA, buf, p_bytes) < 0 || !EVP_DigestUpdate(hash, buf, p_bytes) || + BN_bn2binpad(param->yA, buf, p_bytes) < 0 || !EVP_DigestUpdate(hash, buf, p_bytes) || + !EVP_DigestFinal(hash, out, NULL)) { + fprintf(stderr, "failed to check pkey point param\n"); + return OPENSSL_FAIL; + } + + return OPENSSL_SUCCESS; +} + +int hpre_sm2_compute_z_digest( + uint8_t *out, const EVP_MD *digest, const uint8_t *id, const size_t id_len, const EC_KEY *key) +{ + const EC_GROUP *group = EC_KEY_get0_group(key); + struct hpre_sm2_param *param = NULL; + EVP_MD_CTX *hash = NULL; + uint8_t *buf = NULL; + BN_CTX *ctx = NULL; + int p_bytes; + int ret = OPENSSL_FAIL; + + hash = EVP_MD_CTX_new(); + if (!hash) + return ret; + + ctx = BN_CTX_new(); + if (!ctx) + goto free_hash; + + param = OPENSSL_zalloc(sizeof(struct hpre_sm2_param)); + if (!param) { + fprintf(stderr, "failed to malloc sm2 param\n"); + goto free_ctx; + } + + if (!get_hpre_sm2_param(param, ctx)) + goto free_param; + + if (!hpre_sm2_check_digest_evp_lib(digest, hash, id_len, id)) + goto free_param; + + if (!EC_GROUP_get_curve(group, param->p, param->a, param->b, ctx)) { + fprintf(stderr, "failed to get curve\n"); + goto free_param; + } + + p_bytes = BN_num_bytes(param->p); + buf = OPENSSL_zalloc(p_bytes); + if (!buf) { + fprintf(stderr, "failed to malloc buf\n"); + goto free_param; + } + + if (!check_equation_param(param, hash, buf, p_bytes) || !check_base_point_group_param(param, ctx, key) || + !check_base_point_param(param, hash, buf, p_bytes) || !check_pkey_point_group_param(param, ctx, key) || + !check_pkey_point_param(param, hash, buf, p_bytes, out)) + goto free_buf; + + ret = OPENSSL_SUCCESS; + +free_buf: + OPENSSL_free(buf); +free_param: + OPENSSL_free(param); +free_ctx: + BN_CTX_free(ctx); +free_hash: + EVP_MD_CTX_free(hash); + return ret; +} + +static size_t sm2_field_size(const EC_GROUP *group) +{ + BIGNUM *p = BN_new(); + BIGNUM *a = BN_new(); + BIGNUM *b = BN_new(); + size_t field_size = 0; + size_t p_bits; + + if (p == NULL || a == NULL || b == NULL) + goto done; + + if (!EC_GROUP_get_curve(group, p, a, b, NULL)) + goto done; + + p_bits = BN_num_bits(p); + field_size = BITS_TO_BYTES(p_bits); + +done: + BN_free(p); + BN_free(a); + BN_free(b); + + return field_size; +} + +static int hpre_sm2_ciphertext_size(const EC_KEY *key, const EVP_MD *digest, size_t msg_len, size_t *ct_size) +{ + const size_t field_size = sm2_field_size(EC_KEY_get0_group(key)); + const int md_size = EVP_MD_size(digest); + size_t sz; + + if (field_size == 0 || md_size < 0) + return OPENSSL_FAIL; + + /* + * Integer and string are simple type; set constructed = 0, means + * primitive and definite length encoding. + */ + sz = ECC_POINT_SIZE(ASN1_object_size(0, field_size + 1, V_ASN1_INTEGER)) + + ASN1_object_size(0, md_size, V_ASN1_OCTET_STRING) + ASN1_object_size(0, msg_len, V_ASN1_OCTET_STRING); + *ct_size = ASN1_object_size(1, sz, V_ASN1_SEQUENCE); + + return OPENSSL_SUCCESS; +} + +static int hpre_sm2_smctx_check(SM2_PROV_CTX *sm2_pctx) +{ + + if (!sm2_pctx) { + fprintf(stderr, "smctx is NULL\n"); + return OPENSSL_FAIL; + } + + hpre_sm2_priv_ctx *smctx = sm2_pctx->hsmctx; + if (!smctx || !smctx->e_hpre_sm2_ctx) { + hpre_sm2_update_sess(sm2_pctx); + } + + // if (!smctx->e_hpre_sm2_ctx) { + // hpre_sm2_update_sess(smctx); + // } + + if (!smctx->e_hpre_sm2_ctx->wd_ctx) { + return OPENSSL_FAIL; + } + + return OPENSSL_SUCCESS; +} + +static int hpre_sm2_encrypt_check( + PROV_SM2_ASYM_CTX *psm2ctx, unsigned char *out, size_t *outlen, const unsigned char *in, size_t inlen) +{ + US_DEBUG("sm2_encrypt_check started.\n"); + hpre_sm2_priv_ctx *smctx = psm2ctx->sm2_pctx->hsmctx; + EC_KEY *ec_key = psm2ctx->ec_key; + const EVP_MD *md; + int c3_size; + + if (!hpre_sm2_smctx_check(psm2ctx->sm2_pctx)) { + return OPENSSL_FAIL; + } + + md = (smctx->ctx.md == NULL) ? EVP_sm3() : smctx->ctx.md; + c3_size = EVP_MD_size(md); + if (c3_size <= 0) { + fprintf(stderr, "c3 size error\n"); + return OPENSSL_FAIL; + } + + if (!out) { + if (!hpre_sm2_ciphertext_size(ec_key, md, inlen, outlen)) + return OPENSSL_FAIL; + else + return OPENSSL_SUCCESS; + } + + if (inlen > UINT_MAX) + return OPENSSL_FAIL; + + return OPENSSL_SUCCESS; +} + +static int hpre_sm2_encrypt_init_iot(void *sess, struct wcrypto_ecc_op_data *opdata, unsigned char *in, size_t inlen) +{ + struct wcrypto_ecc_out *ecc_out; + struct wcrypto_ecc_in *ecc_in; + struct wd_dtb e = {0}; + + ecc_out = wcrypto_new_sm2_enc_out(sess, inlen); + if (!ecc_out) { + fprintf(stderr, "failed to new enc out\n"); + return OPENSSL_FAIL; + } + + e.data = (void *)in; + e.dsize = inlen; + ecc_in = wcrypto_new_sm2_enc_in(sess, NULL, &e); + if (!ecc_in) { + fprintf(stderr, "failed to new enc in\n"); + wcrypto_del_ecc_out(sess, ecc_out); + return OPENSSL_FAIL; + } + + opdata->op_type = WCRYPTO_SM2_ENCRYPT; + opdata->in = ecc_in; + opdata->out = ecc_out; + return OPENSSL_SUCCESS; +} + +int hpre_sm2_set_public_key(void *sess, const EC_KEY *eckey) +{ + unsigned char *point_bin = NULL; + struct wcrypto_ecc_point pubkey; + struct wcrypto_ecc_key *ecc_key; + const EC_POINT *point; + const EC_GROUP *group; + int ret, len; + + point = EC_KEY_get0_public_key(eckey); + if (!point) { + fprintf(stderr, "pubkey not set!\n"); + return OPENSSL_FAIL; + } + + group = EC_KEY_get0_group(eckey); + len = EC_POINT_point2buf(group, point, SM2_OCTET_STRING, &point_bin, NULL); + if (!len) { + fprintf(stderr, "EC_POINT_point2buf error.\n"); + return OPENSSL_FAIL; + } + + len /= SM2_ECC_PUBKEY_PARAM_NUM; + pubkey.x.data = (char *)point_bin + 1; + pubkey.x.dsize = len; + pubkey.y.data = pubkey.x.data + len; + pubkey.y.dsize = len; + ecc_key = wcrypto_get_ecc_key(sess); + ret = wcrypto_set_ecc_pubkey(ecc_key, &pubkey); + if (ret) { + fprintf(stderr, "failed to set ecc pubkey\n"); + ret = OPENSSL_FAIL; + } + + OPENSSL_free(point_bin); + + return OPENSSL_SUCCESS; +} + +static int hpre_sm2_update_public_key(hpre_sm2_priv_ctx *smctx, EC_KEY *ec_key) +{ + const EC_GROUP *group; + const EC_POINT *point; + int ret; + + point = EC_KEY_get0_public_key(ec_key); + if (!point) { + fprintf(stderr, "pubkey not set!\n"); + return OPENSSL_FAIL; + } + + if (smctx->pubkey) { + group = EC_KEY_get0_group(ec_key); + ret = EC_POINT_cmp(group, (void *)smctx->pubkey, point, NULL); + if (!ret) + return OPENSSL_SUCCESS; + } + + ret = hpre_sm2_set_public_key(smctx->e_hpre_sm2_ctx->wd_ctx, ec_key); + if (!ret) + return OPENSSL_FAIL; + + smctx->pubkey = point; + return OPENSSL_SUCCESS; +} + +static int hpre_sync_do_sm2(struct hpre_sm2_engine_ctx *engine, struct wcrypto_ecc_op_data *opdata) +{ + int ret = wcrypto_do_sm2(engine->wd_ctx, opdata, NULL); + if (ret != KAE_SUCCESS) { + return OPENSSL_FAIL; + } + + return OPENSSL_SUCCESS; +} + +static int hpre_async_do_sm2( + struct hpre_sm2_engine_ctx *eng_ctx, struct wcrypto_ecc_op_data *opdata, op_done_t *op_done) +{ + int ret = 0; + int cnt = 0; + enum task_type_wd type = ASYNC_TASK_WD_ECC; + void *tag = eng_ctx; + + do { + if (cnt > MAX_SEND_TRY_CNTS) + break; + ret = wcrypto_do_sm2(eng_ctx->wd_ctx, opdata, tag); + if (ret == -WD_EBUSY) { + if ((async_wake_job_v1(op_done->job, ASYNC_STATUS_EAGAIN) == 0 || + (async_pause_job_v1(op_done->job, ASYNC_STATUS_EAGAIN) == 0))) { + US_ERR("hpre wake job or hpre pause job fail!"); + ret = 0; + break; + } + cnt++; + } + } while (ret == -WD_EBUSY); + + if (ret != WD_SUCCESS) + return OPENSSL_FAIL; + + if (async_add_poll_task_v1(eng_ctx, op_done, type) == 0) + return OPENSSL_FAIL; + + return OPENSSL_SUCCESS; +} + +int hpre_sm2_crypto(struct wcrypto_ecc_op_data *opdata, hpre_sm2_priv_ctx *smctx) +{ + op_done_t op; + int ret; + + async_init_op_done_v1(&op); + + if (op.job != NULL && kae_is_async_enabled()) { + if (async_setup_async_event_notification_v1(0) == 0) { + US_ERR("hpre async event notifying failed"); + async_cleanup_op_done_v1(&op); + return OPENSSL_FAIL; + } + } else { + US_DEBUG("hpre rsa no async Job or async disable, back to sync!"); + async_cleanup_op_done_v1(&op); + return hpre_sync_do_sm2(smctx->e_hpre_sm2_ctx, opdata); + } + + if (!hpre_async_do_sm2(smctx->e_hpre_sm2_ctx, opdata, &op)) + goto err; + + do { + ret = async_pause_job_v1(op.job, ASYNC_STATUS_OK); + if (ret == 0) { + US_DEBUG("- pthread_yidle -"); + kae_pthread_yield(); + } + } while (!op.flag || ASYNC_CHK_JOB_RESUMED_UNEXPECTEDLY(ret)); + + if (op.verifyRst <= 0) { + US_ERR("hpre sm2 verify result failed with %d", op.verifyRst); + async_cleanup_op_done_v1(&op); + return OPENSSL_FAIL; + } + + async_cleanup_op_done_v1(&op); + + US_DEBUG("hpre sm2 do async job success!"); + return OPENSSL_SUCCESS; + +err: + US_ERR("hpre sm2 do async job err"); + (void)async_clear_async_event_notification_v1(); + async_cleanup_op_done_v1(&op); + return OPENSSL_FAIL; +} + +static int sm2_cipher_bin_to_ber(const EVP_MD *md, struct wcrypto_ecc_point *c1, struct wd_dtb *c2, struct wd_dtb *c3, + unsigned char *ber, size_t *ber_len) +{ + struct hpre_sm2_ciphertext ctext_struct; + int ciphertext_leni, ret; + BIGNUM *x1, *y1; + + x1 = BN_bin2bn((void *)c1->x.data, c1->x.dsize, NULL); + if (!x1) { + fprintf(stderr, "failed to BN_bin2bn x1\n"); + return OPENSSL_FAIL; + } + + y1 = BN_bin2bn((void *)c1->y.data, c1->y.dsize, NULL); + if (!y1) { + fprintf(stderr, "failed to BN_bin2bn y1\n"); + ret = OPENSSL_FAIL; + goto free_x1; + } + + ctext_struct.C1x = x1; + ctext_struct.C1y = y1; + ctext_struct.C3 = ASN1_OCTET_STRING_new(); + if (!ctext_struct.C3) { + ret = OPENSSL_FAIL; + goto free_y1; + } + + ctext_struct.C2 = ASN1_OCTET_STRING_new(); + if (!ctext_struct.C2) { + ret = OPENSSL_FAIL; + goto free_y1; + } + + if (!ASN1_OCTET_STRING_set(ctext_struct.C3, (void *)c3->data, c3->dsize) || + !ASN1_OCTET_STRING_set(ctext_struct.C2, (void *)c2->data, c2->dsize)) { + fprintf(stderr, "failed to ASN1_OCTET_STRING_set\n"); + ret = OPENSSL_FAIL; + goto free_y1; + } + + ciphertext_leni = i2d_HPRE_SM2_Ciphertext(&ctext_struct, (unsigned char **)&ber); + /* Ensure cast to size_t is safe */ + if (ciphertext_leni < 0) { + ret = OPENSSL_FAIL; + goto free_y1; + } + *ber_len = (size_t)ciphertext_leni; + ret = OPENSSL_SUCCESS; +free_y1: + ASN1_OCTET_STRING_free(ctext_struct.C3); + ASN1_OCTET_STRING_free(ctext_struct.C2); + BN_free(y1); +free_x1: + BN_free(x1); + + return ret; +} + +// 之后需要考虑下异常不走软算的场景 +int hpre_sm2_encrypt( + PROV_SM2_ASYM_CTX *psm2ctx, unsigned char *out, size_t *outlen, const unsigned char *in, size_t inlen) +{ + hpre_sm2_priv_ctx *smctx = psm2ctx->sm2_pctx->hsmctx; + struct wcrypto_ecc_point *c1 = NULL; + struct wd_dtb *c2 = NULL; + struct wd_dtb *c3 = NULL; + struct wcrypto_ecc_op_data opdata; + const EVP_MD *md; + int ret; + + psm2ctx->sm2_pctx->hsmctx->ctx.md = psm2ctx->sm2_pctx->sm2_md->md; // todo 看是不是能够直接用sm2_md->md + + ret = hpre_sm2_encrypt_check(psm2ctx, out, outlen, in, inlen); + if (!ret) { + US_ERR("hpre_sm2_encrypt_check failed ,then switch to soft!\n"); + goto do_soft; + } + + if (smctx->init_status != HPRE_SM2_INIT_SUCC) { + ret = OPENSSL_FAIL; + goto do_soft; + } + + memset(&opdata, 0, sizeof(opdata)); + + ret = hpre_sm2_encrypt_init_iot(smctx->e_hpre_sm2_ctx->wd_ctx, &opdata, (void *)in, inlen); + if (!ret) { + US_ERR("sm2_encrypt_init_iot failed , then switch to soft!\n"); + goto do_soft; + } + + ret = hpre_sm2_update_public_key(psm2ctx->sm2_pctx->hsmctx, psm2ctx->ec_key); + if (!ret) { + ret = OPENSSL_FAIL; + US_ERR("update_public_key failed , then switch to soft!\n"); + goto uninit_iot; + } + + ret = hpre_sm2_crypto(&opdata, smctx); // wcrypto_do_sm2函数返回0是表示成功 + if (!ret) { + ret = OPENSSL_FAIL; + US_ERR("failed to sm2_crypto in encrypt, ret = %d\n", ret); + goto uninit_iot; + } + + md = (smctx->ctx.md == NULL) ? EVP_sm3() : smctx->ctx.md; + wcrypto_get_sm2_enc_out_params(opdata.out, &c1, &c2, &c3); + if (!c1 || !c2 || !c3) { + ret = OPENSSL_FAIL; + goto uninit_iot; + } + + ret = sm2_cipher_bin_to_ber(md, c1, c2, c3, out, outlen); + if (!ret) + goto uninit_iot; + + ret = OPENSSL_SUCCESS; +uninit_iot: + // wcrypto_del_ecc_in(smctx->e_hpre_sm2_ctx->wd_ctx, opdata.in); + // wcrypto_del_ecc_out(smctx->e_hpre_sm2_ctx->wd_ctx, opdata.out); + hpre_free_sm2_eng_ctx(smctx->e_hpre_sm2_ctx, opdata); + if (ret == OPENSSL_SUCCESS) + return ret; +do_soft: + + US_ERR("hpre_sm2_encrypt switch to execute openssl software calculation.\n"); + psm2ctx->sm2_pctx->do_soft = 1; + return OPENSSL_FAIL; + // return kae_prov_sm2_encrypt_sw(psm2ctx, out, outlen, in, inlen); +} + +static int sm2_cipher_ber_to_bin( + unsigned char *ber, size_t ber_len, struct wcrypto_ecc_point *c1, struct wd_dtb *c2, struct wd_dtb *c3) +{ + struct hpre_sm2_ciphertext *ctext_struct; + int len, len1; + + ctext_struct = d2i_HPRE_SM2_Ciphertext(NULL, (const unsigned char **)&ber, ber_len); + if (!ctext_struct) { + fprintf(stderr, "failed to d2i_SM2_Ciphertext\n"); + return OPENSSL_FAIL; + } + + len = BN_num_bytes(ctext_struct->C1x); + len1 = BN_num_bytes(ctext_struct->C1y); + c1->x.data = malloc(len + len1 + ctext_struct->C2->length + ctext_struct->C3->length); + if (!c1->x.data) { + goto free_ctext; + } + c1->y.data = c1->x.data + len; + c3->data = c1->y.data + len1; + c2->data = c3->data + ctext_struct->C3->length; + memcpy(c2->data, ctext_struct->C2->data, ctext_struct->C2->length); + memcpy(c3->data, ctext_struct->C3->data, ctext_struct->C3->length); + c2->dsize = ctext_struct->C2->length; + c3->dsize = ctext_struct->C3->length; + c1->x.dsize = BN_bn2bin(ctext_struct->C1x, (void *)c1->x.data); + c1->y.dsize = BN_bn2bin(ctext_struct->C1y, (void *)c1->y.data); + + HPRE_SM2_Ciphertext_free(ctext_struct); + return OPENSSL_SUCCESS; + +free_ctext: + HPRE_SM2_Ciphertext_free(ctext_struct); + return OPENSSL_FAIL; +} + +static int hpre_sm2_decrypt_init_iot( + void *sess, struct wcrypto_ecc_op_data *opdata, struct wcrypto_ecc_point *c1, struct wd_dtb *c2, struct wd_dtb *c3) +{ + struct wcrypto_ecc_out *ecc_out; + struct wcrypto_ecc_in *ecc_in; + + ecc_out = wcrypto_new_sm2_dec_out(sess, c2->dsize); + if (!ecc_out) { + fprintf(stderr, "failed to new dec out\n"); + return OPENSSL_FAIL; + } + + ecc_in = wcrypto_new_sm2_dec_in(sess, c1, c2, c3); + if (!ecc_in) { + fprintf(stderr, "failed to new dec in\n"); + wcrypto_del_ecc_out(sess, ecc_out); + return OPENSSL_FAIL; + } + + opdata->op_type = WCRYPTO_SM2_DECRYPT; + opdata->in = ecc_in; + opdata->out = ecc_out; + + return OPENSSL_SUCCESS; +} + +int hpre_sm2_set_private_key(void *sess, const EC_KEY *eckey) +{ + unsigned char bin[SM2_MAX_KEY_BYTES]; + struct wcrypto_ecc_key *ecc_key; + const EC_GROUP *group; + struct wd_dtb prikey; + const BIGNUM *d; + size_t degree; + int buflen; + int ret; + + d = EC_KEY_get0_private_key(eckey); + if (!d) { + fprintf(stderr, "private key not set\n"); + return OPENSSL_FAIL; + } + + group = EC_KEY_get0_group(eckey); + if (!group) { + fprintf(stderr, "failed to get ecc group\n"); + return OPENSSL_FAIL; + } + + degree = EC_GROUP_get_degree(group); + buflen = BITS_TO_BYTES(degree); + ecc_key = wcrypto_get_ecc_key(sess); + prikey.data = (void *)bin; + prikey.dsize = BN_bn2binpad(d, bin, buflen); + + ret = wcrypto_set_ecc_prikey(ecc_key, &prikey); + if (ret != KAE_SUCCESS) { + fprintf(stderr, "failed to set ecc prikey, ret = %d\n", ret); + ret = OPENSSL_FAIL; + } // 是否考虑下其他返回码 + + return OPENSSL_SUCCESS; +} + +static int hpre_sm2_update_private_key(hpre_sm2_priv_ctx *smctx, EC_KEY *ec_key) +{ + + const BIGNUM *d; + int ret; + + d = EC_KEY_get0_private_key(ec_key); + if (!d) { + fprintf(stderr, "private key not set\n"); + return OPENSSL_FAIL; + } + + if (smctx->prikey && !BN_cmp(d, smctx->prikey)) + return OPENSSL_SUCCESS; + + ret = hpre_sm2_set_private_key(smctx->e_hpre_sm2_ctx->wd_ctx, ec_key); + if (!ret) + return OPENSSL_FAIL; + + smctx->prikey = d; + return OPENSSL_SUCCESS; +} + +static int hpre_sm2_get_plaintext(struct wcrypto_ecc_op_data *opdata, unsigned char *out, size_t *outlen) +{ + struct wd_dtb *ptext = NULL; + + wcrypto_get_sm2_dec_out_params(opdata->out, &ptext); + if (!ptext) { + fprintf(stderr, "failed to get ptext\n"); + return OPENSSL_FAIL; + } + + if (*outlen < ptext->dsize) { + fprintf(stderr, "outlen(%lu) < (%u)\n", *outlen, ptext->dsize); + return OPENSSL_FAIL; + } + + memcpy(out, ptext->data, ptext->dsize); + *outlen = ptext->dsize; + + return OPENSSL_SUCCESS; +} + +static int hpre_sm2_plaintext_size(const unsigned char *ct, size_t ct_size, size_t *pt_size) +{ + struct hpre_sm2_ciphertext *sm2_ctext; + + sm2_ctext = d2i_HPRE_SM2_Ciphertext(NULL, &ct, ct_size); + if (!sm2_ctext) { + fprintf(stderr, "invalid sm2 encoding\n"); + return OPENSSL_FAIL; + } + + *pt_size = sm2_ctext->C2->length; + HPRE_SM2_Ciphertext_free(sm2_ctext); + + return OPENSSL_SUCCESS; +} + +static int hpre_sm2_decrypt_check( + PROV_SM2_ASYM_CTX *psm2ctx, unsigned char *out, size_t *outlen, const unsigned char *in, size_t inlen) +{ + hpre_sm2_priv_ctx *smctx = psm2ctx->sm2_pctx->hsmctx; + const EVP_MD *md; + int hash_size; + + if (!hpre_sm2_smctx_check(psm2ctx->sm2_pctx)) { + return OPENSSL_FAIL; + } + + if (smctx->init_status != HPRE_SM2_INIT_SUCC) { + fprintf(stderr, "sm2 ctx init failed\n"); + return OPENSSL_FAIL; + } + + md = (smctx->ctx.md == NULL) ? EVP_sm3() : smctx->ctx.md; + hash_size = EVP_MD_size(md); + if (hash_size <= 0) { + fprintf(stderr, "hash size = %d error\n", hash_size); + return OPENSSL_FAIL; + } + + if (!out) { + if (!hpre_sm2_plaintext_size(in, inlen, outlen)) + return OPENSSL_FAIL; + else + return OPENSSL_FAIL; + } + + return OPENSSL_SUCCESS; +} + +int hpre_sm2_decrypt( + PROV_SM2_ASYM_CTX *psm2ctx, unsigned char *out, size_t *outlen, const unsigned char *in, size_t inlen) +{ + hpre_sm2_priv_ctx *smctx = psm2ctx->sm2_pctx->hsmctx; + struct wcrypto_ecc_point c1; + struct wcrypto_ecc_op_data opdata; + struct wd_dtb c2, c3; + const EVP_MD *md; + int ret; + + ret = hpre_sm2_decrypt_check(psm2ctx, out, outlen, in, inlen); + if (!ret) + goto do_soft; + + if (smctx->init_status != HPRE_SM2_INIT_SUCC) { + goto do_soft; + } + + md = (smctx->ctx.md == NULL) ? EVP_sm3() : smctx->ctx.md; + + ret = sm2_cipher_ber_to_bin((void *)in, inlen, &c1, &c2, &c3); + if (!ret) + goto do_soft; + + if (c3.dsize != EVP_MD_size(md)) { + fprintf(stderr, "c3 dsize != hash_size\n"); + goto free_c1; + } + + memset(&opdata, 0, sizeof(opdata)); + ret = hpre_sm2_decrypt_init_iot(smctx->e_hpre_sm2_ctx->wd_ctx, &opdata, &c1, &c2, &c3); + if (!ret) + goto free_c1; + + ret = hpre_sm2_update_private_key(psm2ctx->sm2_pctx->hsmctx, psm2ctx->ec_key); + if (!ret) { + goto uninit_iot; + } + + ret = hpre_sm2_crypto(&opdata, smctx); + if (!ret) { + printf("failed to sm2_crypto in decrypt, ret = %d\n", ret); + goto uninit_iot; + } + + ret = hpre_sm2_get_plaintext(&opdata, out, outlen); + if (!ret) + goto uninit_iot; + + ret = OPENSSL_SUCCESS; +uninit_iot: + // wcrypto_del_ecc_in(smctx->e_hpre_sm2_ctx->wd_ctx, opdata.in); + // wcrypto_del_ecc_out(smctx->e_hpre_sm2_ctx->wd_ctx, opdata.out); + + hpre_free_sm2_eng_ctx(smctx->e_hpre_sm2_ctx, opdata); +free_c1: + free(c1.x.data); + if (ret == OPENSSL_SUCCESS) // 得考虑异常情况不走soft,抛异常 + return ret; +do_soft: + printf("hpre_sm2_decrypt switch to execute openssl software calculation.\n"); + psm2ctx->sm2_pctx->do_soft = 1; + return OPENSSL_FAIL; +} + +static int hpre_sm2_sign_init_iot( + void *sess, struct wcrypto_ecc_op_data *opdata, unsigned char *digest, size_t digest_len) +{ + struct wcrypto_ecc_out *ecc_out; + struct wcrypto_ecc_in *ecc_in; + struct wd_dtb e = {0}; + + ecc_out = wcrypto_new_sm2_sign_out(sess); + if (!ecc_out) { + fprintf(stderr, "failed to new sign out\n"); + return OPENSSL_FAIL; + } + + e.data = (void *)digest; + e.dsize = digest_len; + ecc_in = wcrypto_new_sm2_sign_in(sess, &e, NULL, NULL, 1); + if (!ecc_in) { + fprintf(stderr, "failed to new sign in\n"); + wcrypto_del_ecc_out(sess, ecc_out); + return OPENSSL_FAIL; + } + + opdata->op_type = WCRYPTO_SM2_SIGN; + opdata->in = ecc_in; + opdata->out = ecc_out; + + return OPENSSL_SUCCESS; +} + +bool data_all_zero(const unsigned char *data, size_t dlen) +{ + int i; + + for (i = 0; i < dlen; i++) { + if (data[i]) + return false; + } + + return true; +} + +static int hpre_sm2_sign_check( + PROV_SM2_SIGN_CTX *psm2ctx, unsigned char *sig, size_t *siglen, const unsigned char *tbs, size_t tbslen) +{ + // struct hpre_sm2_priv_ctx *smctx = psm2ctx->sm2_pctx->hsmctx; + EC_KEY *ec_key = psm2ctx->ec_key; + + const int sig_sz = ECDSA_size(ec_key); + + /* + * If 'sig' is NULL, users can use sm2_decrypt API to obtain the valid 'siglen' first, + * then users use the value of 'signlen' to alloc the memory of 'sig' and call the + * sm2_decrypt API a second time to do the decryption task. + */ + if (sig == NULL) { + *siglen = (size_t)sig_sz; + return OPENSSL_SUCCESS; + } + + if (!hpre_sm2_smctx_check(psm2ctx->sm2_pctx)) { + return OPENSSL_FAIL; + } + + if (sig_sz <= 0) { + fprintf(stderr, "sig_sz error\n"); + return OPENSSL_FAIL; + } + + if (*siglen < (size_t)sig_sz) { + fprintf(stderr, "siglen(%lu) < sig_sz(%lu)\n", *siglen, (size_t)sig_sz); + return OPENSSL_FAIL; + } + + if (tbslen > SM2_KEY_BYTES) + return OPENSSL_FAIL; + + if (data_all_zero(tbs, tbslen)) + return OPENSSL_FAIL; + + return OPENSSL_SUCCESS; +} + +static int hpre_sm2_sign_bin_to_ber(EC_KEY *ec, struct wd_dtb *r, struct wd_dtb *s, unsigned char *sig, size_t *siglen) +{ + int ret = OPENSSL_FAIL; + ECDSA_SIG *e_sig; + BIGNUM *br, *bs; + int sltmp; + + e_sig = ECDSA_SIG_new(); + if (!e_sig) { + fprintf(stderr, "failed to ECDSA_SIG_new\n"); + return OPENSSL_FAIL; + } + + br = BN_bin2bn((void *)r->data, r->dsize, NULL); + if (!br) { + fprintf(stderr, "failed to BN_bin2bn r\n"); + goto free_sig; + } + + bs = BN_bin2bn((void *)s->data, s->dsize, NULL); + if (!bs) { + fprintf(stderr, "failed to BN_bin2bn s\n"); + goto free_r; + } + + ret = ECDSA_SIG_set0(e_sig, br, bs); + if (!ret) { + fprintf(stderr, "failed to ECDSA_SIG_set0\n"); + goto free_s; + } + + sltmp = i2d_ECDSA_SIG(e_sig, &sig); + if (sltmp < 0) { + fprintf(stderr, "failed to i2d_ECDSA_SIG\n"); + goto free_s; + } + *siglen = (size_t)sltmp; + ECDSA_SIG_free(e_sig); + return OPENSSL_SUCCESS; + +free_s: + BN_free(bs); +free_r: + BN_free(br); +free_sig: + ECDSA_SIG_free(e_sig); + + return OPENSSL_FAIL; +} + +int hpre_sm2_sign( + PROV_SM2_SIGN_CTX *psm2ctx, unsigned char *sig, size_t *siglen, const unsigned char *tbs, size_t tbslen) +{ + hpre_sm2_priv_ctx *smctx = psm2ctx->sm2_pctx->hsmctx; + struct wd_dtb *r = NULL; + struct wd_dtb *s = NULL; + struct wcrypto_ecc_op_data opdata; + int ret; + + ret = hpre_sm2_sign_check(psm2ctx, sig, siglen, tbs, tbslen); + if (!ret) + goto do_soft; + + if (smctx->init_status != HPRE_SM2_INIT_SUCC) { + goto do_soft; + } + + memset(&opdata, 0, sizeof(opdata)); + ret = hpre_sm2_sign_init_iot(smctx->e_hpre_sm2_ctx->wd_ctx, &opdata, (void *)tbs, tbslen); + if (!ret) + goto do_soft; + + ret = hpre_sm2_update_private_key(psm2ctx->sm2_pctx->hsmctx, psm2ctx->ec_key); + if (!ret) { + goto uninit_iot; + } + + ret = hpre_sm2_crypto(&opdata, smctx); + if (!ret) { + fprintf(stderr, "failed to sm2_crypto in sign, ret = %d\n", ret); + goto uninit_iot; + } + + wcrypto_get_sm2_sign_out_params(opdata.out, &r, &s); + if (!r || !s) { + goto uninit_iot; + } + + ret = hpre_sm2_sign_bin_to_ber(NULL, r, s, sig, siglen); + if (!ret) + goto uninit_iot; + + ret = OPENSSL_SUCCESS; + +uninit_iot: + // wcrypto_del_ecc_in(smctx->e_hpre_sm2_ctx->wd_ctx, opdata.in); + // wcrypto_del_ecc_out(smctx->e_hpre_sm2_ctx->wd_ctx, opdata.out); + hpre_free_sm2_eng_ctx(smctx->e_hpre_sm2_ctx, opdata); + + if (ret == OPENSSL_SUCCESS) { + US_DEBUG("sm2_sign successed!\n"); + return OPENSSL_SUCCESS; + } +do_soft: + US_ERR("sm2_sign failed, switch to execute openssl software calculation.\n"); + psm2ctx->sm2_pctx->do_soft = 1; + return OPENSSL_FAIL; +} + +static int hpre_sm2_verify_check( + PROV_SM2_SIGN_CTX *psm2ctx, const unsigned char *sig, size_t siglen, const unsigned char *tbs, size_t tbslen) +{ + // struct hpre_sm2_priv_ctx *smctx = psm2ctx->sm2_pctx->hsmctx; + + if (!hpre_sm2_smctx_check(psm2ctx->sm2_pctx)) { + return OPENSSL_FAIL; + } + + if (tbslen > SM2_KEY_BYTES) + return OPENSSL_FAIL; + + if (data_all_zero(tbs, tbslen)) + return OPENSSL_FAIL; + + return OPENSSL_SUCCESS; +} + +static int hpre_sm2_verify_init_iot( + void *sess, struct wcrypto_ecc_op_data *opdata, struct wd_dtb *e, struct wd_dtb *r, struct wd_dtb *s) +{ + struct wcrypto_ecc_in *ecc_in; + + ecc_in = wcrypto_new_sm2_verf_in(sess, e, r, s, NULL, 1); + if (!ecc_in) { + fprintf(stderr, "failed to new verf in\n"); + return OPENSSL_FAIL; + } + + opdata->op_type = WCRYPTO_SM2_VERIFY; + opdata->in = ecc_in; + + return OPENSSL_SUCCESS; +} + +static int hpre_sm2_sig_ber_to_bin(EC_KEY *ec, unsigned char *sig, size_t sig_len, struct wd_dtb *r, struct wd_dtb *s) +{ + const unsigned char *p = sig; + unsigned char *der = NULL; + ECDSA_SIG *e_sig = NULL; + int ret, len1, len2; + BIGNUM *b_r, *b_s; + + e_sig = ECDSA_SIG_new(); + if (!e_sig) { + fprintf(stderr, "failed to ECDSA_SIG_new\n"); + return OPENSSL_FAIL; + } + + if (d2i_ECDSA_SIG(&e_sig, &p, sig_len) == NULL) { + fprintf(stderr, "d2i_ECDSA_SIG error\n"); + ret = OPENSSL_FAIL; + goto free_sig; + } + + /* Ensure signature uses DER and doesn't have trailing garbage */ + len1 = i2d_ECDSA_SIG(e_sig, &der); + if (len1 != sig_len || memcmp(sig, der, len1) != 0) { + fprintf(stderr, "sig data error, derlen(%d), sig_len(%lu)\n", len1, sig_len); + ret = OPENSSL_FAIL; + goto free_der; + } + + b_r = (void *)ECDSA_SIG_get0_r((const ECDSA_SIG *)e_sig); + if (!b_r) { + fprintf(stderr, "failed to get r\n"); + ret = OPENSSL_FAIL; + goto free_der; + } + + b_s = (void *)ECDSA_SIG_get0_s((const ECDSA_SIG *)e_sig); + if (!b_s) { + fprintf(stderr, "failed to get s\n"); + ret = OPENSSL_FAIL; + goto free_der; + } + + len1 = BN_num_bytes(b_r); + len2 = BN_num_bytes(b_s); + if (len1 > SM2_MAX_KEY_BYTES || len2 > SM2_MAX_KEY_BYTES) { + fprintf(stderr, "r or s bytes = (%d, %d) error\n", len1, len2); + ret = OPENSSL_FAIL; + goto free_der; + } + r->dsize = BN_bn2bin(b_r, (void *)r->data); + s->dsize = BN_bn2bin(b_s, (void *)s->data); + ret = OPENSSL_SUCCESS; +free_der: + OPENSSL_free(der); +free_sig: + ECDSA_SIG_free(e_sig); + + return ret; +} + +int hpre_sm2_verify( + PROV_SM2_SIGN_CTX *psm2ctx, const unsigned char *sig, size_t siglen, const unsigned char *tbs, size_t tbslen) +{ + hpre_sm2_priv_ctx *smctx = psm2ctx->sm2_pctx->hsmctx; + unsigned char buf_r[SM2_MAX_KEY_BYTES] = {0}; + unsigned char buf_s[SM2_MAX_KEY_BYTES] = {0}; + EC_KEY *ec_key = psm2ctx->ec_key; + struct wd_dtb e = {0}; + struct wd_dtb r = {0}; + struct wd_dtb s = {0}; + struct wcrypto_ecc_op_data opdata; + int ret; + + ret = hpre_sm2_verify_check(psm2ctx, sig, siglen, tbs, tbslen); + if (!ret) { + US_ERR("sm2_verify_check failed.\n"); + goto do_soft; + } + + if (smctx->init_status != HPRE_SM2_INIT_SUCC) { + ret = OPENSSL_FAIL; + goto do_soft; + } + + r.data = (void *)buf_r; + s.data = (void *)buf_s; + r.bsize = SM2_MAX_KEY_BYTES; + s.bsize = SM2_MAX_KEY_BYTES; + ret = hpre_sm2_sig_ber_to_bin(ec_key, (void *)sig, siglen, &r, &s); + if (!ret) + return OPENSSL_FAIL; + + e.data = (void *)tbs; + e.dsize = tbslen; + memset(&opdata, 0, sizeof(opdata)); + ret = hpre_sm2_verify_init_iot(smctx->e_hpre_sm2_ctx->wd_ctx, &opdata, &e, &r, &s); + if (!ret) + goto do_soft; + + ret = hpre_sm2_update_public_key(psm2ctx->sm2_pctx->hsmctx, psm2ctx->ec_key); + if (!ret) { + ret = OPENSSL_FAIL; + US_ERR("sm2_verify_check failed,switch to soft.\n"); + goto uninit_iot; + } + + ret = hpre_sm2_crypto(&opdata, smctx); + if (!ret) { + ret = OPENSSL_FAIL; + fprintf(stderr, "failed to sm2_crypto in verify, ret = %d\n", ret); + US_ERR("uadk_ecc_crypto failed,switch to soft.\n"); + goto uninit_iot; + } + ret = OPENSSL_SUCCESS; + +uninit_iot: + // wcrypto_del_ecc_in(smctx->e_hpre_sm2_ctx->wd_ctx, opdata.in); + // wcrypto_del_ecc_out(smctx->e_hpre_sm2_ctx->wd_ctx, opdata.out); + hpre_free_sm2_eng_ctx(smctx->e_hpre_sm2_ctx, opdata); + if (ret == OPENSSL_SUCCESS) { + US_DEBUG("sm2_verify successed!\n"); + return OPENSSL_SUCCESS; + } +do_soft: + + US_ERR("sm2_verify failed,switch to execute openssl software calculation.\n"); + psm2ctx->sm2_pctx->do_soft = 1; + return OPENSSL_FAIL; + // return openssl_soft_verify(ctx, sig, siglen, tbs, tbslen); +} + +int wd_sm2_init_qnode_pool(void) +{ + kae_queue_pool_destroy(g_hpre_sm2_qnode_pool, NULL); + + g_hpre_sm2_qnode_pool = kae_init_queue_pool(WCRYPTO_SM2); + if (g_hpre_sm2_qnode_pool == NULL) { + US_ERR("hpre rsa qnode poll init fail!\n"); + return KAE_FAIL; + } + + return KAE_SUCCESS; +} + +KAE_QUEUE_POOL_HEAD_S *wd_hpre_sm2_get_qnode_pool(void) +{ + return g_hpre_sm2_qnode_pool; +} + +void wd_sm2_uninit_qnode_pool(void) +{ + kae_queue_pool_destroy(g_hpre_sm2_qnode_pool, free); + g_hpre_sm2_qnode_pool = NULL; +} + +// async poll thread create +int sm2_engine_ctx_poll(void *engnine_ctx) +{ + int ret = 0; + struct hpre_sm2_engine_ctx *eng_ctx = (struct hpre_sm2_engine_ctx *)engnine_ctx; + struct wd_queue *q = eng_ctx->qlist->kae_wd_queue; + +POLL_AGAIN: + ret = wcrypto_sm2_poll(q, 1); + if (!ret) { + goto POLL_AGAIN; + } else if (ret < 0) { + US_ERR("sm2 poll failed\n"); + return ret; + } + return ret; +} + +int hpre_module_sm2_init(void) +{ + + /* init queue */ + wd_sm2_init_qnode_pool(); + + /* register async poll func */ + async_register_poll_fn_v1(ASYNC_TASK_WD_ECC, sm2_engine_ctx_poll); // ASYNC_TASK_WD_ECC 按SVA代码包含sm2 + + return OPENSSL_SUCCESS; +} \ No newline at end of file diff --git a/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_sm2.h b/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_sm2.h new file mode 100644 index 0000000000000000000000000000000000000000..b380e7ef51bb50187ee4d4d885daa56018cdd7a7 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/algorithm/pkey/hpre_sm2.h @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the rsa interface for KAE rsa using wd interface + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HPRE_SM2_H +#define HPRE_SM2_H + +#include +#include "uadk/v1/wd_ecc.h" +#include "../../wdwarp/wd_queue_memory.h" + +extern KAE_QUEUE_POOL_HEAD_S *g_hpre_sm2_qnode_pool; + +#define HPRE_SM2_DO_SOFT (-0xE0) +#define TRANS_BITS_BYTES_SHIFT 3 +#define ECC_POINT_SIZE(n) ((n) * 2) +#define GET_MS_BYTE(n) ((n) >> 8) +#define GET_LS_BYTE(n) ((n) & 0xFF) +#define DGST_SHIFT_NUM(n) (8 - ((n) & 0x7)) +#define ECC_TYPE +#define BITS_TO_BYTES(bits) (((bits) + 7) >> 3) + +#define HPRE_SM2_DO_SOFT (-0xE0) +#define SM2_MAX_KEY_BYTES 66 +#define SM2_GET_RAND_MAX_CNT 100 +#define SM2_OCTET_STRING 0x04 +#define SM2_ECC_PUBKEY_PARAM_NUM 2 +#define SM2_MAX_KEY_BYTES 66 +#define SM2_KEY_BYTES 32 +#define MAX_SEND_TRY_CNTS 50 + +enum { + HPRE_SM2_INIT_FAIL = -1, + HPRE_SM2_UNINIT, + HPRE_SM2_INIT_SUCC +}; + +enum { + MD_UNCHANGED, + MD_CHANGED +}; + +typedef struct hpre_sm2_ciphertext { + BIGNUM *C1x; + BIGNUM *C1y; + ASN1_OCTET_STRING *C3; + ASN1_OCTET_STRING *C2; +} HPRE_SM2_Ciphertext; + +struct hpre_sm2_param { + /* + * p: BIGNUM with the prime number (GFp) or the polynomial + * defining the underlying field (GF2m) + */ + BIGNUM *p; + /* a: BIGNUM for parameter a of the equation */ + BIGNUM *a; + /* b: BIGNUM for parameter b of the equation */ + BIGNUM *b; + /* xG: BIGNUM for the x-coordinate value of G point */ + BIGNUM *xG; + /* yG: BIGNUM for the y-coordinate value of G point */ + BIGNUM *yG; + /* xA: BIGNUM for the x-coordinate value of PA point */ + BIGNUM *xA; + /* yA: BIGNUM for the y-coordinate value of PA point */ + BIGNUM *yA; +}; + +typedef struct hpre_sm2_engine_ctx hpre_sm2_engine_ctx_t; + +typedef struct { + /* Key and paramgen group */ + EC_GROUP *gen_group; + /* Message digest */ + const EVP_MD *md; + /* Distinguishing Identifier, ISO/IEC 15946-3 */ + uint8_t *id; + size_t id_len; + /* Indicates if the 'id' field is set (1) or not (0) */ + int id_set; +} HPRE_SM2_PKEY_CTX; + +typedef struct { + HPRE_SM2_PKEY_CTX ctx; + // handle_t sess; + const BIGNUM *prikey; + const EC_POINT *pubkey; + BIGNUM *order; + int init_status; + /* The nid of digest method */ + int md_nid; + /* The update status of digest method, changed (1), not changed (0) */ + int md_update_status; + hpre_sm2_engine_ctx_t *e_hpre_sm2_ctx; +} hpre_sm2_priv_ctx; + + +struct hpre_sm2_engine_ctx { + void * wd_ctx; + struct wcrypto_ecc_op_data opdata; + struct wcrypto_ecc_ctx_setup setup; + KAE_QUEUE_DATA_NODE_S *qlist; + hpre_sm2_priv_ctx *priv_ctx; +}; + +#define OSSL_MAX_NAME_SIZE 50 /* Algorithm name */ +#define OSSL_MAX_ALGORITHM_ID_SIZE 256 /* AlgorithmIdentifier DER */ + +/* Structure for sm2 key related data */ +typedef struct { + BIGNUM *order; + /* Key and paramgen group */ + EC_GROUP *gen_group; + const BIGNUM *prikey; + const EC_POINT *pubkey; +} SM2_PKEY_DATA; + +/* Structure for sm2 digest method related data */ +typedef struct { + /* The nid of digest method */ + int md_nid; + /* Legacy: update status of digest method, changed (1), unchanged (0) */ + int md_update_status; + /* + * References to the underlying digest implementation. + * |md| caches the digest, always. + * |alloc_md| only holds a reference to an explicitly fetched digest. + */ + EVP_MD_CTX *mdctx; + EVP_MD *md; + EVP_MD *alloc_md; + size_t mdsize; +} SM2_MD_DATA; + +/* Structure for SM2 private context in kae_provider, related to KAE */ +typedef struct { + int init_status; + /* The session related to KAE */ + // handle_t sess; + hpre_sm2_priv_ctx *hsmctx; + SM2_PKEY_DATA *sm2_pd; + SM2_MD_DATA *sm2_md; + int do_soft; +} SM2_PROV_CTX; + + +/* + * To stay same structure with openssl sm2 cipher context, + * add openssl PROV_DIGEST type to kae provider. + * It will not be used in kae provider, so set it all zero. + */ +struct PROV_DIGEST { + const EVP_MD *md; + EVP_MD *alloc_md; + + ENGINE *engine; + + /* The resv is additional field, not in openssl structure. + * Add it to prevent possible field changes of openssl in future. + */ + char resv[OSSL_MAX_NAME_SIZE]; +}; + +typedef struct { + OSSL_LIB_CTX *libctx; + /* Use EC_KEY refer to keymgmt */ + EC_KEY *ec_key; + /* The md will used by openssl, but not used by kae provider */ + struct PROV_DIGEST md; + + SM2_PROV_CTX *sm2_pctx; +} PROV_SM2_ASYM_CTX; + +typedef struct { + OSSL_LIB_CTX *libctx; + char *propq; + /* Use EC_KEY refer to keymgmt */ + EC_KEY *ec_key; + + /* + * Flag to termine if the 'z' digest needs to be computed and fed to the + * hash function. + * This flag should be set on initialization and the compuation should + * be performed only once, on first update. + */ + unsigned int flag_compute_z_digest : 1; + + /* Will used by openssl, but not used by UADK, so put it outside SM2_PROV_CTX */ + char mdname[OSSL_MAX_NAME_SIZE]; + + /* The Algorithm Identifier of the combined signature algorithm */ + unsigned char aid_buf[OSSL_MAX_ALGORITHM_ID_SIZE]; + unsigned char *aid; + size_t aid_len; + + /* + * SM2 ID used for calculating the Z value, + * distinguishing Identifier, ISO/IEC 15946-3 + */ + unsigned char *id; + size_t id_len; + /* Indicates if the 'id' field is set (1) or not (0) */ + int id_set; + + SM2_PROV_CTX *sm2_pctx; +} PROV_SM2_SIGN_CTX; + + +int hpre_module_sm2_init(void); + +void wd_sm2_uninit_qnode_pool(void); + +KAE_QUEUE_POOL_HEAD_S *wd_hpre_sm2_get_qnode_pool(void); + +int hpre_sm2_update_sess(SM2_PROV_CTX *sm2_pctx); + +int hpre_sm2_encrypt(PROV_SM2_ASYM_CTX *psm2ctx, + unsigned char *out, size_t *outlen, + const unsigned char *in, size_t inlen); + +int hpre_sm2_decrypt(PROV_SM2_ASYM_CTX *psm2ctx, + unsigned char *out, size_t *outlen, + const unsigned char *in, size_t inlen); + +int hpre_sm2_sign(PROV_SM2_SIGN_CTX *psm2ctx, unsigned char *sig, size_t *siglen, + const unsigned char *tbs, size_t tbslen); + +int hpre_sm2_verify(PROV_SM2_SIGN_CTX *psm2ctx, + const unsigned char *sig, size_t siglen, + const unsigned char *tbs, size_t tbslen); + +int hpre_sm2_compute_z_digest(uint8_t *out, const EVP_MD *digest, + const uint8_t *id, const size_t id_len, + const EC_KEY *key); + +// todo unuse +// void hpre_sm2_cleanup(PROV_SM2_ASYM_CTX *psm2ctx); + +#endif + diff --git a/KAEOpensslProvider/src/adapter/nosva/async/async_callback.c b/KAEOpensslProvider/src/adapter/nosva/async/async_callback.c new file mode 100644 index 0000000000000000000000000000000000000000..160bbf3ec7cf43b9bdf433e6b52d8255d3cb5e77 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/async/async_callback.c @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides implementation for callback in KAE engine + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#ifndef __USE_GNU +#define __USE_GNU +#endif + +#include +#include +#include +#include + +#include "async_callback.h" +#include "../../common/kae_log.h" + +#include + +void async_init_op_done_v1(op_done_t *op_done) +{ + if (op_done == NULL) { + US_ERR("error! parameter is NULL."); + return; + } + + op_done->flag = 0; + op_done->verifyRst = 0; + op_done->job = ASYNC_get_current_job(); +} + +void async_cleanup_op_done_v1(op_done_t *op_done) +{ + if (op_done == NULL) { + US_ERR("error! parameter is NULL."); + return; + } + + op_done->verifyRst = 0; + + if (op_done->job) + op_done->job = NULL; +} +/*lint -e(10)*/ diff --git a/KAEOpensslProvider/src/adapter/nosva/async/async_callback.h b/KAEOpensslProvider/src/adapter/nosva/async/async_callback.h new file mode 100644 index 0000000000000000000000000000000000000000..9a372fbb1a325e763e172dbaad5925233944bd5b --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/async/async_callback.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides interface for callback in KAE engine + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ASYNC_CALLBACK_H +#define ASYNC_CALLBACK_H + +#include +#include + +typedef struct { + volatile int flag; + volatile int verifyRst; + volatile ASYNC_JOB *job; +} op_done_t; + +void async_init_op_done_v1(op_done_t *op_done); +void async_cleanup_op_done_v1(op_done_t *op_done); +#endif diff --git a/KAEOpensslProvider/src/adapter/nosva/async/async_check.c b/KAEOpensslProvider/src/adapter/nosva/async/async_check.c new file mode 100644 index 0000000000000000000000000000000000000000..d64b23fb59a83b095464382f18a652c9d014d747 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/async/async_check.c @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the implementation for an engine check thread + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include +#include +#include +#include + +#include "../algorithm/cipher/sec_ciphers_wd.h" +#include "../algorithm/cipher/sec_ciphers_aead.h" +#include "../algorithm/digest/sec_digests_wd.h" +#include "../algorithm/pkey/hpre_rsa_wd.h" +#include "../algorithm/pkey/hpre_sm2.h" +#include "../algorithm/pkey/hpre_dh_wd.h" +#include "async_check.h" +#include "../../common/kae_utils.h" +#include "../../common/kae_log.h" + +KAE_CHECK_Q_TASK g_kae_check_q_task = { + .init_flag = NOT_INIT, +}; +static pthread_once_t g_check_thread_is_initialized = PTHREAD_ONCE_INIT; + +static struct kae_spinlock g_kae_async_spinmtx = { + .lock = 0, +}; + +static unsigned int g_kae_async_enabled = 1; + +void kae_enable_async(void) +{ + KAE_SPIN_LOCK(g_kae_async_spinmtx); + g_kae_async_enabled = 1; + KAE_SPIN_UNLOCK(g_kae_async_spinmtx); +} + +void kae_disable_async(void) +{ + KAE_SPIN_LOCK(g_kae_async_spinmtx); + g_kae_async_enabled = 0; + KAE_SPIN_UNLOCK(g_kae_async_spinmtx); +} + +int kae_is_async_enabled(void) +{ + return g_kae_async_enabled; +} + +static void kae_set_exit_flag(void) +{ + g_kae_check_q_task.exit_flag = 1; +} + +static void *kae_checking_q_loop_fn(void *args) +{ + (void)args; + + while (1) { + if (g_kae_check_q_task.exit_flag) + break; + + usleep(KAE_QUEUE_CHECKING_INTERVAL); + if (g_kae_check_q_task.exit_flag) + break; // double check + + kae_queue_pool_check_and_release(wd_ciphers_get_qnode_pool(), wd_ciphers_free_engine_ctx); + kae_queue_pool_check_and_release(wd_aead_get_qnode_pool(), wd_aead_free_engine_ctx); + kae_queue_pool_check_and_release(wd_digests_get_qnode_pool(), wd_digests_free_engine_ctx); + kae_queue_pool_check_and_release(wd_hpre_get_qnode_pool(), NULL); + kae_queue_pool_check_and_release(wd_hpre_sm2_get_qnode_pool(), NULL); + kae_queue_pool_check_and_release(wd_hpre_dh_get_qnode_pool(), NULL); + } + US_INFO("check thread exit normally."); + + return NULL; // lint !e527 +} + +void kae_checking_q_sync_destroy(void) +{ + (void)wd_digests_uninit_qnode_pool(); + (void)wd_ciphers_uninit_qnode_pool(); + (void)wd_hpre_dh_uninit_qnode_pool(); + (void)wd_hpre_uninit_qnode_pool(); + (void)wd_sm2_uninit_qnode_pool(); + (void)wd_aead_uninit_qnode_pool(); +} + +static void kae_checking_q_thread_destroy(void) +{ + kae_set_exit_flag(); + pthread_join(g_kae_check_q_task.thread_id, NULL); + + (void)wd_digests_uninit_qnode_pool(); + (void)wd_ciphers_uninit_qnode_pool(); + (void)wd_hpre_dh_uninit_qnode_pool(); + (void)wd_hpre_uninit_qnode_pool(); + (void)wd_sm2_uninit_qnode_pool(); + (void)wd_aead_uninit_qnode_pool(); +} + +static void kae_check_thread_init(void) +{ + pthread_t thread_id; + + if (g_kae_check_q_task.init_flag == INITED) + return; + + if (!kae_create_thread_joinable(&thread_id, NULL, kae_checking_q_loop_fn, NULL)) { + US_ERR("fail to create check thread"); + return; + } + + g_kae_check_q_task.thread_id = thread_id; + g_kae_check_q_task.init_flag = INITED; + + (void)OPENSSL_atexit(kae_checking_q_thread_destroy); +} + +int kae_checking_q_thread_init(void) +{ + US_DEBUG("check queue thread init begin"); + + if (g_kae_check_q_task.init_flag == INITED) + return 1; + + pthread_once(&g_check_thread_is_initialized, kae_check_thread_init); + + if (g_kae_check_q_task.init_flag != INITED) { + US_ERR("check thread init failed"); + g_check_thread_is_initialized = PTHREAD_ONCE_INIT; + return 0; + } + + return 1; +} + +void kae_check_thread_reset(void) +{ + kae_memset(&g_kae_check_q_task, 0, sizeof(KAE_CHECK_Q_TASK)); + g_check_thread_is_initialized = PTHREAD_ONCE_INIT; +} diff --git a/KAEOpensslProvider/src/adapter/nosva/async/async_check.h b/KAEOpensslProvider/src/adapter/nosva/async/async_check.h new file mode 100644 index 0000000000000000000000000000000000000000..064c02f5efa5846fdbb932e31918fecb9eb1e790 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/async/async_check.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the interface for an engine check thread + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ENGINE_CHECK_H +#define ENGINE_CHECK_H + +#include + +#define KAE_QUEUE_CHECKING_INTERVAL 15000 + +struct kae_check_q_task_s { + int init_flag; + int exit_flag; + pthread_t thread_id; +}; + +typedef struct kae_check_q_task_s KAE_CHECK_Q_TASK; + +void kae_enable_async(void); +void kae_disable_async(void); +int kae_is_async_enabled(void); +int kae_checking_q_thread_init(void); +void kae_check_thread_reset(void); +void kae_checking_q_sync_destroy(void); + +#endif // end of ENGINE_CHECK_H diff --git a/KAEOpensslProvider/src/adapter/nosva/async/async_event.c b/KAEOpensslProvider/src/adapter/nosva/async/async_event.c new file mode 100644 index 0000000000000000000000000000000000000000..78c64c17b992f71ca5465b6d10290f317711b049 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/async/async_event.c @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides implementation for async events in KAE engine + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#ifndef _USE_GNU +#define _USE_GNU +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "async_event.h" +#include "../../common/kae_log.h" + +static const char *kae_async_key = "kae_async_key"; + +static void async_fd_cleanup(ASYNC_WAIT_CTX *ctx, const void *key, OSSL_ASYNC_FD readfd, void *custom) +{ + (void)ctx; + (void)key; + (void)custom; + if (close(readfd) != 0) + US_WARN("Failed to close fd: %d - error: %d\n", readfd, errno); +} + +int async_setup_async_event_notification_v1(int jobStatus) +{ + (void)jobStatus; + ASYNC_JOB *job; + ASYNC_WAIT_CTX *waitctx; + OSSL_ASYNC_FD efd; + void *custom = NULL; + + job = ASYNC_get_current_job(); + if (job == NULL) { + US_ERR("Could not obtain current async job\n"); + return 0; + } + + waitctx = ASYNC_get_wait_ctx(job); + if (waitctx == NULL) { + US_ERR("current job has no waitctx."); + return 0; + } + + if (ASYNC_WAIT_CTX_get_fd(waitctx, kae_async_key, &efd, &custom) == 0) { + efd = eventfd(0, EFD_NONBLOCK); + if (efd == -1) { + US_ERR("efd error."); + return 0; + } + + if (ASYNC_WAIT_CTX_set_wait_fd(waitctx, kae_async_key, efd, custom, async_fd_cleanup) == 0) { + US_ERR("set wait fd error."); + async_fd_cleanup(waitctx, kae_async_key, efd, NULL); + return 0; + } + } + return 1; +} + +int async_clear_async_event_notification_v1(void) +{ + ASYNC_JOB *job; + ASYNC_WAIT_CTX *waitctx; + OSSL_ASYNC_FD efd; + size_t num_add_fds = 0; + size_t num_del_fds = 0; + void *custom = NULL; + + job = ASYNC_get_current_job(); + if (job == NULL) { + US_ERR("no async job."); + return 0; + } + + waitctx = ASYNC_get_wait_ctx(job); + if (waitctx == NULL) { + US_ERR("The job has no waitctx"); + return 0; + } + + if (ASYNC_WAIT_CTX_get_changed_fds(waitctx, NULL, &num_add_fds, NULL, &num_del_fds) == 0) { + US_ERR("no add fds."); + return 0; + } + + if (num_add_fds > 0) { + if (ASYNC_WAIT_CTX_get_fd(waitctx, kae_async_key, &efd, &custom) == 0) { + US_ERR("no fd."); + return 0; + } + + async_fd_cleanup(waitctx, kae_async_key, efd, NULL); + + if (ASYNC_WAIT_CTX_clear_fd(waitctx, kae_async_key) == 0) { + US_ERR("clear fd error."); + return 0; + } + } + + return 1; +} + +int async_pause_job_v1(volatile ASYNC_JOB *job, int jobStatus) +{ + (void)jobStatus; + + ASYNC_WAIT_CTX *waitctx; + OSSL_ASYNC_FD efd; + void *custom = NULL; + uint64_t buf = 0; + int ret = 0; + + waitctx = ASYNC_get_wait_ctx((ASYNC_JOB *)job); + if (waitctx == NULL) { + US_ERR("error. waitctx is NULL\n"); + return ret; + } + + if (ASYNC_pause_job() == 0) { + US_ERR("Failed to pause the job\n"); + return ret; + } + + ret = ASYNC_WAIT_CTX_get_fd(waitctx, kae_async_key, &efd, &custom); + if (ret > 0) { + if (read(efd, &buf, sizeof(uint64_t)) == -1) { + if (errno != EAGAIN) + US_WARN("Failed to read from fd: %d - error: %d\n", efd, errno); + /* Not resumed by the expected async_wake_job() */ + return ASYNC_JOB_RESUMED_UNEXPECTEDLY; + } + } + + return ret; +} + +int async_wake_job_v1(volatile ASYNC_JOB *job, int jobStatus) +{ + (void)jobStatus; + + ASYNC_WAIT_CTX *waitctx; + OSSL_ASYNC_FD efd; + void *custom = NULL; + uint64_t buf = 1; + int ret = 0; + + waitctx = ASYNC_get_wait_ctx((ASYNC_JOB *)job); + if (waitctx == NULL) { + US_ERR("error. waitctx is NULL\n"); + return ret; + } + + ret = ASYNC_WAIT_CTX_get_fd(waitctx, kae_async_key, &efd, &custom); + if (ret > 0) { + if (write(efd, &buf, sizeof(uint64_t)) == -1) + US_ERR("Failed to write to fd: %d - error: %d\n", efd, errno); + } + + US_DEBUG("- async wake job success - "); + return ret; +} +/*lint -e(10)*/ diff --git a/KAEOpensslProvider/src/adapter/nosva/async/async_event.h b/KAEOpensslProvider/src/adapter/nosva/async/async_event.h new file mode 100644 index 0000000000000000000000000000000000000000..b16fa09fb4468933fec3c692d3b6d547a78c5a69 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/async/async_event.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides interface for async events in KAE engine + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ASYNC_EVENTS_H__ +#define __ASYNC_EVENTS_H__ + +#include + +#include + +#define ASYNC_JOB_RESUMED_UNEXPECTEDLY (-1) +#define ASYNC_CHK_JOB_RESUMED_UNEXPECTEDLY(x) ((x) == ASYNC_JOB_RESUMED_UNEXPECTEDLY) + +#define ASYNC_STATUS_UNSUPPORTED 0 +#define ASYNC_STATUS_ERR 1 +#define ASYNC_STATUS_OK 2 +#define ASYNC_STATUS_EAGAIN 3 + +int async_setup_async_event_notification_v1(int jobStatus); +int async_clear_async_event_notification_v1(void); +int async_pause_job_v1(volatile ASYNC_JOB *job, int jobStatus); +int async_wake_job_v1(volatile ASYNC_JOB *job, int jobStatus); + +#endif diff --git a/KAEOpensslProvider/src/adapter/nosva/async/async_fork.c b/KAEOpensslProvider/src/adapter/nosva/async/async_fork.c new file mode 100644 index 0000000000000000000000000000000000000000..fad0cf5e4839f765cf6748adfddc7fe5e9957305 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/async/async_fork.c @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the inplemenation for a KAE engine fork + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "async_fork.h" +#include "async_check.h" +#include "async_poll.h" +#include "../algorithm/pkey/hpre_rsa.h" +#include "../algorithm/pkey/hpre_sm2.h" +#include "../algorithm/pkey/hpre_dh.h" +#include "../algorithm/cipher/sec_ciphers.h" +#include "../algorithm/digest/sec_digests.h" +#include "../../common/kae_log.h" +#include "../algorithm/pkey/hpre_rsa_wd.h" +#include "../algorithm/pkey/hpre_dh_wd.h" +#include "../algorithm/cipher/sec_ciphers_wd.h" +#include "../algorithm/cipher/sec_ciphers_aead.h" +#include "../algorithm/digest/sec_digests_wd.h" + +void engine_init_child_at_fork_handler_v1(void) +{ + US_DEBUG("call engine_init_child_at_fork_handler_v1"); + + if (g_sec_digests_qnode_pool) + g_sec_digests_qnode_pool->pool_use_num = 0; + if (g_sec_ciphers_qnode_pool) + g_sec_ciphers_qnode_pool->pool_use_num = 0; + if (g_sec_aeads_qnode_pool) + g_sec_aeads_qnode_pool->pool_use_num = 0; + if (g_hpre_rsa_qnode_pool) + g_hpre_rsa_qnode_pool->pool_use_num = 0; + if (g_hpre_dh_qnode_pool) + g_hpre_dh_qnode_pool->pool_use_num = 0; + if (g_hpre_sm2_qnode_pool) + g_hpre_sm2_qnode_pool->pool_use_num = 0; + + (void)hpre_module_rsa_init(); + (void)hpre_module_dh_init(); + (void)sec_cipher_module_init(); // cipher + aead + (void)sec_digest_module_init(); + (void)hpre_module_sm2_init(); + + kae_check_thread_reset(); + if (!kae_checking_q_thread_init()) + US_WARN("kae queue check thread init failed"); + async_module_init_v1(); +} + +void engine_do_before_fork_handler(void) +{} + +void engine_init_parent_at_fork_handler(void) +{} diff --git a/KAEOpensslProvider/src/adapter/nosva/async/async_fork.h b/KAEOpensslProvider/src/adapter/nosva/async/async_fork.h new file mode 100644 index 0000000000000000000000000000000000000000..4042d2700aab6b118a703576a8a16c1766ddf930 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/async/async_fork.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the interface for a KAE engine fork + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __HPRE_FORK_H +#define __HPRE_FORK_H + +void engine_init_child_at_fork_handler_v1(void); +void engine_do_before_fork_handler(void); +void engine_init_parent_at_fork_handler(void); + +#endif diff --git a/KAEOpensslProvider/src/adapter/nosva/async/async_poll.c b/KAEOpensslProvider/src/adapter/nosva/async/async_poll.c new file mode 100644 index 0000000000000000000000000000000000000000..cdd8ded3799409db7c53b2c77fc9951808063ddc --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/async/async_poll.c @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the implementation for the KAE engine thread polling + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#ifndef __USE_GNU +#define __USE_GNU +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "async_poll.h" +#include "async_event.h" +#include "async_task_queue.h" +#include "async_check.h" +#include "../../common/kae_log.h" +#include "../../common/kae_utils.h" + +#define ASYNC_POLL_TASK_NUM 1024 + +static void async_polling_thread_destroy(void); + +static void *async_poll_process_func(void *args) +{ + (void)args; + int ret; + async_poll_task *task; + void *eng_ctx; + int type; + op_done_t *op_done; + + while (1) { + if (sem_wait(&g_async_poll_queue.full_sem) != 0) { + if (errno == EINTR) { + /* sem_wait is interrupted by interrupt, continue */ + continue; + } + US_ERR("wait async full_sem failed, errno:%d", errno); // lint !e666 + } + + task = async_get_queue_task_v1(); + if (task == NULL) { + usleep(1); + continue; + } + + eng_ctx = task->eng_ctx; + op_done = task->op_done; + type = task->type; + + US_DEBUG("async poll thread start to recv result."); + + ret = g_async_recv_func[type](eng_ctx); + + op_done->verifyRst = ret; + + op_done->flag = 1; + if (op_done->job) + async_wake_job_v1(op_done->job, ASYNC_STATUS_OK); + + US_DEBUG("process task done."); + } + + US_DEBUG("polling thread exit."); + return NULL; +} + +void async_polling_thread_reset(void) +{ + g_async_poll_queue.init_mark = 0; + kae_memset(&g_async_poll_queue, 0, sizeof(g_async_poll_queue)); +} + +int async_polling_thread_init(void) +{ + pthread_t thread_id; + + US_DEBUG("init polling thread."); + if (g_async_poll_queue.init_mark == INITED) + return 1; + + kae_memset(&g_async_poll_queue, 0, sizeof(async_poll_queue_t)); + + if (pthread_mutex_init(&(g_async_poll_queue.async_task_mutex), NULL) < 0) + US_ERR("init queue mutex failed, errno:%d", errno); // lint !e666 + + if (!async_poll_task_init_v1()) { + US_ERR("init poll task queue failed."); + return 0; + } + + if (kae_create_thread(&thread_id, NULL, async_poll_process_func, NULL) == 0) { + US_DEBUG("fail to create polling thread"); + goto _err; + } + + g_async_poll_queue.thread_id = thread_id; + g_async_poll_queue.init_mark = INITED; + (void)OPENSSL_atexit(async_polling_thread_destroy); + + return 1; + +_err: + async_poll_task_free_v1(); + return 0; +} + +static void async_polling_thread_destroy(void) +{ + if (g_async_poll_queue.exit_mark == 1) + return; + + async_poll_task_free_v1(); + g_async_poll_queue.exit_mark = 1; +} + +void async_module_init_v1(void) +{ + if (kae_is_async_enabled()) { + async_poll_task_free_v1(); + async_polling_thread_reset(); + if (!async_polling_thread_init()) + kae_disable_async(); + } +} +/*lint -e(10)*/ diff --git a/KAEOpensslProvider/src/adapter/nosva/async/async_poll.h b/KAEOpensslProvider/src/adapter/nosva/async/async_poll.h new file mode 100644 index 0000000000000000000000000000000000000000..36e60e3883de15f33fa46917ecc5d94aaead786d --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/async/async_poll.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides interface for the KAE engine thread polling + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ASYNC_POLLING_H +#define ASYNC_POLLING_H +#include +#include "async_callback.h" +#include "async_task_queue.h" + +void async_module_init_v1(void); + +#endif diff --git a/KAEOpensslProvider/src/adapter/nosva/async/async_task_queue.c b/KAEOpensslProvider/src/adapter/nosva/async/async_task_queue.c new file mode 100644 index 0000000000000000000000000000000000000000..afdedd0e2fea8b9289ed426694ead8b3eda9af84 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/async/async_task_queue.c @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the implementation for the KAE engine async task queue + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#ifndef __USE_GNU +#define __USE_GNU +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "async_task_queue.h" +#include "../../common/kae_log.h" +#include "../../common/kae_utils.h" + +#define ASYNC_POLL_TASK_NUM 4096 + +async_poll_queue_t g_async_poll_queue = { + .init_mark = 0, +}; + +async_recv_t g_async_recv_func[ASYNC_TASK_WD_MAX]; + +int async_register_poll_fn_v1(int type, async_recv_t func) +{ + if (type < 0 || type >= ASYNC_TASK_WD_MAX) { + US_ERR("alg register async func fail! alg type=%d", type); + return -1; + } + + g_async_recv_func[type] = func; + return 0; +} + +int async_poll_task_init_v1(void) +{ + int ret; + + kae_memset(&g_async_poll_queue, 0, sizeof(g_async_poll_queue)); + + g_async_poll_queue.async_poll_task_queue_head = + (async_poll_task *)malloc(sizeof(async_poll_task) * ASYNC_POLL_TASK_NUM); + if (g_async_poll_queue.async_poll_task_queue_head == NULL) { + US_ERR("no enough memory for task queue, errno=%d", errno); // lint !e666 + return 0; + } + kae_memset(g_async_poll_queue.async_poll_task_queue_head, 0, sizeof(async_poll_task) * ASYNC_POLL_TASK_NUM); + g_async_poll_queue.left_task = ASYNC_POLL_TASK_NUM; + + ret = sem_init(&g_async_poll_queue.empty_sem, 0, (unsigned int)g_async_poll_queue.left_task); + if (ret != 0) { + US_ERR("fail to init empty semaphore, errno=%d", errno); // lint !e666 + goto _err; + } + + if (sem_init(&g_async_poll_queue.full_sem, 0, 0) != 0) { + US_ERR("fail to init full semaphore, errno=%d", errno); // lint !e666 + goto _err; + } + + US_DEBUG("async poll task init done."); + return 1; +_err: + async_poll_task_free_v1(); + return 0; +} + +async_poll_task *async_get_queue_task_v1(void) +{ + async_poll_task *task_queue; + async_poll_task *cur_task; + int tail_pos; + + if (pthread_mutex_lock(&g_async_poll_queue.async_task_mutex) != 0) { + US_ERR("lock queue mutex failed, errno:%d", errno); // lint !e666 + return NULL; + } + + tail_pos = g_async_poll_queue.tail_pos; + task_queue = g_async_poll_queue.async_poll_task_queue_head; + cur_task = &task_queue[tail_pos]; + + g_async_poll_queue.tail_pos = (tail_pos + 1) % ASYNC_POLL_TASK_NUM; + g_async_poll_queue.cur_task--; + g_async_poll_queue.left_task++; + + if (pthread_mutex_unlock(&g_async_poll_queue.async_task_mutex) != 0) + US_ERR("unlock queue mutex failed, errno:%d", errno); // lint !e666 + + if (sem_post(&g_async_poll_queue.empty_sem) != 0) + US_ERR("post empty sem failed, errno:%d", errno); // lint !e666 + + US_DEBUG("get task end"); + return cur_task; +} + +static int async_add_queue_task(void *eng_ctx, op_done_t *op_done, enum task_type_wd type) +{ + async_poll_task *task_queue; + async_poll_task *task; + int head_pos; + + if (sem_wait(&g_async_poll_queue.empty_sem) != 0) { + US_ERR("wait empty sem failed, errno:%d", errno); // lint !e666 + return 0; + } + + if (pthread_mutex_lock(&g_async_poll_queue.async_task_mutex) != 0) + US_ERR("lock queue mutex failed, errno:%d", errno); // lint !e666 + + head_pos = g_async_poll_queue.head_pos; + task_queue = g_async_poll_queue.async_poll_task_queue_head; + task = &task_queue[head_pos]; + task->eng_ctx = eng_ctx; + task->op_done = op_done; + task->type = type; + + head_pos = (head_pos + 1) % ASYNC_POLL_TASK_NUM; + g_async_poll_queue.head_pos = head_pos; + g_async_poll_queue.cur_task++; + g_async_poll_queue.left_task--; + + if (pthread_mutex_unlock(&g_async_poll_queue.async_task_mutex) != 0) + US_ERR("unlock queue mutex failed, errno:%d", errno); // lint !e666 + + if (sem_post(&g_async_poll_queue.full_sem) != 0) + US_ERR("post full sem failed, errno:%d", errno); // lint !e666 + + US_DEBUG("add task success"); + return 1; +} + +static void async_poll_queue_free(void) +{ + async_poll_task *task = g_async_poll_queue.async_poll_task_queue_head; + + if (task != NULL) + OPENSSL_free(task); + g_async_poll_queue.async_poll_task_queue_head = NULL; +} + +int async_add_poll_task_v1(void *eng_ctx, op_done_t *op_done, enum task_type_wd type) +{ + US_DEBUG("start to add task to poll queue"); + return async_add_queue_task(eng_ctx, op_done, type); +} + +void async_poll_task_free_v1(void) +{ + int error; + + error = pthread_mutex_lock(&g_async_poll_queue.async_task_mutex); + if (error != 0) { + US_ERR("lock mutex failed, errno=%d", errno); // lint !e666 + return; + } + async_poll_queue_free(); + pthread_mutex_unlock(&g_async_poll_queue.async_task_mutex); + + sem_destroy(&g_async_poll_queue.empty_sem); + sem_destroy(&g_async_poll_queue.full_sem); + pthread_mutex_destroy(&g_async_poll_queue.async_task_mutex); + + US_DEBUG("async task free succ"); +} +/*lint -e(10)*/ diff --git a/KAEOpensslProvider/src/adapter/nosva/async/async_task_queue.h b/KAEOpensslProvider/src/adapter/nosva/async/async_task_queue.h new file mode 100644 index 0000000000000000000000000000000000000000..972baab95dcdf1b7ac425e884d248c74d86f02f9 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/async/async_task_queue.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides interface for the KAE engine async task queue + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ASYNC_TASK_QUEUE_H +#define ASYNC_TASK_QUEUE_H +#include +#include "async_callback.h" +#include + +#include + +enum task_type_wd { + ASYNC_TASK_WD_CIPHER = 0x1, + ASYNC_TASK_WD_DIGEST, + ASYNC_TASK_WD_AEAD, + ASYNC_TASK_WD_RSA, + ASYNC_TASK_WD_DH, + ASYNC_TASK_WD_ECC, + ASYNC_TASK_WD_MAX +}; + +typedef int (*async_recv_t)(void *engine_ctx); + +struct async_wd_polling_arg { + enum task_type_wd type; + void *eng_ctx; + op_done_t *op_done; +}; +typedef struct async_wd_polling_arg async_poll_task; + +typedef struct async_poll_queue_t { + async_poll_task *async_poll_task_queue_head; + int head_pos; + int tail_pos; + int cur_task; + int left_task; + int shutdown; + sem_t empty_sem; + sem_t full_sem; + pthread_mutex_t async_task_mutex; + pthread_t thread_id; + int init_mark; + int exit_mark; +} async_poll_queue_t; + +extern async_poll_queue_t g_async_poll_queue; +extern async_recv_t g_async_recv_func[ASYNC_TASK_WD_MAX]; + +int async_register_poll_fn_v1(int type, async_recv_t async_recv); +int async_poll_task_init_v1(void); +async_poll_task *async_get_queue_task_v1(void); + +int async_add_poll_task_v1(void *ctx, op_done_t *op_done, enum task_type_wd type); +void async_poll_task_free_v1(void); + +#endif diff --git a/KAEOpensslProvider/src/adapter/nosva/nosva.h b/KAEOpensslProvider/src/adapter/nosva/nosva.h new file mode 100644 index 0000000000000000000000000000000000000000..3f388689ffa0aa9cc436528f3622a102314ee749 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/nosva.h @@ -0,0 +1,30 @@ +/* + * Copyright 2025 Huawei Technologies Co.,Ltd.All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef NOSVA_H +#define NOSVA_H + +extern int sec_cipher_module_init(void); + +extern int sec_digest_module_init(void); + +extern int hpre_module_dh_init(void); + +extern int hpre_module_rsa_init(void); + +extern int hpre_module_sm2_init(void); + +#endif diff --git a/KAEOpensslProvider/src/adapter/nosva/wdwarp/wd_alg_queue.c b/KAEOpensslProvider/src/adapter/nosva/wdwarp/wd_alg_queue.c new file mode 100644 index 0000000000000000000000000000000000000000..2f9757d04cf6462f2d0a3f0c33ad95ba5db4a1f2 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/wdwarp/wd_alg_queue.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the wd queue management module + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wd_alg_queue.h" +#include "../../common/kae_log.h" + +struct wd_queue *wd_new_queue(int algtype) +{ + struct wd_queue *queue = (struct wd_queue *)kae_malloc(sizeof(struct wd_queue)); + int ret; + + if (queue == NULL) { + US_ERR("malloc failed"); + return NULL; + } + + kae_memset(queue, 0, sizeof(struct wd_queue)); + + switch (algtype) { + case WCRYPTO_RSA: + queue->capa.alg = "rsa"; + break; + case WCRYPTO_DH: + queue->capa.alg = "dh"; + break; + case WCRYPTO_CIPHER: + queue->capa.alg = "cipher"; + break; + case WCRYPTO_DIGEST: + queue->capa.alg = "digest"; + break; + case WCRYPTO_SM2: + queue->capa.alg = "sm2"; + break; + case WCRYPTO_AEAD: + queue->capa.alg = "aead"; + break; + case WCRYPTO_COMP: + case WCRYPTO_EC: + case WCRYPTO_RNG: + default: + US_WARN("not support algtype:%d", algtype); + kae_free(queue); + queue = NULL; + return NULL; + } + + ret = wd_request_queue(queue); + if (ret) { + US_ERR("request wd queue fail!errno:%d", ret); + kae_free(queue); + queue = NULL; + return NULL; + } + + return queue; +} + +void wd_free_queue(struct wd_queue *queue) +{ + if (queue != NULL) { + wd_release_queue(queue); + kae_free(queue); + queue = NULL; + } +} + +// int wd_get_nosva_dev_num(const char *algorithm) +// { +// return wd_get_available_dev_num(algorithm); +// } diff --git a/KAEOpensslProvider/src/adapter/nosva/wdwarp/wd_alg_queue.h b/KAEOpensslProvider/src/adapter/nosva/wdwarp/wd_alg_queue.h new file mode 100644 index 0000000000000000000000000000000000000000..c0ebbd443ee4df63fdbf90d638d8ed68635079cc --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/wdwarp/wd_alg_queue.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the interface for wd_alg_queue.c + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __WD_ALG_QUEUE_H +#define __WD_ALG_QUEUE_H + +#include +#include "../../common/kae_utils.h" + +struct wd_queue *wd_new_queue(int algtype); + +void wd_free_queue(struct wd_queue *queue); + +// int wd_get_nosva_dev_num(const char *algorithm); +#endif diff --git a/KAEOpensslProvider/src/adapter/nosva/wdwarp/wd_queue_memory.c b/KAEOpensslProvider/src/adapter/nosva/wdwarp/wd_queue_memory.c new file mode 100644 index 0000000000000000000000000000000000000000..029dd71d77060dee551615d2e67475b3fcdc80bb --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/wdwarp/wd_queue_memory.c @@ -0,0 +1,496 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the implementation for KAE engine of wd queue memory management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "wd_queue_memory.h" +#include "../../common/kae_utils.h" +#include "../../common/kae_log.h" + +#define MAXBLOCKSIZE 0x90000 +#define MAXRSVMEM 0x400000 + +#define MAXBLOCKSIZE 0x90000 +#define MAXRSVMEM 0x400000 + +const char *g_alg_type[] = { + "rsa", + "dh", + "cipher", + "digest", + "comp", + "ec", + "rng", + "ecdh", + "x25519", + "x448", + "ecdsa", + "sm2", + "aead", +}; + +struct wd_queue_mempool *wd_queue_mempool_create(struct wd_queue *q, unsigned int block_size, unsigned int block_num) +{ + void *addr = NULL; + unsigned long rsv_mm_sz; + struct wd_queue_mempool *pool = NULL; + unsigned int bitmap_sz; + const unsigned int BLOCKS_PER_BITMAP = 32; + + if (block_size > MAXBLOCKSIZE) { + US_ERR("error! current blk size is beyond 576k"); + return NULL; + } + + rsv_mm_sz = (unsigned long)block_size * (unsigned long)block_num; + if (rsv_mm_sz > (unsigned long)MAXRSVMEM) { + US_ERR("error! current mem size is beyond 4M"); + return NULL; + } + + addr = wd_reserve_memory(q, rsv_mm_sz); + if (addr == NULL) { + US_ERR("reserve_memory fail!"); + return NULL; + } + kae_memset(addr, 0, rsv_mm_sz); + + bitmap_sz = (block_num / BLOCKS_PER_BITMAP + 1) * sizeof(unsigned int); + pool = (struct wd_queue_mempool *)kae_malloc(sizeof(struct wd_queue_mempool) + bitmap_sz); + if (pool == NULL) { + US_ERR("Alloc pool handle fail!"); + return NULL; + } + kae_memset(pool, 0, sizeof(struct wd_queue_mempool) + bitmap_sz); + + pool->base = addr; + sem_init(&pool->mempool_sem, 0, 1); + pool->block_size = block_size; + pool->block_num = block_num; + pool->free_num = block_num; + pool->bitmap = (unsigned int *)(pool + 1); + pool->mem_size = rsv_mm_sz; + pool->q = q; + + return pool; +} + +struct wd_queue_mempool *create_alg_wd_queue_mempool(int algtype, struct wd_queue *q) +{ + struct wd_queue_mempool *mempool = NULL; + unsigned int block_size; + unsigned int block_num; + + switch (algtype) { + case WCRYPTO_RSA: + block_size = RSA_BLOCK_SIZE; + block_num = RSA_BLOCK_NUM; + break; + case WCRYPTO_DH: + block_size = DH_BLOCK_SIZE; + block_num = DH_BLOCK_NUM; + break; + case WCRYPTO_CIPHER: + block_size = CIPHER_BLOCK_SIZE; + block_num = CIPHER_BLOCK_NUM; + break; + case WCRYPTO_DIGEST: + block_size = DIGEST_BLOCK_SIZE; + block_num = DIGEST_BLOCK_NUM; + break; + case WCRYPTO_SM2: + block_size = SM2_BLOCK_SIZE; // 4352 + block_num = SM2_BLOCK_NUM; + break; + case WCRYPTO_AEAD: + block_size = (600 * 1024); + block_num = 16; + break; + case WCRYPTO_COMP: + case WCRYPTO_EC: + case WCRYPTO_RNG: + default: + US_WARN("%s not support algtype:%d", __func__, algtype); + return NULL; + } + +#ifdef NO_WD_BLK_POOL + mempool = wd_queue_mempool_create(q, block_size, block_num); +#else + struct wd_blkpool_setup setup; + + kae_memset(&setup, 0, sizeof(setup)); + setup.block_size = block_size; + setup.block_num = block_num; + setup.align_size = 64; // align with 64 + + mempool = (struct wd_queue_mempool *)wd_blkpool_create(q, &setup); +#endif + + return mempool; +} + +void wd_queue_mempool_destroy(struct wd_queue_mempool *pool) +{ + wd_blkpool_destroy(pool); +} + +void *kae_dma_map(void *usr, void *va, size_t sz) +{ + return wd_blk_iova_map(usr, va); +} + +void kae_dma_unmap(void *usr, void *va, void *dma, size_t sz) +{ + return wd_blk_iova_unmap(usr, dma, va); +} + +void *kae_wd_alloc_blk(void *pool, size_t size) +{ + if (pool == NULL) { + US_ERR("mem pool empty!"); + return NULL; + } + +#ifdef NO_WD_BLK_POOL + struct wd_queue_mempool *mempool = (struct wd_queue_mempool *)pool; + + if (size > (size_t)mempool->block_size) { + US_ERR("alloc size error, over one block size."); + return NULL; + } + return wd_queue_pool_alloc_buf((struct wd_queue_mempool *)pool); +#else + return wd_alloc_blk(pool); +#endif +} + +void kae_wd_free_blk(void *pool, void *blk) +{ +#ifdef NO_WD_BLK_POOL + wd_queue_pool_free_buf((struct wd_queue_mempool *)pool, blk); +#else + wd_free_blk(pool, blk); +#endif +} + +KAE_QUEUE_POOL_HEAD_S *kae_init_queue_pool(int algtype) +{ + KAE_QUEUE_POOL_HEAD_S *kae_pool = NULL; + + kae_pool = (KAE_QUEUE_POOL_HEAD_S *)kae_malloc(sizeof(KAE_QUEUE_POOL_HEAD_S)); + if (kae_pool == NULL) { + US_ERR("malloc pool head fail!"); + return NULL; + } + + /* fill data of head */ + kae_pool->algtype = algtype; + kae_pool->next = NULL; + kae_pool->pool_use_num = 0; + + /* malloc a pool */ + kae_pool->kae_queue_pool = + (KAE_QUEUE_POOL_NODE_S *)kae_malloc(KAE_QUEUE_POOL_MAX_SIZE * sizeof(KAE_QUEUE_POOL_NODE_S)); + if (kae_pool->kae_queue_pool == NULL) { + US_ERR("malloc failed"); + kae_free(kae_pool); + return NULL; + } + kae_memset(kae_pool->kae_queue_pool, 0, KAE_QUEUE_POOL_MAX_SIZE * sizeof(KAE_QUEUE_POOL_NODE_S)); + + pthread_mutex_init(&kae_pool->kae_queue_mutex, NULL); + pthread_mutex_init(&kae_pool->destroy_mutex, NULL); + + US_DEBUG("kae init %s queue success", g_alg_type[algtype]); + + return kae_pool; +} + +static KAE_QUEUE_DATA_NODE_S *kae_get_queue_data_from_list(KAE_QUEUE_POOL_HEAD_S *pool_head) +{ + int i = 0; + KAE_QUEUE_DATA_NODE_S *queue_data_node = NULL; + KAE_QUEUE_POOL_HEAD_S *temp_pool = pool_head; + + US_DEBUG("kae get queue node from pool start."); + + if ((pool_head->pool_use_num == 0) && (pool_head->next == NULL)) + return queue_data_node; + + while (temp_pool != NULL) { + for (i = 0; i < temp_pool->pool_use_num; i++) { + if (temp_pool->kae_queue_pool[i].node_data == NULL) + continue; + + if (KAE_SPIN_TRYLOCK(temp_pool->kae_queue_pool[i].spinlock)) { + if (temp_pool->kae_queue_pool[i].node_data == NULL) { + KAE_SPIN_UNLOCK(temp_pool->kae_queue_pool[i].spinlock); + continue; + } else { + queue_data_node = temp_pool->kae_queue_pool[i].node_data; + temp_pool->kae_queue_pool[i].node_data = (KAE_QUEUE_DATA_NODE_S *)NULL; + KAE_SPIN_UNLOCK(temp_pool->kae_queue_pool[i].spinlock); + + US_DEBUG("kae queue pool first success. queue_data_node=%p queue_node id =%d", queue_data_node, i); + return queue_data_node; + } + } + } + /* next pool */ + temp_pool = temp_pool->next; + } + + return queue_data_node; +} + +static void kae_free_wd_queue_memory(KAE_QUEUE_DATA_NODE_S *queue_node, release_engine_ctx_cb release_fn) +{ + if (queue_node != NULL) { + if (release_fn != NULL && queue_node->engine_ctx != NULL) { + release_fn(queue_node->engine_ctx); + queue_node->engine_ctx = NULL; + } + + if (queue_node->kae_queue_mem_pool != NULL) { + wd_queue_mempool_destroy(queue_node->kae_queue_mem_pool); + queue_node->kae_queue_mem_pool = NULL; + } + if (queue_node->kae_wd_queue != NULL) { + wd_free_queue(queue_node->kae_wd_queue); + queue_node->kae_wd_queue = NULL; + } + + kae_free(queue_node); + queue_node = NULL; + } + + US_DEBUG("free wd queue success"); +} + +static KAE_QUEUE_DATA_NODE_S *kae_new_wd_queue_memory(int algtype) +{ + KAE_QUEUE_DATA_NODE_S *queue_node = NULL; + + queue_node = (KAE_QUEUE_DATA_NODE_S *)kae_malloc(sizeof(KAE_QUEUE_DATA_NODE_S)); + if (queue_node == NULL) { + US_ERR("malloc failed"); + return NULL; + } + kae_memset(queue_node, 0, sizeof(KAE_QUEUE_DATA_NODE_S)); + + queue_node->kae_wd_queue = wd_new_queue(algtype); + if (queue_node->kae_wd_queue == NULL) { + US_ERR("new wd queue fail"); + goto err; + } + + queue_node->kae_queue_mem_pool = create_alg_wd_queue_mempool(algtype, queue_node->kae_wd_queue); + if (queue_node->kae_queue_mem_pool == NULL) { + US_ERR("request mempool fail!"); + goto err; + } + + return queue_node; + +err: + kae_free_wd_queue_memory(queue_node, NULL); + return NULL; +} + +KAE_QUEUE_DATA_NODE_S *kae_get_node_from_pool(KAE_QUEUE_POOL_HEAD_S *pool_head) +{ + KAE_QUEUE_DATA_NODE_S *queue_data_node = NULL; + + if (pool_head == NULL) { + US_ERR("input params pool_head is null"); + return NULL; + } + + queue_data_node = kae_get_queue_data_from_list(pool_head); + if (queue_data_node == NULL) + queue_data_node = kae_new_wd_queue_memory(pool_head->algtype); + + return queue_data_node; +} + +static void kae_set_pool_use_num(KAE_QUEUE_POOL_HEAD_S *pool, int set_num) +{ + pthread_mutex_lock(&pool->kae_queue_mutex); + if (set_num > pool->pool_use_num) + pool->pool_use_num = set_num; + (void)pthread_mutex_unlock(&pool->kae_queue_mutex); +} + +int kae_put_node_to_pool(KAE_QUEUE_POOL_HEAD_S *pool_head, KAE_QUEUE_DATA_NODE_S *node_data) +{ + int i = 0; + KAE_QUEUE_POOL_HEAD_S *temp_pool = pool_head; + KAE_QUEUE_POOL_HEAD_S *last_pool = NULL; + + if (node_data == NULL || pool_head == NULL) + return 0; + + US_DEBUG("Add nodedata to pool"); + + while (temp_pool != NULL) { + for (i = 0; i < KAE_QUEUE_POOL_MAX_SIZE; i++) { + if (temp_pool->kae_queue_pool[i].node_data) + continue; + + if (KAE_SPIN_TRYLOCK(temp_pool->kae_queue_pool[i].spinlock)) { + if (temp_pool->kae_queue_pool[i].node_data) { + KAE_SPIN_UNLOCK(temp_pool->kae_queue_pool[i].spinlock); + continue; + } else { + temp_pool->kae_queue_pool[i].node_data = node_data; + temp_pool->kae_queue_pool[i].add_time = time((time_t *)NULL); + KAE_SPIN_UNLOCK(temp_pool->kae_queue_pool[i].spinlock); + if (i >= temp_pool->pool_use_num) + kae_set_pool_use_num(temp_pool, i + 1); + + US_DEBUG("kae put queue node to pool, queue_node id is %d.", i); + return 1; + } + } + } + last_pool = temp_pool; + temp_pool = temp_pool->next; + /* if no empty pool to add,new a pool */ + if (temp_pool == NULL) { + pthread_mutex_lock(&last_pool->destroy_mutex); + if (last_pool->next == NULL) { + temp_pool = kae_init_queue_pool(last_pool->algtype); + if (temp_pool == NULL) { + (void)pthread_mutex_unlock(&last_pool->destroy_mutex); + break; + } + last_pool->next = temp_pool; + } + (void)pthread_mutex_unlock(&last_pool->destroy_mutex); + } + } + /* if not added,free it */ + kae_free_wd_queue_memory(node_data, NULL); + return 0; +} + +void kae_queue_pool_reset(KAE_QUEUE_POOL_HEAD_S *pool_head) +{ + (void)pool_head; +} + +void kae_queue_pool_destroy(KAE_QUEUE_POOL_HEAD_S *pool_head, release_engine_ctx_cb release_fn) +{ + int error = 0; + int i = 0; + KAE_QUEUE_DATA_NODE_S *queue_data_node = (KAE_QUEUE_DATA_NODE_S *)NULL; + KAE_QUEUE_POOL_HEAD_S *temp_pool = NULL; + KAE_QUEUE_POOL_HEAD_S *cur_pool = pool_head; + + while (cur_pool != NULL) { + error = pthread_mutex_lock(&cur_pool->destroy_mutex); + if (error != 0) { + (void)pthread_mutex_unlock(&cur_pool->destroy_mutex); + return; + } + + error = pthread_mutex_lock(&cur_pool->kae_queue_mutex); + if (error != 0) { + (void)pthread_mutex_unlock(&cur_pool->destroy_mutex); + return; + } + for (i = 0; i < cur_pool->pool_use_num; i++) { + queue_data_node = cur_pool->kae_queue_pool[i].node_data; + if (queue_data_node != NULL) { + kae_free_wd_queue_memory(queue_data_node, release_fn); + US_DEBUG("kae queue node destroy success. queue_node id =%d", i); + cur_pool->kae_queue_pool[i].node_data = NULL; + } + } + US_DEBUG("pool use num :%d.", cur_pool->pool_use_num); + + kae_free(cur_pool->kae_queue_pool); + + (void)pthread_mutex_unlock(&cur_pool->kae_queue_mutex); + (void)pthread_mutex_unlock(&cur_pool->destroy_mutex); + + pthread_mutex_destroy(&cur_pool->kae_queue_mutex); + pthread_mutex_destroy(&cur_pool->destroy_mutex); + + temp_pool = cur_pool->next; + + kae_free(cur_pool); + + cur_pool = temp_pool; + } + + US_DEBUG("kae queue pool destroy success."); +} + +void kae_queue_pool_check_and_release(KAE_QUEUE_POOL_HEAD_S *pool_head, release_engine_ctx_cb release_fn) +{ + int i = 0; + int error; + time_t current_time; + KAE_QUEUE_DATA_NODE_S *queue_data_node = NULL; + KAE_QUEUE_POOL_HEAD_S *cur_pool = pool_head; + + current_time = time((time_t *)NULL); + + while (cur_pool != NULL) { + error = pthread_mutex_lock(&cur_pool->destroy_mutex); + if (error != 0) { + cur_pool = cur_pool->next; + (void)pthread_mutex_unlock(&cur_pool->destroy_mutex); + continue; + } + if (cur_pool->kae_queue_pool == NULL) { + (void)pthread_mutex_unlock(&cur_pool->destroy_mutex); + cur_pool = cur_pool->next; + continue; + } + + for (i = cur_pool->pool_use_num - 1; i >= 0; i--) { + if (cur_pool->kae_queue_pool[i].node_data == NULL) + continue; + + if (difftime(current_time, cur_pool->kae_queue_pool[i].add_time) < CHECK_QUEUE_TIME_SECONDS) + continue; + + if (KAE_SPIN_TRYLOCK(cur_pool->kae_queue_pool[i].spinlock)) { + if ((cur_pool->kae_queue_pool[i].node_data == NULL) || + (difftime(current_time, cur_pool->kae_queue_pool[i].add_time) < CHECK_QUEUE_TIME_SECONDS)) { + KAE_SPIN_UNLOCK(cur_pool->kae_queue_pool[i].spinlock); + continue; + } else { + queue_data_node = cur_pool->kae_queue_pool[i].node_data; + cur_pool->kae_queue_pool[i].node_data = (KAE_QUEUE_DATA_NODE_S *)NULL; + KAE_SPIN_UNLOCK(cur_pool->kae_queue_pool[i].spinlock); + + kae_free_wd_queue_memory(queue_data_node, release_fn); + + US_DEBUG("hpre queue list release success. queue node id =%d", i); + } + } + } + + (void)pthread_mutex_unlock(&cur_pool->destroy_mutex); + cur_pool = cur_pool->next; + } +} diff --git a/KAEOpensslProvider/src/adapter/nosva/wdwarp/wd_queue_memory.h b/KAEOpensslProvider/src/adapter/nosva/wdwarp/wd_queue_memory.h new file mode 100644 index 0000000000000000000000000000000000000000..cf34f0f5958900080536868621470d8b574e7030 --- /dev/null +++ b/KAEOpensslProvider/src/adapter/nosva/wdwarp/wd_queue_memory.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2019. Huawei Technologies Co.,Ltd.All rights reserved. + * + * Description: This file provides the interface for wd_queue_memory.c + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __WD_QUEUE_MEMORY_H +#define __WD_QUEUE_MEMORY_H + +#include +#include +#include "wd_alg_queue.h" +#include "../../common/kae_utils.h" + +#define KAE_QUEUE_POOL_MAX_SIZE 512 +#define CHECK_QUEUE_TIME_SECONDS 5 // seconds + +/* + * once use 3 block for ctx&pubkey*prikey. + * the max Concurrent num = HPRE_BLOCK_NUM/3 + * when use 4096bit rsa. block use max is 3576. + * 3576 = sizeof(ctx)(248)+ pubkey_size(1024) + prikey_size(2304) + * that means max block used is 2304. set 4096 for reserve + */ +#define RSA_BLOCK_NUM 16 +#define RSA_BLOCK_SIZE 4096 + +#define DH_BLOCK_NUM 16 +#define DH_BLOCK_SIZE 4096 + +#define SM2_BLOCK_NUM 16 +#define SM2_BLOCK_SIZE 4096 + +#define CIPHER_BLOCK_NUM 4 +#define CIPHER_BLOCK_SIZE (272 * 1024) + +#define DIGEST_BLOCK_NUM 4 +#define DIGEST_BLOCK_SIZE (512 * 1024) + +typedef void (*release_engine_ctx_cb)(void *engine_ctx); + +typedef struct KAE_QUEUE_DATA_NODE { + struct wd_queue *kae_wd_queue; + struct wd_queue_mempool *kae_queue_mem_pool; + void *engine_ctx; +} KAE_QUEUE_DATA_NODE_S; + +typedef struct KAE_QUEUE_POOL_NODE { + struct kae_spinlock spinlock; + time_t add_time; + KAE_QUEUE_DATA_NODE_S *node_data; +} KAE_QUEUE_POOL_NODE_S; + +typedef struct KAE_QUEUE_POOL_HEAD { + int pool_use_num; + int algtype; /* alg type,just init at init pool */ + pthread_mutex_t destroy_mutex; + pthread_mutex_t kae_queue_mutex; + struct KAE_QUEUE_POOL_HEAD *next; /* next pool */ + KAE_QUEUE_POOL_NODE_S *kae_queue_pool; /* point to a attray */ +} KAE_QUEUE_POOL_HEAD_S; + +struct wd_queue_mempool { + struct wd_queue *q; + void *base; + unsigned int *bitmap; + unsigned int block_size; + unsigned int block_num; + unsigned int mem_size; + unsigned int block_align_size; + unsigned int free_num; + unsigned int fail_times; + unsigned long long index; + sem_t mempool_sem; + int dev; +}; + +struct wd_queue_mempool *wd_queue_mempool_create(struct wd_queue *q, unsigned int block_size, unsigned int block_num); + +void wd_queue_mempool_destroy(struct wd_queue_mempool *pool); + +void kae_wd_free_blk(void *pool, void *blk); +void *kae_wd_alloc_blk(void *pool, size_t size); + +void *kae_dma_map(void *usr, void *va, size_t sz); + +void kae_dma_unmap(void *usr, void *va, void *dma, size_t sz); + +KAE_QUEUE_POOL_HEAD_S *kae_init_queue_pool(int algtype); +KAE_QUEUE_DATA_NODE_S *kae_get_node_from_pool(KAE_QUEUE_POOL_HEAD_S *pool_head); +int kae_put_node_to_pool(KAE_QUEUE_POOL_HEAD_S *pool_head, KAE_QUEUE_DATA_NODE_S *node_data); +void kae_queue_pool_reset(KAE_QUEUE_POOL_HEAD_S *pool_head); +void kae_queue_pool_destroy(KAE_QUEUE_POOL_HEAD_S *pool_head, release_engine_ctx_cb release_fn); +void kae_queue_pool_check_and_release(KAE_QUEUE_POOL_HEAD_S *pool_head, release_engine_ctx_cb release_ectx_fn); + +#endif diff --git a/KAEOpensslProvider/src/provider/prov_nosva.c b/KAEOpensslProvider/src/provider/prov_nosva.c new file mode 100644 index 0000000000000000000000000000000000000000..3f54622306e1b351ba809b7db662896ea5573eef --- /dev/null +++ b/KAEOpensslProvider/src/provider/prov_nosva.c @@ -0,0 +1,343 @@ +/* + * Copyright 2025 Huawei Technologies Co.,Ltd.All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "prov_nosva/prov.h" +#include "prov_nosva/internal/prov_bio.h" +#include "prov_nosva/prov_pkey.h" +#include "prov_nosva/prov_digest.h" +#include "../adapter/nosva/nosva.h" +#include "../adapter/common/kae_log.h" +#include "../adapter/nosva/async/async_poll.h" +#include "../adapter/nosva/async/async_check.h" + +static const char KAE_DEFAULT_PROPERTIES[] = "provider=kae_provider"; +static OSSL_PROVIDER *prov; + +/* Functions provided by the core */ +static OSSL_FUNC_core_gettable_params_fn *c_gettable_params; +static OSSL_FUNC_core_get_params_fn *c_get_params; +static OSSL_FUNC_core_get_libctx_fn *c_get_libctx; + +struct kae_provider_params { + char *enable_soft_offload; +} kae_params; + +static int uadk_rsa_nosva; +static int uadk_sm2_nosva; +// static int uadk_dh_nosva; +static int uadk_digest_nosva; +static int uadk_cipher_nosva; + +/* offload small packets to sw */ +int enable_soft_offload; + +// default 0 +int rsa_switch_soft = 0; + +int sm2_switch_soft = 0; + +// int dh_switch_soft = 0; + +int digest_switch_soft = 0; + +int cipher_switch_soft = 0; + +const OSSL_ALGORITHM kae_prov_digests[] = { + {OSSL_DIGEST_NAME_MD5, KAE_DEFAULT_PROPERTIES, kae_md5_functions, "kae_provider md5"}, + {OSSL_DIGEST_NAME_SM3, KAE_DEFAULT_PROPERTIES, kae_sm3_functions, "kae_provider sm3"}, + {NULL, NULL, NULL}}; + +const OSSL_ALGORITHM kae_prov_ciphers[] = { + {"AES-128-CBC", KAE_DEFAULT_PROPERTIES, kae_aes_128_cbc_functions, "kae_provider aes-128-cbc"}, + {"AES-192-CBC", KAE_DEFAULT_PROPERTIES, kae_aes_192_cbc_functions, "kae_provider aes-192-cbc"}, + {"AES-256-CBC", KAE_DEFAULT_PROPERTIES, kae_aes_256_cbc_functions, "kae_provider aes-256-cbc"}, + {"AES-128-ECB", KAE_DEFAULT_PROPERTIES, kae_aes_128_ecb_functions, "kae_provider aes-128-ecb"}, + {"AES-192-ECB", KAE_DEFAULT_PROPERTIES, kae_aes_192_ecb_functions, "kae_provider aes-192-ecb"}, + {"AES-256-ECB", KAE_DEFAULT_PROPERTIES, kae_aes_256_ecb_functions, "kae_provider aes-256-ecb"}, + {"AES-128-XTS", KAE_DEFAULT_PROPERTIES, kae_aes_128_xts_functions, "kae_provider aes-128-xts"}, + {"AES-256-XTS", KAE_DEFAULT_PROPERTIES, kae_aes_256_xts_functions, "kae_provider aes-256-xts"}, + {"AES-128-CTR", KAE_DEFAULT_PROPERTIES, kae_aes_128_ctr_functions, "kae_provider aes-128-ctr"}, + {"AES-192-CTR", KAE_DEFAULT_PROPERTIES, kae_aes_192_ctr_functions, "kae_provider aes-192-ctr"}, + {"AES-256-CTR", KAE_DEFAULT_PROPERTIES, kae_aes_256_ctr_functions, "kae_provider aes-256-ctr"}, + {"AES-128-OFB", KAE_DEFAULT_PROPERTIES, kae_aes_128_ofb128_functions, "kae_provider aes-128-ofb"}, + {"AES-192-OFB", KAE_DEFAULT_PROPERTIES, kae_aes_192_ofb128_functions, "kae_provider aes-192-ofb"}, + {"AES-256-OFB", KAE_DEFAULT_PROPERTIES, kae_aes_256_ofb128_functions, "kae_provider aes-256-ofb"}, + {"AES-128-CFB", KAE_DEFAULT_PROPERTIES, kae_aes_128_cfb128_functions, "kae_provider aes-128-cfb"}, + {"AES-192-CFB", KAE_DEFAULT_PROPERTIES, kae_aes_192_cfb128_functions, "kae_provider aes-192-cfb"}, + {"AES-256-CFB", KAE_DEFAULT_PROPERTIES, kae_aes_256_cfb128_functions, "kae_provider aes-256-cfb"}, + {"SM4-CBC", KAE_DEFAULT_PROPERTIES, kae_sm4_cbc_functions, "kae_provider sm4-cbc"}, + {"SM4-ECB", KAE_DEFAULT_PROPERTIES, kae_sm4_ecb_functions, "kae_provider sm4-ecb"}, + {"SM4-OFB", KAE_DEFAULT_PROPERTIES, kae_sm4_ofb128_functions, "kae_provider sm4-ofb"}, + {"SM4-CFB", KAE_DEFAULT_PROPERTIES, kae_sm4_cfb128_functions, "kae_provider sm4-cfb"}, + {"SM4-CTR", KAE_DEFAULT_PROPERTIES, kae_sm4_ctr_functions, "kae_provider sm4-ctr"}, + {NULL, NULL, NULL}}; +static const OSSL_ALGORITHM kae_prov_signature[] = { + {"RSA", KAE_DEFAULT_PROPERTIES, kae_rsa_signature_functions, "kae_provider rsa_signature"}, + {"SM2", KAE_DEFAULT_PROPERTIES, kae_sm2_signature_functions, "kae_provider sm2_signature"}, + {NULL, NULL, NULL}}; + +static const OSSL_ALGORITHM kae_prov_keymgmt[] = { + {"RSA", KAE_DEFAULT_PROPERTIES, kae_rsa_keymgmt_functions, "kae RSA Keymgmt implementation."}, + // {"DH", KAE_DEFAULT_PROPERTIES, kae_dh_keymgmt_functions, "kae DH Keymgmt implementation."}, + {"SM2", KAE_DEFAULT_PROPERTIES, kae_sm2_keymgmt_functions, "kae SM2 Keymgmt implementation."}, + {NULL, NULL, NULL}}; + +static const OSSL_ALGORITHM kae_prov_asym_cipher[] = { + {"RSA", KAE_DEFAULT_PROPERTIES, kae_rsa_asym_cipher_functions, "kae RSA asym cipher implementation."}, + {"SM2", KAE_DEFAULT_PROPERTIES, kae_sm2_asym_cipher_functions, "kae SM2 asym cipher implementation."}, + {NULL, NULL, NULL}}; + +static const OSSL_ALGORITHM kae_prov_keyexch[] = { + // {"DH", KAE_DEFAULT_PROPERTIES, kae_dh_keyexch_functions, "KAE DH keyexch implementation"}, {NULL, NULL, NULL} + }; + +static const OSSL_ALGORITHM *kae_query(void *provctx, int operation_id, int *no_cache) +{ + static int prov_init; + + prov = (OSSL_PROVIDER *)OSSL_PROVIDER_load(NULL, "default"); + if (!prov_init) { + prov_init = 1; + /* kae_provider takes the highest priority + * and overwrite the openssl.cnf property. + */ + EVP_set_default_properties(NULL, "?provider=kae_provider"); + } + + *no_cache = 0; + switch (operation_id) { + case OSSL_OP_DIGEST: + return kae_prov_digests; + case OSSL_OP_CIPHER: + return kae_prov_ciphers; + case OSSL_OP_SIGNATURE: + return kae_prov_signature; + case OSSL_OP_KEYMGMT: + return kae_prov_keymgmt; + case OSSL_OP_ASYM_CIPHER: + return kae_prov_asym_cipher; + case OSSL_OP_KEYEXCH: + return kae_prov_keyexch; + case OSSL_OP_STORE: + return prov->query_operation(provctx, operation_id, no_cache); + } + return NULL; +} + +static void kae_teardown(void *provctx) +{ + struct kae_prov_ctx *ctx = (struct kae_prov_ctx *)provctx; + OPENSSL_free(ctx); + + kae_checking_q_sync_destroy(); + OSSL_PROVIDER_unload(prov); + async_poll_task_free_v1(); +} + +static const OSSL_DISPATCH kae_dispatch_table[] = {{OSSL_FUNC_PROVIDER_QUERY_OPERATION, (void (*)(void))kae_query}, + {OSSL_FUNC_PROVIDER_TEARDOWN, (void (*)(void))kae_teardown}, + {0, NULL}}; + +int kae_get_params_from_core(const OSSL_CORE_HANDLE *handle) +{ + OSSL_PARAM core_params[2], *p = core_params; + + *p++ = OSSL_PARAM_construct_utf8_ptr("enable_soft_offload", (char **)&kae_params.enable_soft_offload, 0); + + *p = OSSL_PARAM_construct_end(); + + if (!c_get_params(handle, core_params)) { + fprintf(stderr, "WARN: KAE get parameters from core is failed.\n"); + return 0; + } + + if (kae_params.enable_soft_offload) { + enable_soft_offload = atoi(kae_params.enable_soft_offload); + } else { + enable_soft_offload = 1; + } + + return 1; +} + +static void provider_init_child_at_fork_handler(void) +{ + async_module_init_v1(); +} + +static int kae_prov_ctx_set_core_bio_method(struct kae_prov_ctx *ctx) +{ + KAE_BIO_METHOD *core_bio; + + core_bio = ossl_bio_prov_init_bio_method(); + if (core_bio == NULL) { + fprintf(stderr, "failed to set bio from dispatch\n"); + return 0; + } + + ctx->corebiometh = core_bio; + + return 1; +} + +static void ossl_prov_core_from_dispatch(const OSSL_DISPATCH *fns) +{ + while (fns && fns->function_id != 0) { + switch (fns->function_id) { + case OSSL_FUNC_CORE_GETTABLE_PARAMS: + c_gettable_params = OSSL_FUNC_core_gettable_params(fns); + break; + case OSSL_FUNC_CORE_GET_PARAMS: + c_get_params = OSSL_FUNC_core_get_params(fns); + break; + case OSSL_FUNC_CORE_GET_LIBCTX: + c_get_libctx = OSSL_FUNC_core_get_libctx(fns); + break; + default: + /* Just ignore anything we don't understand */ + break; + } + fns++; + } +} + +int OSSL_provider_init( + const OSSL_CORE_HANDLE *handle, const OSSL_DISPATCH *oin, const OSSL_DISPATCH **out, void **provctx) +{ + struct kae_prov_ctx *ctx; + int ret; + int dev_num; + + if (oin == NULL) { + fprintf(stderr, "failed to get dispatch in\n"); + return 0; + } + + ossl_prov_bio_from_dispatch(oin); + ossl_prov_core_from_dispatch(oin); + + kae_debug_init_log(); + + dev_num = wd_get_available_dev_num("rsa"); + if (dev_num > 0) { + if (!hpre_module_rsa_init()) { + fprintf(stderr, "kae nosva rsa module init fail, switch to soft.\n"); + rsa_switch_soft = 1; + } else { + uadk_rsa_nosva = 1; + printf("kae nosva rsa module init success.\n"); + } + } else { + fprintf(stderr, "no available rsa dev, switch to soft.\n"); + rsa_switch_soft = 1; + } + + dev_num = wd_get_available_dev_num("sm2"); + if (dev_num > 0) { + if (!hpre_module_sm2_init()) { + fprintf(stderr, "kae nosva sm2 module init fail, switch to soft.\n"); + sm2_switch_soft = 1; + } else { + uadk_sm2_nosva = 1; + printf("kae nosva sm2 module init success.\n"); + } + } else { + fprintf(stderr, "no available sm2 dev, switch to soft.\n"); + sm2_switch_soft = 1; + } + + // dev_num = wd_get_available_dev_num("dh"); + // if (dev_num > 0) { + // if (!hpre_module_dh_init()) { + // fprintf(stderr, "kae nosva dh module init fail, switch to soft.\n"); + // dh_switch_soft = 1; + // } else { + // uadk_dh_nosva = 1; + // printf("kae nosva dh module init success.\n"); + // } + // } else { + // fprintf(stderr, "no available dh dev, switch to soft.\n"); + // dh_switch_soft = 1; + // } + + dev_num = wd_get_available_dev_num("digest"); + if (dev_num > 0) { + if (!sec_digest_module_init()) { + fprintf(stderr, "kae nosva digest module init fail, switch to soft.\n"); + digest_switch_soft = 1; + } else { + uadk_digest_nosva = 1; + printf("kae nosva digest module init success.\n"); + } + } else { + fprintf(stderr, "no available digest dev, switch to soft.\n"); + digest_switch_soft = 1; + } + + dev_num = wd_get_available_dev_num("cipher"); + if (dev_num > 0) { + if (!sec_cipher_module_init()) { + fprintf(stderr, "kae nosva cipher module init fail, switch to soft.\n"); + cipher_switch_soft = 1; + } else { + uadk_cipher_nosva = 1; + printf("kae nosva cipher module init success.\n"); + } + } else { + fprintf(stderr, "no available cipher dev, switch to soft.\n"); + cipher_switch_soft = 1; + } + + /* get parameters from kae_provider.cnf */ + if (!kae_get_params_from_core(handle)) + return 0; + + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx == NULL) { + fprintf(stderr, "failed to alloc ctx\n"); + return 0; + } + + /* Set handle from core to get core functions */ + ctx->handle = handle; + ctx->libctx = (OSSL_LIB_CTX *)c_get_libctx(handle); + + ret = kae_prov_ctx_set_core_bio_method(ctx); + if (!ret) + return 0; + + async_module_init_v1(); + + pthread_atfork(NULL, NULL, provider_init_child_at_fork_handler); + + *provctx = (void *)ctx; + *out = kae_dispatch_table; + + return 1; +} \ No newline at end of file diff --git a/KAEOpensslProvider/src/provider/prov_nosva/internal/prov_bio.c b/KAEOpensslProvider/src/provider/prov_nosva/internal/prov_bio.c new file mode 100644 index 0000000000000000000000000000000000000000..b98b2f729763b407173243ea707bcfa124592d33 --- /dev/null +++ b/KAEOpensslProvider/src/provider/prov_nosva/internal/prov_bio.c @@ -0,0 +1,268 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include +#include +#include "prov_bio.h" + +#define KAE_PRO_SUCCESS 1 +#define KAE_PRO_FAIL 0 + +/* Functions provided by bio */ +static OSSL_FUNC_BIO_new_file_fn *c_bio_new_file; +static OSSL_FUNC_BIO_new_membuf_fn *c_bio_new_membuf; +static OSSL_FUNC_BIO_read_ex_fn *c_bio_read_ex; +static OSSL_FUNC_BIO_write_ex_fn *c_bio_write_ex; +static OSSL_FUNC_BIO_gets_fn *c_bio_gets; +static OSSL_FUNC_BIO_puts_fn *c_bio_puts; +static OSSL_FUNC_BIO_ctrl_fn *c_bio_ctrl; +static OSSL_FUNC_BIO_up_ref_fn *c_bio_up_ref; +static OSSL_FUNC_BIO_free_fn *c_bio_free; +static OSSL_FUNC_BIO_vprintf_fn *c_bio_vprintf; + +void ossl_prov_bio_from_dispatch(const OSSL_DISPATCH *fns) +{ + while (fns && fns->function_id != 0) { + switch (fns->function_id) { + case OSSL_FUNC_BIO_NEW_FILE: + if (c_bio_new_file == NULL) + c_bio_new_file = OSSL_FUNC_BIO_new_file(fns); + break; + case OSSL_FUNC_BIO_NEW_MEMBUF: + if (c_bio_new_membuf == NULL) + c_bio_new_membuf = OSSL_FUNC_BIO_new_membuf(fns); + break; + case OSSL_FUNC_BIO_READ_EX: + if (c_bio_read_ex == NULL) + c_bio_read_ex = OSSL_FUNC_BIO_read_ex(fns); + break; + case OSSL_FUNC_BIO_WRITE_EX: + if (c_bio_write_ex == NULL) + c_bio_write_ex = OSSL_FUNC_BIO_write_ex(fns); + break; + case OSSL_FUNC_BIO_GETS: + if (c_bio_gets == NULL) + c_bio_gets = OSSL_FUNC_BIO_gets(fns); + break; + case OSSL_FUNC_BIO_PUTS: + if (c_bio_puts == NULL) + c_bio_puts = OSSL_FUNC_BIO_puts(fns); + break; + case OSSL_FUNC_BIO_CTRL: + if (c_bio_ctrl == NULL) + c_bio_ctrl = OSSL_FUNC_BIO_ctrl(fns); + break; + case OSSL_FUNC_BIO_UP_REF: + if (c_bio_up_ref == NULL) + c_bio_up_ref = OSSL_FUNC_BIO_up_ref(fns); + break; + case OSSL_FUNC_BIO_FREE: + if (c_bio_free == NULL) + c_bio_free = OSSL_FUNC_BIO_free(fns); + break; + case OSSL_FUNC_BIO_VPRINTF: + if (c_bio_vprintf == NULL) + c_bio_vprintf = OSSL_FUNC_BIO_vprintf(fns); + break; + } + fns++; + } +} + +OSSL_CORE_BIO *ossl_prov_bio_new_file(const char *filename, const char *mode) +{ + if (c_bio_new_file == NULL) + return NULL; + + return c_bio_new_file(filename, mode); +} + +OSSL_CORE_BIO *ossl_prov_bio_new_membuf(const char *filename, int len) +{ + if (c_bio_new_membuf == NULL) + return NULL; + + return c_bio_new_membuf(filename, len); +} + +int ossl_prov_bio_read_ex(OSSL_CORE_BIO *bio, void *data, size_t data_len, + size_t *bytes_read) +{ + if (c_bio_read_ex == NULL) + return KAE_PRO_FAIL; + + return c_bio_read_ex(bio, data, data_len, bytes_read); +} + +int ossl_prov_bio_write_ex(OSSL_CORE_BIO *bio, const void *data, size_t data_len, + size_t *written) +{ + if (c_bio_write_ex == NULL) + return KAE_PRO_FAIL; + + return c_bio_write_ex(bio, data, data_len, written); +} + +int ossl_prov_bio_gets(OSSL_CORE_BIO *bio, char *buf, int size) +{ + if (c_bio_gets == NULL) + return -1; + + return c_bio_gets(bio, buf, size); +} + +int ossl_prov_bio_puts(OSSL_CORE_BIO *bio, const char *str) +{ + if (c_bio_puts == NULL) + return -1; + + return c_bio_puts(bio, str); +} + +int ossl_prov_bio_ctrl(OSSL_CORE_BIO *bio, int cmd, long num, void *ptr) +{ + if (c_bio_ctrl == NULL) + return -1; + + return c_bio_ctrl(bio, cmd, num, ptr); +} + +int ossl_prov_bio_up_ref(OSSL_CORE_BIO *bio) +{ + if (c_bio_up_ref == NULL) + return KAE_PRO_FAIL; + + return c_bio_up_ref(bio); +} + +int ossl_prov_bio_free(OSSL_CORE_BIO *bio) +{ + if (c_bio_free == NULL) + return KAE_PRO_FAIL; + + return c_bio_free(bio); +} + +int ossl_prov_bio_vprintf(OSSL_CORE_BIO *bio, const char *format, va_list ap) +{ + if (c_bio_vprintf == NULL) + return -1; + + return c_bio_vprintf(bio, format, ap); +} + +int ossl_prov_bio_printf(OSSL_CORE_BIO *bio, const char *format, ...) +{ + va_list ap; + int ret; + + va_start(ap, format); + ret = ossl_prov_bio_vprintf(bio, format, ap); + va_end(ap); + + return ret; +} + +#ifndef FIPS_MODULE +/* No direct BIO support in the FIPS module */ + +static int bio_core_read_ex(BIO *bio, char *data, size_t data_len, + size_t *bytes_read) +{ + return ossl_prov_bio_read_ex(BIO_get_data(bio), data, data_len, bytes_read); +} + +static int bio_core_write_ex(BIO *bio, const char *data, size_t data_len, + size_t *written) +{ + return ossl_prov_bio_write_ex(BIO_get_data(bio), data, data_len, written); +} + +static long bio_core_ctrl(BIO *bio, int cmd, long num, void *ptr) +{ + return ossl_prov_bio_ctrl(BIO_get_data(bio), cmd, num, ptr); +} + +static int bio_core_gets(BIO *bio, char *buf, int size) +{ + return ossl_prov_bio_gets(BIO_get_data(bio), buf, size); +} + +static int bio_core_puts(BIO *bio, const char *str) +{ + return ossl_prov_bio_puts(BIO_get_data(bio), str); +} + +static int bio_core_new(BIO *bio) +{ + BIO_set_init(bio, 1); + + return KAE_PRO_SUCCESS; +} + +BIO_METHOD *ossl_prov_ctx_get0_core_bio_method(KAE_PROV_CTX *ctx) +{ + if (ctx == NULL) + return NULL; + + return ctx->corebiometh; +} + +static int bio_core_free(BIO *bio) +{ + BIO_set_init(bio, 0); + ossl_prov_bio_free(BIO_get_data(bio)); + + return KAE_PRO_SUCCESS; +} + +BIO_METHOD *ossl_bio_prov_init_bio_method(void) +{ + BIO_METHOD *corebiometh = NULL; + + corebiometh = BIO_meth_new(BIO_TYPE_CORE_TO_PROV, "BIO to Core filter"); + if (corebiometh == NULL + || !BIO_meth_set_write_ex(corebiometh, bio_core_write_ex) + || !BIO_meth_set_read_ex(corebiometh, bio_core_read_ex) + || !BIO_meth_set_puts(corebiometh, bio_core_puts) + || !BIO_meth_set_gets(corebiometh, bio_core_gets) + || !BIO_meth_set_ctrl(corebiometh, bio_core_ctrl) + || !BIO_meth_set_create(corebiometh, bio_core_new) + || !BIO_meth_set_destroy(corebiometh, bio_core_free)) { + BIO_meth_free(corebiometh); + return NULL; + } + + return corebiometh; +} + +BIO *ossl_bio_new_from_core_bio(KAE_PROV_CTX *provctx, OSSL_CORE_BIO *corebio) +{ + BIO_METHOD *corebiometh = ossl_prov_ctx_get0_core_bio_method(provctx); + BIO *outbio; + + if (corebiometh == NULL) + return NULL; + + outbio = BIO_new(corebiometh); + if (outbio == NULL) + return NULL; + + if (!ossl_prov_bio_up_ref(corebio)) { + BIO_free(outbio); + return NULL; + } + + BIO_set_data(outbio, corebio); + + return outbio; +} +#endif diff --git a/KAEOpensslProvider/src/provider/prov_nosva/internal/prov_bio.h b/KAEOpensslProvider/src/provider/prov_nosva/internal/prov_bio.h new file mode 100644 index 0000000000000000000000000000000000000000..3fef9beb5daf06daacf89770a47cf1b1d8eea8f0 --- /dev/null +++ b/KAEOpensslProvider/src/provider/prov_nosva/internal/prov_bio.h @@ -0,0 +1,36 @@ +/* +* @Copyright: Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved. +* @Description: +* @Author: NieWeiQiang +* @Date: 2024-12-03 +* @LastEditTime: 2024-12-03 +*/ +#ifndef KAE_PROV_BIO_H +#define KAE_PROV_BIO_H + +#include +#include +#include +#include "../prov.h" + +void ossl_prov_bio_from_dispatch(const OSSL_DISPATCH *fns); + +OSSL_CORE_BIO *ossl_prov_bio_new_file(const char *filename, const char *mode); +OSSL_CORE_BIO *ossl_prov_bio_new_membuf(const char *filename, int len); +int ossl_prov_bio_read_ex(OSSL_CORE_BIO *bio, void *data, size_t data_len, + size_t *bytes_read); +int ossl_prov_bio_write_ex(OSSL_CORE_BIO *bio, const void *data, size_t data_len, + size_t *written); +int ossl_prov_bio_gets(OSSL_CORE_BIO *bio, char *buf, int size); +int ossl_prov_bio_puts(OSSL_CORE_BIO *bio, const char *str); +int ossl_prov_bio_ctrl(OSSL_CORE_BIO *bio, int cmd, long num, void *ptr); +int ossl_prov_bio_up_ref(OSSL_CORE_BIO *bio); +int ossl_prov_bio_free(OSSL_CORE_BIO *bio); +int ossl_prov_bio_vprintf(OSSL_CORE_BIO *bio, const char *format, va_list ap); +int ossl_prov_bio_printf(OSSL_CORE_BIO *bio, const char *format, ...); + +BIO_METHOD *ossl_bio_prov_init_bio_method(void); +BIO *ossl_bio_new_from_core_bio(KAE_PROV_CTX *provctx, OSSL_CORE_BIO *corebio); +BIO_METHOD *ossl_prov_ctx_get0_core_bio_method(KAE_PROV_CTX *ctx); + +#endif \ No newline at end of file diff --git a/KAEOpensslProvider/src/provider/prov_nosva/internal/prov_der_writer.c b/KAEOpensslProvider/src/provider/prov_nosva/internal/prov_der_writer.c new file mode 100644 index 0000000000000000000000000000000000000000..a02850623ef5def0ffd05d59b119e0994ef150f5 --- /dev/null +++ b/KAEOpensslProvider/src/provider/prov_nosva/internal/prov_der_writer.c @@ -0,0 +1,342 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include +#include "prov_der_writer.h" + +#define PACKET_LEN_TAG 30 +#define DER_P_OBJECT 6 +#define DER_OID_SZ_sm2_with_SM3 10 +#define DER_OID_SZ_ecdsa_with_SHA1 9 +#define DER_OID_SZ_ecdsa_with_SHA224 10 +#define DER_OID_SZ_ecdsa_with_SHA256 10 +#define DER_OID_SZ_ecdsa_with_SHA384 10 +#define DER_OID_SZ_ecdsa_with_SHA512 10 +#define DER_OID_SZ_id_ecdsa_with_sha3_224 11 +#define DER_OID_SZ_id_ecdsa_with_sha3_256 11 +#define DER_OID_SZ_id_ecdsa_with_sha3_384 11 +#define DER_OID_SZ_id_ecdsa_with_sha3_512 11 + +static const unsigned char +ossl_der_oid_id_ecdsa_with_sha1[DER_OID_SZ_ecdsa_with_SHA1] = { + DER_P_OBJECT, 7, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x01 +}; + +static const unsigned char +ossl_der_oid_id_ecdsa_with_sha224[DER_OID_SZ_ecdsa_with_SHA224] = { + DER_P_OBJECT, 8, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x01 +}; + +static const unsigned char +ossl_der_oid_id_ecdsa_with_sha256[DER_OID_SZ_ecdsa_with_SHA256] = { + DER_P_OBJECT, 8, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02 +}; + +static const unsigned char +ossl_der_oid_id_ecdsa_with_sha384[DER_OID_SZ_ecdsa_with_SHA384] = { + DER_P_OBJECT, 8, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x03 +}; + +static const unsigned char +ossl_der_oid_id_ecdsa_with_sha512[DER_OID_SZ_ecdsa_with_SHA384] = { + DER_P_OBJECT, 8, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x04 +}; + +static const unsigned char +ossl_der_oid_id_ecdsa_with_sha3_224[DER_OID_SZ_id_ecdsa_with_sha3_224] = { + DER_P_OBJECT, 9, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x09 +}; + +static const unsigned char +ossl_der_oid_id_ecdsa_with_sha3_256[DER_OID_SZ_id_ecdsa_with_sha3_256] = { + DER_P_OBJECT, 9, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x0A +}; + +static const unsigned char +ossl_der_oid_id_ecdsa_with_sha3_384[DER_OID_SZ_id_ecdsa_with_sha3_384] = { + DER_P_OBJECT, 9, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x0B +}; + +static const unsigned char +ossl_der_oid_id_ecdsa_with_sha3_512[DER_OID_SZ_id_ecdsa_with_sha3_512] = { + DER_P_OBJECT, 9, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x0C +}; + +static const unsigned char +ossl_der_oid_sm2_with_SM3[DER_OID_SZ_sm2_with_SM3] = { + 6, 8, 0x2A, 0x81, 0x1C, 0xCF, 0x55, 0x01, 0x83, 0x75 +}; + +static int int_start_context(WPACKET *pkt, int tag) +{ + if (tag < 0) + return 1; + if (!ossl_assert(tag <= PACKET_LEN_TAG)) + return 0; + + return WPACKET_start_sub_packet(pkt); +} + +static int int_end_context(WPACKET *pkt, int tag) +{ + /* + * If someone set the flag WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH on this + * sub-packet and this sub-packet has nothing written to it, the DER length + * will not be written, and the total written size will be unchanged before + * and after WPACKET_close(). We use size1 and size2 to determine if + * anything was written, and only write our tag if it has. + * + */ + size_t size1, size2; + + if (tag < 0) + return 1; + if (!ossl_assert(tag <= PACKET_LEN_TAG)) + return 0; + + /* Context specific are normally (?) constructed */ + tag |= DER_F_CONSTRUCTED | DER_C_CONTEXT; + + return WPACKET_get_total_written(pkt, &size1) + && WPACKET_close(pkt) + && WPACKET_get_total_written(pkt, &size2) + && (size1 == size2 || WPACKET_put_bytes_u8(pkt, tag)); +} + +int ossl_DER_w_precompiled(WPACKET *pkt, int tag, + const unsigned char *precompiled, + size_t precompiled_n) +{ + return int_start_context(pkt, tag) + && WPACKET_memcpy(pkt, precompiled, precompiled_n) + && int_end_context(pkt, tag); +} + +int ossl_DER_w_boolean(WPACKET *pkt, int tag, int b) +{ + return int_start_context(pkt, tag) + && WPACKET_start_sub_packet(pkt) + && (!b || WPACKET_put_bytes_u8(pkt, 0xFF)) + && !WPACKET_close(pkt) + && !WPACKET_put_bytes_u8(pkt, DER_P_BOOLEAN) + && int_end_context(pkt, tag); +} + +int ossl_DER_w_octet_string(WPACKET *pkt, int tag, + const unsigned char *data, size_t data_n) +{ + return int_start_context(pkt, tag) + && WPACKET_start_sub_packet(pkt) + && WPACKET_memcpy(pkt, data, data_n) + && WPACKET_close(pkt) + && WPACKET_put_bytes_u8(pkt, DER_P_OCTET_STRING) + && int_end_context(pkt, tag); +} + +int ossl_DER_w_octet_string_uint32(WPACKET *pkt, int tag, uint32_t value) +{ + unsigned char tmp[4] = { 0, 0, 0, 0 }; + unsigned char *pbuf = tmp + (sizeof(tmp) - 1); + + while (value > 0) { + *pbuf-- = (value & 0xFF); + value >>= LOW_BIT_SIZE; + } + + return ossl_DER_w_octet_string(pkt, tag, tmp, sizeof(tmp)); +} + +static int int_der_w_integer(WPACKET *pkt, int tag, + int (*put_bytes)(WPACKET *pkt, const void *v, + unsigned int *top_byte), + const void *v) +{ + unsigned int top_byte = 0; + + return int_start_context(pkt, tag) + && WPACKET_start_sub_packet(pkt) + && put_bytes(pkt, v, &top_byte) + && ((top_byte & 0x80) == 0 || WPACKET_put_bytes_u8(pkt, 0)) + && WPACKET_close(pkt) + && WPACKET_put_bytes_u8(pkt, DER_P_INTEGER) + && int_end_context(pkt, tag); +} + +static int int_put_bytes_uint32(WPACKET *pkt, const void *v, + unsigned int *top_byte) +{ + const uint32_t *value = v; + uint32_t tmp = *value; + size_t n = 0; + + while (tmp != 0) { + n++; + *top_byte = (tmp & 0xFF); + tmp >>= LOW_BIT_SIZE; + } + + if (n == 0) + n = 1; + + return WPACKET_put_bytes__(pkt, *value, n); +} + +/* For integers, we only support unsigned values for now */ +int ossl_DER_w_uint32(WPACKET *pkt, int tag, uint32_t v) +{ + return int_der_w_integer(pkt, tag, int_put_bytes_uint32, &v); +} + +static BN_ULONG *bn_get_words(const BIGNUM *a) +{ + return a->d; +} + +static int int_put_bytes_bn(WPACKET *pkt, const void *v, + unsigned int *top_byte) +{ + unsigned char *p = NULL; + size_t n = BN_num_bytes(v); + + /* The BIGNUM limbs are in LE order */ + *top_byte = + ((bn_get_words(v)[(n - 1) / BN_BYTES]) + >> (BYTES_TO_BITS_OFFSET * ((n - 1) % BN_BYTES))) + & 0xFF; + + if (!WPACKET_allocate_bytes(pkt, n, &p)) + return 0; + + if (p != NULL) + BN_bn2bin(v, p); + + return 1; +} + +int ossl_DER_w_bn(WPACKET *pkt, int tag, const BIGNUM *v) +{ + if (v == NULL || BN_is_negative(v)) + return 0; + + if (BN_is_zero(v)) + return ossl_DER_w_uint32(pkt, tag, 0); + + return int_der_w_integer(pkt, tag, int_put_bytes_bn, v); +} + +int ossl_DER_w_null(WPACKET *pkt, int tag) +{ + return int_start_context(pkt, tag) + && WPACKET_start_sub_packet(pkt) + && WPACKET_close(pkt) + && WPACKET_put_bytes_u8(pkt, DER_P_NULL) + && int_end_context(pkt, tag); +} + +/* Constructed things need a start and an end */ +int ossl_DER_w_begin_sequence(WPACKET *pkt, int tag) +{ + return int_start_context(pkt, tag) + && WPACKET_start_sub_packet(pkt); +} + +int ossl_DER_w_end_sequence(WPACKET *pkt, int tag) +{ + /* + * If someone set the flag WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH on this + * sub-packet and this sub-packet has nothing written to it, the DER length + * will not be written, and the total written size will be unchanged before + * and after WPACKET_close(). We use size1 and size2 to determine if + * anything was written, and only write our tag if it has. + * Because we know that int_end_context() needs to do the same check, + * we reproduce this flag if the written length was unchanged, or we will + * have an erroneous context tag. + */ + size_t size1, size2; + + return WPACKET_get_total_written(pkt, &size1) + && WPACKET_close(pkt) + && WPACKET_get_total_written(pkt, &size2) + && (size1 == size2 + ? WPACKET_set_flags(pkt, WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH) + : WPACKET_put_bytes_u8(pkt, DER_F_CONSTRUCTED | DER_P_SEQUENCE)) + && int_end_context(pkt, tag); +} + +int ossl_DER_w_algorithmIdentifier_SM2_with_MD(WPACKET *pkt, int cont, + EC_KEY *ec, int mdnid) +{ + const unsigned char *precompiled = NULL; + size_t precompiled_sz = 0; + + switch (mdnid) { + case NID_sm3: + precompiled = ossl_der_oid_sm2_with_SM3; + precompiled_sz = sizeof(ossl_der_oid_sm2_with_SM3); + break; + default: + return 0; + } + + return ossl_DER_w_begin_sequence(pkt, cont) /* No parameters (yet?) */ + && ossl_DER_w_precompiled(pkt, -1, precompiled, precompiled_sz) + && ossl_DER_w_end_sequence(pkt, cont); +} + +int ossl_DER_w_algorithmIdentifier_ECDSA_with_MD(WPACKET *pkt, int cont, + EC_KEY *ec, int mdnid) +{ + const unsigned char *precompiled = NULL; + size_t precompiled_sz = 0; + +#define MD_CASE(name) \ +do { \ + precompiled = ossl_der_oid_id_ecdsa_with_##name; \ + precompiled_sz = sizeof(ossl_der_oid_id_ecdsa_with_##name); \ +} while (0) + + switch (mdnid) { + case NID_sha1: + MD_CASE(sha1); + break; + case NID_sha224: + MD_CASE(sha224); + break; + case NID_sha256: + MD_CASE(sha256); + break; + case NID_sha384: + MD_CASE(sha384); + break; + case NID_sha512: + MD_CASE(sha512); + break; + case NID_sha3_224: + MD_CASE(sha3_224); + break; + case NID_sha3_256: + MD_CASE(sha3_256); + break; + case NID_sha3_384: + MD_CASE(sha3_384); + break; + case NID_sha3_512: + MD_CASE(sha3_512); + break; + default: + return 0; + } + + return ossl_DER_w_begin_sequence(pkt, cont) && + /* No parameters (yet?) */ + ossl_DER_w_precompiled(pkt, -1, precompiled, precompiled_sz) && + ossl_DER_w_end_sequence(pkt, cont); +} diff --git a/KAEOpensslProvider/src/provider/prov_nosva/internal/prov_der_writer.h b/KAEOpensslProvider/src/provider/prov_nosva/internal/prov_der_writer.h new file mode 100644 index 0000000000000000000000000000000000000000..c3734349e1c53a3ad7b63115e36a102f2894d9e3 --- /dev/null +++ b/KAEOpensslProvider/src/provider/prov_nosva/internal/prov_der_writer.h @@ -0,0 +1,131 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ +#ifndef KAE_PROV_DER_WRITER_H +#define KAE_PROV_DER_WRITER_H +#include +#include +#include +#include +#include "prov_packet.h" +#include "../../../adapter/common/kae_utils.h" + +/* + * NOTE: X.690 numbers the identifier octet bits 1 to 8. + * We use the same numbering in comments here. + */ + +/* Well known primitive tags */ + +/* + * DER UNIVERSAL tags, occupying bits 1-5 in the DER identifier byte + * These are only valid for the UNIVERSAL class. With the other classes, + * these bits have a different meaning. + */ +#define DER_P_EOC 0 /* BER End Of Contents tag */ +#define DER_P_BOOLEAN 1 +#define DER_P_INTEGER 2 +#define DER_P_BIT_STRING 3 +#define DER_P_OCTET_STRING 4 +#define DER_P_NULL 5 +#define DER_P_OBJECT 6 +#define DER_P_OBJECT_DESCRIPTOR 7 +#define DER_P_EXTERNAL 8 +#define DER_P_REAL 9 +#define DER_P_ENUMERATED 10 +#define DER_P_UTF8STRING 12 +#define DER_P_SEQUENCE 16 +#define DER_P_SET 17 +#define DER_P_NUMERICSTRING 18 +#define DER_P_PRINTABLESTRING 19 +#define DER_P_T61STRING 20 +#define DER_P_VIDEOTEXSTRING 21 +#define DER_P_IA5STRING 22 +#define DER_P_UTCTIME 23 +#define DER_P_GENERALIZEDTIME 24 +#define DER_P_GRAPHICSTRING 25 +#define DER_P_ISO64STRING 26 +#define DER_P_GENERALSTRING 27 +#define DER_P_UNIVERSALSTRING 28 +#define DER_P_BMPSTRING 30 + +/* DER Flags, occupying bit 6 in the DER identifier byte */ +#define DER_F_PRIMITIVE 0x00 +#define DER_F_CONSTRUCTED 0x20 + +/* DER classes tags, occupying bits 7-8 in the DER identifier byte */ +#define DER_C_UNIVERSAL 0x00 +#define DER_C_APPLICATION 0x40 +#define DER_C_CONTEXT 0x80 +#define DER_C_PRIVATE 0xC0 + +/* + * Run-time constructors. + * + * They all construct DER backwards, so care should be taken to use them + * that way. + */ + +/* This can be used for all items that don't have a context */ +#define DER_NO_CONTEXT -1 + +struct bignum_st { + BN_ULONG *d; /* Pointer to an array of 'BN_BITS2' bit chunks. */ + int top; /* Index of last used d +1. */ + /* The next are internal book keeping for bn_expand. */ + int dmax; /* Size of the d array. */ + int neg; /* one if the number is negative */ + int flags; +}; + +struct ec_key_st { + const EC_KEY_METHOD *meth; + ENGINE *engine; + int version; + EC_GROUP *group; + EC_POINT *pub_key; + BIGNUM *priv_key; + unsigned int enc_flag; + point_conversion_form_t conv_form; + int references; + int flags; +#ifndef FIPS_MODULE + CRYPTO_EX_DATA ex_data; +#endif + void *lock; + OSSL_LIB_CTX *libctx; + char *propq; + + /* Provider data */ + size_t dirty_cnt; /* If any key material changes, increment this */ +}; + +int ossl_DER_w_precompiled(WPACKET *pkt, int tag, + const unsigned char *precompiled, + size_t precompiled_n); + +int ossl_DER_w_boolean(WPACKET *pkt, int tag, int b); +int ossl_DER_w_uint32(WPACKET *pkt, int tag, uint32_t v); +int ossl_DER_w_bn(WPACKET *pkt, int tag, const BIGNUM *v); +int ossl_DER_w_null(WPACKET *pkt, int tag); +int ossl_DER_w_octet_string(WPACKET *pkt, int tag, + const unsigned char *data, size_t data_n); +int ossl_DER_w_octet_string_uint32(WPACKET *pkt, int tag, uint32_t value); + +/* + * All constructors for constructed elements have a begin and a end function + */ +int ossl_DER_w_begin_sequence(WPACKET *pkt, int tag); +int ossl_DER_w_end_sequence(WPACKET *pkt, int tag); + +int ossl_DER_w_algorithmIdentifier_SM2_with_MD(WPACKET *pkt, int cont, + EC_KEY *ec, int mdnid); +int ossl_DER_w_algorithmIdentifier_ECDSA_with_MD(WPACKET *pkt, int cont, + EC_KEY *ec, int mdnid); +#endif diff --git a/KAEOpensslProvider/src/provider/prov_nosva/internal/prov_ffc.c b/KAEOpensslProvider/src/provider/prov_nosva/internal/prov_ffc.c new file mode 100644 index 0000000000000000000000000000000000000000..48d7479f73bb3742efcdb3eb33ab305a6d804f99 --- /dev/null +++ b/KAEOpensslProvider/src/provider/prov_nosva/internal/prov_ffc.c @@ -0,0 +1,2030 @@ +// SPDX-License-Identifier: Apache-2.0 +/* + * Copyright 2015-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ +#include +#include +#include +#include +#include +#include +#include "prov_ffc.h" + +#if BN_BITS2 == 64 +#define BN_DEF(lo, hi) (BN_ULONG)hi << 32 | lo +#else +#define BN_DEF(lo, hi) lo, hi +#endif + +/* DH parameters from RFC3526 */ + +# ifndef FIPS_MODULE +/* + * "1536-bit MODP Group" from RFC3526, Section 2. + * + * The prime is: 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 } + * + * RFC3526 specifies a generator of 2. + * RFC2412 specifies a generator of 22. + */ +static const BN_ULONG modp_1536_p[] = { + BN_DEF(0xFFFFFFFF, 0xFFFFFFFF), BN_DEF(0xCA237327, 0xF1746C08), + BN_DEF((0x4ABC9804), (0x670C354E)), BN_DEF((0x7096966D), (0x9ED52907)), + BN_DEF(0x208552BB, 0x1C62F356), BN_DEF(0xDCA3AD96, 0x83655D23), + BN_DEF(0xFD24CF5F, 0x69163FA8), BN_DEF(0x1C55D39A, 0x98DA4836), + BN_DEF(0xA163BF05, 0xC2007CB8), BN_DEF(0xECE45B3D, 0x49286651), + BN_DEF(0x7C4B1FE6, 0xAE9F2411), BN_DEF(0x5A899FA5, 0xEE386BFB), + BN_DEF(0xF406B7ED, 0x0BFF5CB6), BN_DEF(0xA637ED6B, 0xF44C42E9), + BN_DEF(0x625E7EC6, 0xE485B576), BN_DEF(0x6D51C245, 0x4FE1356D), + BN_DEF(0xF25F1437, 0x302B0A6D), BN_DEF(0xCD3A431B, 0xEF9519B3), + BN_DEF(0x8E3404DD, 0x514A0879), BN_DEF(0x3B139B22, 0x020BBEA6), + BN_DEF(0x8A67CC74, 0x29024E08), BN_DEF(0x80DC1CD1, 0xC4C6628B), + BN_DEF(0x2168C234, 0xC90FDAA2), BN_DEF(0xFFFFFFFF, 0xFFFFFFFF) +}; + +/* q = (p - 1) / 2 */ +static const BN_ULONG modp_1536_q[] = { + BN_DEF(0xFFFFFFFF, 0xFFFFFFFF), BN_DEF(0x6511B993, 0x78BA3604), + BN_DEF(0x255E4C02, 0xB3861AA7), BN_DEF(0xB84B4B36, 0xCF6A9483), + BN_DEF(0x1042A95D, 0x0E3179AB), BN_DEF(0xEE51D6CB, 0xC1B2AE91), + BN_DEF(0x7E9267AF, 0x348B1FD4), BN_DEF(0x0E2AE9CD, 0xCC6D241B), + BN_DEF(0x50B1DF82, 0xE1003E5C), BN_DEF(0xF6722D9E, 0x24943328), + BN_DEF(0xBE258FF3, 0xD74F9208), BN_DEF(0xAD44CFD2, 0xF71C35FD), + BN_DEF(0x7A035BF6, 0x85FFAE5B), BN_DEF(0xD31BF6B5, 0x7A262174), + BN_DEF(0x312F3F63, 0xF242DABB), BN_DEF(0xB6A8E122, 0xA7F09AB6), + BN_DEF(0xF92F8A1B, 0x98158536), BN_DEF(0xE69D218D, 0xF7CA8CD9), + BN_DEF(0xC71A026E, 0x28A5043C), BN_DEF(0x1D89CD91, 0x0105DF53), + BN_DEF(0x4533E63A, 0x94812704), BN_DEF(0xC06E0E68, 0x62633145), + BN_DEF(0x10B4611A, 0xE487ED51), BN_DEF(0xFFFFFFFF, 0x7FFFFFFF) +}; +# endif /* FIPS_MODULE */ + +/* + * "2048-bit MODP Group" from RFC3526, Section 3. + * + * The prime is: 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 } + * + * RFC3526 specifies a generator of 2. + */ +static const BN_ULONG modp_2048_p[] = { + BN_DEF(0xFFFFFFFF, 0xFFFFFFFF), BN_DEF(0x8AACAA68, 0x15728E5A), + BN_DEF(0x98FA0510, 0x15D22618), BN_DEF(0xEA956AE5, 0x3995497C), + BN_DEF(0x95581718, 0xDE2BCBF6), BN_DEF(0x6F4C52C9, 0xB5C55DF0), + BN_DEF(0xEC07A28F, 0x9B2783A2), BN_DEF(0x180E8603, 0xE39E772C), + BN_DEF(0x2E36CE3B, 0x32905E46), BN_DEF(0xCA18217C, 0xF1746C08), + BN_DEF(0x4ABC9804, 0x670C354E), BN_DEF(0x7096966D, 0x9ED52907), + BN_DEF(0x208552BB, 0x1C62F356), BN_DEF(0xDCA3AD96, 0x83655D23), + BN_DEF(0xFD24CF5F, 0x69163FA8), BN_DEF(0x1C55D39A, 0x98DA4836), + BN_DEF((0xA163BF05), (0xC2007CB8)), BN_DEF(0xECE45B3D, 0x49286651), + BN_DEF(0x7C4B1FE6, 0xAE9F2411), BN_DEF(0x5A899FA5, 0xEE386BFB), + BN_DEF(0xF406B7ED, 0x0BFF5CB6), BN_DEF(0xA637ED6B, 0xF44C42E9), + BN_DEF((0x625E7EC6), (0xE485B576)), BN_DEF(0x6D51C245, 0x4FE1356D), + BN_DEF(0xF25F1437, 0x302B0A6D), BN_DEF(0xCD3A431B, 0xEF9519B3), + BN_DEF((0x8E3404DD), (0x514A0879)), BN_DEF(0x3B139B22, 0x020BBEA6), + BN_DEF(0x8A67CC74, 0x29024E08), BN_DEF(0x80DC1CD1, 0xC4C6628B), + BN_DEF(0x2168C234, 0xC90FDAA2), BN_DEF(0xFFFFFFFF, 0xFFFFFFFF) +}; +/* q = (p - 1) / 2 */ +static const BN_ULONG modp_2048_q[] = { + BN_DEF(0xFFFFFFFF, 0x7FFFFFFF), BN_DEF(0x45565534, 0x0AB9472D), + BN_DEF((0x4C7D0288), 0x8AE9130C), BN_DEF(0x754AB572, 0x1CCAA4BE), + BN_DEF(0x4AAC0B8C, 0xEF15E5FB), BN_DEF(0x37A62964, 0xDAE2AEF8), + BN_DEF(0x7603D147, 0xCD93C1D1), BN_DEF(0x0C074301, 0xF1CF3B96), + BN_DEF(0x171B671D, 0x19482F23), BN_DEF(0x650C10BE, 0x78BA3604), + BN_DEF((0x255E4C02), 0xB3861AA7), BN_DEF(0xB84B4B36, 0xCF6A9483), + BN_DEF(0x1042A95D, 0x0E3179AB), BN_DEF(0xEE51D6CB, 0xC1B2AE91), + BN_DEF(0x7E9267AF, 0x348B1FD4), BN_DEF(0x0E2AE9CD, 0xCC6D241B), + BN_DEF(0x50B1DF82, 0xE1003E5C), BN_DEF(0xF6722D9E, 0x24943328), + BN_DEF(0xBE258FF3, 0xD74F9208), BN_DEF(0xAD44CFD2, 0xF71C35FD), + BN_DEF((0x7A035BF6), 0x85FFAE5B), BN_DEF(0xD31BF6B5, 0x7A262174), + BN_DEF(0x312F3F63, 0xF242DABB), BN_DEF(0xB6A8E122, 0xA7F09AB6), + BN_DEF(0xF92F8A1B, 0x98158536), BN_DEF(0xE69D218D, 0xF7CA8CD9), + BN_DEF(0xC71A026E, 0x28A5043C), BN_DEF(0x1D89CD91, 0x0105DF53), + BN_DEF((0x4533E63A), 0x94812704), BN_DEF(0xC06E0E68, 0x62633145), + BN_DEF(0x10B4611A, 0xE487ED51), BN_DEF(0xFFFFFFFF, 0x7FFFFFFF), +}; + +/*- + * "3072-bit MODP Group" from RFC3526, Section 4. + * + * The prime is: 2^3072 - 2^3008 - 1 + 2^64 * { [2^2942 pi] + 1690314 } + * + * RFC3526 specifies a generator of 2. + */ +static const BN_ULONG modp_3072_p[] = { + BN_DEF(0xFFFFFFFF, 0xFFFFFFFF), BN_DEF(0xA93AD2CA, 0x4B82D120), + BN_DEF(0xE0FD108E, 0x43DB5BFC), BN_DEF(0x74E5AB31, 0x08E24FA0), + BN_DEF(0xBAD946E2, 0x770988C0), BN_DEF(0x7A615D6C, 0xBBE11757), + BN_DEF(0x177B200C, 0x521F2B18), BN_DEF(0x3EC86A64, 0xD8760273), + BN_DEF(0xD98A0864, 0xF12FFA06), BN_DEF(0x1AD2EE6B, 0xCEE3D226), + BN_DEF(0x4A25619D, 0x1E8C94E0), BN_DEF(0xDB0933D7, 0xABF5AE8C), + BN_DEF(0xA6E1E4C7, 0xB3970F85), BN_DEF(0x5D060C7D, 0x8AEA7157), + BN_DEF(0x58DBEF0A, 0xECFB8504), BN_DEF(0xDF1CBA64, 0xA85521AB), + BN_DEF(0x04507A33, 0xAD33170D), BN_DEF(0x8AAAC42D, 0x15728E5A), + BN_DEF(0x98FA0510, 0x15D22618), BN_DEF(0xEA956AE5, 0x3995497C), + BN_DEF(0x95581718, 0xDE2BCBF6), BN_DEF(0x6F4C52C9, 0xB5C55DF0), + BN_DEF(0xEC07A28F, 0x9B2783A2), BN_DEF(0x180E8603, 0xE39E772C), + BN_DEF(0x2E36CE3B, 0x32905E46), BN_DEF(0xCA18217C, 0xF1746C08), + BN_DEF(0x4ABC9804, 0x670C354E), BN_DEF(0x7096966D, 0x9ED52907), + BN_DEF(0x208552BB, 0x1C62F356), BN_DEF(0xDCA3AD96, 0x83655D23), + BN_DEF((0xFD24CF5F), (0x69163FA8)), BN_DEF(0x1C55D39A, 0x98DA4836), + BN_DEF(0xA163BF05, 0xC2007CB8), BN_DEF(0xECE45B3D, 0x49286651), + BN_DEF((0x7C4B1FE6), (0xAE9F2411)), BN_DEF(0x5A899FA5, 0xEE386BFB), + BN_DEF(0xF406B7ED, 0x0BFF5CB6), BN_DEF(0xA637ED6B, 0xF44C42E9), + BN_DEF(0x625E7EC6, 0xE485B576), BN_DEF(0x6D51C245, 0x4FE1356D), + BN_DEF(0xF25F1437, 0x302B0A6D), BN_DEF(0xCD3A431B, 0xEF9519B3), + BN_DEF(0x8E3404DD, 0x514A0879), BN_DEF(0x3B139B22, 0x020BBEA6), + BN_DEF((0x8A67CC74), (0x29024E08)), BN_DEF(0x80DC1CD1, 0xC4C6628B), + BN_DEF(0x2168C234, 0xC90FDAA2), BN_DEF(0xFFFFFFFF, 0xFFFFFFFF) +}; +/* q = (p - 1) / 2 */ +static const BN_ULONG modp_3072_q[] = { + BN_DEF(0xFFFFFFFF, 0x7FFFFFFF), BN_DEF(0x549D6965, 0x25C16890), + BN_DEF(0x707E8847, 0xA1EDADFE), BN_DEF(0x3A72D598, 0x047127D0), + BN_DEF(0x5D6CA371, 0x3B84C460), BN_DEF(0xBD30AEB6, 0x5DF08BAB), + BN_DEF(0x0BBD9006, 0x290F958C), BN_DEF(0x9F643532, 0x6C3B0139), + BN_DEF(0x6CC50432, 0xF897FD03), BN_DEF(0x0D697735, 0xE771E913), + BN_DEF(0x2512B0CE, 0x8F464A70), BN_DEF(0x6D8499EB, 0xD5FAD746), + BN_DEF(0xD370F263, 0xD9CB87C2), BN_DEF(0xAE83063E, 0x457538AB), + BN_DEF(0x2C6DF785, 0x767DC282), BN_DEF(0xEF8E5D32, 0xD42A90D5), + BN_DEF(0x82283D19, 0xD6998B86), BN_DEF(0x45556216, 0x0AB9472D), + BN_DEF(0x4C7D0288, 0x8AE9130C), BN_DEF(0x754AB572, 0x1CCAA4BE), + BN_DEF(0x4AAC0B8C, (0xEF15E5FB)), BN_DEF(0x37A62964, 0xDAE2AEF8), + BN_DEF(0x7603D147, 0xCD93C1D1), BN_DEF(0x0C074301, 0xF1CF3B96), + BN_DEF(0x171B671D, 0x19482F23), BN_DEF(0x650C10BE, 0x78BA3604), + BN_DEF(0x255E4C02, (0xB3861AA7)), BN_DEF(0xB84B4B36, 0xCF6A9483), + BN_DEF(0x1042A95D, 0x0E3179AB), BN_DEF(0xEE51D6CB, 0xC1B2AE91), + BN_DEF(0x7E9267AF, 0x348B1FD4), BN_DEF(0x0E2AE9CD, 0xCC6D241B), + BN_DEF(0x50B1DF82, 0xE1003E5C), BN_DEF(0xF6722D9E, 0x24943328), + BN_DEF(0xBE258FF3, 0xD74F9208), BN_DEF(0xAD44CFD2, 0xF71C35FD), + BN_DEF(0x7A035BF6, (0x85FFAE5B)), BN_DEF(0xD31BF6B5, 0x7A262174), + BN_DEF(0x312F3F63, 0xF242DABB), BN_DEF(0xB6A8E122, 0xA7F09AB6), + BN_DEF(0xF92F8A1B, 0x98158536), BN_DEF(0xE69D218D, 0xF7CA8CD9), + BN_DEF(0xC71A026E, (0x28A5043C)), BN_DEF(0x1D89CD91, 0x0105DF53), + BN_DEF(0x4533E63A, 0x94812704), BN_DEF(0xC06E0E68, 0x62633145), + BN_DEF(0x10B4611A, 0xE487ED51), BN_DEF(0xFFFFFFFF, 0x7FFFFFFF), +}; + +/*- + * "4096-bit MODP Group" from RFC3526, Section 5. + * + * The prime is: 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 } + * + * RFC3526 specifies a generator of 2. + */ +static const BN_ULONG modp_4096_p[] = { + BN_DEF(0xFFFFFFFF, 0xFFFFFFFF), BN_DEF(0x34063199, 0x4DF435C9), + BN_DEF(0x90A6C08F, 0x86FFB7DC), BN_DEF(0x8D8FDDC1, 0x93B4EA98), + BN_DEF(0xD5B05AA9, 0xD0069127), BN_DEF(0x2170481C, 0xB81BDD76), + BN_DEF(0xCEE2D7AF, 0x1F612970), BN_DEF(0x515BE7ED, 0x233BA186), + BN_DEF(0xA090C3A2, 0x99B2964F), BN_DEF(0x4E6BC05D, 0x287C5947), + BN_DEF(0x1FBECAA6, 0x2E8EFC14), BN_DEF(0x04DE8EF9, 0xDBBBC2DB), + BN_DEF(0x2AD44CE8, 0x2583E9CA), BN_DEF(0xB6150BDA, 0x1A946834), + BN_DEF(0x6AF4E23C, 0x99C32718), BN_DEF(0xBDBA5B26, 0x88719A10), + BN_DEF(0xA787E6D7, 0x1A723C12), BN_DEF(0xA9210801, 0x4B82D120), + BN_DEF(0xE0FD108E, 0x43DB5BFC), BN_DEF(0x74E5AB31, 0x08E24FA0), + BN_DEF(0xBAD946E2, 0x770988C0), BN_DEF(0x7A615D6C, 0xBBE11757), + BN_DEF(0x177B200C, 0x521F2B18), BN_DEF(0x3EC86A64, 0xD8760273), + BN_DEF(0xD98A0864, 0xF12FFA06), BN_DEF(0x1AD2EE6B, 0xCEE3D226), + BN_DEF(0x4A25619D, 0x1E8C94E0), BN_DEF(0xDB0933D7, 0xABF5AE8C), + BN_DEF(0xA6E1E4C7, 0xB3970F85), BN_DEF(0x5D060C7D, 0x8AEA7157), + BN_DEF(0x58DBEF0A, 0xECFB8504), BN_DEF(0xDF1CBA64, 0xA85521AB), + BN_DEF(0x04507A33, 0xAD33170D), BN_DEF(0x8AAAC42D, 0x15728E5A), + BN_DEF(0x98FA0510, 0x15D22618), BN_DEF(0xEA956AE5, 0x3995497C), + BN_DEF(0x95581718, 0xDE2BCBF6), BN_DEF(0x6F4C52C9, 0xB5C55DF0), + BN_DEF(0xEC07A28F, 0x9B2783A2), BN_DEF(0x180E8603, 0xE39E772C), + BN_DEF(0x2E36CE3B, 0x32905E46), BN_DEF(0xCA18217C, 0xF1746C08), + BN_DEF(0x4ABC9804, 0x670C354E), BN_DEF(0x7096966D, 0x9ED52907), + BN_DEF(0x208552BB, 0x1C62F356), BN_DEF(0xDCA3AD96, 0x83655D23), + BN_DEF((0xFD24CF5F), 0x69163FA8), BN_DEF(0x1C55D39A, 0x98DA4836), + BN_DEF(0xA163BF05, 0xC2007CB8), BN_DEF(0xECE45B3D, 0x49286651), + BN_DEF(0x7C4B1FE6, (0xAE9F2411)), BN_DEF(0x5A899FA5, 0xEE386BFB), + BN_DEF(0xF406B7ED, 0x0BFF5CB6), BN_DEF(0xA637ED6B, 0xF44C42E9), + BN_DEF((0x625E7EC6), 0xE485B576), BN_DEF(0x6D51C245, 0x4FE1356D), + BN_DEF(0xF25F1437, 0x302B0A6D), BN_DEF(0xCD3A431B, 0xEF9519B3), + BN_DEF(0x8E3404DD, 0x514A0879), BN_DEF(0x3B139B22, 0x020BBEA6), + BN_DEF(0x8A67CC74, (0x29024E08)), BN_DEF(0x80DC1CD1, 0xC4C6628B), + BN_DEF(0x2168C234, 0xC90FDAA2), BN_DEF(0xFFFFFFFF, 0xFFFFFFFF) +}; +/* q = (p - 1) / 2 */ +static const BN_ULONG modp_4096_q[] = { + BN_DEF(0xFFFFFFFF, 0xFFFFFFFF), BN_DEF(0x9A0318CC, 0xA6FA1AE4), + BN_DEF(0x48536047, 0xC37FDBEE), BN_DEF(0x46C7EEE0, 0xC9DA754C), + BN_DEF(0xEAD82D54, 0x68034893), BN_DEF(0x10B8240E, 0xDC0DEEBB), + BN_DEF(0x67716BD7, 0x8FB094B8), BN_DEF(0x28ADF3F6, 0x119DD0C3), + BN_DEF(0xD04861D1, 0xCCD94B27), BN_DEF(0xA735E02E, 0x143E2CA3), + BN_DEF(0x0FDF6553, 0x97477E0A), BN_DEF(0x826F477C, 0x6DDDE16D), + BN_DEF(0x156A2674, 0x12C1F4E5), BN_DEF(0x5B0A85ED, 0x0D4A341A), + BN_DEF(0x357A711E, 0x4CE1938C), BN_DEF(0x5EDD2D93, 0xC438CD08), + BN_DEF(0x53C3F36B, 0x8D391E09), BN_DEF(0x54908400, 0x25C16890), + BN_DEF(0x707E8847, 0xA1EDADFE), BN_DEF(0x3A72D598, 0x047127D0), + BN_DEF(0x5D6CA371, 0x3B84C460), BN_DEF(0xBD30AEB6, 0x5DF08BAB), + BN_DEF(0x0BBD9006, 0x290F958C), BN_DEF(0x9F643532, 0x6C3B0139), + BN_DEF(0x6CC50432, 0xF897FD03), BN_DEF(0x0D697735, 0xE771E913), + BN_DEF(0x2512B0CE, 0x8F464A70), BN_DEF(0x6D8499EB, 0xD5FAD746), + BN_DEF(0xD370F263, 0xD9CB87C2), BN_DEF(0xAE83063E, 0x457538AB), + BN_DEF(0x2C6DF785, 0x767DC282), BN_DEF(0xEF8E5D32, 0xD42A90D5), + BN_DEF(0x82283D19, 0xD6998B86), BN_DEF(0x45556216, 0x0AB9472D), + BN_DEF(0x4C7D0288, 0x8AE9130C), BN_DEF(0x754AB572, 0x1CCAA4BE), + BN_DEF(0x4AAC0B8C, 0xEF15E5FB), BN_DEF(0x37A62964, 0xDAE2AEF8), + BN_DEF(0x7603D147, 0xCD93C1D1), BN_DEF(0x0C074301, 0xF1CF3B96), + BN_DEF(0x171B671D, 0x19482F23), BN_DEF(0x650C10BE, (0x78BA3604)), + BN_DEF(0x255E4C02, 0xB3861AA7), BN_DEF(0xB84B4B36, 0xCF6A9483), + BN_DEF(0x1042A95D, 0x0E3179AB), BN_DEF(0xEE51D6CB, 0xC1B2AE91), + BN_DEF(0x7E9267AF, 0x348B1FD4), BN_DEF(0x0E2AE9CD, 0xCC6D241B), + BN_DEF(0x50B1DF82, 0xE1003E5C), BN_DEF(0xF6722D9E, (0x24943328)), + BN_DEF(0xBE258FF3, 0xD74F9208), BN_DEF(0xAD44CFD2, 0xF71C35FD), + BN_DEF(0x7A035BF6, 0x85FFAE5B), BN_DEF(0xD31BF6B5, 0x7A262174), + BN_DEF(0x312F3F63, 0xF242DABB), BN_DEF(0xB6A8E122, 0xA7F09AB6), + BN_DEF(0xF92F8A1B, 0x98158536), BN_DEF(0xE69D218D, (0xF7CA8CD9)), + BN_DEF(0xC71A026E, 0x28A5043C), BN_DEF(0x1D89CD91, 0x0105DF53), + BN_DEF(0x4533E63A, 0x94812704), BN_DEF(0xC06E0E68, 0x62633145), + BN_DEF(0x10B4611A, 0xE487ED51), BN_DEF(0xFFFFFFFF, 0x7FFFFFFF), +}; + +/* DH parameters from RFC5114 */ +static const BN_ULONG dh1024_160_p[] = { + BN_DEF(0x2E4A4371, 0xDF1FB2BC), BN_DEF(0x6D4DA708, 0xE68CFDA7), + BN_DEF(0x365C1A65, 0x45BF37DF), BN_DEF(0x0DC8B4BD, 0xA151AF5F), + BN_DEF(0xF55BCCC0, 0xFAA31A4F), BN_DEF(0xE5644738, 0x4EFFD6FA), + BN_DEF(0x219A7372, 0x98488E9C), BN_DEF(0x90C4BD70, 0xACCBDD7D), + BN_DEF(0xD49B83BF, 0x24975C3C), BN_DEF(0xA9061123, 0x13ECB4AE), + BN_DEF(0x2EE652C0, 0x9838EF1E), BN_DEF(0x75A23D18, 0x6073E286), + BN_DEF(0x52D23B61, 0x9A6A9DCA), BN_DEF(0xFB06A3C6, 0x52C99FBC), + BN_DEF(0xAE5D54EC, 0xDE92DE5E), BN_DEF(0xA080E01D, 0xB10B8F96) +}; +static const BN_ULONG dh1024_160_q[] = { + BN_DEF(0x49462353, 0x64B7CB9D), BN_DEF(0x8ABA4E7D, 0x81A8DF27), + (BN_ULONG)0xF518AA87 +}; +static const BN_ULONG dh1024_160_g[] = { + BN_DEF(0x22B3B2E5, 0x855E6EEB), BN_DEF(0xF97C2A24, 0x858F4DCE), + BN_DEF(0x18D08BC8, 0x2D779D59), BN_DEF(0x8E73AFA3, 0xD662A4D1), + BN_DEF(0x69B6A28A, 0x1DBF0A01), BN_DEF(0x7A091F53, 0xA6A24C08), + BN_DEF(0x63F80A76, 0x909D0D22), BN_DEF(0xB9A92EE1, 0xD7FBD7D3), + BN_DEF(0x9E2749F4, 0x5E91547F), BN_DEF(0xB01B886A, 0x160217B4), + BN_DEF(0x5504F213, 0x777E690F), BN_DEF(0x5C41564B, 0x266FEA1E), + BN_DEF(0x14266D31, 0xD6406CFF), BN_DEF(0x58AC507F, 0xF8104DD2), + BN_DEF(0xEFB99905, 0x6765A442), BN_DEF(0xC3FD3412, 0xA4D1CBD5) +}; + +static const BN_ULONG dh2048_224_p[] = { + BN_DEF(0x0C10E64F, 0x0AC4DFFE), BN_DEF(0x4E71B81C, 0xCF9DE538), + BN_DEF(0xFFA31F71, 0x7EF363E2), BN_DEF(0x6B8E75B9, 0xE3FB73C1), + BN_DEF(0x4BA80A29, 0xC9B53DCF), BN_DEF(0x16E79763, 0x23F10B0E), + BN_DEF(0x13042E9B, 0xC52172E4), BN_DEF(0xC928B2B9, 0xBE60E69C), + BN_DEF(0xB9E587E8, 0x80CD86A1), BN_DEF(0x98C641A4, 0x315D75E1), + BN_DEF(0x44328387, 0xCDF93ACC), BN_DEF(0xDC0A486D, 0x15987D9A), + BN_DEF(0x1FD5A074, 0x7310F712), BN_DEF(0xDE31EFDC, 0x278273C7), + BN_DEF(0x415D9330, 0x1602E714), BN_DEF(0xBC8985DB, 0x81286130), + BN_DEF(0x70918836, 0xB3BF8A31), BN_DEF(0xB9C49708, 0x6A00E0A0), + BN_DEF(0x8BBC27BE, 0xC6BA0B2C), BN_DEF(0xED34DBF6, 0xC9F98D11), + BN_DEF(0xB6C12207, 0x7AD5B7D0), BN_DEF(0x55B7394B, 0xD91E8FEF), + BN_DEF(0xEFDA4DF8, 0x9037C9ED), BN_DEF(0xAD6AC212, 0x6D3F8152), + BN_DEF(0x1274A0A6, 0x1DE6B85A), BN_DEF(0x309C180E, 0xEB3D688A), + BN_DEF(0x7BA1DF15, 0xAF9A3C40), BN_DEF(0xF95A56DB, 0xE6FA141D), + BN_DEF(0xB61D0A75, 0xB54B1597), BN_DEF(0x683B9FD1, 0xA20D64E5), + BN_DEF(0x9559C51F, 0xD660FAA7), BN_DEF(0x9123A9D0, 0xAD107E1E) +}; +static const BN_ULONG dh2048_224_q[] = { + BN_DEF(0xB36371EB, 0xBF389A99), BN_DEF(0x4738CEBC, 0x1F80535A), + BN_DEF(0x99717710, 0xC58D93FE), (BN_ULONG)0x801C0D34 +}; +static const BN_ULONG dh2048_224_g[] = { + BN_DEF(0x191F2BFA, 0x84B890D3), BN_DEF(0x2A7065B3, 0x81BC087F), + BN_DEF(0xF6EC0179, 0x19C418E1), BN_DEF(0x71CFFF4C, 0x7B5A0F1C), + BN_DEF(0x9B6AA4BD, 0xEDFE72FE), BN_DEF(0x94B30269, 0x81E1BCFE), + BN_DEF(0x8D6C0191, 0x566AFBB4), BN_DEF(0x409D13CD, 0xB539CCE3), + BN_DEF(0x5F2FF381, 0x6AA21E7F), BN_DEF(0x770589EF, 0xD9E263E4), + BN_DEF(0xD19963DD, 0x10E183ED), BN_DEF(0x150B8EEB, 0xB70A8137), + BN_DEF(0x28C8F8AC, 0x051AE3D4), BN_DEF(0x0C1AB15B, 0xBB77A86F), + BN_DEF(0x16A330EF, 0x6E3025E3), BN_DEF(0xD6F83456, 0x19529A45), + BN_DEF(0x118E98D1, 0xF180EB34), BN_DEF(0x50717CBE, 0xB5F6C6B2), + BN_DEF(0xDA7460CD, 0x09939D54), BN_DEF(0x22EA1ED4, 0xE2471504), + BN_DEF(0x521BC98A, 0xB8A762D0), BN_DEF(0x5AC1348B, 0xF4D02727), + BN_DEF(0x1999024A, 0xC1766910), BN_DEF(0xA8D66AD7, 0xBE5E9001), + BN_DEF(0x620A8652, 0xC57DB17C), BN_DEF(0x00C29F52, 0xAB739D77), + BN_DEF(0xA70C4AFA, 0xDD921F01), BN_DEF(0x10B9A6F0, 0xA6824A4E), + BN_DEF(0xCFE4FFE3, 0x74866A08), BN_DEF(0x89998CAF, 0x6CDEBE7B), + BN_DEF(0x8FFDAC50, 0x9DF30B5C), BN_DEF(0x4F2D9AE3, 0xAC4032EF) +}; + +static const BN_ULONG dh2048_256_p[] = { + BN_DEF(0x1E1A1597, 0xDB094AE9), BN_DEF(0xD7EF09CA, 0x693877FA), + BN_DEF(0x6E11715F, 0x6116D227), BN_DEF(0xC198AF12, 0xA4B54330), + BN_DEF(0xD7014103, 0x75F26375), BN_DEF(0x54E710C3, 0xC3A3960A), + BN_DEF(0xBD0BE621, 0xDED4010A), BN_DEF(0x89962856, 0xC0B857F6), + BN_DEF(0x71506026, 0xB3CA3F79), BN_DEF(0xE6B486F6, 0x1CCACB83), + BN_DEF(0x14056425, 0x67E144E5), BN_DEF(0xA41825D9, 0xF6A167B5), + BN_DEF(0x96524D8E, 0x3AD83477), BN_DEF(0x51BFA4AB, 0xF13C6D9A), + BN_DEF(0x35488A0E, 0x2D525267), BN_DEF(0xCAA6B790, 0xB63ACAE1), + BN_DEF(0x81B23F76, 0x4FDB70C5), BN_DEF(0x12307F5C, 0xBC39A0BF), + BN_DEF(0xB1E59BB8, 0xB941F54E), BN_DEF(0xD45F9088, 0x6C5BFC11), + BN_DEF(0x4275BF7B, 0x22E0B1EF), BN_DEF(0x5B4758C0, 0x91F9E672), + BN_DEF(0x6BCF67ED, 0x5A8A9D30), BN_DEF(0x97517ABD, 0x209E0C64), + BN_DEF(0x830E9A7C, 0x3BF4296D), BN_DEF(0x34096FAA, 0x16C3D911), + BN_DEF(0x61B2AA30, 0xFAF7DF45), BN_DEF(0xD61957D4, 0xE00DF8F1), + BN_DEF(0x435E3B00, 0x5D2CEED4), BN_DEF(0x660DD0F2, 0x8CEEF608), + BN_DEF(0x65195999, 0xFFBBD19C), BN_DEF(0xB4B6663C, 0x87A8E61D) +}; +static const BN_ULONG dh2048_256_q[] = { + BN_DEF(0x64F5FBD3, 0xA308B0FE), BN_DEF(0x1EB3750B, 0x99B1A47D), + BN_DEF(0x40129DA2, 0xB4479976), BN_DEF(0xA709A097, 0x8CF83642) +}; +static const BN_ULONG dh2048_256_g[] = { + BN_DEF(0x6CC41659, 0x664B4C0F), BN_DEF(0xEF98C582, 0x5E2327CF), + BN_DEF(0xD4795451, 0xD647D148), BN_DEF(0x90F00EF8, 0x2F630784), + BN_DEF(0x1DB246C3, 0x184B523D), BN_DEF(0xCDC67EB6, 0xC7891428), + BN_DEF(0x0DF92B52, 0x7FD02837), BN_DEF(0x64E0EC37, 0xB3353BBB), + BN_DEF(0x57CD0915, 0xECD06E15), BN_DEF(0xDF016199, 0xB7D2BBD2), + BN_DEF(0x052588B9, 0xC8484B1E), BN_DEF(0x13D3FE14, 0xDB2A3B73), + BN_DEF(0xD182EA0A, 0xD052B985), BN_DEF(0xE83B9C80, 0xA4BD1BFF), + BN_DEF(0xFB3F2E55, 0xDFC967C1), BN_DEF(0x767164E1, 0xB5045AF2), + BN_DEF(0x6F2F9193, 0x1D14348F), BN_DEF(0x428EBC83, 0x64E67982), + BN_DEF(0x82D6ED38, 0x8AC376D2), BN_DEF(0xAAB8A862, 0x777DE62A), + BN_DEF(0xE9EC144B, 0xDDF463E5), BN_DEF(0xC77A57F2, 0x0196F931), + BN_DEF(0x41000A65, 0xA55AE313), BN_DEF(0xC28CBB18, 0x901228F8), + BN_DEF(0x7E8C6F62, 0xBC3773BF), BN_DEF(0x0C6B47B1, 0xBE3A6C1B), + BN_DEF(0xAC0BB555, 0xFF4FED4A), BN_DEF(0x77BE463F, 0x10DBC150), + BN_DEF(0x1A0BA125, 0x07F4793A), BN_DEF(0x21EF2054, 0x4CA7B18F), + BN_DEF(0x60EDBD48, 0x2E775066), BN_DEF(0x73134D0B, 0x3FB32C9B) +}; + +/* Primes from RFC 7919 */ +static const BN_ULONG ffdhe2048_p[] = { + BN_DEF(0xFFFFFFFF, 0xFFFFFFFF), BN_DEF(0x61285C97, 0x886B4238), + BN_DEF(0xC1B2EFFA, 0xC6F34A26), BN_DEF(0x7D1683B2, 0xC58EF183), + BN_DEF(0x2EC22005, 0x3BB5FCBC), BN_DEF(0x4C6FAD73, 0xC3FE3B1B), + BN_DEF(0xEEF28183, 0x8E4F1232), BN_DEF(0xE98583FF, 0x9172FE9C), + BN_DEF(0x28342F61, 0xC03404CD), BN_DEF(0xCDF7E2EC, 0x9E02FCE1), + BN_DEF(0xEE0A6D70, 0x0B07A7C8), BN_DEF(0x6372BB19, 0xAE56EDE7), + BN_DEF(0xDE394DF4, 0x1D4F42A3), BN_DEF(0x60D7F468, 0xB96ADAB7), + BN_DEF(0xB2C8E3FB, 0xD108A94B), BN_DEF(0xB324FB61, 0xBC0AB182), + BN_DEF(0x483A797A, 0x30ACCA4F), BN_DEF(0x36ADE735, 0x1DF158A1), + BN_DEF(0xF3EFE872, 0xE2A689DA), BN_DEF(0xE0E68B77, 0x984F0C70), + BN_DEF(0x7F57C935, 0xB557135E), BN_DEF(0x3DED1AF3, 0x85636555), + BN_DEF(0x5F066ED0, 0x2433F51F), BN_DEF(0xD5FD6561, 0xD3DF1ED5), + BN_DEF(0xAEC4617A, 0xF681B202), BN_DEF(0x630C75D8, 0x7D2FE363), + BN_DEF(0x249B3EF9, 0xCC939DCE), BN_DEF(0x146433FB, 0xA9E13641), + BN_DEF(0xCE2D3695, 0xD8B9C583), BN_DEF(0x273D3CF1, 0xAFDC5620), + BN_DEF(0xA2BB4A9A, 0xADF85458), BN_DEF(0xFFFFFFFF, 0xFFFFFFFF) +}; +/* q = (p - 1) / 2 */ +static const BN_ULONG ffdhe2048_q[] = { + BN_DEF(0xFFFFFFFF, 0xFFFFFFFF), BN_DEF(0x30942E4B, 0x4435A11C), + BN_DEF(0x60D977FD, 0x6379A513), BN_DEF(0xBE8B41D9, 0xE2C778C1), + BN_DEF(0x17611002, 0x9DDAFE5E), BN_DEF(0xA637D6B9, 0xE1FF1D8D), + BN_DEF(0x777940C1, 0xC7278919), BN_DEF(0x74C2C1FF, 0xC8B97F4E), + BN_DEF(0x941A17B0, 0x601A0266), BN_DEF(0xE6FBF176, 0x4F017E70), + BN_DEF(0x770536B8, 0x8583D3E4), BN_DEF(0xB1B95D8C, 0x572B76F3), + BN_DEF(0xEF1CA6FA, 0x0EA7A151), BN_DEF(0xB06BFA34, 0xDCB56D5B), + BN_DEF(0xD96471FD, 0xE88454A5), BN_DEF(0x59927DB0, 0x5E0558C1), + BN_DEF(0xA41D3CBD, 0x98566527), BN_DEF(0x9B56F39A, 0x0EF8AC50), + BN_DEF(0x79F7F439, 0xF15344ED), BN_DEF(0x707345BB, 0xCC278638), + BN_DEF(0x3FABE49A, 0xDAAB89AF), BN_DEF(0x9EF68D79, 0x42B1B2AA), + BN_DEF(0xAF833768, 0x9219FA8F), BN_DEF(0xEAFEB2B0, 0x69EF8F6A), + BN_DEF(0x576230BD, 0x7B40D901), BN_DEF(0xB1863AEC, 0xBE97F1B1), + BN_DEF(0x124D9F7C, 0xE649CEE7), BN_DEF(0x8A3219FD, 0xD4F09B20), + BN_DEF(0xE7169B4A, 0xEC5CE2C1), BN_DEF(0x139E9E78, 0x57EE2B10), + BN_DEF(0x515DA54D, 0xD6FC2A2C), BN_DEF(0xFFFFFFFF, 0x7FFFFFFF), +}; + +static const BN_ULONG ffdhe3072_p[] = { + BN_DEF(0xFFFFFFFF, 0xFFFFFFFF), BN_DEF(0x66C62E37, 0x25E41D2B), + BN_DEF(0x3FD59D7C, 0x3C1B20EE), BN_DEF(0xFA53DDEF, 0x0ABCD06B), + BN_DEF(0xD5C4484E, 0x1DBF9A42), BN_DEF(0x9B0DEADA, 0xABC52197), + BN_DEF(0x22363A0D, 0xE86D2BC5), BN_DEF(0x9C9DF69E, 0x5CAE82AB), + BN_DEF(0x71F54BFF, 0x64F2E21E), BN_DEF(0xE2D74DD3, 0xF4FD4452), + BN_DEF(0xBC437944, 0xB4130C93), BN_DEF(0x85139270, 0xAEFE1309), + BN_DEF(0xC186D91C, 0x598CB0FA), BN_DEF(0x91F7F7EE, 0x7AD91D26), + BN_DEF(0xD6E6C907, 0x61B46FC9), BN_DEF(0xF99C0238, 0xBC34F4DE), + BN_DEF(0x6519035B, 0xDE355B3B), BN_DEF(0x611FCFDC, 0x886B4238), + BN_DEF(0xC1B2EFFA, 0xC6F34A26), BN_DEF(0x7D1683B2, 0xC58EF183), + BN_DEF(0x2EC22005, 0x3BB5FCBC), BN_DEF(0x4C6FAD73, 0xC3FE3B1B), + BN_DEF(0xEEF28183, 0x8E4F1232), BN_DEF(0xE98583FF, 0x9172FE9C), + BN_DEF(0x28342F61, 0xC03404CD), BN_DEF(0xCDF7E2EC, 0x9E02FCE1), + BN_DEF(0xEE0A6D70, 0x0B07A7C8), BN_DEF(0x6372BB19, 0xAE56EDE7), + BN_DEF(0xDE394DF4, 0x1D4F42A3), BN_DEF(0x60D7F468, 0xB96ADAB7), + BN_DEF(0xB2C8E3FB, 0xD108A94B), BN_DEF(0xB324FB61, 0xBC0AB182), + BN_DEF(0x483A797A, 0x30ACCA4F), BN_DEF(0x36ADE735, 0x1DF158A1), + BN_DEF(0xF3EFE872, 0xE2A689DA), BN_DEF(0xE0E68B77, 0x984F0C70), + BN_DEF(0x7F57C935, 0xB557135E), BN_DEF(0x3DED1AF3, 0x85636555), + BN_DEF(0x5F066ED0, 0x2433F51F), BN_DEF(0xD5FD6561, 0xD3DF1ED5), + BN_DEF(0xAEC4617A, 0xF681B202), BN_DEF(0x630C75D8, 0x7D2FE363), + BN_DEF(0x249B3EF9, 0xCC939DCE), BN_DEF(0x146433FB, 0xA9E13641), + BN_DEF(0xCE2D3695, 0xD8B9C583), BN_DEF(0x273D3CF1, 0xAFDC5620), + BN_DEF(0xA2BB4A9A, 0xADF85458), BN_DEF(0xFFFFFFFF, 0xFFFFFFFF) +}; +/* q = (p - 1) / 2 */ +static const BN_ULONG ffdhe3072_q[] = { + BN_DEF(0xFFFFFFFF, 0xFFFFFFFF), BN_DEF(0xB363171B, 0x12F20E95), + BN_DEF(0x1FEACEBE, 0x9E0D9077), BN_DEF(0xFD29EEF7, 0x055E6835), + BN_DEF(0x6AE22427, 0x0EDFCD21), BN_DEF(0xCD86F56D, 0xD5E290CB), + BN_DEF(0x911B1D06, 0x743695E2), BN_DEF(0xCE4EFB4F, 0xAE574155), + BN_DEF(0x38FAA5FF, 0xB279710F), BN_DEF(0x716BA6E9, 0x7A7EA229), + BN_DEF(0xDE21BCA2, 0x5A098649), BN_DEF(0xC289C938, 0x577F0984), + BN_DEF(0x60C36C8E, 0x2CC6587D), BN_DEF(0x48FBFBF7, 0xBD6C8E93), + BN_DEF(0xEB736483, 0x30DA37E4), BN_DEF(0x7CCE011C, 0xDE1A7A6F), + BN_DEF(0xB28C81AD, 0x6F1AAD9D), BN_DEF(0x308FE7EE, 0x4435A11C), + BN_DEF(0x60D977FD, 0x6379A513), BN_DEF(0xBE8B41D9, 0xE2C778C1), + BN_DEF(0x17611002, 0x9DDAFE5E), BN_DEF(0xA637D6B9, 0xE1FF1D8D), + BN_DEF(0x777940C1, 0xC7278919), BN_DEF(0x74C2C1FF, 0xC8B97F4E), + BN_DEF(0x941A17B0, 0x601A0266), BN_DEF(0xE6FBF176, 0x4F017E70), + BN_DEF(0x770536B8, 0x8583D3E4), BN_DEF(0xB1B95D8C, 0x572B76F3), + BN_DEF(0xEF1CA6FA, 0x0EA7A151), BN_DEF(0xB06BFA34, 0xDCB56D5B), + BN_DEF(0xD96471FD, 0xE88454A5), BN_DEF(0x59927DB0, 0x5E0558C1), + BN_DEF(0xA41D3CBD, 0x98566527), BN_DEF(0x9B56F39A, 0x0EF8AC50), + BN_DEF(0x79F7F439, 0xF15344ED), BN_DEF(0x707345BB, 0xCC278638), + BN_DEF(0x3FABE49A, 0xDAAB89AF), BN_DEF(0x9EF68D79, 0x42B1B2AA), + BN_DEF(0xAF833768, 0x9219FA8F), BN_DEF(0xEAFEB2B0, 0x69EF8F6A), + BN_DEF(0x576230BD, 0x7B40D901), BN_DEF(0xB1863AEC, 0xBE97F1B1), + BN_DEF(0x124D9F7C, 0xE649CEE7), BN_DEF(0x8A3219FD, 0xD4F09B20), + BN_DEF(0xE7169B4A, 0xEC5CE2C1), BN_DEF(0x139E9E78, 0x57EE2B10), + BN_DEF(0x515DA54D, 0xD6FC2A2C), BN_DEF(0xFFFFFFFF, 0x7FFFFFFF), +}; + +static const BN_ULONG ffdhe4096_p[] = { + BN_DEF(0xFFFFFFFF, 0xFFFFFFFF), BN_DEF(0x5E655F6A, 0xC68A007E), + BN_DEF(0xF44182E1, 0x4DB5A851), BN_DEF(0x7F88A46B, 0x8EC9B55A), + BN_DEF(0xCEC97DCF, 0x0A8291CD), BN_DEF(0xF98D0ACC, 0x2A4ECEA9), + BN_DEF(0x7140003C, 0x1A1DB93D), BN_DEF(0x33CB8B7A, 0x092999A3), + BN_DEF(0x71AD0038, 0x6DC778F9), BN_DEF(0x918130C4, 0xA907600A), + BN_DEF(0x2D9E6832, 0xED6A1E01), BN_DEF(0xEFB4318A, 0x7135C886), + BN_DEF(0x7E31CC7A, 0x87F55BA5), BN_DEF(0x55034004, 0x7763CF1D), + BN_DEF(0xD69F6D18, 0xAC7D5F42), BN_DEF(0xE58857B6, 0x7930E9E4), + BN_DEF(0x164DF4FB, 0x6E6F52C3), BN_DEF(0x669E1EF1, 0x25E41D2B), + BN_DEF(0x3FD59D7C, 0x3C1B20EE), BN_DEF(0xFA53DDEF, 0x0ABCD06B), + BN_DEF(0xD5C4484E, 0x1DBF9A42), BN_DEF(0x9B0DEADA, 0xABC52197), + BN_DEF(0x22363A0D, 0xE86D2BC5), BN_DEF(0x9C9DF69E, 0x5CAE82AB), + BN_DEF(0x71F54BFF, 0x64F2E21E), BN_DEF(0xE2D74DD3, 0xF4FD4452), + BN_DEF(0xBC437944, 0xB4130C93), BN_DEF(0x85139270, 0xAEFE1309), + BN_DEF(0xC186D91C, 0x598CB0FA), BN_DEF(0x91F7F7EE, 0x7AD91D26), + BN_DEF(0xD6E6C907, 0x61B46FC9), BN_DEF(0xF99C0238, 0xBC34F4DE), + BN_DEF(0x6519035B, 0xDE355B3B), BN_DEF(0x611FCFDC, 0x886B4238), + BN_DEF(0xC1B2EFFA, 0xC6F34A26), BN_DEF(0x7D1683B2, 0xC58EF183), + BN_DEF(0x2EC22005, 0x3BB5FCBC), BN_DEF(0x4C6FAD73, 0xC3FE3B1B), + BN_DEF(0xEEF28183, 0x8E4F1232), BN_DEF(0xE98583FF, 0x9172FE9C), + BN_DEF(0x28342F61, 0xC03404CD), BN_DEF(0xCDF7E2EC, 0x9E02FCE1), + BN_DEF(0xEE0A6D70, 0x0B07A7C8), BN_DEF(0x6372BB19, 0xAE56EDE7), + BN_DEF(0xDE394DF4, 0x1D4F42A3), BN_DEF(0x60D7F468, 0xB96ADAB7), + BN_DEF(0xB2C8E3FB, 0xD108A94B), BN_DEF(0xB324FB61, 0xBC0AB182), + BN_DEF(0x483A797A, 0x30ACCA4F), BN_DEF(0x36ADE735, 0x1DF158A1), + BN_DEF(0xF3EFE872, 0xE2A689DA), BN_DEF(0xE0E68B77, 0x984F0C70), + BN_DEF(0x7F57C935, 0xB557135E), BN_DEF(0x3DED1AF3, 0x85636555), + BN_DEF(0x5F066ED0, 0x2433F51F), BN_DEF(0xD5FD6561, 0xD3DF1ED5), + BN_DEF(0xAEC4617A, 0xF681B202), BN_DEF(0x630C75D8, 0x7D2FE363), + BN_DEF(0x249B3EF9, 0xCC939DCE), BN_DEF(0x146433FB, 0xA9E13641), + BN_DEF(0xCE2D3695, 0xD8B9C583), BN_DEF(0x273D3CF1, 0xAFDC5620), + BN_DEF(0xA2BB4A9A, 0xADF85458), BN_DEF(0xFFFFFFFF, 0xFFFFFFFF) +}; +/* q = (p - 1) / 2 */ +static const BN_ULONG ffdhe4096_q[] = { + BN_DEF(0xFFFFFFFF, 0x7FFFFFFF), BN_DEF(0x2F32AFB5, 0xE345003F), + BN_DEF(0xFA20C170, 0xA6DAD428), BN_DEF(0x3FC45235, 0xC764DAAD), + BN_DEF(0xE764BEE7, 0x054148E6), BN_DEF(0xFCC68566, 0x15276754), + BN_DEF(0xB8A0001E, 0x0D0EDC9E), BN_DEF(0x99E5C5BD, 0x0494CCD1), + BN_DEF(0xB8D6801C, 0x36E3BC7C), BN_DEF(0x48C09862, 0x5483B005), + BN_DEF(0x96CF3419, 0x76B50F00), BN_DEF(0x77DA18C5, 0x389AE443), + BN_DEF(0xBF18E63D, 0x43FAADD2), BN_DEF(0xAA81A002, 0x3BB1E78E), + BN_DEF(0x6B4FB68C, 0x563EAFA1), BN_DEF(0x72C42BDB, 0xBC9874F2), + BN_DEF(0x8B26FA7D, 0xB737A961), BN_DEF(0xB34F0F78, 0x12F20E95), + BN_DEF(0x1FEACEBE, 0x9E0D9077), BN_DEF(0xFD29EEF7, 0x055E6835), + BN_DEF(0x6AE22427, 0x0EDFCD21), BN_DEF(0xCD86F56D, 0xD5E290CB), + BN_DEF(0x911B1D06, 0x743695E2), BN_DEF(0xCE4EFB4F, 0xAE574155), + BN_DEF(0x38FAA5FF, 0xB279710F), BN_DEF(0x716BA6E9, 0x7A7EA229), + BN_DEF(0xDE21BCA2, 0x5A098649), BN_DEF(0xC289C938, 0x577F0984), + BN_DEF(0x60C36C8E, 0x2CC6587D), BN_DEF(0x48FBFBF7, 0xBD6C8E93), + BN_DEF(0xEB736483, 0x30DA37E4), BN_DEF(0x7CCE011C, 0xDE1A7A6F), + BN_DEF(0xB28C81AD, 0x6F1AAD9D), BN_DEF(0x308FE7EE, 0x4435A11C), + BN_DEF(0x60D977FD, 0x6379A513), BN_DEF(0xBE8B41D9, 0xE2C778C1), + BN_DEF(0x17611002, 0x9DDAFE5E), BN_DEF(0xA637D6B9, 0xE1FF1D8D), + BN_DEF(0x777940C1, 0xC7278919), BN_DEF(0x74C2C1FF, 0xC8B97F4E), + BN_DEF(0x941A17B0, 0x601A0266), BN_DEF(0xE6FBF176, 0x4F017E70), + BN_DEF(0x770536B8, 0x8583D3E4), BN_DEF(0xB1B95D8C, 0x572B76F3), + BN_DEF(0xEF1CA6FA, 0x0EA7A151), BN_DEF(0xB06BFA34, 0xDCB56D5B), + BN_DEF(0xD96471FD, 0xE88454A5), BN_DEF(0x59927DB0, 0x5E0558C1), + BN_DEF(0xA41D3CBD, 0x98566527), BN_DEF(0x9B56F39A, 0x0EF8AC50), + BN_DEF(0x79F7F439, 0xF15344ED), BN_DEF(0x707345BB, 0xCC278638), + BN_DEF(0x3FABE49A, 0xDAAB89AF), BN_DEF(0x9EF68D79, 0x42B1B2AA), + BN_DEF(0xAF833768, 0x9219FA8F), BN_DEF(0xEAFEB2B0, 0x69EF8F6A), + BN_DEF(0x576230BD, 0x7B40D901), BN_DEF(0xB1863AEC, 0xBE97F1B1), + BN_DEF(0x124D9F7C, 0xE649CEE7), BN_DEF(0x8A3219FD, 0xD4F09B20), + BN_DEF(0xE7169B4A, 0xEC5CE2C1), BN_DEF(0x139E9E78, 0x57EE2B10), + BN_DEF(0x515DA54D, 0xD6FC2A2C), BN_DEF(0xFFFFFFFF, 0x7FFFFFFF), +}; + +make_dh_bn(dh1024_160_p); +make_dh_bn(dh1024_160_q); +make_dh_bn(dh1024_160_g); +make_dh_bn(dh2048_224_p); +make_dh_bn(dh2048_224_q); +make_dh_bn(dh2048_224_g); +make_dh_bn(dh2048_256_p); +make_dh_bn(dh2048_256_q); +make_dh_bn(dh2048_256_g); + +make_dh_bn(ffdhe2048_p); +make_dh_bn(ffdhe2048_q); +make_dh_bn(ffdhe3072_p); +make_dh_bn(ffdhe3072_q); +make_dh_bn(ffdhe4096_p); +make_dh_bn(ffdhe4096_q); + +# ifndef FIPS_MODULE +make_dh_bn(modp_1536_p); +make_dh_bn(modp_1536_q); +# endif +make_dh_bn(modp_2048_p); +make_dh_bn(modp_2048_q); +make_dh_bn(modp_3072_p); +make_dh_bn(modp_3072_q); +make_dh_bn(modp_4096_p); +make_dh_bn(modp_4096_q); + +int ossl_ffc_params_set_seed(FFC_PARAMS *params, + const unsigned char *seed, size_t seedlen) +{ + if (params == NULL) + return 0; + + if (params->seed != NULL) { + if (params->seed == seed) + return 1; + OPENSSL_free(params->seed); + } + + if (seed != NULL && seedlen > 0) { + params->seed = OPENSSL_memdup(seed, seedlen); + if (params->seed == NULL) + return 0; + params->seedlen = seedlen; + } else { + params->seed = NULL; + params->seedlen = 0; + } + + return 1; +} + +static int ffc_bn_cpy(BIGNUM **dst, const BIGNUM *src) +{ + BIGNUM *a; + + /* + * If source is read only just copy the pointer, so + * we don't have to reallocate it. + */ + if (src == NULL) { + a = NULL; + goto end; + } + + if (BN_get_flags(src, BN_FLG_STATIC_DATA) && !BN_get_flags(src, BN_FLG_MALLOCED)) { + a = (BIGNUM *)src; + goto end; + } + + a = BN_dup(src); + if (a == NULL) + return 0; + +end: + BN_clear_free(*dst); + *dst = a; + + return 1; +} + +int ossl_ffc_params_copy(FFC_PARAMS *dst, const FFC_PARAMS *src) +{ + if (src == NULL || dst == NULL) + return 0; + + if (!ffc_bn_cpy(&dst->p, src->p) || + !ffc_bn_cpy(&dst->g, src->g) || + !ffc_bn_cpy(&dst->q, src->q) || + !ffc_bn_cpy(&dst->j, src->j)) + return 0; + + OPENSSL_free(dst->seed); + dst->seedlen = src->seedlen; + if (src->seed != NULL) { + dst->seed = OPENSSL_memdup(src->seed, src->seedlen); + if (dst->seed == NULL) + return 0; + } else { + dst->seed = NULL; + } + dst->nid = src->nid; + dst->pcounter = src->pcounter; + dst->h = src->h; + dst->gindex = src->gindex; + dst->flags = src->flags; + + return 1; +} + +void ossl_ffc_params_get0_pqg(const FFC_PARAMS *d, const BIGNUM **p, + const BIGNUM **q, const BIGNUM **g) +{ + if (d == NULL) + return; + + if (p != NULL) + *p = d->p; + + if (q != NULL) + *q = d->q; + + if (g != NULL) + *g = d->g; +} + +const DH_NAMED_GROUP *ossl_ffc_uid_to_dh_named_group(int uid) +{ + size_t i; + + for (i = 0; i < OSSL_NELEM(dh_named_groups); ++i) { + if (dh_named_groups[i].uid == uid) + return &dh_named_groups[i]; + } + + return NULL; +} + + +void ossl_ffc_params_set0_pqg(FFC_PARAMS *d, BIGNUM *p, BIGNUM *q, BIGNUM *g) +{ + if (d == NULL) + return; + + if (p != NULL && p != d->p) { + BN_free(d->p); + d->p = p; + } + + if (q != NULL && q != d->q) { + BN_free(d->q); + d->q = q; + } + + if (g != NULL && g != d->g) { + BN_free(d->g); + d->g = g; + } +} + +int ossl_ffc_named_group_set(FFC_PARAMS *ffc, const DH_NAMED_GROUP *group) +{ + if (ffc == NULL || group == NULL) + return 0; + + ossl_ffc_params_set0_pqg(ffc, (BIGNUM *)group->p, (BIGNUM *)group->q, + (BIGNUM *)group->g); + ffc->keylength = group->keylength; + + /* flush the cached nid, The DH layer is responsible for caching */ + ffc->nid = NID_undef; + + return 1; +} + +int ossl_ffc_named_group_get_uid(const DH_NAMED_GROUP *group) +{ + if (group == NULL) + return NID_undef; + + return group->uid; +} + +void ossl_ffc_params_set_gindex(FFC_PARAMS *params, int index) +{ + if (params == NULL) + return; + + params->gindex = index; +} + +void ossl_ffc_params_set_pcounter(FFC_PARAMS *params, int index) +{ + if (params == NULL) + return; + + params->pcounter = index; +} + +void ossl_ffc_params_set_h(FFC_PARAMS *params, int index) +{ + if (params == NULL) + return; + + params->h = index; +} + +int ossl_ffc_set_digest(FFC_PARAMS *params, const char *alg, const char *props) +{ + if (params == NULL) + return 0; + + params->mdname = alg; + params->mdprops = props; + + return 1; +} + +void ossl_ffc_params_enable_flags(FFC_PARAMS *params, unsigned int flags, + int enable) +{ + if (params == NULL) + return; + + if (enable) + params->flags |= flags; + else + params->flags &= ~flags; +} + +int ossl_ffc_params_cmp(const FFC_PARAMS *a, const FFC_PARAMS *b, int ignore_q) +{ + if (a == NULL || b == NULL) + return 0; + + return BN_cmp(a->p, b->p) == 0 + && BN_cmp(a->g, b->g) == 0 + && (ignore_q || BN_cmp(a->q, b->q) == 0); /* Note: q may be NULL */ +} + +void ossl_ffc_params_init(FFC_PARAMS *params) +{ + if (params == NULL) + return; + + memset(params, 0, sizeof(*params)); + params->pcounter = -1; + params->gindex = FFC_UNVERIFIABLE_GINDEX; + params->flags = FFC_PARAM_FLAG_VALIDATE_PQG; +} + +void ossl_ffc_params_cleanup(FFC_PARAMS *params) +{ + if (params == NULL) + return; + + BN_free(params->p); + BN_free(params->q); + BN_free(params->g); + BN_free(params->j); + OPENSSL_free(params->seed); + ossl_ffc_params_init(params); +} + +/* FIPS186-4 A.2.1 Unverifiable Generation of Generator g */ +static int generate_unverifiable_g(BN_CTX *ctx, BN_MONT_CTX *mont, BIGNUM *g, + BIGNUM *hbn, const BIGNUM *p, + const BIGNUM *e, const BIGNUM *pm1, + int *hret) +{ + int h = 2; + + /* Step (2): choose h (where 1 < h)*/ + if (!BN_set_word(hbn, h)) + return 0; + + for (;;) { + /* Step (3): g = h^e % p */ + if (!BN_mod_exp_mont(g, hbn, e, p, ctx, mont)) + return 0; + /* Step (4): Finish if g > 1 */ + if (BN_cmp(g, BN_value_one()) > 0) + break; + + /* Step (2) Choose any h in the range 1 < h < (p-1) */ + if (!BN_add_word(hbn, 1) || BN_cmp(hbn, pm1) >= 0) + return 0; + ++h; + } + *hret = h; + + return 1; +} + +/* Generation of p is the same for FIPS 186-4 & FIPS 186-2 */ +static int generate_p(BN_CTX *ctx, const EVP_MD *evpmd, int max_counter, int n, + unsigned char *buf, size_t buf_len, const BIGNUM *q, + BIGNUM *p, int L, BN_GENCB *cb, int *counter, + int *res) +{ + unsigned char md[EVP_MAX_MD_SIZE]; + BIGNUM *W, *X, *tmp, *c, *test; + int ret = -1; + int i, j, k, r; + int mdsize; + + BN_CTX_start(ctx); + W = BN_CTX_get(ctx); + X = BN_CTX_get(ctx); + c = BN_CTX_get(ctx); + test = BN_CTX_get(ctx); + tmp = BN_CTX_get(ctx); + if (tmp == NULL) + goto err; + + if (!BN_lshift(test, BN_value_one(), L - 1)) + goto err; + + mdsize = EVP_MD_get_size(evpmd); + if (mdsize <= 0) + goto err; + + /* + * A.1.1.2 Step (10) AND + * A.1.1.2 Step (12) + * offset = 1 (this is handled below) + */ + /* + * A.1.1.2 Step (11) AND + * A.1.1.3 Step (13) + */ + for (i = 0; i <= max_counter; i++) { + if ((i != 0) && !BN_GENCB_call(cb, 0, i)) + goto err; + + BN_zero(W); + /* seed_tmp buffer contains "seed + offset - 1" */ + for (j = 0; j <= n; j++) { + /* obtain "seed + offset + j" by incrementing by 1: */ + for (k = (int)buf_len - 1; k >= 0; k--) { + buf[k]++; + if (buf[k] != 0) + break; + } + /* + * A.1.1.2 Step (11.1) AND + * A.1.1.3 Step (13.1) + * tmp = V(j) = Hash((seed + offset + j) % 2^seedlen) + */ + if (!EVP_Digest(buf, buf_len, md, NULL, evpmd, NULL) || + (BN_bin2bn(md, mdsize, tmp) == NULL) || + /* + * A.1.1.2 Step (11.2) + * A.1.1.3 Step (13.2) + * W += V(j) * 2^(outlen * j) + */ + !BN_lshift(tmp, tmp, (mdsize << 3) * j) || + !BN_add(W, W, tmp)) + goto err; + } + + /* + * A.1.1.2 Step (11.3) AND + * A.1.1.3 Step (13.3) + * X = W + 2^(L-1) where W < 2^(L-1) + */ + if (!BN_mask_bits(W, L - 1) || + !BN_copy(X, W) || + !BN_add(X, X, test) || + /* + * A.1.1.2 Step (11.4) AND + * A.1.1.3 Step (13.4) + * c = X mod 2q + */ + !BN_lshift1(tmp, q) || + !BN_mod(c, X, tmp, ctx) || + /* + * A.1.1.2 Step (11.5) AND + * A.1.1.3 Step (13.5) + * p = X - (c - 1) + */ + !BN_sub(tmp, c, BN_value_one()) || + !BN_sub(p, X, tmp)) + goto err; + + /* + * A.1.1.2 Step (11.6) AND + * A.1.1.3 Step (13.6) + * if (p < 2 ^ (L-1)) continue + * This makes sure the top bit is set. + */ + if (BN_cmp(p, test) >= 0) { + /* + * A.1.1.2 Step (11.7) AND + * A.1.1.3 Step (13.7) + * Test if p is prime + * (This also makes sure the bottom bit is set) + */ + r = BN_check_prime(p, ctx, cb); + /* A.1.1.2 Step (11.8) : Return if p is prime */ + if (r > 0) { + *counter = i; + ret = 1; /* return success */ + goto err; + } + if (r != 0) + goto err; + } + /* Step (11.9) : offset = offset + n + 1 is done auto-magically */ + } + /* No prime P found */ + ret = 0; + *res |= FFC_CHECK_P_NOT_PRIME; + +err: + BN_CTX_end(ctx); + return ret; +} + +static OSSL_LIB_CTX *ossl_bn_get_libctx(BN_CTX *ctx) +{ + if (ctx == NULL) + return NULL; + + return ctx->libctx; +} + +static int generate_q_fips186_2(BN_CTX *ctx, BIGNUM *q, const EVP_MD *evpmd, + unsigned char *buf, unsigned char *seed, + size_t qsize, int generate_seed, int *retm, + int *res, BN_GENCB *cb) +{ + OSSL_LIB_CTX *libctx = ossl_bn_get_libctx(ctx); + unsigned char buf2[EVP_MAX_MD_SIZE]; + unsigned char md[EVP_MAX_MD_SIZE]; + int i, r, ret = 0, m = *retm; + + /* find q */ + for (;;) { + /* step 1 */ + if (!BN_GENCB_call(cb, 0, m++)) + goto err; + + if (generate_seed && RAND_bytes_ex(libctx, seed, qsize, 0) <= 0) + goto err; + + memcpy(buf, seed, qsize); + memcpy(buf2, seed, qsize); + + /* precompute "SEED + 1" for step 7: */ + for (i = (int)qsize - 1; i >= 0; i--) { + buf[i]++; + if (buf[i] != 0) + break; + } + + /* step 2 */ + if (!EVP_Digest(seed, qsize, md, NULL, evpmd, NULL)) + goto err; + if (!EVP_Digest(buf, qsize, buf2, NULL, evpmd, NULL)) + goto err; + for (i = 0; i < (int)qsize; i++) + md[i] ^= buf2[i]; + + /* step 3 */ + md[0] |= 0x80; + md[qsize - 1] |= 0x01; + if (!BN_bin2bn(md, (int)qsize, q)) + goto err; + + /* step 4 */ + r = BN_check_prime(q, ctx, cb); + if (r > 0) { + /* Found a prime */ + ret = 1; + goto err; + } + if (r != 0) + goto err; /* Exit if error */ + /* Try another iteration if it wasnt prime - was in old code.. */ + generate_seed = 1; + } +err: + *retm = m; + return ret; +} + +/* + * Verify that the passed in L, N pair for DH or DSA is valid. + * Returns 0 if invalid, otherwise it returns the security strength. + */ + +#ifdef FIPS_MODULE +static int ffc_validate_LN(size_t L, size_t N, int type, int verify) +{ + if (type == FFC_PARAM_TYPE_DH) { + /* Valid DH L,N parameters from SP800-56Ar3 5.5.1 Table 1 */ + if (L == L_P_2048BITS && (N == N_Q_224BITS || N == N_Q_256BITS)) + return SECURITY_STR_112BITS; +# ifndef OPENSSL_NO_DH + ERR_raise(ERR_LIB_DH, DH_R_BAD_FFC_PARAMETERS); +# endif + } else if (type == FFC_PARAM_TYPE_DSA) { + /* Valid DSA L,N parameters from FIPS 186-4 Section 4.2 */ + /* In fips mode 1024/160 can only be used for verification */ + if (verify && L == L_P_1024BITS && N == N_Q_160BITS) + return SECURITY_STR_80BITS; + if (L == L_P_2048BITS && (N == N_Q_224BITS || N == N_Q_256BITS)) + return SECURITY_STR_112BITS; + if (L == L_P_3072BITS && N == N_Q_256BITS) + return SECURITY_STR_128BITS; +# ifndef OPENSSL_NO_DSA + ERR_raise(ERR_LIB_DSA, DSA_R_BAD_FFC_PARAMETERS); +# endif + } + + return 0; +} +#else +static int ffc_validate_LN(size_t L, size_t N, int type, int verify) +{ + if (type == FFC_PARAM_TYPE_DH) { + /* Allow legacy 1024/160 in non fips mode */ + if (L == L_P_1024BITS && N == N_Q_160BITS) + return SECURITY_STR_80BITS; + /* Valid DH L,N parameters from SP800-56Ar3 5.5.1 Table 1 */ + if (L == L_P_2048BITS && (N == N_Q_224BITS || N == N_Q_256BITS)) + return SECURITY_STR_112BITS; +# ifndef OPENSSL_NO_DH + ERR_raise(ERR_LIB_DH, DH_R_BAD_FFC_PARAMETERS); +# endif + } else if (type == FFC_PARAM_TYPE_DSA) { + if (L >= L_P_3072BITS && N >= N_Q_256BITS) + return SECURITY_STR_128BITS; + if (L >= L_P_2048BITS && N >= N_Q_224BITS) + return SECURITY_STR_112BITS; + if (L >= L_P_1024BITS && N >= N_Q_160BITS) + return SECURITY_STR_80BITS; +# ifndef OPENSSL_NO_DSA + ERR_raise(ERR_LIB_DSA, DSA_R_BAD_FFC_PARAMETERS); +# endif + } + + return 0; +} +#endif /* FIPS_MODULE */ + +static int ossl_ffc_params_set_validate_params(FFC_PARAMS *params, + const unsigned char *seed, + size_t seedlen, int counter) +{ + if (!ossl_ffc_params_set_seed(params, seed, seedlen)) + return 0; + params->pcounter = counter; + + return 1; +} + +static const char *default_mdname(size_t N) +{ + if (N == N_Q_160BITS) + return "SHA1"; + else if (N == N_Q_224BITS) + return "SHA-224"; + else if (N == N_Q_256BITS) + return "SHA-256"; + + return NULL; +} + +/* FIPS186-4 A.2.2 Unverifiable partial validation of Generator g */ +static int ossl_ffc_params_validate_unverifiable_g(BN_CTX *ctx, BN_MONT_CTX *mont, + const BIGNUM *p, const BIGNUM *q, + const BIGNUM *g, BIGNUM *tmp, + int *ret) +{ + /* + * A.2.2 Step (1) AND + * A.2.4 Step (2) + * Verify that 2 <= g <= (p - 1) + */ + if (BN_cmp(g, BN_value_one()) <= 0 || BN_cmp(g, p) >= 0) { + *ret |= FFC_ERROR_NOT_SUITABLE_GENERATOR; + return 0; + } + + /* + * A.2.2 Step (2) AND + * A.2.4 Step (3) + * Check g^q mod p = 1 + */ + if (!BN_mod_exp_mont(tmp, g, q, p, ctx, mont)) + return 0; + if (BN_cmp(tmp, BN_value_one()) != 0) { + *ret |= FFC_ERROR_NOT_SUITABLE_GENERATOR; + return 0; + } + + return 1; +} + +/* Note this function is only used for verification in fips mode */ +int ossl_ffc_params_FIPS186_2_gen_verify(OSSL_LIB_CTX *libctx, + FFC_PARAMS *params, int mode, int type, + size_t L, size_t N, int *res, + BN_GENCB *cb) +{ + unsigned char seed[SHA256_DIGEST_LENGTH]; + unsigned char buf[SHA256_DIGEST_LENGTH]; + unsigned char *seed_in = params->seed; + int ok = FFC_PARAM_RET_STATUS_FAILED; + size_t seed_len = params->seedlen; + int use_random_seed, rv, verify; + BN_MONT_CTX *mont = NULL; + BIGNUM *r0, *test, *tmp; + const char *def_name; + unsigned int flags; + BN_CTX *ctx = NULL; + EVP_MD *md = NULL; + BIGNUM *g = NULL; + BIGNUM *q = NULL; + BIGNUM *p = NULL; + int pcounter = 0; + int counter = 0; + int hret = -1; + size_t qsize; + int done = 0; + int m = 0; + int n = 0; + + verify = (mode == FFC_PARAM_MODE_VERIFY); + flags = verify ? params->flags : 0; + *res = 0; + + if (params->mdname != NULL) { + md = EVP_MD_fetch(libctx, params->mdname, params->mdprops); + } else { + if (N == 0) { + if (L >= L_P_2048BITS) + N = TRANS_BYTES_TO_BITS(SHA256_DIGEST_LENGTH); + else + N = TRANS_BYTES_TO_BITS(SHA_DIGEST_LENGTH); + } + + def_name = default_mdname(N); + if (def_name == NULL) { + *res = FFC_CHECK_INVALID_Q_VALUE; + goto err; + } + md = EVP_MD_fetch(libctx, def_name, params->mdprops); + } + if (md == NULL) + goto err; + + if (N == 0) + N = TRANS_BYTES_TO_BITS(EVP_MD_get_size(md)); + + qsize = TRANS_BITS_TO_BYTES(N); + + /* + * The original spec allowed L = 512 + 64*j (j = 0.. 8) + * https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar2.pdf + * says that 512 can be used for legacy verification. + */ + if (L < L_P_512BITS) { + *res = FFC_CHECK_BAD_LN_PAIR; + goto err; + } + if (qsize != SHA_DIGEST_LENGTH && + qsize != SHA224_DIGEST_LENGTH && + qsize != SHA256_DIGEST_LENGTH) { + /* invalid q size */ + *res = FFC_CHECK_INVALID_Q_VALUE; + goto err; + } + /* Padding 'L' to the integer multiple of 64 */ + L = PADDING_LEN(L); + + if (seed_in != NULL) { + if (seed_len < qsize) { + *res = FFC_CHECK_INVALID_SEED_SIZE; + goto err; + } + /* Only consume as much seed as is expected. */ + if (seed_len > qsize) + seed_len = qsize; + memcpy(seed, seed_in, seed_len); + } + + ctx = BN_CTX_new_ex(libctx); + if (ctx == NULL) + goto err; + + BN_CTX_start(ctx); + + r0 = BN_CTX_get(ctx); + g = BN_CTX_get(ctx); + q = BN_CTX_get(ctx); + p = BN_CTX_get(ctx); + tmp = BN_CTX_get(ctx); + test = BN_CTX_get(ctx); + if (test == NULL) + goto err; + + if (!BN_lshift(test, BN_value_one(), L - 1)) + goto err; + + if (!verify) { + /* For generation: p & q must both be NULL or NON-NULL */ + if ((params->p != NULL) != (params->q != NULL)) { + *res = FFC_CHECK_INVALID_PQ; + goto err; + } + } else { + if ((flags & FFC_PARAM_FLAG_VALIDATE_PQ) != 0) { + /* Validation of p,q requires seed and counter to be valid */ + if (seed_in == NULL || params->pcounter < 0) { + *res = FFC_CHECK_MISSING_SEED_OR_COUNTER; + goto err; + } + } + if ((flags & FFC_PARAM_FLAG_VALIDATE_G) != 0) { + /* validation of g also requires g to be set */ + if (params->g == NULL) { + *res = FFC_CHECK_INVALID_G; + goto err; + } + } + } + + if (params->p != NULL && ((flags & FFC_PARAM_FLAG_VALIDATE_PQ) == 0)) { + /* p and q already exists so only generate g */ + p = params->p; + q = params->q; + goto g_only; + /* otherwise to validate p and q */ + } + + use_random_seed = (seed_in == NULL); + do { + if (!generate_q_fips186_2(ctx, q, md, buf, seed, qsize, + use_random_seed, &m, res, cb)) + goto err; + + if (!BN_GENCB_call(cb, GENCB_NEXT, 0)) + goto err; + if (!BN_GENCB_call(cb, GENCB_RETRY, 0)) + goto err; + + /* step 6 compute the block num with digest length 160 bits */ + n = (L - 1) / 160; + counter = 4 * L - 1; /* Was 4096 */ + /* Validation requires the counter to be supplied */ + if (verify) { + if (params->pcounter > counter) { + *res = FFC_CHECK_INVALID_COUNTER; + goto err; + } + counter = params->pcounter; + } + + rv = generate_p(ctx, md, counter, n, buf, qsize, q, p, L, cb, + &pcounter, res); + if (rv > 0) + done = 1; /* found it */ + else if (rv == -1) + goto err; + else + /* This is what the old code did - probably not a good idea! */ + use_random_seed = 1; + } while (!done); + + if (!BN_GENCB_call(cb, GENCB_NEXT, 1)) + goto err; + + if (verify) { + if (pcounter != counter) { + *res = FFC_CHECK_COUNTER_MISMATCH; + goto err; + } + + if (BN_cmp(p, params->p) != 0) { + *res = FFC_CHECK_P_MISMATCH; + goto err; + } + } + /* If validating p & q only then skip the g validation test */ + if ((flags & FFC_PARAM_FLAG_VALIDATE_PQG) == FFC_PARAM_FLAG_VALIDATE_PQ) + goto pass; + +g_only: + mont = BN_MONT_CTX_new(); + if (mont == NULL) + goto err; + if (!BN_MONT_CTX_set(mont, p, ctx)) + goto err; + + if (!verify) { + /* We now need to generate g */ + /* set test = p - 1 */ + if (!BN_sub(test, p, BN_value_one())) + goto err; + /* Set r0 = (p - 1) / q */ + if (!BN_div(r0, NULL, test, q, ctx)) + goto err; + if (!generate_unverifiable_g(ctx, mont, g, tmp, p, r0, test, &hret)) + goto err; + } else if (((flags & FFC_PARAM_FLAG_VALIDATE_G) != 0) && + !ossl_ffc_params_validate_unverifiable_g(ctx, mont, p, q, + params->g, tmp, res)) { + goto err; + } + + if (!BN_GENCB_call(cb, GENCB_RETRY, 1)) + goto err; + + if (!verify) { + if (p != params->p) { + BN_free(params->p); + params->p = BN_dup(p); + } + if (q != params->q) { + BN_free(params->q); + params->q = BN_dup(q); + } + if (g != params->g) { + BN_free(params->g); + params->g = BN_dup(g); + } + if (params->p == NULL || params->q == NULL || params->g == NULL) + goto err; + if (!ossl_ffc_params_set_validate_params(params, seed, qsize, pcounter)) + goto err; + params->h = hret; + } +pass: + if ((flags & FFC_PARAM_FLAG_VALIDATE_G) != 0) + ok = FFC_PARAM_RET_STATUS_UNVERIFIABLE_G; + else + ok = FFC_PARAM_RET_STATUS_SUCCESS; +err: + if (ctx != NULL) + BN_CTX_end(ctx); + BN_CTX_free(ctx); + BN_MONT_CTX_free(mont); + EVP_MD_free(md); + return ok; +} + +/* This should no longer be used in FIPS mode */ +int ossl_ffc_params_FIPS186_2_generate(OSSL_LIB_CTX *libctx, FFC_PARAMS *params, + int type, size_t L, size_t N, + int *res, BN_GENCB *cb) +{ + if (!ossl_ffc_params_FIPS186_2_gen_verify(libctx, params, + FFC_PARAM_MODE_GENERATE, + type, L, N, res, cb)) + return 0; + + ossl_ffc_params_enable_flags(params, FFC_PARAM_FLAG_VALIDATE_LEGACY, 1); + + return 1; +} + +static int generate_q_fips186_4(BN_CTX *ctx, BIGNUM *q, const EVP_MD *evpmd, + int qsize, unsigned char *seed, size_t seedlen, + int generate_seed, int *retm, int *res, + BN_GENCB *cb) +{ + int ret = 0, r; + int m = *retm; + unsigned char md[EVP_MAX_MD_SIZE]; + int mdsize = EVP_MD_get_size(evpmd); + unsigned char *pmd; + OSSL_LIB_CTX *libctx = ossl_bn_get_libctx(ctx); + + /* find q */ + for (;;) { + if (!BN_GENCB_call(cb, 0, m++)) + goto err; + + /* A.1.1.2 Step (5) : generate seed with size seed_len */ + if (generate_seed + && RAND_bytes_ex(libctx, seed, seedlen, 0) <= 0) + goto err; + /* + * A.1.1.2 Step (6) AND + * A.1.1.3 Step (7) + * U = Hash(seed) % (2^(N-1)) + */ + if (!EVP_Digest(seed, seedlen, md, NULL, evpmd, NULL)) + goto err; + /* Take least significant bits of md */ + if (mdsize > qsize) + pmd = md + mdsize - qsize; + else + pmd = md; + if (mdsize < qsize) + memset(md + mdsize, 0, qsize - mdsize); + + /* + * A.1.1.2 Step (7) AND + * A.1.1.3 Step (8) + * q = U + 2^(N-1) + (1 - U %2) (This sets top and bottom bits) + */ + pmd[0] |= 0x80; + pmd[qsize-1] |= 0x01; + if (!BN_bin2bn(pmd, qsize, q)) + goto err; + + /* + * A.1.1.2 Step (8) AND + * A.1.1.3 Step (9) + * Test if q is prime + */ + r = BN_check_prime(q, ctx, cb); + if (r > 0) { + ret = 1; + goto err; + } + /* + * A.1.1.3 Step (9) : If the provided seed didn't produce a prime q + * return an error. + */ + if (!generate_seed) { + *res |= FFC_CHECK_Q_NOT_PRIME; + goto err; + } + if (r != 0) + goto err; + /* A.1.1.2 Step (9) : if q is not prime, try another q */ + } + +err: + *retm = m; + return ret; +} + +/* + * FIPS186-4 A.2 Generation of canonical generator g. + * + * It requires the following values as input: + * 'evpmd' digest, 'p' prime, 'e' cofactor, gindex and seed. + * tmp is a passed in temporary BIGNUM. + * mont is used in a BN_mod_exp_mont() with a modulus of p. + * Returns a value in g. + */ +static int generate_canonical_g(BN_CTX *ctx, BN_MONT_CTX *mont, + const EVP_MD *evpmd, BIGNUM *g, BIGNUM *w, + const BIGNUM *p, const BIGNUM *e, + int gindex, unsigned char *seed, size_t seedlen) +{ + unsigned char md[EVP_MAX_MD_SIZE]; + EVP_MD_CTX *mctx; + int counter = 1; + int ret = 0; + int mdsize; + + mdsize = EVP_MD_get_size(evpmd); + if (mdsize <= 0) + return 0; + + mctx = EVP_MD_CTX_new(); + if (mctx == NULL) + return 0; + + /* + * A.2.3 Step (4) & (5) + * A.2.4 Step (6) & (7) + * counter = 0; counter += 1 + */ + for (counter = 1; counter <= 0xFFFF; ++counter) { + /* + * A.2.3 Step (7) & (8) & (9) + * A.2.4 Step (9) & (10) & (11) + * W = Hash(seed || "ggen" || index || counter) + * g = W^e % p + */ + static const unsigned char ggen[4] = { 0x67, 0x67, 0x65, 0x6e }; + + /* Get last 8 bits of gindex to the first byte of md */ + md[0] = (unsigned char)(gindex & 0xff); + /* Get second 8 bits of counter to the second byte of md */ + md[1] = (unsigned char)((counter >> 8) & 0xff); + /* Get last 8 bits of counter to the third byte of md */ + md[2] = (unsigned char)(counter & 0xff); + /* Compute digest: W = Hash(seed || "ggen" || index || counter) */ + if (!EVP_DigestInit_ex(mctx, evpmd, NULL) || + !EVP_DigestUpdate(mctx, seed, seedlen) || + !EVP_DigestUpdate(mctx, ggen, sizeof(ggen)) || + /* Hash the first three bytes of md, corresponds to 'index || counter' */ + !EVP_DigestUpdate(mctx, md, 3) || + !EVP_DigestFinal_ex(mctx, md, NULL) || + (BN_bin2bn(md, mdsize, w) == NULL) || + !BN_mod_exp_mont(g, w, e, p, ctx, mont)) + break; /* exit on failure */ + /* + * A.2.3 Step (10) + * A.2.4 Step (12) + * Found a value for g if (g >= 2) + */ + if (BN_cmp(g, BN_value_one()) > 0) { + ret = 1; + break; /* found g */ + } + } + + EVP_MD_CTX_free(mctx); + + return ret; +} + +/* + * FIPS 186-4 FFC parameter generation (as defined in Appendix A). + * The same code is used for validation (when validate_flags != 0) + * + * The primes p & q are generated/validated using: + * A.1.1.2 Generation of probable primes p & q using approved hash. + * A.1.1.3 Validation of generated probable primes + * + * Generator 'g' has 2 types in FIPS 186-4: + * (1) A.2.1 unverifiable generation of generator g. + * A.2.2 Assurance of the validity of unverifiable generator g. + * (2) A.2.3 Verifiable Canonical Generation of the generator g. + * A.2.4 Validation for Canonical Generation of the generator g. + * + * Notes: + * (1) is only a partial validation of g, The validation of (2) requires + * the seed and index used during generation as input. + * + * params: used to pass in values for generation and validation. + * params->md: is the digest to use, If this value is NULL, then the digest is + * chosen using the value of N. + * params->flags: + * For validation one of: + * -FFC_PARAM_FLAG_VALIDATE_PQ + * -FFC_PARAM_FLAG_VALIDATE_G + * -FFC_PARAM_FLAG_VALIDATE_PQG + * For generation of p & q: + * - This is skipped if p & q are passed in. + * - If the seed is passed in then generation of p & q uses this seed (and if + * this fails an error will occur). + * - Otherwise the seed is generated, and values of p & q are generated and + * the value of seed and counter are optionally returned. + * For the generation of g (after the generation of p, q): + * - If the seed has been generated or passed in and a valid gindex is passed + * in then canonical generation of g is used otherwise unverifiable + * generation of g is chosen. + * For validation of p & q: + * - p, q, and the seed and counter used for generation must be passed in. + * For validation of g: + * - For a partial validation : p, q and g are required. + * - For a canonical validation : the gindex and seed used for generation are + * also required. + * mode: The mode - either FFC_PARAM_MODE_GENERATE or FFC_PARAM_MODE_VERIFY. + * type: The key type - FFC_PARAM_TYPE_DSA or FFC_PARAM_TYPE_DH. + * L: is the size of the prime p in bits (e.g 2048) + * N: is the size of the prime q in bits (e.g 256) + * res: A returned failure reason (One of FFC_CHECK_XXXX), + * or 0 for general failures. + * cb: A callback (can be NULL) that is called during different phases + * + * Returns: + * - FFC_PARAM_RET_STATUS_FAILED: if there was an error, or validation failed. + * - FFC_PARAM_RET_STATUS_SUCCESS if the generation or validation succeeded. + * - FFC_PARAM_RET_STATUS_UNVERIFIABLE_G if the validation of G succeeded, + * but G is unverifiable. + */ +static int ossl_ffc_params_FIPS186_4_gen_verify(OSSL_LIB_CTX *libctx, + FFC_PARAMS *params, int mode, + int type, size_t L, size_t N, + int *res, BN_GENCB *cb) +{ + int ok = FFC_PARAM_RET_STATUS_FAILED; + unsigned char *seed = NULL, *seed_tmp = NULL; + int mdsize, counter = 0, pcounter = 0, r = 0; + size_t seedlen = 0; + BIGNUM *tmp, *pm1, *e, *test; + BIGNUM *g = NULL, *q = NULL, *p = NULL; + BN_MONT_CTX *mont = NULL; + int n = 0, m = 0, qsize; + int canonical_g = 0, hret = 0; + BN_CTX *ctx = NULL; + EVP_MD_CTX *mctx = NULL; + EVP_MD *md = NULL; + int verify = (mode == FFC_PARAM_MODE_VERIFY); + unsigned int flags = verify ? params->flags : 0; + const char *def_name; + + *res = 0; + + if (params->mdname != NULL) { + md = EVP_MD_fetch(libctx, params->mdname, params->mdprops); + } else { + if (N == 0) { + if (L >= L_P_2048BITS) + N = TRANS_BYTES_TO_BITS(SHA256_DIGEST_LENGTH); + else + N = TRANS_BYTES_TO_BITS(SHA_DIGEST_LENGTH); + } + + def_name = default_mdname(N); + if (def_name == NULL) { + *res = FFC_CHECK_INVALID_Q_VALUE; + goto err; + } + md = EVP_MD_fetch(libctx, def_name, params->mdprops); + } + + if (md == NULL) + goto err; + mdsize = EVP_MD_get_size(md); + if (mdsize <= 0) + goto err; + + if (N == 0) + N = TRANS_BYTES_TO_BITS((size_t)mdsize); + + qsize = TRANS_BITS_TO_BYTES(N); + + /* + * A.1.1.2 Step (1) AND + * A.1.1.3 Step (3) + * Check that the L,N pair is an acceptable pair. + */ + if (L <= N || !ffc_validate_LN(L, N, type, verify)) { + *res = FFC_CHECK_BAD_LN_PAIR; + goto err; + } + + mctx = EVP_MD_CTX_new(); + if (mctx == NULL) + goto err; + + ctx = BN_CTX_new_ex(libctx); + if (ctx == NULL) + goto err; + + BN_CTX_start(ctx); + g = BN_CTX_get(ctx); + pm1 = BN_CTX_get(ctx); + e = BN_CTX_get(ctx); + test = BN_CTX_get(ctx); + tmp = BN_CTX_get(ctx); + if (tmp == NULL) + goto err; + + seedlen = params->seedlen; + if (seedlen == 0) + seedlen = (size_t)mdsize; + /* If the seed was passed in - use this value as the seed */ + if (params->seed != NULL) + seed = params->seed; + + if (!verify) { + /* For generation: p & q must both be NULL or NON-NULL */ + if ((params->p == NULL) != (params->q == NULL)) { + *res = FFC_CHECK_INVALID_PQ; + goto err; + } + } else { + /* Validation of p,q requires seed and counter to be valid */ + if ((flags & FFC_PARAM_FLAG_VALIDATE_PQ) != 0) { + if (seed == NULL || params->pcounter < 0) { + *res = FFC_CHECK_MISSING_SEED_OR_COUNTER; + goto err; + } + } + + if ((flags & FFC_PARAM_FLAG_VALIDATE_G) != 0) { + /* validation of g also requires g to be set */ + if (params->g == NULL) { + *res = FFC_CHECK_INVALID_G; + goto err; + } + } + } + + /* + * If p & q are passed in and + * validate_flags = 0 then skip the generation of PQ. + * validate_flags = VALIDATE_G then also skip the validation of PQ. + */ + if (params->p != NULL && ((flags & FFC_PARAM_FLAG_VALIDATE_PQ) == 0)) { + /* p and q already exists so only generate g */ + p = params->p; + q = params->q; + goto g_only; + /* otherwise to validate p & q */ + } + + /* p & q will be used for generation and validation */ + p = BN_CTX_get(ctx); + q = BN_CTX_get(ctx); + if (q == NULL) + goto err; + + /* + * A.1.1.2 Step (2) AND + * A.1.1.3 Step (6) + * Return invalid if seedlen < N + */ + if ((TRANS_BYTES_TO_BITS(seedlen)) < N) { + *res = FFC_CHECK_INVALID_SEED_SIZE; + goto err; + } + + seed_tmp = OPENSSL_malloc(seedlen); + if (seed_tmp == NULL) + goto err; + + if (seed == NULL) { + /* Validation requires the seed to be supplied */ + if (verify) { + *res = FFC_CHECK_MISSING_SEED_OR_COUNTER; + goto err; + } + /* if the seed is not supplied then alloc a seed buffer */ + seed = OPENSSL_malloc(seedlen); + if (seed == NULL) + goto err; + } + + /* A.1.1.2 Step (11): max loop count = 4L - 1 */ + counter = 4 * L - 1; + /* Validation requires the counter to be supplied */ + if (verify) { + /* A.1.1.3 Step (4) : if (counter > (4L -1)) return INVALID */ + if (params->pcounter > counter) { + *res = FFC_CHECK_INVALID_COUNTER; + goto err; + } + counter = params->pcounter; + } + + /* + * A.1.1.2 Step (3) AND + * A.1.1.3 Step (10) + * n = floor(L / hash_outlen) - 1 + */ + n = (L - 1) / (mdsize << 3); + + /* Calculate 2^(L-1): Used in step A.1.1.2 Step (11.3) */ + if (!BN_lshift(test, BN_value_one(), L - 1)) + goto err; + + for (;;) { + if (!generate_q_fips186_4(ctx, q, md, qsize, seed, seedlen, + seed != params->seed, &m, res, cb)) + goto err; + /* A.1.1.3 Step (9): Verify that q matches the expected value */ + if (verify && (BN_cmp(q, params->q) != 0)) { + *res = FFC_CHECK_Q_MISMATCH; + goto err; + } + + if (!BN_GENCB_call(cb, GENCB_NEXT, 0)) + goto err; + if (!BN_GENCB_call(cb, GENCB_RETRY, 0)) + goto err; + + memcpy(seed_tmp, seed, seedlen); + r = generate_p(ctx, md, counter, n, seed_tmp, seedlen, q, p, L, + cb, &pcounter, res); + if (r > 0) + break; /* found p */ + if (r < 0) + goto err; + /* + * A.1.1.3 Step (14): + * If we get here we failed to get a p for the given seed. If the + * seed is not random then it needs to fail (as it will always fail). + */ + if (seed == params->seed) { + *res = FFC_CHECK_P_NOT_PRIME; + goto err; + } + } + if (!BN_GENCB_call(cb, GENCB_NEXT, 1)) + goto err; + /* + * Gets here if we found p. + * A.1.1.3 Step (14): return error if i != counter OR computed_p != known_p. + */ + if (verify && (pcounter != counter || (BN_cmp(p, params->p) != 0))) + goto err; + + /* If validating p & q only then skip the g validation test */ + if ((flags & FFC_PARAM_FLAG_VALIDATE_PQG) == FFC_PARAM_FLAG_VALIDATE_PQ) + goto pass; + +g_only: + mont = BN_MONT_CTX_new(); + if (mont == NULL) + goto err; + if (!BN_MONT_CTX_set(mont, p, ctx)) + goto err; + + if (((flags & FFC_PARAM_FLAG_VALIDATE_G) != 0) && + !ossl_ffc_params_validate_unverifiable_g(ctx, mont, p, q, params->g, + tmp, res)) + goto err; + + /* + * A.2.1 Step (1) AND + * A.2.3 Step (3) AND + * A.2.4 Step (5) + * e = (p - 1) / q (i.e- Cofactor 'e' is given by p = q * e + 1) + */ + if (!(BN_sub(pm1, p, BN_value_one()) && BN_div(e, NULL, pm1, q, ctx))) + goto err; + + /* Canonical g requires a seed and index to be set */ + if ((seed != NULL) && (params->gindex != FFC_UNVERIFIABLE_GINDEX)) { + canonical_g = 1; + if (!generate_canonical_g(ctx, mont, md, g, tmp, p, e, + params->gindex, seed, seedlen)) { + *res = FFC_CHECK_INVALID_G; + goto err; + } + /* A.2.4 Step (13): Return valid if computed_g == g */ + if (verify && BN_cmp(g, params->g) != 0) { + *res = FFC_CHECK_G_MISMATCH; + goto err; + } + } else if (!verify) { + if (!generate_unverifiable_g(ctx, mont, g, tmp, p, e, pm1, &hret)) + goto err; + } + + if (!BN_GENCB_call(cb, GENCB_RETRY, 1)) + goto err; + + if (!verify) { + if (p != params->p) { + BN_free(params->p); + params->p = BN_dup(p); + } + if (q != params->q) { + BN_free(params->q); + params->q = BN_dup(q); + } + if (g != params->g) { + BN_free(params->g); + params->g = BN_dup(g); + } + if (params->p == NULL || params->q == NULL || params->g == NULL) + goto err; + + if (!ossl_ffc_params_set_validate_params(params, seed, seedlen, pcounter)) + goto err; + params->h = hret; + } +pass: + if ((flags & FFC_PARAM_FLAG_VALIDATE_G) != 0 && (canonical_g == 0)) + /* Return for the case where g is partially valid */ + ok = FFC_PARAM_RET_STATUS_UNVERIFIABLE_G; + else + ok = FFC_PARAM_RET_STATUS_SUCCESS; +err: + if (seed != params->seed) + OPENSSL_free(seed); + OPENSSL_free(seed_tmp); + if (ctx != NULL) + BN_CTX_end(ctx); + BN_CTX_free(ctx); + BN_MONT_CTX_free(mont); + EVP_MD_CTX_free(mctx); + EVP_MD_free(md); + return ok; +} + +int ossl_ffc_params_FIPS186_4_generate(OSSL_LIB_CTX *libctx, FFC_PARAMS *params, + int type, size_t L, size_t N, + int *res, BN_GENCB *cb) +{ + return ossl_ffc_params_FIPS186_4_gen_verify(libctx, params, + FFC_PARAM_MODE_GENERATE, + type, L, N, res, cb); +} + +/* + * Multiply two scaled integers together and rescale the result. + */ +static ossl_inline uint64_t mul2(uint64_t a, uint64_t b) +{ + return a * b / DH_SCALE; +} + +/* + * Calculate the natural logarithm of a 64 bit scaled integer. + * This is done by calculating a base two logarithm and scaling. + * The maximum logarithm (base 2) is 64 and this reduces base e, so + * a 32 bit result should not overflow. The argument passed must be + * greater than unity so we don't need to handle negative results. + */ +static uint32_t ilog_e(uint64_t v) +{ + uint32_t i, r = 0; + + /* + * Scale down the value into the range 1 .. 2. + * + * If fractional numbers need to be processed, another loop needs + * to go here that checks v < scale and if so multiplies it by 2 and + * reduces r by scale. This also means making r signed. + */ + while (v >= (DH_C1_923 << 1)) { + v >>= 1; + r += DH_C1_923; + } + for (i = (DH_C1_923 >> 1); i != 0; i = (i >> 1)) { + v = mul2(v, v); + if (v >= (DH_C1_923 << 1)) { + v >>= 1; + r += i; + } + } + r = (r * (uint64_t)DH_C1_923) / DH_LOG_E; + + return r; +} + +/* + * Calculate the cube root of a 64 bit scaled integer. + * Although the cube root of a 64 bit number does fit into a 32 bit unsigned + * integer, this is not guaranteed after scaling, so this function has a + * 64 bit return. This uses the shifting nth root algorithm with some + * algebraic simplifications. + */ +static uint64_t icbrt64(uint64_t x) +{ + uint64_t r = 0; + uint64_t b; + int s; + + for (s = DH_MAX_EXPONENT; s >= 0; s -= DH_EXPONENT_SHIFT_3) { + r <<= 1; + b = DH_EXPONENT_SHIFT_3 * r * (r + 1) + 1; + if ((x >> s) >= b) { + x -= b << s; + r++; + } + } + + return r * DH_CBRT_SCALE; +} + +uint16_t ossl_ifc_ffc_compute_security_bits(int n) +{ + uint16_t y, cap; + uint32_t lx; + uint64_t x; + + /* + * Look for common values as listed in standards. + * These values are not exactly equal to the results from the formulae in + * the standards but are defined to be canonical. + */ + switch (n) { + case DH_STANDARDS_P_2048BIT: /* SP 800-56B rev 2 Appendix D and FIPS 140-2 IG 7.5 */ + return DH_P_SECURITY_112BITS; + case DH_STANDARDS_P_3072BIT: /* SP 800-56B rev 2 Appendix D and FIPS 140-2 IG 7.5 */ + return DH_P_SECURITY_128BITS; + case DH_STANDARDS_P_4096BIT: /* SP 800-56B rev 2 Appendix D */ + return DH_P_SECURITY_152BITS; + case DH_STANDARDS_P_6144BIT: /* SP 800-56B rev 2 Appendix D */ + return DH_P_SECURITY_176BITS; + case DH_STANDARDS_P_7680BIT: /* FIPS 140-2 IG 7.5 */ + return DH_P_SECURITY_192BITS; + case DH_STANDARDS_P_8192BIT: /* SP 800-56B rev 2 Appendix D */ + return DH_P_SECURITY_200BITS; + case DH_STANDARDS_P_15360BIT: /* FIPS 140-2 IG 7.5 */ + return DH_P_SECURITY_256BITS; + } + + /* + * The first incorrect result (i.e. not accurate or off by one low) occurs + * for n = 699668. The true value here is 1200. Instead of using this n + * as the check threshold, the smallest n such that the correct result is + * 1200 is used instead. + */ + if (n >= DH_STANDARDS_P_MAX_BIT) + return DH_P_SECURITY_1200BITS; + if (n < DH_STANDARDS_P_MIN_BIT) + return 0; + + /* + * To ensure that the output is non-decreasing with respect to n, + * a cap needs to be applied to the two values where the function over + * estimates the strength (according to the above fast path). + */ + if (n <= DH_STANDARDS_P_7680BIT) + cap = DH_P_SECURITY_192BITS; + else if (n <= DH_STANDARDS_P_15360BIT) + cap = DH_P_SECURITY_256BITS; + else + cap = DH_P_SECURITY_1200BITS; + + x = n * DH_LOG_2; + lx = ilog_e(x); + y = (uint16_t)((mul2(DH_C1_923, icbrt64(mul2(mul2(x, lx), lx))) - DH_C4_690) / + DH_LOG_2); + y = (y + DH_CAI_NUM4) & ~DH_CAI_NUM7; + if (y > cap) + y = cap; + + return y; +} diff --git a/KAEOpensslProvider/src/provider/prov_nosva/internal/prov_ffc.h b/KAEOpensslProvider/src/provider/prov_nosva/internal/prov_ffc.h new file mode 100644 index 0000000000000000000000000000000000000000..97b2816f6c0f066ec26baad2a4e95f6cf6112766 --- /dev/null +++ b/KAEOpensslProvider/src/provider/prov_nosva/internal/prov_ffc.h @@ -0,0 +1,323 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright 2015-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ +#ifndef KAE_PROV_FFC_H +#define KAE_PROV_FFC_H + +#include +#include +#include +#include +#include "../../../adapter/nosva/algorithm/pkey/hpre_dh.h" + +/* Default value for gindex when canonical generation of g is not used */ +#define FFC_UNVERIFIABLE_GINDEX -1 +#define FFC_PARAM_FLAG_VALIDATE_PQ 0x01 +#define FFC_PARAM_FLAG_VALIDATE_G 0x02 +#define FFC_PARAM_FLAG_VALIDATE_PQG \ + (FFC_PARAM_FLAG_VALIDATE_PQ | FFC_PARAM_FLAG_VALIDATE_G) +#define FFC_PARAM_FLAG_VALIDATE_LEGACY 0x04 + +/* The different types of FFC keys */ +#define FFC_PARAM_TYPE_DSA 0 +#define FFC_PARAM_TYPE_DH 1 + +/* + * The mode used by functions that share code for both generation and + * verification. See ossl_ffc_params_FIPS186_4_gen_verify(). + */ +#define FFC_PARAM_MODE_VERIFY 0 +#define FFC_PARAM_MODE_GENERATE 1 + +/* Return codes for generation and validation of FFC parameters */ +#define FFC_PARAM_RET_STATUS_FAILED 0 +#define FFC_PARAM_RET_STATUS_SUCCESS 1 +/* Returned if validating and g is only partially verifiable */ +#define FFC_PARAM_RET_STATUS_UNVERIFIABLE_G 2 + +/* + * NB: These values must align with the equivalently named macros in + * openssl/dh.h. We cannot use those macros here in case DH has been disabled. + */ +#define FFC_CHECK_P_NOT_PRIME 0x00001 +#define FFC_CHECK_P_NOT_SAFE_PRIME 0x00002 +#define FFC_CHECK_UNKNOWN_GENERATOR 0x00004 +#define FFC_CHECK_NOT_SUITABLE_GENERATOR 0x00008 +#define FFC_CHECK_Q_NOT_PRIME 0x00010 +#define FFC_CHECK_INVALID_Q_VALUE 0x00020 +#define FFC_CHECK_INVALID_J_VALUE 0x00040 + +#define FFC_CHECK_BAD_LN_PAIR 0x00080 +#define FFC_CHECK_INVALID_SEED_SIZE 0x00100 +#define FFC_CHECK_MISSING_SEED_OR_COUNTER 0x00200 +#define FFC_CHECK_INVALID_G 0x00400 +#define FFC_CHECK_INVALID_PQ 0x00800 +#define FFC_CHECK_INVALID_COUNTER 0x01000 +#define FFC_CHECK_P_MISMATCH 0x02000 +#define FFC_CHECK_Q_MISMATCH 0x04000 +#define FFC_CHECK_G_MISMATCH 0x08000 +#define FFC_CHECK_COUNTER_MISMATCH 0x10000 + +/* Validation Return codes */ +#define FFC_ERROR_PUBKEY_TOO_SMALL 0x01 +#define FFC_ERROR_PUBKEY_TOO_LARGE 0x02 +#define FFC_ERROR_PUBKEY_INVALID 0x04 +#define FFC_ERROR_NOT_SUITABLE_GENERATOR 0x08 +#define FFC_ERROR_PRIVKEY_TOO_SMALL 0x10 +#define FFC_ERROR_PRIVKEY_TOO_LARGE 0x20 +#define FFC_ERROR_PASSED_NULL_PARAM 0x40 + +/* How many bignums are in each "pool item"; */ +#define BN_CTX_POOL_SIZE 16 + +/* The size of prime p and prime q */ +#define L_P_512BITS 512 +#define L_P_1024BITS 1024 +#define L_P_2048BITS 2048 +#define L_P_3072BITS 3072 +#define N_Q_160BITS 160 +#define N_Q_224BITS 224 +#define N_Q_256BITS 256 + +/* Security strength of DH or DSA */ +#define SECURITY_STR_80BITS 80 +#define SECURITY_STR_112BITS 112 +#define SECURITY_STR_128BITS 128 + +#define GENCB_NEXT 2 +#define GENCB_RETRY 3 + +#define TRANS_BYTES_TO_BITS(bytes) ((bytes) << 3) +#define TRANS_BITS_TO_BYTES(bits) ((bits) >> 3) +#define PADDING_LEN(len) ((len + 63) / 64 * 64) + +#define OSSL_NELEM(x) (sizeof(x)/sizeof((x)[0])) +/* Macro to make a BIGNUM from static data */ +#define make_dh_bn(x) \ + const BIGNUM ossl_bignum_##x = { \ + (BN_ULONG *) x, \ + OSSL_NELEM(x), \ + OSSL_NELEM(x), \ + 0, BN_FLG_STATIC_DATA \ + } \ + +/* Define some constants, none exceed 32 bits */ +#define DH_LOG_2 0x02c5c8 +#define DH_LOG_E 0x05c551 +#define DH_C1_923 0x07b126 +#define DH_C4_690 0x12c28f +#define DH_CBRT_SCALE (1 << (2 * 18 / 3)) +#define DH_SCALE (1 << 18) +#define DH_MAX_EXPONENT 63 +#define DH_EXPONENT_SHIFT_3 3 + +/* modulus size */ +#define DH_STANDARDS_P_2048BIT 2048 +#define DH_STANDARDS_P_3072BIT 3072 +#define DH_STANDARDS_P_4096BIT 4096 +#define DH_STANDARDS_P_6144BIT 6144 +#define DH_STANDARDS_P_7680BIT 7680 +#define DH_STANDARDS_P_8192BIT 8192 +#define DH_STANDARDS_P_15360BIT 15360 +#define DH_STANDARDS_P_MAX_BIT 687737 +#define DH_STANDARDS_P_MIN_BIT 8 + +/* security bits */ +#define DH_P_SECURITY_112BITS 112 +#define DH_P_SECURITY_128BITS 128 +#define DH_P_SECURITY_152BITS 152 +#define DH_P_SECURITY_176BITS 176 +#define DH_P_SECURITY_192BITS 192 +#define DH_P_SECURITY_200BITS 200 +#define DH_P_SECURITY_256BITS 256 +#define DH_P_SECURITY_1200BITS 1200 + +/* constant adjustment item */ +#define DH_CAI_NUM4 4 +#define DH_CAI_NUM7 7 + +struct bignum_st { + /* Pointer to an array of 'BN_BITS2' bit chunks. */ + BN_ULONG *d; + /* Index of last used d +1. */ + int top; + /* The next are internal book keeping for bn_expand. */ + /* Size of the d array. */ + int dmax; + /* one if the number is negative */ + int neg; + int flags; +}; + +/* A wrapper to manage the "stack frames" */ +typedef struct bignum_ctx_stack { + /* Array of indexes into the bignum stack */ + unsigned int *indexes; + /* Number of stack frames, and the size of the allocated array */ + unsigned int depth, size; +} BN_STACK; + +/* A bundle of bignums that can be linked with other bundles */ +typedef struct bignum_pool_item { + /* The bignum values */ + BIGNUM vals[BN_CTX_POOL_SIZE]; + /* Linked-list admin */ + struct bignum_pool_item *prev, *next; +} BN_POOL_ITEM; + +/* A linked-list of bignums grouped in bundles */ +typedef struct bignum_pool { + /* Linked-list admin */ + BN_POOL_ITEM *head, *current, *tail; + /* Stack depth and allocation size */ + unsigned int used, size; +} BN_POOL; + +/* The opaque BN_CTX type */ +struct bignum_ctx { + /* The bignum bundles */ + BN_POOL pool; + /* The "stack frames", if you will */ + BN_STACK stack; + /* The number of bignums currently assigned */ + unsigned int used; + /* Depth of stack overflow */ + int err_stack; + /* Block "gets" until an "end" (compatibility behaviour) */ + int too_many; + /* Flags. */ + int flags; + /* The library context */ + OSSL_LIB_CTX *libctx; +}; + +static const BN_ULONG value_2 = 2; +static const BIGNUM ossl_bignum_const_2 = { + (BN_ULONG *)&value_2, 1, 1, 0, BN_FLG_STATIC_DATA +}; + +#define declare_dh_bn(x) \ + extern const BIGNUM ossl_bignum_dh##x##_p; \ + extern const BIGNUM ossl_bignum_dh##x##_q; \ + extern const BIGNUM ossl_bignum_dh##x##_g \ + +declare_dh_bn(1024_160); +declare_dh_bn(2048_224); +declare_dh_bn(2048_256); + +extern const BIGNUM ossl_bignum_ffdhe2048_p; +extern const BIGNUM ossl_bignum_ffdhe3072_p; +extern const BIGNUM ossl_bignum_ffdhe4096_p; +extern const BIGNUM ossl_bignum_ffdhe2048_q; +extern const BIGNUM ossl_bignum_ffdhe3072_q; +extern const BIGNUM ossl_bignum_ffdhe4096_q; + +extern const BIGNUM ossl_bignum_modp_1536_p; +extern const BIGNUM ossl_bignum_modp_2048_p; +extern const BIGNUM ossl_bignum_modp_3072_p; +extern const BIGNUM ossl_bignum_modp_4096_p; + +extern const BIGNUM ossl_bignum_modp_1536_q; +extern const BIGNUM ossl_bignum_modp_2048_q; +extern const BIGNUM ossl_bignum_modp_3072_q; +extern const BIGNUM ossl_bignum_modp_4096_q; + +#define FFDHE(sz, keylength) { \ + SN_ffdhe##sz, NID_ffdhe##sz, \ + sz, \ + keylength, \ + &ossl_bignum_ffdhe##sz##_p, &ossl_bignum_ffdhe##sz##_q, \ + &ossl_bignum_const_2, \ + } + +#define MODP(sz, keylength) { \ + SN_modp_##sz, NID_modp_##sz, \ + sz, \ + keylength, \ + &ossl_bignum_modp_##sz##_p, &ossl_bignum_modp_##sz##_q, \ + &ossl_bignum_const_2 \ + } + +#define RFC5114(name, uid, sz, tag) { \ + name, uid, \ + sz, \ + 0, \ + &ossl_bignum_dh##tag##_p, &ossl_bignum_dh##tag##_q, \ + &ossl_bignum_dh##tag##_g \ + } + +struct dh_named_group_st { + const char *name; + int uid; +#ifndef OPENSSL_NO_DH + int32_t nbits; + int keylength; + const BIGNUM *p; + const BIGNUM *q; + const BIGNUM *g; +#endif +}; +typedef struct dh_named_group_st DH_NAMED_GROUP; +/* + * The private key length values are taken from RFC7919 with the values for + * MODP primes given the same lengths as the equivalent FFDHE. + * The MODP 1536 value is approximated. + */ +static const DH_NAMED_GROUP dh_named_groups[] = { + FFDHE(2048, 225), + FFDHE(3072, 275), + FFDHE(4096, 325), +#ifndef FIPS_MODULE + MODP(1536, 200), +#endif + MODP(2048, 225), + MODP(3072, 275), + MODP(4096, 325), + /* + * Additional dh named groups from RFC 5114 that have a different g. + * The uid can be any unique identifier. + */ +#ifndef FIPS_MODULE + RFC5114("dh_1024_160", 1, 1024, 1024_160), + RFC5114("dh_2048_224", 2, 2048, 2048_224), + RFC5114("dh_2048_256", 3, 2048, 2048_256), +#endif +}; + +int ossl_ffc_params_set_seed(FFC_PARAMS *params, + const unsigned char *seed, size_t seedlen); +int ossl_ffc_params_copy(FFC_PARAMS *dst, const FFC_PARAMS *src); +void ossl_ffc_params_get0_pqg(const FFC_PARAMS *d, const BIGNUM **p, + const BIGNUM **q, const BIGNUM **g); +const DH_NAMED_GROUP *ossl_ffc_uid_to_dh_named_group(int uid); +void ossl_ffc_params_set0_pqg(FFC_PARAMS *d, BIGNUM *p, BIGNUM *q, BIGNUM *g); +int ossl_ffc_named_group_set(FFC_PARAMS *ffc, const DH_NAMED_GROUP *group); +int ossl_ffc_named_group_get_uid(const DH_NAMED_GROUP *group); +void ossl_ffc_params_set_gindex(FFC_PARAMS *params, int index); +void ossl_ffc_params_set_pcounter(FFC_PARAMS *params, int index); +void ossl_ffc_params_set_h(FFC_PARAMS *params, int index); +int ossl_ffc_set_digest(FFC_PARAMS *params, const char *alg, const char *props); +void ossl_ffc_params_enable_flags(FFC_PARAMS *params, unsigned int flags, + int enable); +int ossl_ffc_params_cmp(const FFC_PARAMS *a, const FFC_PARAMS *b, int ignore_q); +void ossl_ffc_params_init(FFC_PARAMS *params); +void ossl_ffc_params_cleanup(FFC_PARAMS *params); +int ossl_ffc_params_FIPS186_2_generate(OSSL_LIB_CTX *libctx, FFC_PARAMS *params, + int type, size_t L, size_t N, + int *res, BN_GENCB *cb); +int ossl_ffc_params_FIPS186_2_gen_verify(OSSL_LIB_CTX *libctx, + FFC_PARAMS *params, int mode, int type, + size_t L, size_t N, int *res, + BN_GENCB *cb); +int ossl_ffc_params_FIPS186_4_generate(OSSL_LIB_CTX *libctx, FFC_PARAMS *params, + int type, size_t L, size_t N, + int *res, BN_GENCB *cb); +uint16_t ossl_ifc_ffc_compute_security_bits(int n); + +#endif \ No newline at end of file diff --git a/KAEOpensslProvider/src/provider/prov_nosva/internal/prov_packet.c b/KAEOpensslProvider/src/provider/prov_nosva/internal/prov_packet.c new file mode 100644 index 0000000000000000000000000000000000000000..6453d0a996d8c9e6deca1a661d4f5939b1437bff --- /dev/null +++ b/KAEOpensslProvider/src/provider/prov_nosva/internal/prov_packet.c @@ -0,0 +1,514 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright 2015-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ +#include +#include "prov_packet.h" + +#define DEFAULT_BUF_SIZE 256 +#define REF_SIZE_LIMIT 2 + +#define GETBUF(p) (((p)->staticbuf != NULL) \ + ? (p)->staticbuf \ + : ((p)->buf != NULL \ + ? (unsigned char *)(p)->buf->data \ + : NULL)) + +int WPACKET_allocate_bytes(WPACKET *pkt, size_t len, unsigned char **allocbytes) +{ + if (!WPACKET_reserve_bytes(pkt, len, allocbytes)) + return 0; + + pkt->written += len; + pkt->curr += len; + return 1; +} + +int WPACKET_sub_allocate_bytes__(WPACKET *pkt, size_t len, + unsigned char **allocbytes, size_t lenbytes) +{ + if (!WPACKET_start_sub_packet_len__(pkt, lenbytes) + || !WPACKET_allocate_bytes(pkt, len, allocbytes) + || !WPACKET_close(pkt)) + return 0; + + return 1; +} + +int WPACKET_reserve_bytes(WPACKET *pkt, size_t len, unsigned char **allocbytes) +{ + size_t newlen; + size_t reflen; + + /* Internal API, so should not fail */ + if (!ossl_assert(pkt->subs != NULL && len != 0)) + return 0; + + if (pkt->maxsize - pkt->written < len) + return 0; + + if (pkt->buf != NULL && (pkt->buf->length - pkt->written < len)) { + reflen = (len > pkt->buf->length) ? len : pkt->buf->length; + if (reflen > SIZE_MAX / REF_SIZE_LIMIT) { + newlen = SIZE_MAX; + } else { + newlen = reflen * REF_SIZE_LIMIT; + if (newlen < DEFAULT_BUF_SIZE) + newlen = DEFAULT_BUF_SIZE; + } + + if (BUF_MEM_grow(pkt->buf, newlen) == 0) + return 0; + } + + if (allocbytes != NULL) { + *allocbytes = WPACKET_get_curr(pkt); + if (pkt->endfirst && *allocbytes != NULL) + *allocbytes -= len; + } + + return 1; +} + +int WPACKET_sub_reserve_bytes__(WPACKET *pkt, size_t len, + unsigned char **allocbytes, size_t lenbytes) +{ + if (pkt->endfirst && lenbytes > 0) + return 0; + + if (!WPACKET_reserve_bytes(pkt, lenbytes + len, allocbytes)) + return 0; + + if (*allocbytes != NULL) + *allocbytes += lenbytes; + + return 1; +} + +static size_t maxmaxsize(size_t lenbytes) +{ + if (lenbytes >= sizeof(size_t) || lenbytes == 0) + return SIZE_MAX; + + return ((size_t)1 << (lenbytes * BYTES_TO_BITS_OFFSET)) - 1 + lenbytes; +} + +static int wpacket_intern_init_len(WPACKET *pkt, size_t lenbytes) +{ + unsigned char *lenchars; + + pkt->curr = 0; + pkt->written = 0; + + pkt->subs = OPENSSL_zalloc(sizeof(*pkt->subs)); + if (pkt->subs == NULL) { + ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE); + return 0; + } + + if (lenbytes == 0) + return 1; + + pkt->subs->pwritten = lenbytes; + pkt->subs->lenbytes = lenbytes; + + if (!WPACKET_allocate_bytes(pkt, lenbytes, &lenchars)) { + OPENSSL_free(pkt->subs); + pkt->subs = NULL; + return 0; + } + pkt->subs->packet_len = 0; + + return 1; +} + +int WPACKET_init_static_len(WPACKET *pkt, unsigned char *buf, size_t len, + size_t lenbytes) +{ + size_t max = maxmaxsize(lenbytes); + + /* Internal API, so should not fail */ + if (!ossl_assert(buf != NULL && len > 0)) + return 0; + + pkt->staticbuf = buf; + pkt->buf = NULL; + pkt->maxsize = (max < len) ? max : len; + pkt->endfirst = 0; + + return wpacket_intern_init_len(pkt, lenbytes); +} + +int WPACKET_init_der(WPACKET *pkt, unsigned char *buf, size_t len) +{ + /* Internal API, so should not fail */ + if (!ossl_assert(buf != NULL && len > 0)) + return 0; + + pkt->staticbuf = buf; + pkt->buf = NULL; + pkt->maxsize = len; + pkt->endfirst = 1; + + return wpacket_intern_init_len(pkt, 0); +} + +int WPACKET_init_len(WPACKET *pkt, BUF_MEM *buf, size_t lenbytes) +{ + /* Internal API, so should not fail */ + if (!ossl_assert(buf != NULL)) + return 0; + + pkt->staticbuf = NULL; + pkt->buf = buf; + pkt->maxsize = maxmaxsize(lenbytes); + pkt->endfirst = 0; + + return wpacket_intern_init_len(pkt, lenbytes); +} + +int WPACKET_init(WPACKET *pkt, BUF_MEM *buf) +{ + return WPACKET_init_len(pkt, buf, 0); +} + +int WPACKET_init_null(WPACKET *pkt, size_t lenbytes) +{ + pkt->staticbuf = NULL; + pkt->buf = NULL; + pkt->maxsize = maxmaxsize(lenbytes); + pkt->endfirst = 0; + + return wpacket_intern_init_len(pkt, 0); +} + +int WPACKET_init_null_der(WPACKET *pkt) +{ + pkt->staticbuf = NULL; + pkt->buf = NULL; + pkt->maxsize = SIZE_MAX; + pkt->endfirst = 1; + + return wpacket_intern_init_len(pkt, 0); +} + +int WPACKET_set_flags(WPACKET *pkt, unsigned int flags) +{ + /* Internal API, so should not fail */ + if (!ossl_assert(pkt->subs != NULL)) + return 0; + + pkt->subs->flags = flags; + + return 1; +} + +/* Store the |value| of length |len| at location |data| */ +static int put_value(unsigned char *data, uint64_t value, size_t len) +{ + if (data == NULL) + return 1; + + for (data += len - 1; len > 0; len--) { + *data = (unsigned char)(value & 0xff); + data--; + value >>= LOW_BIT_SIZE; + } + + /* Check whether we could fit the value in the assigned number of bytes */ + if (value > 0) + return 0; + + return 1; +} + +/* + * Internal helper function used by WPACKET_close(), WPACKET_finish() and + * WPACKET_fill_lengths() to close a sub-packet and write out its length if + * necessary. If |doclose| is 0 then it goes through the motions of closing + * (i.e. it fills in all the lengths), but doesn't actually close anything. + */ +static int wpacket_intern_close(WPACKET *pkt, WPACKET_SUB *sub, int doclose) +{ + size_t packlen = pkt->written - sub->pwritten; + + if (packlen == 0 + && (sub->flags & WPACKET_FLAGS_NON_ZERO_LENGTH) != 0) + return 0; + + if (packlen == 0 + && sub->flags & WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH) { + /* We can't handle this case. Return an error */ + if (!doclose) + return 0; + + /* Deallocate any bytes allocated for the length of the WPACKET */ + if ((pkt->curr - sub->lenbytes) == sub->packet_len) { + pkt->written -= sub->lenbytes; + pkt->curr -= sub->lenbytes; + } + + /* Don't write out the packet length */ + sub->packet_len = 0; + sub->lenbytes = 0; + } + + /* Write out the WPACKET length if needed */ + if (sub->lenbytes > 0) { + unsigned char *buf = GETBUF(pkt); + + if (buf != NULL + && !put_value(&buf[sub->packet_len], packlen, + sub->lenbytes)) + return 0; + } else if (pkt->endfirst && sub->parent != NULL + && (packlen != 0 || (sub->flags + & WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH) == 0)) { + size_t tmplen = packlen; + size_t numlenbytes = 1; + + while ((tmplen = tmplen >> LOW_BIT_SIZE) > 0) + numlenbytes++; + if (!WPACKET_put_bytes__(pkt, packlen, numlenbytes)) + return 0; + if (packlen > 0x7f) { + numlenbytes |= 0x80; + if (!WPACKET_put_bytes_u8(pkt, numlenbytes)) + return 0; + } + } + + if (doclose) { + pkt->subs = sub->parent; + OPENSSL_free(sub); + } + + return 1; +} + +int WPACKET_fill_lengths(WPACKET *pkt) +{ + WPACKET_SUB *sub; + + if (!ossl_assert(pkt->subs != NULL)) + return 0; + + for (sub = pkt->subs; sub != NULL; sub = sub->parent) { + if (!wpacket_intern_close(pkt, sub, 0)) + return 0; + } + + return 1; +} + +int WPACKET_close(WPACKET *pkt) +{ + /* + * Internal API, so should not fail - but we do negative testing of this + * so no assert (otherwise the tests fail) + */ + if (pkt->subs == NULL || pkt->subs->parent == NULL) + return 0; + + return wpacket_intern_close(pkt, pkt->subs, 1); +} + +int WPACKET_finish(WPACKET *pkt) +{ + int ret; + + /* + * Internal API, so should not fail - but we do negative testing of this + * so no assert (otherwise the tests fail) + */ + if (pkt->subs == NULL || pkt->subs->parent != NULL) + return 0; + + ret = wpacket_intern_close(pkt, pkt->subs, 1); + if (ret) { + OPENSSL_free(pkt->subs); + pkt->subs = NULL; + } + + return ret; +} + +int WPACKET_start_sub_packet_len__(WPACKET *pkt, size_t lenbytes) +{ + WPACKET_SUB *sub; + unsigned char *lenchars; + + /* Internal API, so should not fail */ + if (!ossl_assert(pkt->subs != NULL)) + return 0; + + /* We don't support lenbytes greater than 0 when doing endfirst writing */ + if (lenbytes > 0 && pkt->endfirst) + return 0; + + sub = OPENSSL_zalloc(sizeof(*sub)); + if (sub == NULL) { + ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE); + return 0; + } + + sub->parent = pkt->subs; + pkt->subs = sub; + sub->pwritten = pkt->written + lenbytes; + sub->lenbytes = lenbytes; + + if (lenbytes == 0) { + sub->packet_len = 0; + return 1; + } + + sub->packet_len = pkt->written; + + if (!WPACKET_allocate_bytes(pkt, lenbytes, &lenchars)) + return 0; + + return 1; +} + +int WPACKET_start_sub_packet(WPACKET *pkt) +{ + return WPACKET_start_sub_packet_len__(pkt, 0); +} + +int WPACKET_put_bytes__(WPACKET *pkt, uint64_t val, size_t size) +{ + unsigned char *data; + + /* Internal API, so should not fail */ + if (!ossl_assert(size <= sizeof(uint64_t)) + || !WPACKET_allocate_bytes(pkt, size, &data) + || !put_value(data, val, size)) + return 0; + + return 1; +} + +int WPACKET_set_max_size(WPACKET *pkt, size_t maxsize) +{ + WPACKET_SUB *sub; + size_t lenbytes; + + /* Internal API, so should not fail */ + if (!ossl_assert(pkt->subs != NULL)) + return 0; + + /* Find the WPACKET_SUB for the top level */ + for (sub = pkt->subs; sub->parent != NULL; sub = sub->parent) + continue; + + lenbytes = sub->lenbytes; + if (lenbytes == 0) + lenbytes = sizeof(pkt->maxsize); + + if (maxmaxsize(lenbytes) < maxsize || maxsize < pkt->written) + return 0; + + pkt->maxsize = maxsize; + + return 1; +} + +int WPACKET_memset(WPACKET *pkt, int ch, size_t len) +{ + unsigned char *dest; + + if (len == 0) + return 1; + + if (!WPACKET_allocate_bytes(pkt, len, &dest)) + return 0; + + if (dest != NULL) + memset(dest, ch, len); + + return 1; +} + +int WPACKET_memcpy(WPACKET *pkt, const void *src, size_t len) +{ + unsigned char *dest; + + if (len == 0) + return 1; + + if (!WPACKET_allocate_bytes(pkt, len, &dest)) + return 0; + + if (dest != NULL) + memcpy(dest, src, len); + + return 1; +} + +int WPACKET_sub_memcpy__(WPACKET *pkt, const void *src, size_t len, + size_t lenbytes) +{ + if (!WPACKET_start_sub_packet_len__(pkt, lenbytes) + || !WPACKET_memcpy(pkt, src, len) + || !WPACKET_close(pkt)) + return 0; + + return 1; +} + +int WPACKET_get_total_written(WPACKET *pkt, size_t *written) +{ + /* Internal API, so should not fail */ + if (!ossl_assert(written != NULL)) + return 0; + + *written = pkt->written; + + return 1; +} + +int WPACKET_get_length(WPACKET *pkt, size_t *len) +{ + /* Internal API, so should not fail */ + if (!ossl_assert(pkt->subs != NULL && len != NULL)) + return 0; + + *len = pkt->written - pkt->subs->pwritten; + + return 1; +} + +unsigned char *WPACKET_get_curr(WPACKET *pkt) +{ + unsigned char *buf = GETBUF(pkt); + + if (buf == NULL) + return NULL; + + if (pkt->endfirst) + return buf + pkt->maxsize - pkt->curr; + + return buf + pkt->curr; +} + +int WPACKET_is_null_buf(WPACKET *pkt) +{ + return pkt->buf == NULL && pkt->staticbuf == NULL; +} + +void WPACKET_cleanup(WPACKET *pkt) +{ + WPACKET_SUB *sub, *parent; + + for (sub = pkt->subs; sub != NULL; sub = parent) { + parent = sub->parent; + OPENSSL_free(sub); + } + + pkt->subs = NULL; +} diff --git a/KAEOpensslProvider/src/provider/prov_nosva/internal/prov_packet.h b/KAEOpensslProvider/src/provider/prov_nosva/internal/prov_packet.h new file mode 100644 index 0000000000000000000000000000000000000000..f418d9e9fe67d4f35d2f7bb870fd48b438edc3bb --- /dev/null +++ b/KAEOpensslProvider/src/provider/prov_nosva/internal/prov_packet.h @@ -0,0 +1,959 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright 2015-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef KAE_PROV_PACKET_H +#define KAE_PROV_PACKET_H + +#include +#include +#include +#include +#include + +#ifdef NDEBUG +#define ossl_assert(x) ((x) != 0) +#else +__owur static ossl_inline int ossl_assert_int(int expr, const char *exprstr, + const char *file, int line) +{ + if (!expr) + OPENSSL_die(exprstr, file, line); + + return expr; +} + +#define ossl_assert(x) ossl_assert_int((x) != 0, "Assertion failed: "#x, \ + __FILE__, __LINE__) + +#endif + +#define LOW_BIT_SIZE 8 +#define BYTES_TO_BITS_OFFSET 8 + +typedef struct { + /* Pointer to where we are currently reading from */ + const unsigned char *curr; + /* Number of bytes remaining */ + size_t remaining; +} PACKET; + +/* Internal unchecked shorthand; don't use outside this file. */ +static ossl_inline void packet_forward(PACKET *pkt, size_t len) +{ + pkt->curr += len; + pkt->remaining -= len; +} + +/* + * Returns the number of bytes remaining to be read in the PACKET + */ +static ossl_inline size_t PACKET_remaining(const PACKET *pkt) +{ + return pkt->remaining; +} + +/* + * Returns a pointer to the first byte after the packet data. + * Useful for integrating with non-PACKET parsing code. + * Specifically, we use PACKET_end() to verify that a d2i_... call + * has consumed the entire packet contents. + */ +static ossl_inline const unsigned char *PACKET_end(const PACKET *pkt) +{ + return pkt->curr + pkt->remaining; +} + +/* + * Returns a pointer to the PACKET's current position. + * For use in non-PACKETized APIs. + */ +static ossl_inline const unsigned char *PACKET_data(const PACKET *pkt) +{ + return pkt->curr; +} + +/* + * Initialise a PACKET with |len| bytes held in |buf|. This does not make a + * copy of the data so |buf| must be present for the whole time that the PACKET + * is being used. + */ +__owur static ossl_inline int PACKET_buf_init(PACKET *pkt, + const unsigned char *buf, + size_t len) +{ + /* Sanity check for negative values. */ + if (len > (size_t)(SIZE_MAX / 2)) + return 0; + + pkt->curr = buf; + pkt->remaining = len; + return 1; +} + +/* Initialize a PACKET to hold zero bytes. */ +static ossl_inline void PACKET_null_init(PACKET *pkt) +{ + pkt->curr = NULL; + pkt->remaining = 0; +} + +/* + * Returns 1 if the packet has length |num| and its contents equal the |num| + * bytes read from |ptr|. Returns 0 otherwise (lengths or contents not equal). + * If lengths are equal, performs the comparison in constant time. + */ +__owur static ossl_inline int PACKET_equal(const PACKET *pkt, const void *ptr, + size_t num) +{ + if (PACKET_remaining(pkt) != num) + return 0; + return CRYPTO_memcmp(pkt->curr, ptr, num) == 0; +} + +/* + * Peek ahead and initialize |subpkt| with the next |len| bytes read from |pkt|. + * Data is not copied: the |subpkt| packet will share its underlying buffer with + * the original |pkt|, so data wrapped by |pkt| must outlive the |subpkt|. + */ +__owur static ossl_inline int PACKET_peek_sub_packet(const PACKET *pkt, + PACKET *subpkt, size_t len) +{ + if (PACKET_remaining(pkt) < len) + return 0; + + return PACKET_buf_init(subpkt, pkt->curr, len); +} + +/* + * Initialize |subpkt| with the next |len| bytes read from |pkt|. Data is not + * copied: the |subpkt| packet will share its underlying buffer with the + * original |pkt|, so data wrapped by |pkt| must outlive the |subpkt|. + */ +__owur static ossl_inline int PACKET_get_sub_packet(PACKET *pkt, + PACKET *subpkt, size_t len) +{ + if (!PACKET_peek_sub_packet(pkt, subpkt, len)) + return 0; + + packet_forward(pkt, len); + + return 1; +} + +/* + * Peek ahead at 2 bytes in network order from |pkt| and store the value in + * |*data| + */ +__owur static ossl_inline int PACKET_peek_net_2(const PACKET *pkt, + unsigned int *data) +{ + if (PACKET_remaining(pkt) < 2) + return 0; + + *data = ((unsigned int)(*pkt->curr)) << 8; + *data |= *(pkt->curr + 1); + + return 1; +} + +/* Equivalent of n2s */ +/* Get 2 bytes in network order from |pkt| and store the value in |*data| */ +__owur static ossl_inline int PACKET_get_net_2(PACKET *pkt, unsigned int *data) +{ + if (!PACKET_peek_net_2(pkt, data)) + return 0; + + packet_forward(pkt, 2); + + return 1; +} + +/* Same as PACKET_get_net_2() but for a size_t */ +__owur static ossl_inline int PACKET_get_net_2_len(PACKET *pkt, size_t *data) +{ + unsigned int i; + int ret = PACKET_get_net_2(pkt, &i); + + if (ret) + *data = (size_t)i; + + return ret; +} + +/* + * Peek ahead at 3 bytes in network order from |pkt| and store the value in + * |*data| + */ +__owur static ossl_inline int PACKET_peek_net_3(const PACKET *pkt, + unsigned long *data) +{ + if (PACKET_remaining(pkt) < 3) + return 0; + + *data = ((unsigned long)(*pkt->curr)) << 16; + *data |= ((unsigned long)(*(pkt->curr + 1))) << 8; + *data |= *(pkt->curr + 2); + + return 1; +} + +/* Equivalent of n2l3 */ +/* Get 3 bytes in network order from |pkt| and store the value in |*data| */ +__owur static ossl_inline int PACKET_get_net_3(PACKET *pkt, unsigned long *data) +{ + if (!PACKET_peek_net_3(pkt, data)) + return 0; + + packet_forward(pkt, 3); + + return 1; +} + +/* Same as PACKET_get_net_3() but for a size_t */ +__owur static ossl_inline int PACKET_get_net_3_len(PACKET *pkt, size_t *data) +{ + unsigned long i; + int ret = PACKET_get_net_3(pkt, &i); + + if (ret) + *data = (size_t)i; + + return ret; +} + +/* + * Peek ahead at 4 bytes in network order from |pkt| and store the value in + * |*data| + */ +__owur static ossl_inline int PACKET_peek_net_4(const PACKET *pkt, + unsigned long *data) +{ + if (PACKET_remaining(pkt) < 4) + return 0; + + *data = ((unsigned long)(*pkt->curr)) << 24; + *data |= ((unsigned long)(*(pkt->curr + 1))) << 16; + *data |= ((unsigned long)(*(pkt->curr + 2))) << 8; + *data |= *(pkt->curr + 3); + + return 1; +} + +/* + * Peek ahead at 8 bytes in network order from |pkt| and store the value in + * |*data| + */ +__owur static ossl_inline int PACKET_peek_net_8(const PACKET *pkt, + uint64_t *data) +{ + if (PACKET_remaining(pkt) < 8) + return 0; + + *data = ((uint64_t)(*pkt->curr)) << 56; + *data |= ((uint64_t)(*(pkt->curr + 1))) << 48; + *data |= ((uint64_t)(*(pkt->curr + 2))) << 40; + *data |= ((uint64_t)(*(pkt->curr + 3))) << 32; + *data |= ((uint64_t)(*(pkt->curr + 4))) << 24; + *data |= ((uint64_t)(*(pkt->curr + 5))) << 16; + *data |= ((uint64_t)(*(pkt->curr + 6))) << 8; + *data |= *(pkt->curr + 7); + + return 1; +} + +/* Equivalent of n2l */ +/* Get 4 bytes in network order from |pkt| and store the value in |*data| */ +__owur static ossl_inline int PACKET_get_net_4(PACKET *pkt, unsigned long *data) +{ + if (!PACKET_peek_net_4(pkt, data)) + return 0; + + packet_forward(pkt, 4); + + return 1; +} + +/* Same as PACKET_get_net_4() but for a size_t */ +__owur static ossl_inline int PACKET_get_net_4_len(PACKET *pkt, size_t *data) +{ + unsigned long i; + int ret = PACKET_get_net_4(pkt, &i); + + if (ret) + *data = (size_t)i; + + return ret; +} + +/* Get 8 bytes in network order from |pkt| and store the value in |*data| */ +__owur static ossl_inline int PACKET_get_net_8(PACKET *pkt, uint64_t *data) +{ + if (!PACKET_peek_net_8(pkt, data)) + return 0; + + packet_forward(pkt, 8); + + return 1; +} + +/* Peek ahead at 1 byte from |pkt| and store the value in |*data| */ +__owur static ossl_inline int PACKET_peek_1(const PACKET *pkt, + unsigned int *data) +{ + if (!PACKET_remaining(pkt)) + return 0; + + *data = *pkt->curr; + + return 1; +} + +/* Get 1 byte from |pkt| and store the value in |*data| */ +__owur static ossl_inline int PACKET_get_1(PACKET *pkt, unsigned int *data) +{ + if (!PACKET_peek_1(pkt, data)) + return 0; + + packet_forward(pkt, 1); + + return 1; +} + +/* Same as PACKET_get_1() but for a size_t */ +__owur static ossl_inline int PACKET_get_1_len(PACKET *pkt, size_t *data) +{ + unsigned int i; + int ret = PACKET_get_1(pkt, &i); + + if (ret) + *data = (size_t)i; + + return ret; +} + +/* + * Peek ahead at 4 bytes in reverse network order from |pkt| and store the value + * in |*data| + */ +__owur static ossl_inline int PACKET_peek_4(const PACKET *pkt, + unsigned long *data) +{ + if (PACKET_remaining(pkt) < 4) + return 0; + + *data = *pkt->curr; + *data |= ((unsigned long)(*(pkt->curr + 1))) << 8; + *data |= ((unsigned long)(*(pkt->curr + 2))) << 16; + *data |= ((unsigned long)(*(pkt->curr + 3))) << 24; + + return 1; +} + +/* Equivalent of c2l */ +/* + * Get 4 bytes in reverse network order from |pkt| and store the value in + * |*data| + */ +__owur static ossl_inline int PACKET_get_4(PACKET *pkt, unsigned long *data) +{ + if (!PACKET_peek_4(pkt, data)) + return 0; + + packet_forward(pkt, 4); + + return 1; +} + +/* + * Peek ahead at |len| bytes from the |pkt| and store a pointer to them in + * |*data|. This just points at the underlying buffer that |pkt| is using. The + * caller should not free this data directly (it will be freed when the + * underlying buffer gets freed + */ +__owur static ossl_inline int PACKET_peek_bytes(const PACKET *pkt, + const unsigned char **data, + size_t len) +{ + if (PACKET_remaining(pkt) < len) + return 0; + + *data = pkt->curr; + + return 1; +} + +/* + * Read |len| bytes from the |pkt| and store a pointer to them in |*data|. This + * just points at the underlying buffer that |pkt| is using. The caller should + * not free this data directly (it will be freed when the underlying buffer gets + * freed + */ +__owur static ossl_inline int PACKET_get_bytes(PACKET *pkt, + const unsigned char **data, + size_t len) +{ + if (!PACKET_peek_bytes(pkt, data, len)) + return 0; + + packet_forward(pkt, len); + + return 1; +} + +/* Peek ahead at |len| bytes from |pkt| and copy them to |data| */ +__owur static ossl_inline int PACKET_peek_copy_bytes(const PACKET *pkt, + unsigned char *data, + size_t len) +{ + if (PACKET_remaining(pkt) < len) + return 0; + + memcpy(data, pkt->curr, len); + + return 1; +} + +/* + * Read |len| bytes from |pkt| and copy them to |data|. + * The caller is responsible for ensuring that |data| can hold |len| bytes. + */ +__owur static ossl_inline int PACKET_copy_bytes(PACKET *pkt, + unsigned char *data, size_t len) +{ + if (!PACKET_peek_copy_bytes(pkt, data, len)) + return 0; + + packet_forward(pkt, len); + + return 1; +} + +/* + * Copy packet data to |dest|, and set |len| to the number of copied bytes. + * If the packet has more than |dest_len| bytes, nothing is copied. + * Returns 1 if the packet data fits in |dest_len| bytes, 0 otherwise. + * Does not forward PACKET position (because it is typically the last thing + * done with a given PACKET). + */ +__owur static ossl_inline int PACKET_copy_all(const PACKET *pkt, + unsigned char *dest, + size_t dest_len, size_t *len) +{ + if (PACKET_remaining(pkt) > dest_len) { + *len = 0; + return 0; + } + + *len = pkt->remaining; + memcpy(dest, pkt->curr, pkt->remaining); + + return 1; +} + +/* + * Copy |pkt| bytes to a newly allocated buffer and store a pointer to the + * result in |*data|, and the length in |len|. + * If |*data| is not NULL, the old data is OPENSSL_free'd. + * If the packet is empty, or malloc fails, |*data| will be set to NULL. + * Returns 1 if the malloc succeeds and 0 otherwise. + * Does not forward PACKET position (because it is typically the last thing + * done with a given PACKET). + */ +__owur static ossl_inline int PACKET_memdup(const PACKET *pkt, + unsigned char **data, size_t *len) +{ + size_t length; + + OPENSSL_free(*data); + *data = NULL; + *len = 0; + + length = PACKET_remaining(pkt); + + if (length == 0) + return 1; + + *data = OPENSSL_memdup(pkt->curr, length); + if (*data == NULL) + return 0; + + *len = length; + return 1; +} + +/* + * Read a C string from |pkt| and copy to a newly allocated, NUL-terminated + * buffer. Store a pointer to the result in |*data|. + * If |*data| is not NULL, the old data is OPENSSL_free'd. + * If the data in |pkt| does not contain a NUL-byte, the entire data is + * copied and NUL-terminated. + * Returns 1 if the malloc succeeds and 0 otherwise. + * Does not forward PACKET position (because it is typically the last thing done + * with a given PACKET). + */ +__owur static ossl_inline int PACKET_strndup(const PACKET *pkt, char **data) +{ + OPENSSL_free(*data); + + /* This will succeed on an empty packet, unless pkt->curr == NULL. */ + *data = OPENSSL_strndup((const char *)pkt->curr, PACKET_remaining(pkt)); + return (*data != NULL); +} + +/* Returns 1 if |pkt| contains at least one 0-byte, 0 otherwise. */ +static ossl_inline int PACKET_contains_zero_byte(const PACKET *pkt) +{ + return memchr(pkt->curr, 0, pkt->remaining) != NULL; +} + +/* Move the current reading position forward |len| bytes */ +__owur static ossl_inline int PACKET_forward(PACKET *pkt, size_t len) +{ + if (PACKET_remaining(pkt) < len) + return 0; + + packet_forward(pkt, len); + + return 1; +} + +/* + * Reads a variable-length vector prefixed with a one-byte length, and stores + * the contents in |subpkt|. |pkt| can equal |subpkt|. + * Data is not copied: the |subpkt| packet will share its underlying buffer with + * the original |pkt|, so data wrapped by |pkt| must outlive the |subpkt|. + * Upon failure, the original |pkt| and |subpkt| are not modified. + */ +__owur static ossl_inline int PACKET_get_length_prefixed_1(PACKET *pkt, + PACKET *subpkt) +{ + unsigned int length; + const unsigned char *data; + PACKET tmp = *pkt; + + if (!PACKET_get_1(&tmp, &length) || + !PACKET_get_bytes(&tmp, &data, (size_t)length)) { + return 0; + } + + *pkt = tmp; + subpkt->curr = data; + subpkt->remaining = length; + + return 1; +} + +/* + * Like PACKET_get_length_prefixed_1, but additionally, fails when there are + * leftover bytes in |pkt|. + */ +__owur static ossl_inline int PACKET_as_length_prefixed_1(PACKET *pkt, + PACKET *subpkt) +{ + unsigned int length; + const unsigned char *data; + PACKET tmp = *pkt; + + if (!PACKET_get_1(&tmp, &length) || + !PACKET_get_bytes(&tmp, &data, (size_t)length) || + PACKET_remaining(&tmp) != 0) { + return 0; + } + + *pkt = tmp; + subpkt->curr = data; + subpkt->remaining = length; + + return 1; +} + +/* + * Reads a variable-length vector prefixed with a two-byte length, and stores + * the contents in |subpkt|. |pkt| can equal |subpkt|. + * Data is not copied: the |subpkt| packet will share its underlying buffer with + * the original |pkt|, so data wrapped by |pkt| must outlive the |subpkt|. + * Upon failure, the original |pkt| and |subpkt| are not modified. + */ +__owur static ossl_inline int PACKET_get_length_prefixed_2(PACKET *pkt, + PACKET *subpkt) +{ + unsigned int length; + const unsigned char *data; + PACKET tmp = *pkt; + + if (!PACKET_get_net_2(&tmp, &length) || + !PACKET_get_bytes(&tmp, &data, (size_t)length)) { + return 0; + } + + *pkt = tmp; + subpkt->curr = data; + subpkt->remaining = length; + + return 1; +} + +/* + * Like PACKET_get_length_prefixed_2, but additionally, fails when there are + * leftover bytes in |pkt|. + */ +__owur static ossl_inline int PACKET_as_length_prefixed_2(PACKET *pkt, + PACKET *subpkt) +{ + unsigned int length; + const unsigned char *data; + PACKET tmp = *pkt; + + if (!PACKET_get_net_2(&tmp, &length) || + !PACKET_get_bytes(&tmp, &data, (size_t)length) || + PACKET_remaining(&tmp) != 0) { + return 0; + } + + *pkt = tmp; + subpkt->curr = data; + subpkt->remaining = length; + + return 1; +} + +/* + * Reads a variable-length vector prefixed with a three-byte length, and stores + * the contents in |subpkt|. |pkt| can equal |subpkt|. + * Data is not copied: the |subpkt| packet will share its underlying buffer with + * the original |pkt|, so data wrapped by |pkt| must outlive the |subpkt|. + * Upon failure, the original |pkt| and |subpkt| are not modified. + */ +__owur static ossl_inline int PACKET_get_length_prefixed_3(PACKET *pkt, + PACKET *subpkt) +{ + unsigned long length; + const unsigned char *data; + PACKET tmp = *pkt; + + if (!PACKET_get_net_3(&tmp, &length) || + !PACKET_get_bytes(&tmp, &data, (size_t)length)) { + return 0; + } + + *pkt = tmp; + subpkt->curr = data; + subpkt->remaining = length; + + return 1; +} + +/* Writeable packets */ + +typedef struct wpacket_sub WPACKET_SUB; +struct wpacket_sub { + /* The parent WPACKET_SUB if we have one or NULL otherwise */ + WPACKET_SUB *parent; + + /* + * Offset into the buffer where the length of this WPACKET goes. We use an + * offset in case the buffer grows and gets reallocated. + */ + size_t packet_len; + + /* Number of bytes in the packet_len or 0 if we don't write the length */ + size_t lenbytes; + + /* Number of bytes written to the buf prior to this packet starting */ + size_t pwritten; + + /* Flags for this sub-packet */ + unsigned int flags; +}; + +typedef struct wpacket_st WPACKET; +struct wpacket_st { + /* The buffer where we store the output data */ + BUF_MEM *buf; + + /* Fixed sized buffer which can be used as an alternative to buf */ + unsigned char *staticbuf; + + /* + * Offset into the buffer where we are currently writing. We use an offset + * in case the buffer grows and gets reallocated. + */ + size_t curr; + + /* Number of bytes written so far */ + size_t written; + + /* Maximum number of bytes we will allow to be written to this WPACKET */ + size_t maxsize; + + /* Our sub-packets (always at least one if not finished) */ + WPACKET_SUB *subs; + + /* Writing from the end first? */ + unsigned int endfirst : 1; +}; + +/* Flags */ + +/* Default */ +#define WPACKET_FLAGS_NONE 0 + +/* Error on WPACKET_close() if no data written to the WPACKET */ +#define WPACKET_FLAGS_NON_ZERO_LENGTH 1 + +/* + * Abandon all changes on WPACKET_close() if no data written to the WPACKET, + * i.e. this does not write out a zero packet length + */ +#define WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH 2 + + +/* + * Initialise a WPACKET with the buffer in |buf|. The buffer must exist + * for the whole time that the WPACKET is being used. Additionally |lenbytes| of + * data is preallocated at the start of the buffer to store the length of the + * WPACKET once we know it. + */ +int WPACKET_init_len(WPACKET *pkt, BUF_MEM *buf, size_t lenbytes); + +/* + * Same as WPACKET_init_len except there is no preallocation of the WPACKET + * length. + */ +int WPACKET_init(WPACKET *pkt, BUF_MEM *buf); + +/* + * Same as WPACKET_init_len except there is no underlying buffer. No data is + * ever actually written. We just keep track of how much data would have been + * written if a buffer was there. + */ +int WPACKET_init_null(WPACKET *pkt, size_t lenbytes); + +/* + * Same as WPACKET_init_null except we set the WPACKET to assume DER length + * encoding for sub-packets. + */ +int WPACKET_init_null_der(WPACKET *pkt); + +/* + * Same as WPACKET_init_len except we do not use a growable BUF_MEM structure. + * A fixed buffer of memory |buf| of size |len| is used instead. A failure will + * occur if you attempt to write beyond the end of the buffer + */ +int WPACKET_init_static_len(WPACKET *pkt, unsigned char *buf, size_t len, + size_t lenbytes); + +/* + * Same as WPACKET_init_static_len except lenbytes is always 0, and we set the + * WPACKET to write to the end of the buffer moving towards the start and use + * DER length encoding for sub-packets. + */ +int WPACKET_init_der(WPACKET *pkt, unsigned char *buf, size_t len); + +/* + * Set the flags to be applied to the current sub-packet + */ +int WPACKET_set_flags(WPACKET *pkt, unsigned int flags); + +/* + * Closes the most recent sub-packet. It also writes out the length of the + * packet to the required location (normally the start of the WPACKET) if + * appropriate. The top level WPACKET should be closed using WPACKET_finish() + * instead of this function. + */ +int WPACKET_close(WPACKET *pkt); + +/* + * The same as WPACKET_close() but only for the top most WPACKET. Additionally + * frees memory resources for this WPACKET. + */ +int WPACKET_finish(WPACKET *pkt); + +/* + * Iterate through all the sub-packets and write out their lengths as if they + * were being closed. The lengths will be overwritten with the final lengths + * when the sub-packets are eventually closed (which may be different if more + * data is added to the WPACKET). This function fails if a sub-packet is of 0 + * length and WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH is set. + */ +int WPACKET_fill_lengths(WPACKET *pkt); + +/* + * Initialise a new sub-packet. Additionally |lenbytes| of data is preallocated + * at the start of the sub-packet to store its length once we know it. Don't + * call this directly. Use the convenience macros below instead. + */ +int WPACKET_start_sub_packet_len__(WPACKET *pkt, size_t lenbytes); + +/* + * Convenience macros for calling WPACKET_start_sub_packet_len with different + * lengths + */ +#define WPACKET_start_sub_packet_u8(pkt) \ + WPACKET_start_sub_packet_len__((pkt), 1) +#define WPACKET_start_sub_packet_u16(pkt) \ + WPACKET_start_sub_packet_len__((pkt), 2) +#define WPACKET_start_sub_packet_u24(pkt) \ + WPACKET_start_sub_packet_len__((pkt), 3) +#define WPACKET_start_sub_packet_u32(pkt) \ + WPACKET_start_sub_packet_len__((pkt), 4) + +/* + * Same as WPACKET_start_sub_packet_len__() except no bytes are pre-allocated + * for the sub-packet length. + */ +int WPACKET_start_sub_packet(WPACKET *pkt); + +/* + * Allocate bytes in the WPACKET for the output. This reserves the bytes + * and counts them as "written", but doesn't actually do the writing. A pointer + * to the allocated bytes is stored in |*allocbytes|. |allocbytes| may be NULL. + * WARNING: the allocated bytes must be filled in immediately, without further + * WPACKET_* calls. If not then the underlying buffer may be realloc'd and + * change its location. + */ +int WPACKET_allocate_bytes(WPACKET *pkt, size_t len, + unsigned char **allocbytes); + +/* + * The same as WPACKET_allocate_bytes() except additionally a new sub-packet is + * started for the allocated bytes, and then closed immediately afterwards. The + * number of length bytes for the sub-packet is in |lenbytes|. Don't call this + * directly. Use the convenience macros below instead. + */ +int WPACKET_sub_allocate_bytes__(WPACKET *pkt, size_t len, + unsigned char **allocbytes, size_t lenbytes); + +/* + * Convenience macros for calling WPACKET_sub_allocate_bytes with different + * lengths + */ +#define WPACKET_sub_allocate_bytes_u8(pkt, len, bytes) \ + WPACKET_sub_allocate_bytes__((pkt), (len), (bytes), 1) +#define WPACKET_sub_allocate_bytes_u16(pkt, len, bytes) \ + WPACKET_sub_allocate_bytes__((pkt), (len), (bytes), 2) +#define WPACKET_sub_allocate_bytes_u24(pkt, len, bytes) \ + WPACKET_sub_allocate_bytes__((pkt), (len), (bytes), 3) +#define WPACKET_sub_allocate_bytes_u32(pkt, len, bytes) \ + WPACKET_sub_allocate_bytes__((pkt), (len), (bytes), 4) + +/* + * The same as WPACKET_allocate_bytes() except the reserved bytes are not + * actually counted as written. Typically this will be for when we don't know + * how big arbitrary data is going to be up front, but we do know what the + * maximum size will be. If this function is used, then it should be immediately + * followed by a WPACKET_allocate_bytes() call before any other WPACKET + * functions are called (unless the write to the allocated bytes is abandoned). + * + * For example: If we are generating a signature, then the size of that + * signature may not be known in advance. We can use WPACKET_reserve_bytes() to + * handle this: + * if (!WPACKET_sub_reserve_bytes_u16(&pkt, EVP_PKEY_get_size(pkey), &sigbytes1) + * || EVP_SignFinal(md_ctx, sigbytes1, &siglen, pkey) <= 0 + * || !WPACKET_sub_allocate_bytes_u16(&pkt, siglen, &sigbytes2) + * || sigbytes1 != sigbytes2) + * goto err; + */ +int WPACKET_reserve_bytes(WPACKET *pkt, size_t len, unsigned char **allocbytes); + +/* + * The "reserve_bytes" equivalent of WPACKET_sub_allocate_bytes__() + */ +int WPACKET_sub_reserve_bytes__(WPACKET *pkt, size_t len, + unsigned char **allocbytes, size_t lenbytes); + +/* + * Convenience macros for WPACKET_sub_reserve_bytes with different lengths + */ +#define WPACKET_sub_reserve_bytes_u8(pkt, len, bytes) \ + WPACKET_reserve_bytes__((pkt), (len), (bytes), 1) +#define WPACKET_sub_reserve_bytes_u16(pkt, len, bytes) \ + WPACKET_sub_reserve_bytes__((pkt), (len), (bytes), 2) +#define WPACKET_sub_reserve_bytes_u24(pkt, len, bytes) \ + WPACKET_sub_reserve_bytes__((pkt), (len), (bytes), 3) +#define WPACKET_sub_reserve_bytes_u32(pkt, len, bytes) \ + WPACKET_sub_reserve_bytes__((pkt), (len), (bytes), 4) + +/* + * Write the value stored in |val| into the WPACKET. The value will consume + * |bytes| amount of storage. An error will occur if |val| cannot be + * accommodated in |bytes| storage, e.g. attempting to write the value 256 into + * 1 byte will fail. Don't call this directly. Use the convenience macros below + * instead. + */ +int WPACKET_put_bytes__(WPACKET *pkt, uint64_t val, size_t bytes); + +/* + * Convenience macros for calling WPACKET_put_bytes with different + * lengths + */ +#define WPACKET_put_bytes_u8(pkt, val) \ + WPACKET_put_bytes__((pkt), (val), 1) +#define WPACKET_put_bytes_u16(pkt, val) \ + WPACKET_put_bytes__((pkt), (val), 2) +#define WPACKET_put_bytes_u24(pkt, val) \ + WPACKET_put_bytes__((pkt), (val), 3) +#define WPACKET_put_bytes_u32(pkt, val) \ + WPACKET_put_bytes__((pkt), (val), 4) +#define WPACKET_put_bytes_u64(pkt, val) \ + WPACKET_put_bytes__((pkt), (val), 8) + +/* Set a maximum size that we will not allow the WPACKET to grow beyond */ +int WPACKET_set_max_size(WPACKET *pkt, size_t maxsize); + +/* Copy |len| bytes of data from |*src| into the WPACKET. */ +int WPACKET_memcpy(WPACKET *pkt, const void *src, size_t len); + +/* Set |len| bytes of data to |ch| into the WPACKET. */ +int WPACKET_memset(WPACKET *pkt, int ch, size_t len); + +/* + * Copy |len| bytes of data from |*src| into the WPACKET and prefix with its + * length (consuming |lenbytes| of data for the length). Don't call this + * directly. Use the convenience macros below instead. + */ +int WPACKET_sub_memcpy__(WPACKET *pkt, const void *src, size_t len, + size_t lenbytes); + +/* Convenience macros for calling WPACKET_sub_memcpy with different lengths */ +#define WPACKET_sub_memcpy_u8(pkt, src, len) \ + WPACKET_sub_memcpy__((pkt), (src), (len), 1) +#define WPACKET_sub_memcpy_u16(pkt, src, len) \ + WPACKET_sub_memcpy__((pkt), (src), (len), 2) +#define WPACKET_sub_memcpy_u24(pkt, src, len) \ + WPACKET_sub_memcpy__((pkt), (src), (len), 3) +#define WPACKET_sub_memcpy_u32(pkt, src, len) \ + WPACKET_sub_memcpy__((pkt), (src), (len), 4) + +/* + * Return the total number of bytes written so far to the underlying buffer + * including any storage allocated for length bytes + */ +int WPACKET_get_total_written(WPACKET *pkt, size_t *written); + +/* + * Returns the length of the current sub-packet. This excludes any bytes + * allocated for the length itself. + */ +int WPACKET_get_length(WPACKET *pkt, size_t *len); + +/* + * Returns a pointer to the current write location, but does not allocate any + * bytes. + */ +unsigned char *WPACKET_get_curr(WPACKET *pkt); + +/* Returns true if the underlying buffer is actually NULL */ +int WPACKET_is_null_buf(WPACKET *pkt); + +/* Release resources in a WPACKET if a failure has occurred. */ +void WPACKET_cleanup(WPACKET *pkt); + +#endif /* OSSL_INTERNAL_PACKET_H */ diff --git a/KAEOpensslProvider/src/provider/prov_nosva/internal/prov_sizes.h b/KAEOpensslProvider/src/provider/prov_nosva/internal/prov_sizes.h new file mode 100644 index 0000000000000000000000000000000000000000..b14fdfa31f275bb156b569b3926883a20a6375b1 --- /dev/null +++ b/KAEOpensslProvider/src/provider/prov_nosva/internal/prov_sizes.h @@ -0,0 +1,23 @@ +/* + * Copyright 2020-2025 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef KAE_PROV_SIZES_H +# define KAE_PROV_SIZES_H +# pragma once + +/* + * Max sizes used to allocate buffers with a fixed sizes, for example for + * stack allocations, structure fields, ... + */ +# define OSSL_MAX_NAME_SIZE 50 /* Algorithm name */ +# define OSSL_MAX_PROPQUERY_SIZE 256 /* Property query strings */ +# define OSSL_MAX_ALGORITHM_ID_SIZE 256 /* AlgorithmIdentifier DER */ +# define OSSL_MAX_CODEC_STRUCT_SIZE 32 /* DATA_STRUCTURE name */ + +#endif diff --git a/KAEOpensslProvider/src/provider/prov_nosva/prov.h b/KAEOpensslProvider/src/provider/prov_nosva/prov.h new file mode 100644 index 0000000000000000000000000000000000000000..f1a7eabe23cfe7ed5cc0e439264fd591699f23bb --- /dev/null +++ b/KAEOpensslProvider/src/provider/prov_nosva/prov.h @@ -0,0 +1,159 @@ +/* + * Copyright 2025 Huawei Technologies Co.,Ltd.All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef KAE_PROVIDER_H +#define KAE_PROVIDER_H +#include + +#define FUNC_MAX_NUM 32 + +#define KAE_P_SUCCESS 1 +#define KAE_P_FAIL 0 + +#define OPENSSL_SUCCESS (1) +#define OPENSSL_FAIL (0) + +struct ossl_provider_st { + /* Flag bits */ + unsigned int flag_initialized : 1; + unsigned int flag_activated : 1; + unsigned int flag_fallback : 1; /* Can be used as fallback */ + + /* Getting and setting the flags require synchronization */ + void *flag_lock; + + /* OpenSSL library side data */ + /* Crypto reference counter */ + int refcnt; + /* Lock for the ref counter */ + void *refcnt_lock; + int activatecnt; + char *name; + char *path; + void *module; + OSSL_provider_init_fn *init_function; + + STACK_OF(INFOPAIR) * parameters; + OSSL_LIB_CTX *libctx; /* The library context this instance is in */ + struct provider_store_st *store; /* The store this instance belongs to */ +#ifndef FIPS_MODULE + /* + * In the FIPS module inner provider, this isn't needed, since the + * error upcalls are always direct calls to the outer provider. + */ + int error_lib; /* ERR library number, one for each provider */ +#ifndef OPENSSL_NO_ERR + char *error_strings; /* Copy of what the provider gives us */ +#endif +#endif + + /* Provider side functions */ + OSSL_FUNC_provider_teardown_fn *teardown; + OSSL_FUNC_provider_gettable_params_fn *gettable_params; + OSSL_FUNC_provider_get_params_fn *get_params; + OSSL_FUNC_provider_get_capabilities_fn *get_capabilities; + OSSL_FUNC_provider_self_test_fn *self_test; + OSSL_FUNC_provider_query_operation_fn *query_operation; + OSSL_FUNC_provider_unquery_operation_fn *unquery_operation; + + /* + * Cache of bit to indicate of query_operation() has been called on + * a specific operation or not. + */ + unsigned char *operation_bits; + size_t operation_bits_sz; + void *opbits_lock; + +#ifndef FIPS_MODULE + /* Whether this provider is the child of some other provider */ + const OSSL_CORE_HANDLE *handle; + unsigned int ischild : 1; +#endif + + /* Provider side data */ + void *provctx; + const OSSL_DISPATCH *dispatch; +}; + +typedef struct bio_method_st { + int type; + char *name; + int (*bwrite)(BIO *bio, const char *data, size_t datal, size_t *written); + int (*bwrite_old)(BIO *bio, const char *data, int datal); + int (*bread)(BIO *bio, char *data, size_t datal, size_t *read); + int (*bread_old)(BIO *bio, char *data, int datal); + int (*bputs)(BIO *bio, const char *buf); + int (*bgets)(BIO *bio, char *buf, int size); + long (*ctrl)(BIO *bio, int cmd, long larg, void *parg); + int (*create)(BIO *bio); + int (*destroy)(BIO *bio); + long (*callback_ctrl)(BIO *bio, int cmd, BIO_info_cb *fp); +} KAE_BIO_METHOD; + +typedef struct kae_prov_ctx { + const OSSL_CORE_HANDLE *handle; + OSSL_LIB_CTX *libctx; + KAE_BIO_METHOD *corebiometh; +} KAE_PROV_CTX; + +static inline OSSL_LIB_CTX *prov_libctx_of(struct kae_prov_ctx *ctx) +{ + if (ctx == NULL) + return NULL; + return ctx->libctx; +} + +extern const OSSL_DISPATCH kae_md5_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH kae_sm3_functions[FUNC_MAX_NUM]; + +extern const OSSL_DISPATCH kae_aes_128_cbc_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH kae_aes_192_cbc_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH kae_aes_256_cbc_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH kae_aes_128_cts_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH kae_aes_192_cts_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH kae_aes_256_cts_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH kae_aes_128_ecb_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH kae_aes_192_ecb_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH kae_aes_256_ecb_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH kae_aes_128_xts_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH kae_aes_256_xts_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH kae_aes_128_ctr_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH kae_aes_192_ctr_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH kae_aes_256_ctr_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH kae_aes_128_ofb128_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH kae_aes_192_ofb128_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH kae_aes_256_ofb128_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH kae_aes_128_cfb128_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH kae_aes_192_cfb128_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH kae_aes_256_cfb128_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH kae_sm4_cbc_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH kae_sm4_ecb_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH kae_sm4_ofb128_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH kae_sm4_cfb128_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH kae_sm4_ctr_functions[FUNC_MAX_NUM]; + +extern const OSSL_DISPATCH kae_rsa_signature_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH kae_rsa_keymgmt_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH kae_rsa_asym_cipher_functions[FUNC_MAX_NUM]; + +extern const OSSL_DISPATCH kae_dh_keymgmt_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH kae_dh_keyexch_functions[FUNC_MAX_NUM]; + +extern const OSSL_DISPATCH kae_sm2_keymgmt_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH kae_sm2_signature_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH kae_sm2_asym_cipher_functions[FUNC_MAX_NUM]; + +#endif diff --git a/KAEOpensslProvider/src/provider/prov_nosva/prov_cipher.c b/KAEOpensslProvider/src/provider/prov_nosva/prov_cipher.c new file mode 100644 index 0000000000000000000000000000000000000000..5d494ad6ab370d931a2077c0cda05fe9467e2abd --- /dev/null +++ b/KAEOpensslProvider/src/provider/prov_nosva/prov_cipher.c @@ -0,0 +1,776 @@ +/* + * Copyright 2025 Huawei Technologies Co.,Ltd.All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include "prov.h" +#include "prov_cipher.h" +#include "../../adapter/common/kae_log.h" +#include "../../adapter/nosva/algorithm/cipher/sec_ciphers_utils.h" + +EVP_CIPHER *get_default_soft_cipher(int nid) +{ + EVP_CIPHER *cipher; + switch (nid) { + case NID_aes_128_cbc: + cipher = EVP_CIPHER_fetch(NULL, "AES-128-CBC", "provider=default"); + break; + case NID_aes_192_cbc: + cipher = EVP_CIPHER_fetch(NULL, "AES-192-CBC", "provider=default"); + break; + case NID_aes_256_cbc: + cipher = EVP_CIPHER_fetch(NULL, "AES-256-CBC", "provider=default"); + break; + case NID_aes_128_ecb: + cipher = EVP_CIPHER_fetch(NULL, "AES-128-ECB", "provider=default"); + break; + case NID_aes_192_ecb: + cipher = EVP_CIPHER_fetch(NULL, "AES-192-ECB", "provider=default"); + break; + case NID_aes_256_ecb: + cipher = EVP_CIPHER_fetch(NULL, "AES-256-ECB", "provider=default"); + break; + case NID_sm4_cbc: + cipher = EVP_CIPHER_fetch(NULL, "SM4-CBC", "provider=default"); + break; + case NID_sm4_ecb: + cipher = EVP_CIPHER_fetch(NULL, "SM4-ECB", "provider=default"); + break; + case NID_des_ede3_cbc: + cipher = EVP_CIPHER_fetch(NULL, "DES-EDE3-CBC", "provider=default"); + break; + case NID_des_ede3_ecb: + cipher = EVP_CIPHER_fetch(NULL, "DES-EDE3-ECB", "provider=default"); + break; + case NID_aes_128_ctr: + cipher = EVP_CIPHER_fetch(NULL, "AES-128-CTR", "provider=default"); + break; + case NID_aes_192_ctr: + cipher = EVP_CIPHER_fetch(NULL, "AES-192-CTR", "provider=default"); + break; + case NID_aes_256_ctr: + cipher = EVP_CIPHER_fetch(NULL, "AES-256-CTR", "provider=default"); + break; + case NID_aes_128_ofb128: + cipher = EVP_CIPHER_fetch(NULL, "AES-128-OFB", "provider=default"); + break; + case NID_aes_192_ofb128: + cipher = EVP_CIPHER_fetch(NULL, "AES-192-OFB", "provider=default"); + break; + case NID_aes_256_ofb128: + cipher = EVP_CIPHER_fetch(NULL, "AES-256-OFB", "provider=default"); + break; + case NID_aes_128_cfb128: + cipher = EVP_CIPHER_fetch(NULL, "AES-128-CFB", "provider=default"); + break; + case NID_aes_192_cfb128: + cipher = EVP_CIPHER_fetch(NULL, "AES-192-CFB", "provider=default"); + break; + case NID_aes_256_cfb128: + cipher = EVP_CIPHER_fetch(NULL, "AES-256-CFB", "provider=default"); + break; + case NID_sm4_ofb128: + cipher = EVP_CIPHER_fetch(NULL, "SM4-OFB", "provider=default"); + break; + case NID_sm4_cfb128: + cipher = EVP_CIPHER_fetch(NULL, "SM4-CFB", "provider=default"); + break; + case NID_sm4_ctr: + cipher = EVP_CIPHER_fetch(NULL, "SM4-CTR", "provider=default"); + break; + case NID_aes_128_xts: + cipher = EVP_CIPHER_fetch(NULL, "AES-128-XTS", "provider=default"); + break; + case NID_aes_256_xts: + cipher = EVP_CIPHER_fetch(NULL, "AES-256-XTS", "provider=default"); + break; + default: + cipher = NULL; + break; + } + + return cipher; +} + +int ciphers_sw_impl_init(cipher_priv_ctx *priv, const unsigned char *key, const unsigned char *iv, int enc) +{ + priv->sw_ctx = EVP_CIPHER_CTX_new(); + if (!priv->sw_ctx) { + fprintf(stderr, "EVP_CIPHER_CTX_new failed.\n"); + return OPENSSL_FAIL; + } + + if (unlikely(priv->sw_cipher == NULL)) { + US_ERR("get openssl software cipher failed. nid = %d", priv->nid); + return OPENSSL_FAIL; + } + + if (!EVP_CipherInit_ex2(priv->sw_ctx, priv->sw_cipher, key, iv, priv->encrypt, NULL)) { + fprintf(stderr, "cipher soft init failed!\n"); + return OPENSSL_FAIL; + } + + return OPENSSL_SUCCESS; +} + +static void init_soft_cipher_ctx(cipher_priv_ctx *priv, const unsigned char *key, const unsigned char *iv) +{ + priv->sw_cipher = get_default_soft_cipher(priv->nid); + ciphers_sw_impl_init(priv, key, iv, priv->encrypt); +} + +static int kae_cipher_einit(void *vctx, const unsigned char *key, size_t keylen, const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + cipher_priv_ctx *priv = (cipher_priv_ctx *)vctx; + int ret; + + if (!vctx) + return KAE_P_FAIL; + + priv->encrypt = 1; + + ret = sec_ciphers_init_priv_ctx(priv, key, keylen, iv, ivlen); + if (priv->c_mode == XTS && priv->ecb_encryto) { + if (priv->ecb_encryto->key2_len == 32) { // 256-xts key2len is 32 + priv->ecb_encryto->cipher_type = get_default_soft_cipher(NID_aes_256_ecb); + } else { + priv->ecb_encryto->cipher_type = get_default_soft_cipher(NID_aes_128_ecb); + } + } + + init_soft_cipher_ctx(priv, key, iv); + + return ret; +} + +static int kae_cipher_dinit(void *vctx, const unsigned char *key, size_t keylen, const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + cipher_priv_ctx *priv = (cipher_priv_ctx *)vctx; + int ret; + + if (!vctx) + return KAE_P_FAIL; + + priv->encrypt = 0; + + ret = sec_ciphers_init_priv_ctx(priv, key, keylen, iv, ivlen); + if (priv->c_mode == XTS && priv->ecb_encryto) { + if (priv->ecb_encryto->key2_len == 32) { // 256-xts key2len is 32 + priv->ecb_encryto->cipher_type = get_default_soft_cipher(NID_aes_256_ecb); + } else { + priv->ecb_encryto->cipher_type = get_default_soft_cipher(NID_aes_128_ecb); + } + } + + init_soft_cipher_ctx(priv, key, iv); + + return ret; +} + +static int prov_cipher_soft_update( + cipher_priv_ctx *priv, unsigned char *out, int *outl, const unsigned char *in, size_t len) +{ + if (!priv->sw_cipher) + return KAE_P_FAIL; + + if (!EVP_CipherInit_ex2(priv->sw_ctx, priv->sw_cipher, priv->key, priv->iv, priv->encrypt, NULL)) { + fprintf(stderr, "cipher soft init error!\n"); + return KAE_P_FAIL; + } + + if (!EVP_CipherUpdate(priv->sw_ctx, out, outl, in, len)) { + fprintf(stderr, "cipher soft update error!\n"); + return KAE_P_FAIL; + } + + return KAE_P_SUCCESS; +} + +/* + * Fills the buffer with trailing data from an encryption/decryption that didn't + * fit into a full block. + */ +static int ossl_cipher_trailingdata( + unsigned char *buf, size_t *buflen, size_t blocksize, const unsigned char **in, size_t *inlen) +{ + if (*inlen == 0) + return KAE_P_SUCCESS; + + if (*buflen + *inlen > blocksize) { + ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); + return KAE_P_FAIL; + } + + memcpy(buf + *buflen, *in, *inlen); + *buflen += *inlen; + *inlen = 0; + + return KAE_P_SUCCESS; +} + +static size_t ossl_cipher_fillblock( + unsigned char *buf, size_t *buflen, size_t blocksize, const unsigned char **in, size_t *inlen) +{ + size_t blockmask = ~(blocksize - 1); + size_t bufremain = blocksize - *buflen; + + if (*inlen < bufremain) + bufremain = *inlen; + memcpy(buf + *buflen, *in, bufremain); + *in += bufremain; + *inlen -= bufremain; + *buflen += bufremain; + + return *inlen & blockmask; +} + +static int prov_do_cipher( + cipher_priv_ctx *priv, unsigned char *out, size_t *outl, size_t outsize, const unsigned char *in, size_t inlen) +{ + size_t blksz = priv->blk_size; + size_t nextblocks; + int outlint = 0; + int ret; + + if (priv->buf_size != 0) + nextblocks = ossl_cipher_fillblock(priv->buf, &priv->buf_size, blksz, &in, &inlen); + else + nextblocks = inlen & ~(blksz - 1); + + /* + * If we're decrypting and we end an update on a block boundary we hold + * the last block back in case this is the last update call and the last + * block is padded. + */ + if (priv->buf_size == blksz && (priv->encrypt || inlen > 0 || !priv->pad)) { + ret = sec_ciphers_do_cipher(priv, out, outsize, priv->buf, blksz); + if (ret != KAE_P_SUCCESS) { + fprintf(stderr, "do hw ciphers failed.\n"); + if (priv->sw_cipher) + goto do_soft; + return ret; + } + + priv->buf_size = 0; + outlint = blksz; + out += blksz; + } + + if (nextblocks == 0) + goto out; + + if (!priv->encrypt && priv->pad && nextblocks == inlen) + nextblocks -= blksz; + + if (nextblocks > 0) { + ret = sec_ciphers_do_cipher(priv, out, outsize, in, nextblocks); + if (ret != KAE_P_SUCCESS) { + // fprintf(stderr, "last block do hw ciphers failed.\n"); + if (priv->sw_cipher) + goto do_soft; + return ret; + } + + outlint += nextblocks; + in += nextblocks; + inlen -= nextblocks; + } +out: + if (inlen != 0 && !ossl_cipher_trailingdata(priv->buf, &priv->buf_size, blksz, &in, &inlen)) + return KAE_P_FAIL; + + *outl = outlint; + return inlen == 0; + +do_soft: + + ret = prov_cipher_soft_update(priv, out, &outlint, in, inlen); + if (ret) { + *outl = outlint; + return KAE_P_SUCCESS; + } + + return KAE_P_FAIL; +} + +static int kae_cipher_block_update( + void *vctx, unsigned char *output, size_t *outl, size_t outsize, const unsigned char *input, size_t inl) +{ + cipher_priv_ctx *priv = (cipher_priv_ctx *)vctx; + + if (!vctx || !input || !output || !outl) + return KAE_P_FAIL; + + if (inl == 0) { + *outl = 0; + return KAE_P_SUCCESS; + } + + if (outsize < inl) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return KAE_P_FAIL; + } + + return prov_do_cipher(priv, output, outl, outsize, input, inl); +} + +static int kae_cipher_stream_update( + void *vctx, unsigned char *output, size_t *outl, size_t outsize, const unsigned char *input, size_t inl) +{ + cipher_priv_ctx *priv = (cipher_priv_ctx *)vctx; + int len = 0; + int ret; + + if (!vctx || !outl || !input || !output) + return KAE_P_FAIL; + + if (inl == 0) { + *outl = 0; + return KAE_P_SUCCESS; + } + + if (outsize < inl) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return KAE_P_FAIL; + } + + ret = sec_ciphers_do_cipher(priv, output, outsize, input, inl); + if (ret == KAE_CRYPTO_FAIL) { + if (priv->sw_cipher) + goto do_soft; + } + if (ret != KAE_P_SUCCESS) { + return ret; + } + + *outl = inl; + return KAE_P_SUCCESS; + +do_soft: + /* have isseu if both using hw and soft partly */ + ret = prov_cipher_soft_update(priv, output, &len, input, inl); + if (ret) { + *outl = len; + return KAE_P_SUCCESS; + } + + fprintf(stderr, "do soft ciphers failed.\n"); + + return KAE_P_FAIL; +} + +/* Pad the final block for encryption */ +void ossl_cipher_padblock(unsigned char *buf, size_t *buflen, size_t blocksize) +{ + size_t i; + unsigned char pad = (unsigned char)(blocksize - *buflen); + + for (i = *buflen; i < blocksize; i++) + buf[i] = pad; +} + +static int prov_cipher_soft_final(cipher_priv_ctx *priv, unsigned char *out, size_t *outl) +{ + int sw_final_len = 0; + + if (!priv->sw_cipher) + return KAE_P_FAIL; + + if (!EVP_CipherFinal_ex(priv->sw_ctx, out, &sw_final_len)) { + fprintf(stderr, "cipher soft final failed.\n"); + return KAE_P_FAIL; + } + + *outl = sw_final_len; + // priv->switch_flag = 0; + + return KAE_P_SUCCESS; +} + +static int kae_cipher_block_encrypto(cipher_priv_ctx *priv, unsigned char *out, size_t *outl, size_t outsize) +{ + size_t blksz = priv->blk_size; + int ret; + + if (priv->pad) { + ossl_cipher_padblock(priv->buf, &priv->buf_size, blksz); + } else if (priv->buf_size == 0) { + *outl = 0; + return KAE_P_SUCCESS; + } else if (priv->buf_size != blksz) { + ERR_raise(ERR_LIB_PROV, PROV_R_WRONG_FINAL_BLOCK_LENGTH); + return KAE_P_FAIL; + } + + if (outsize < blksz) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return KAE_P_FAIL; + } + + ret = sec_ciphers_do_cipher(priv, out, outsize, priv->buf, blksz); + if (ret != KAE_P_SUCCESS) { + fprintf(stderr, "do hw ciphers failed, switch to soft ciphers.\n"); + return prov_cipher_soft_final(priv, out, outl); + } + + *outl = blksz; + + return KAE_P_SUCCESS; +} + +static int ossl_cipher_unpadblock(unsigned char *buf, size_t *buflen, size_t blocksize) +{ + size_t len = *buflen; + size_t pad, i; + + if (len != blocksize) { + // ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); + return KAE_P_FAIL; + } + + /* + * The following assumes that the ciphertext has been authenticated. + * Otherwise it provides a padding oracle. + */ + pad = buf[blocksize - 1]; + if (pad == 0 || pad > blocksize) { + // ERR_raise(ERR_LIB_PROV, PROV_R_BAD_DECRYPT); + return KAE_P_FAIL; + } + for (i = 0; i < pad; i++) { + if (buf[--len] != pad) { + // ERR_raise(ERR_LIB_PROV, PROV_R_BAD_DECRYPT); + return KAE_P_FAIL; + } + } + *buflen = len; + + return KAE_P_SUCCESS; +} + +static int kae_cipher_block_decrypto(cipher_priv_ctx *priv, unsigned char *out, size_t *outl, size_t outsize) +{ + int ret; + + /* Dec should handle last blk since pad */ + if (priv->buf_size != priv->blk_size) { + if (priv->buf_size == 0 && !priv->pad) { + *outl = 0; + return KAE_P_SUCCESS; + } + ERR_raise(ERR_LIB_PROV, PROV_R_WRONG_FINAL_BLOCK_LENGTH); + return KAE_P_FAIL; + } + + ret = sec_ciphers_do_cipher(priv, priv->buf, outsize, priv->buf, priv->blk_size); + if (ret != KAE_P_SUCCESS) { + fprintf(stderr, "do hw ciphers failed, switch to soft ciphers.\n"); + return prov_cipher_soft_final(priv, out, outl); + } + + if (priv->pad && !ossl_cipher_unpadblock(priv->buf, &priv->buf_size, priv->blk_size)) { + /* ERR_raise already called */ + return KAE_P_FAIL; + } + + if (outsize < priv->buf_size) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return KAE_P_FAIL; + } + + memcpy(out, priv->buf, priv->buf_size); + *outl = priv->buf_size; + priv->buf_size = 0; + + return KAE_P_SUCCESS; +} + +static int kae_cipher_block_final(void *vctx, unsigned char *out, size_t *outl, size_t outsize) +{ + cipher_priv_ctx *priv = (cipher_priv_ctx *)vctx; + int ret; + + if (!vctx || !out || !outl) + return KAE_P_FAIL; + + // if (priv->switch_flag == KAE_DO_SOFT) + // return kae_prov_cipher_soft_final(priv, out, outl); + + if (priv->encrypt) + ret = kae_cipher_block_encrypto(priv, out, outl, outsize); + else + ret = kae_cipher_block_decrypto(priv, out, outl, outsize); + + return ret; +} + +static int kae_cipher_stream_final(void *vctx, unsigned char *out, size_t *outl, size_t outsize) +{ + // cipher_priv_ctx *priv = (cipher_priv_ctx *)vctx; + + if (!vctx || !out || !outl) + return KAE_P_FAIL; + + // if (priv->switch_flag == KAE_DO_SOFT) + // return prov_cipher_soft_final(priv, out, outl); + + *outl = 0; + + return KAE_P_SUCCESS; +} + +static int kae_cipher_cipher( + void *vctx, unsigned char *output, size_t *outl, size_t outsize, const unsigned char *input, size_t inl) +{ + cipher_priv_ctx *priv = (cipher_priv_ctx *)vctx; + int ret; + + if (!vctx || !output || !input || !outl) + return KAE_P_FAIL; + + if (inl == 0) { + *outl = 0; + return KAE_P_SUCCESS; + } + + if (outsize < inl) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return KAE_P_FAIL; + } + + ret = prov_do_cipher(priv, output, outl, outsize, input, inl); + if (ret != KAE_P_SUCCESS) + return ret; + + *outl = inl; + + return KAE_P_SUCCESS; +} + +static void kae_cipher_freectx(void *dctx) +{ + cipher_priv_ctx *priv = (cipher_priv_ctx *)dctx; + + if (priv == NULL) + return; + + if (priv->sw_cipher) + EVP_CIPHER_free(priv->sw_cipher); + + if (priv->sw_ctx) + EVP_CIPHER_CTX_free(priv->sw_ctx); + + sec_ciphers_priv_ctx_cleanup(priv); + + OPENSSL_clear_free(priv, sizeof(*priv)); +} + +int prov_cipher_generic_get_params( + OSSL_PARAM params[], unsigned int md, uint64_t flags, size_t kbits, size_t blkbits, size_t ivbits) +{ + OSSL_PARAM *p; + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_MODE); + if (p != NULL && !OSSL_PARAM_set_uint(p, md)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return KAE_P_FAIL; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_CUSTOM_IV); + if (p != NULL && !OSSL_PARAM_set_int(p, (flags & PROV_CIPHER_FLAG_CUSTOM_IV) != 0)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return KAE_P_FAIL; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, kbits)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return KAE_P_FAIL; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_BLOCK_SIZE); + if (p != NULL && !OSSL_PARAM_set_size_t(p, blkbits)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return KAE_P_FAIL; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, ivbits)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return KAE_P_FAIL; + } + + return KAE_P_SUCCESS; +} + +static const OSSL_PARAM prov_cipher_known_gettable_params[] = {OSSL_PARAM_uint(OSSL_CIPHER_PARAM_MODE, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_BLOCK_SIZE, NULL), + OSSL_PARAM_int(OSSL_CIPHER_PARAM_AEAD, NULL), + OSSL_PARAM_int(OSSL_CIPHER_PARAM_CUSTOM_IV, NULL), + OSSL_PARAM_int(OSSL_CIPHER_PARAM_CTS, NULL), + OSSL_PARAM_int(OSSL_CIPHER_PARAM_HAS_RAND_KEY, NULL), + OSSL_PARAM_END}; + +static const OSSL_PARAM *kae_cipher_gettable_params(ossl_unused void *provctx) +{ + return prov_cipher_known_gettable_params; +} + +static int kae_cipher_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + cipher_priv_ctx *priv = (cipher_priv_ctx *)vctx; + OSSL_PARAM *p; + + if (!vctx || !params) + return KAE_P_FAIL; + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, priv->key_len)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return KAE_P_FAIL; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, priv->iv_len)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return KAE_P_FAIL; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_PADDING); + if (p != NULL && !OSSL_PARAM_set_uint(p, priv->pad)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return KAE_P_FAIL; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IV); + if (p != NULL && !OSSL_PARAM_set_octet_string(p, priv->iv, priv->iv_len) && + !OSSL_PARAM_set_octet_ptr(p, &priv->iv, priv->iv_len)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return KAE_P_FAIL; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_UPDATED_IV); + if (p != NULL && !OSSL_PARAM_set_octet_string(p, priv->iv, priv->iv_len) && + !OSSL_PARAM_set_octet_ptr(p, &priv->iv, priv->iv_len)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return KAE_P_FAIL; + } + // p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_CTS_MODE); + // if (p != NULL) { + // const char *name = ossl_cipher_cbc_cts_mode_id2name(priv->c_mode); + + // if (name == NULL || !OSSL_PARAM_set_utf8_string(p, name)) { + // ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + // return KAE_P_FAIL; + // } + // } + return KAE_P_SUCCESS; +} + +static const OSSL_PARAM prov_default_ctx_params[] = {OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL), + OSSL_PARAM_uint(OSSL_CIPHER_PARAM_PADDING, NULL), + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_IV, NULL, 0), + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_UPDATED_IV, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_CIPHER_PARAM_CTS_MODE, NULL, 0), + OSSL_PARAM_END}; + +static const OSSL_PARAM *kae_cipher_gettable_ctx_params(ossl_unused void *cctx, ossl_unused void *provctx) +{ + return prov_default_ctx_params; +} + +static int kae_cipher_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + cipher_priv_ctx *priv = (cipher_priv_ctx *)vctx; + const OSSL_PARAM *p; + + if (!vctx) + return KAE_P_FAIL; + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_PADDING); + if (p != NULL) { + unsigned int pad; + + if (!OSSL_PARAM_get_uint(p, &pad)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return KAE_P_FAIL; + } + priv->pad = pad ? 1 : 0; + EVP_CIPHER_CTX_set_padding(priv->sw_ctx, pad); + } + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p != NULL) { + size_t keylen; + + if (!OSSL_PARAM_get_size_t(p, &keylen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return KAE_P_FAIL; + } + if (priv->key_len != keylen) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return KAE_P_FAIL; + } + } + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_IVLEN); + if (p != NULL) { + size_t ivlen; + + if (!OSSL_PARAM_get_size_t(p, &ivlen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return KAE_P_FAIL; + } + if (priv->iv_len != ivlen) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); + return KAE_P_FAIL; + } + } + + // p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_CTS_MODE); + // if (p != NULL) { + // int id; + + // if (p->data_type != OSSL_PARAM_UTF8_STRING) { + // ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + // return KAE_P_FAIL; + // } + + // id = ossl_cipher_cbc_cts_mode_name2id(p->data); + // if (id < 0) { + // ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + // return KAE_P_FAIL; + // } + + // priv->c_mode = (unsigned int)id; + // // priv->setup.mode = priv->c_mode; + // // strncpy(priv->alg_name, cts_modes[id - WD_CIPHER_CBC_CS1].kae_alg_name, + // // ALG_NAME_SIZE - 1); + // } + + return KAE_P_SUCCESS; +} + +static const OSSL_PARAM prov_settable_ctx_params[] = {OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL), + OSSL_PARAM_uint(OSSL_CIPHER_PARAM_PADDING, NULL), + OSSL_PARAM_utf8_string(OSSL_CIPHER_PARAM_CTS_MODE, NULL, 0), + OSSL_PARAM_END}; + +const OSSL_PARAM *kae_cipher_settable_ctx_params(ossl_unused void *cctx, ossl_unused void *provctx) +{ + return prov_settable_ctx_params; +} diff --git a/KAEOpensslProvider/src/provider/prov_nosva/prov_cipher.h b/KAEOpensslProvider/src/provider/prov_nosva/prov_cipher.h new file mode 100644 index 0000000000000000000000000000000000000000..e4b5835110f144f8c32b05732e109bace0e43750 --- /dev/null +++ b/KAEOpensslProvider/src/provider/prov_nosva/prov_cipher.h @@ -0,0 +1,107 @@ +/* + * Copyright 2025 Huawei Technologies Co.,Ltd.All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef KAE_PROV_CIPHER_H +#define KAE_PROV_CIPHER_H + +#include +#include "../../adapter/nosva/algorithm/cipher/sec_ciphers.h" + +#define PROV_CIPHER_FLAG_CUSTOM_IV 0x0002 + +static OSSL_FUNC_cipher_encrypt_init_fn kae_cipher_einit; +static OSSL_FUNC_cipher_decrypt_init_fn kae_cipher_dinit; +static OSSL_FUNC_cipher_update_fn kae_cipher_block_update; +static OSSL_FUNC_cipher_update_fn kae_cipher_stream_update; +static OSSL_FUNC_cipher_final_fn kae_cipher_block_final; +static OSSL_FUNC_cipher_final_fn kae_cipher_stream_final; +static OSSL_FUNC_cipher_cipher_fn kae_cipher_cipher; +static OSSL_FUNC_cipher_freectx_fn kae_cipher_freectx; +static OSSL_FUNC_cipher_gettable_params_fn kae_cipher_gettable_params; +static OSSL_FUNC_cipher_get_ctx_params_fn kae_cipher_get_ctx_params; +static OSSL_FUNC_cipher_gettable_ctx_params_fn kae_cipher_gettable_ctx_params; +static OSSL_FUNC_cipher_set_ctx_params_fn kae_cipher_set_ctx_params; +static OSSL_FUNC_cipher_settable_ctx_params_fn kae_cipher_settable_ctx_params; +static OSSL_FUNC_cipher_cipher_fn kae_cipher_cipher; + +int prov_cipher_generic_get_params( + OSSL_PARAM params[], unsigned int md, uint64_t flags, size_t kbits, size_t blkbits, size_t ivbits); + +#define KAE_CIPHER_DESCR(nm, blksize, keylen, ivlen, flags, e_nid, algnm, mode, typ) \ + static OSSL_FUNC_cipher_newctx_fn kae_##nm##_newctx; \ + static void *kae_##nm##_newctx(void *provctx) \ + { \ + cipher_priv_ctx *ctx = OPENSSL_zalloc(sizeof(*ctx)); \ + if (ctx == NULL) \ + return NULL; \ + \ + ctx->blk_size = blksize; \ + ctx->key_len = keylen; \ + ctx->iv_len = ivlen; \ + ctx->nid = e_nid; \ + strncpy(ctx->alg_name, #algnm, ALG_NAME_SIZE - 1); \ + if (strcmp(#typ, "block") == 0) \ + ctx->pad = 1; \ + return ctx; \ + } \ + static OSSL_FUNC_cipher_get_params_fn kae_##nm##_get_params; \ + static int kae_##nm##_get_params(OSSL_PARAM params[]) \ + { \ + return prov_cipher_generic_get_params(params, mode, flags, keylen, blksize, ivlen); \ + } \ + const OSSL_DISPATCH kae_##nm##_functions[] = {{OSSL_FUNC_CIPHER_NEWCTX, (void (*)(void))kae_##nm##_newctx}, \ + {OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))kae_cipher_freectx}, \ + {OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))kae_cipher_einit}, \ + {OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))kae_cipher_dinit}, \ + {OSSL_FUNC_CIPHER_UPDATE, (void (*)(void))kae_cipher_##typ##_update}, \ + {OSSL_FUNC_CIPHER_FINAL, (void (*)(void))kae_cipher_##typ##_final}, \ + {OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))kae_cipher_cipher}, \ + {OSSL_FUNC_CIPHER_GET_PARAMS, (void (*)(void))kae_##nm##_get_params}, \ + {OSSL_FUNC_CIPHER_GETTABLE_PARAMS, (void (*)(void))kae_cipher_gettable_params}, \ + {OSSL_FUNC_CIPHER_GET_CTX_PARAMS, (void (*)(void))kae_cipher_get_ctx_params}, \ + {OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, (void (*)(void))kae_cipher_gettable_ctx_params}, \ + {OSSL_FUNC_CIPHER_SET_CTX_PARAMS, (void (*)(void))kae_cipher_set_ctx_params}, \ + {OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, (void (*)(void))kae_cipher_settable_ctx_params}, \ + {0, NULL}} + +KAE_CIPHER_DESCR(aes_128_cbc, 16, 16, 16, 0, NID_aes_128_cbc, cbc(aes), EVP_CIPH_CBC_MODE, block); +KAE_CIPHER_DESCR(aes_192_cbc, 16, 24, 16, 0, NID_aes_192_cbc, cbc(aes), EVP_CIPH_CBC_MODE, block); +KAE_CIPHER_DESCR(aes_256_cbc, 16, 32, 16, 0, NID_aes_256_cbc, cbc(aes), EVP_CIPH_CBC_MODE, block); +KAE_CIPHER_DESCR(aes_128_ecb, 16, 16, 0, 0, NID_aes_128_ecb, ecb(aes), EVP_CIPH_ECB_MODE, block); +KAE_CIPHER_DESCR(aes_192_ecb, 16, 24, 0, 0, NID_aes_192_ecb, ecb(aes), EVP_CIPH_ECB_MODE, block); +KAE_CIPHER_DESCR(aes_256_ecb, 16, 32, 0, 0, NID_aes_256_ecb, ecb(aes), EVP_CIPH_ECB_MODE, block); +KAE_CIPHER_DESCR( + aes_128_xts, 1, 32, 16, PROV_CIPHER_FLAG_CUSTOM_IV, NID_aes_128_xts, xts(aes), EVP_CIPH_XTS_MODE, stream); +KAE_CIPHER_DESCR( + aes_256_xts, 1, 64, 16, PROV_CIPHER_FLAG_CUSTOM_IV, NID_aes_256_xts, xts(aes), EVP_CIPH_XTS_MODE, stream); +KAE_CIPHER_DESCR(sm4_cbc, 16, 16, 16, 0, NID_sm4_cbc, cbc(sm4), EVP_CIPH_CBC_MODE, block); +KAE_CIPHER_DESCR(sm4_ecb, 16, 16, 0, 0, NID_sm4_ecb, ecb(sm4), EVP_CIPH_ECB_MODE, block); + +/* v3 */ +KAE_CIPHER_DESCR(aes_128_ctr, 1, 16, 16, 0, NID_aes_128_ctr, ctr(aes), EVP_CIPH_CTR_MODE, stream); +KAE_CIPHER_DESCR(aes_192_ctr, 1, 24, 16, 0, NID_aes_192_ctr, ctr(aes), EVP_CIPH_CTR_MODE, stream); +KAE_CIPHER_DESCR(aes_256_ctr, 1, 32, 16, 0, NID_aes_256_ctr, ctr(aes), EVP_CIPH_CTR_MODE, stream); +KAE_CIPHER_DESCR(aes_128_ofb128, 1, 16, 16, 0, NID_aes_128_ofb128, ofb(aes), EVP_CIPH_OFB_MODE, stream); +KAE_CIPHER_DESCR(aes_192_ofb128, 1, 24, 16, 0, NID_aes_192_ofb128, ofb(aes), EVP_CIPH_OFB_MODE, stream); +KAE_CIPHER_DESCR(aes_256_ofb128, 1, 32, 16, 0, NID_aes_256_ofb128, ofb(aes), EVP_CIPH_OFB_MODE, stream); +KAE_CIPHER_DESCR(aes_128_cfb128, 1, 16, 16, 0, NID_aes_128_cfb128, cfb(aes), EVP_CIPH_CFB_MODE, stream); +KAE_CIPHER_DESCR(aes_192_cfb128, 1, 24, 16, 0, NID_aes_192_cfb128, cfb(aes), EVP_CIPH_CFB_MODE, stream); +KAE_CIPHER_DESCR(aes_256_cfb128, 1, 32, 16, 0, NID_aes_256_cfb128, cfb(aes), EVP_CIPH_CFB_MODE, stream); +KAE_CIPHER_DESCR(sm4_ofb128, 1, 16, 16, 0, NID_sm4_ofb128, ofb(sm4), EVP_CIPH_OFB_MODE, stream); +KAE_CIPHER_DESCR(sm4_cfb128, 1, 16, 16, 0, NID_sm4_cfb128, cfb(sm4), EVP_CIPH_CFB_MODE, stream); +KAE_CIPHER_DESCR(sm4_ctr, 1, 16, 16, 0, NID_sm4_ctr, ctr(sm4), EVP_CIPH_CTR_MODE, stream); + +#endif \ No newline at end of file diff --git a/KAEOpensslProvider/src/provider/prov_nosva/prov_dh.c b/KAEOpensslProvider/src/provider/prov_nosva/prov_dh.c new file mode 100644 index 0000000000000000000000000000000000000000..1be740f528687413d74f0cc10e5bbc66c84b1bb8 --- /dev/null +++ b/KAEOpensslProvider/src/provider/prov_nosva/prov_dh.c @@ -0,0 +1,1163 @@ +/* + * Copyright 2025 Huawei Technologies Co.,Ltd.All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "prov.h" +#include "prov_pkey.h" +#include "internal/prov_ffc.h" +#include "../../adapter/common/kae_log.h" +#include "../../adapter/common/kae_types.h" +#include "../../adapter/nosva/algorithm/pkey/hpre_dh.h" + +KAE_PKEY_KEYMGMT_DESCR(dh, DH); +KAE_PKEY_KEYEXCH_DESCR(dh, DH); + +static void *kae_keymgmt_dh_new(void *provctx) +{ + if (get_default_dh_keymgmt().new_fun == NULL) + return NULL; + + return get_default_dh_keymgmt().new_fun(provctx); +} + +static void kae_keymgmt_dh_free(void *keydata) +{ + if (get_default_dh_keymgmt().free == NULL) + return; + + get_default_dh_keymgmt().free(keydata); +} + +static ossl_inline int kae_keymgmt_dh_get_params(void *key, OSSL_PARAM params[]) +{ + if (get_default_dh_keymgmt().get_params == NULL) + return KAE_P_FAIL; + + return get_default_dh_keymgmt().get_params(key, params); +} + +static const OSSL_PARAM *kae_keymgmt_dh_gettable_params(void *provctx) +{ + if (get_default_dh_keymgmt().gettable_params == NULL) + return NULL; + + return get_default_dh_keymgmt().gettable_params(provctx); +} + +static int kae_keymgmt_dh_set_params(void *key, const OSSL_PARAM params[]) +{ + if (get_default_dh_keymgmt().set_params == NULL) + return KAE_P_FAIL; + + return get_default_dh_keymgmt().set_params(key, params); +} + +static const OSSL_PARAM *kae_keymgmt_dh_settable_params(void *provctx) +{ + if (get_default_dh_keymgmt().settable_params == NULL) + return NULL; + + return get_default_dh_keymgmt().settable_params(provctx); +} + +static void *kae_keymgmt_dh_gen_init(void *provctx, int selection, const OSSL_PARAM params[]) +{ + if (get_default_dh_keymgmt().gen_init == NULL) + return NULL; + + return get_default_dh_keymgmt().gen_init(provctx, selection, params); +} + +static int kae_keymgmt_dh_gen_set_template(void *genctx, void *templ) +{ + if (get_default_dh_keymgmt().gen_set_template == NULL) + return KAE_P_FAIL; + + return get_default_dh_keymgmt().gen_set_template(genctx, templ); +} + +static int kae_keymgmt_dh_gen_set_params(void *genctx, const OSSL_PARAM params[]) +{ + if (get_default_dh_keymgmt().gen_set_params == NULL) + return KAE_P_FAIL; + + return get_default_dh_keymgmt().gen_set_params(genctx, params); +} + +static const OSSL_PARAM *kae_keymgmt_dh_gen_settable_params(ossl_unused void *genctx, ossl_unused void *provctx) +{ + if (get_default_dh_keymgmt().gen_settable_params == NULL) + return NULL; + + return get_default_dh_keymgmt().gen_settable_params(genctx, provctx); +} + +static int ossl_dh_get_named_group_uid_from_size(int pbits) +{ + int nid; + + /* + * Just choose an approved safe prime group. + * The alternative to this is to generate FIPS186-4 domain parameters i.e. + * return dh_generate_ffc_parameters(ret, prime_len, 0, NULL, cb); + * As the FIPS186-4 generated params are for backwards compatibility, + * the safe prime group should be used as the default. + */ + switch (pbits) { + case DH2048BITS: + nid = NID_ffdhe2048; + break; + case DH3072BITS: + nid = NID_ffdhe3072; + break; + case DH4096BITS: + nid = NID_ffdhe4096; + break; + /* + * Retain the commonly supported part. The different specifications are + * listed in the unsupported prime_len scope: + * 'pbits' 6144 and 8192 are supported by OpenSSL but not supported by kae, + * 'pbits' 768/1024/1536 are not supported by OpenSSL. + * + */ + default: + return NID_undef; + } + + return nid; +} + +static DH *ossl_dh_new_ex(OSSL_LIB_CTX *libctx) +{ + DH *dh = OPENSSL_zalloc(sizeof(*dh)); + + if (dh == NULL) { + fprintf(stderr, "failed to alloc dh\n"); + return NULL; + } + + dh->references = 1; + dh->lock = CRYPTO_THREAD_lock_new(); + if (dh->lock == NULL) { + fprintf(stderr, "failed to new dh thread lock\n"); + OPENSSL_free(dh); + return NULL; + } + + dh->libctx = libctx; + + return dh; +} + +static FFC_PARAMS *ossl_dh_get0_params(DH *dh) +{ + if (dh == NULL) + return NULL; + + return &dh->params; +} + +static void ossl_dh_free_ex(DH *dh) +{ + if (dh) { + CRYPTO_THREAD_lock_free(dh->lock); + OPENSSL_free(dh); + } +} + +static int dh_gencb(int p, int n, BN_GENCB *cb) +{ + OSSL_PARAM params[] = {OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END}; + PROV_DH_KEYMGMT_CTX *gctx = BN_GENCB_get_arg(cb); + + params[0] = OSSL_PARAM_construct_int(OSSL_GEN_PARAM_POTENTIAL, &p); + params[1] = OSSL_PARAM_construct_int(OSSL_GEN_PARAM_ITERATION, &n); + + return gctx->cb(params, gctx->cbarg); +} + +static int ossl_dh_generate_ffc_parameters(DH *dh, int type, int pbits, int qbits, BN_GENCB *cb) +{ + int ret, res; + + if (type == DH_PARAMGEN_TYPE_FIPS_186_2) + ret = ossl_ffc_params_FIPS186_2_generate(dh->libctx, &dh->params, FFC_PARAM_TYPE_DH, pbits, qbits, &res, cb); + else + ret = ossl_ffc_params_FIPS186_4_generate(dh->libctx, &dh->params, FFC_PARAM_TYPE_DH, pbits, qbits, &res, cb); + if (ret > 0) + dh->dirty_cnt++; + + return ret; +} + +static int prov_dh_gen_params_cb(PROV_DH_KEYMGMT_CTX *gctx, DH *dh, OSSL_CALLBACK *cb, void *cb_params) +{ + int ret = KAE_P_SUCCESS; + BN_GENCB *gencb; + + if (cb == NULL || cb_params == NULL) { + fprintf(stderr, "invalid: cb function or param is NULL\n"); + return KAE_P_FAIL; + } + + gctx->cb = cb; + gctx->cbarg = cb_params; + /* gencb can be NULL */ + gencb = BN_GENCB_new(); + if (gencb != NULL) + BN_GENCB_set(gencb, dh_gencb, gctx); + + if ((gctx->selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) { + /* + * NOTE: The old safe prime generator code is not used in fips mode, + * (i.e internally it ignores the generator and chooses a named + * group based on pbits. + */ + if (gctx->gen_type == DH_PARAMGEN_TYPE_GENERATOR) + ret = DH_generate_parameters_ex(dh, gctx->pbits, gctx->generator, gencb); + else + ret = ossl_dh_generate_ffc_parameters(dh, gctx->gen_type, gctx->pbits, gctx->qbits, gencb); + if (ret <= 0) { + fprintf(stderr, "failed to generate ffc parameters\n"); + ret = KAE_P_FAIL; + } + } + + if (gencb) + BN_GENCB_free(gencb); + + return ret; +} + +static DH *prov_dh_gen_params_ex(PROV_DH_KEYMGMT_CTX *gctx, FFC_PARAMS **ffc) +{ + DH *dh; + + /* Use existing params */ + dh = ossl_dh_new_ex(gctx->libctx); + if (dh == NULL) { + fprintf(stderr, "failed to new dh by nid\n"); + return NULL; + } + + *ffc = ossl_dh_get0_params(dh); + if (*ffc == NULL) { + fprintf(stderr, "failed to get ffc params\n"); + goto free_dh; + } + + /* Copy the template value if one was passed */ + if (gctx->ffc_params != NULL && ossl_ffc_params_copy(*ffc, gctx->ffc_params) == 0) { + fprintf(stderr, "failed to copy params\n"); + goto free_dh; + } + + if (ossl_ffc_params_set_seed(*ffc, gctx->seed, gctx->seedlen) == 0) { + fprintf(stderr, "failed to set seed\n"); + goto free_dh; + } + + if (gctx->gindex != -1) { + ossl_ffc_params_set_gindex(*ffc, gctx->gindex); + if (gctx->pcounter != -1) + ossl_ffc_params_set_pcounter(*ffc, gctx->pcounter); + } else if (gctx->hindex != 0) { + ossl_ffc_params_set_h(*ffc, gctx->hindex); + } + + if (gctx->mdname) { + if (ossl_ffc_set_digest(*ffc, gctx->mdname, gctx->mdprops) == 0) { + fprintf(stderr, "failed to set digest\n"); + goto free_dh; + } + } + + return dh; + +free_dh: + ossl_dh_free_ex(dh); + + return NULL; +} + +static DH *prov_dh_gen_params_with_group(PROV_DH_KEYMGMT_CTX *gctx, FFC_PARAMS **ffc) +{ + const DH_NAMED_GROUP *group; + DH *dh = NULL; + + /* Select a named group if there is not one already */ + if (gctx->group_nid == NID_undef) { + gctx->group_nid = ossl_dh_get_named_group_uid_from_size(gctx->pbits); + if (gctx->group_nid == NID_undef) { + fprintf(stderr, "failed to get named group uid from size\n"); + return NULL; + } + } + + group = ossl_ffc_uid_to_dh_named_group(gctx->group_nid); + if (!group) { + fprintf(stderr, "failed to get dh named group\n"); + return NULL; + } + + dh = ossl_dh_new_ex(gctx->libctx); + if (dh == NULL) { + fprintf(stderr, "failed to get dh from libctx\n"); + return NULL; + } + + dh->meth = DH_get_default_method(); + ossl_ffc_named_group_set(&dh->params, group); + dh->params.nid = ossl_ffc_named_group_get_uid(group); + dh->dirty_cnt++; + + *ffc = ossl_dh_get0_params(dh); + if (*ffc == NULL) { + fprintf(stderr, "failed to gen ffc params\n"); + ossl_dh_free_ex(dh); + return NULL; + } + + return dh; +} + +static DH *prov_dh_gen_params(PROV_DH_KEYMGMT_CTX *gctx, FFC_PARAMS **ffc, OSSL_CALLBACK *cb, void *cb_params) +{ + DH *dh; + int ret; + + /* For parameter generation - If there is a group name just create it */ + if (gctx->gen_type == DH_PARAMGEN_TYPE_GROUP && gctx->ffc_params == NULL) { + dh = prov_dh_gen_params_with_group(gctx, ffc); + if (dh == NULL || *ffc == NULL) + return NULL; + } else { + dh = prov_dh_gen_params_ex(gctx, ffc); + if (dh == NULL || *ffc == NULL) + return NULL; + + ret = prov_dh_gen_params_cb(gctx, dh, cb, cb_params); + if (ret == KAE_P_FAIL) { + ossl_dh_free_ex(dh); + return NULL; + } + } + + return dh; +} + +static void *kae_dh_sw_gen(void *genctx, OSSL_CALLBACK *cb, void *cb_params) +{ + if (!get_default_dh_keymgmt().gen) + return NULL; + + fprintf(stderr, "switch to openssl software calculation in dh generation.\n"); + return get_default_dh_keymgmt().gen(genctx, cb, cb_params); +} + +static void prov_dh_free_params(DH *dh) +{ + FFC_PARAMS *ffc; + + ffc = ossl_dh_get0_params(dh); + if (ffc) + ossl_ffc_params_cleanup(ffc); + + /* + * Release DH object that allocated by uadk_prov_dh_gen_params_ex() or + * uadk_prov_dh_gen_params_with_group(). + */ + ossl_dh_free_ex(dh); +} + +static void *kae_keymgmt_dh_gen(void *genctx, OSSL_CALLBACK *cb, void *cb_params) +{ + PROV_DH_KEYMGMT_CTX *gctx = (PROV_DH_KEYMGMT_CTX *)genctx; + FFC_PARAMS *ffc = NULL; + DH *dh = NULL; + int ret = KAE_P_FAIL; + + if (gctx == NULL) { + fprintf(stderr, "invalid: keygen ctx is NULL\n"); + return NULL; + } + + /* + * If a group name is selected then the type is group regardless of what + * the user selected. This overrides rather than errors for backwards + * compatibility. + */ + if (gctx->group_nid != NID_undef) + gctx->gen_type = DH_PARAMGEN_TYPE_GROUP; + + dh = prov_dh_gen_params(gctx, &ffc, cb, cb_params); + if (dh == NULL || ffc == NULL) { + ret = KAE_P_FAIL; + goto free_gen_params; + } + /* DH key generation */ + if ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) { + if (ffc->p == NULL || ffc->g == NULL) { + fprintf(stderr, "invalid: ffc->p or ffc->g is NULL\n"); + goto free_gen_params; + } + + if (gctx->priv_len > 0) + (void)DH_set_length(dh, (long)gctx->priv_len); + + ossl_ffc_params_enable_flags( + ffc, FFC_PARAM_FLAG_VALIDATE_LEGACY, gctx->gen_type == DH_PARAMGEN_TYPE_FIPS_186_2); + + ret = hpre_dh_generate_key(dh); + if (ret != KAE_P_SUCCESS) { + fprintf(stderr, "failed to do dh generation key\n"); + goto free_gen_params; + } + } + + DH_clear_flags(dh, DH_FLAG_TYPE_MASK); + DH_set_flags(dh, gctx->dh_type); + + return dh; + +free_gen_params: + prov_dh_free_params(dh); + + if (ret == KAE_P_FAIL) + return kae_dh_sw_gen(genctx, cb, cb_params); + return NULL; +} + +static void kae_keymgmt_dh_gen_cleanup(void *genctx) +{ + if (get_default_dh_keymgmt().gen_cleanup == NULL) + return; + + get_default_dh_keymgmt().gen_cleanup(genctx); +} + +static void *kae_keymgmt_dh_load(const void *reference, size_t reference_sz) +{ + if (get_default_dh_keymgmt().load == NULL) + return NULL; + + return get_default_dh_keymgmt().load(reference, reference_sz); +} + +static int kae_keymgmt_dh_has(const void *keydata, int selection) +{ + if (get_default_dh_keymgmt().has == NULL) + return KAE_P_FAIL; + + return get_default_dh_keymgmt().has(keydata, selection); +} + +static int kae_keymgmt_dh_validate(const void *keydata, int selection, int checktype) +{ + if (get_default_dh_keymgmt().validate == NULL) + return KAE_P_FAIL; + + return get_default_dh_keymgmt().validate(keydata, selection, checktype); +} + +static int kae_keymgmt_dh_match(const void *keydata1, const void *keydata2, int selection) +{ + if (get_default_dh_keymgmt().match == NULL) + return KAE_P_FAIL; + + return get_default_dh_keymgmt().match(keydata1, keydata2, selection); +} + +static int kae_keymgmt_dh_import(void *keydata, int selection, const OSSL_PARAM params[]) +{ + if (get_default_dh_keymgmt().import == NULL) + return KAE_P_FAIL; + + return get_default_dh_keymgmt().import(keydata, selection, params); +} + +static const OSSL_PARAM *kae_keymgmt_dh_import_types(int selection) +{ + if (get_default_dh_keymgmt().import_types == NULL) + return NULL; + + return get_default_dh_keymgmt().import_types(selection); +} + +static int kae_keymgmt_dh_export(void *keydata, int selection, OSSL_CALLBACK *cb, void *cb_params) +{ + if (get_default_dh_keymgmt().export_fun == NULL) + return KAE_P_FAIL; + + return get_default_dh_keymgmt().export_fun(keydata, selection, cb, cb_params); +} + +static const OSSL_PARAM *kae_keymgmt_dh_export_types(int selection) +{ + if (get_default_dh_keymgmt().export_types == NULL) + return NULL; + + return get_default_dh_keymgmt().export_types(selection); +} + +static void *kae_keymgmt_dh_dup(const void *keydata_from, int selection) +{ + if (get_default_dh_keymgmt().dup == NULL) + return NULL; + + return get_default_dh_keymgmt().dup(keydata_from, selection); +} + +static const char *kae_keymgmt_dh_query_operation_name(int operation_id) +{ + if (get_default_dh_keymgmt().query_operation_name == NULL) + return NULL; + + return get_default_dh_keymgmt().query_operation_name(operation_id); +} + +static void *kae_keyexch_dh_newctx(void *provctx) +{ + PROV_DH_KEYEXCH_CTX *pdhctx; + + pdhctx = OPENSSL_zalloc(sizeof(PROV_DH_KEYEXCH_CTX)); + if (pdhctx == NULL) { + fprintf(stderr, "failed to alloc pdhctx\n"); + return NULL; + } + + /* The libctx maybe NULL, if libctx is NULL, will use default ctx. */ + pdhctx->libctx = prov_libctx_of(provctx); + pdhctx->kdf_type = PROV_DH_KDF_NONE; + + return pdhctx; +} + +static int prov_dh_locate_kdf_type(PROV_DH_KEYEXCH_CTX *pdhctx, const OSSL_PARAM params[]) +{ + char name[DH_MAX_PARAM_LEN + 1] = {'\0'}; + const OSSL_PARAM *p; + char *str; + + p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_TYPE); + if (p != NULL) { + str = name; + if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name))) + return KAE_P_FAIL; + + if (name[0] == '\0') + pdhctx->kdf_type = PROV_DH_KDF_NONE; + else if (strcmp(name, OSSL_KDF_NAME_X942KDF_ASN1) == 0) + pdhctx->kdf_type = PROV_DH_KDF_X9_42_ASN1; + else + return KAE_P_FAIL; + } + + return KAE_P_SUCCESS; +} + +static int prov_dh_locate_kdf_digest(PROV_DH_KEYEXCH_CTX *pdhctx, const OSSL_PARAM params[]) +{ + char mdprops[DH_MAX_PARAM_LEN + 1] = {'\0'}; + char name[DH_MAX_PARAM_LEN + 1] = {'\0'}; + const OSSL_PARAM *p; + char *str; + + p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST); + if (p != NULL) { + str = name; + if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name))) + return KAE_P_FAIL; + + str = mdprops; + p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS); + if (p != NULL) + if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(mdprops))) + return KAE_P_FAIL; + + if (pdhctx->kdf_md) + EVP_MD_free(pdhctx->kdf_md); + + pdhctx->kdf_md = EVP_MD_fetch(pdhctx->libctx, name, mdprops); + if (pdhctx->kdf_md == NULL) + return KAE_P_FAIL; + } + + return KAE_P_SUCCESS; +} + +static int prov_dh_locate_kdf_outlen(PROV_DH_KEYEXCH_CTX *pdhctx, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p; + size_t outlen = 0; + + p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN); + if (p != NULL) { + if (!OSSL_PARAM_get_size_t(p, &outlen)) + return KAE_P_FAIL; + pdhctx->kdf_outlen = outlen; + } + + return KAE_P_SUCCESS; +} + +static int prov_dh_locate_kdf_ukm(PROV_DH_KEYEXCH_CTX *pdhctx, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p; + void *tmp_ukm = NULL; + size_t tmp_ukmlen; + + p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_UKM); + if (p != NULL) { + if (pdhctx->kdf_ukm) + OPENSSL_free(pdhctx->kdf_ukm); + pdhctx->kdf_ukm = NULL; + pdhctx->kdf_ukmlen = 0; + + /* ukm is an optional field so it can be NULL */ + if (p->data != NULL && p->data_size != 0) { + if (!OSSL_PARAM_get_octet_string(p, &tmp_ukm, 0, &tmp_ukmlen)) + return KAE_P_FAIL; + pdhctx->kdf_ukm = tmp_ukm; + pdhctx->kdf_ukmlen = tmp_ukmlen; + } + } + + return KAE_P_SUCCESS; +} + +static int prov_dh_locate_kdf_pad(PROV_DH_KEYEXCH_CTX *pdhctx, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p; + unsigned int pad = 0; + + p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_PAD); + if (p != NULL) { + if (!OSSL_PARAM_get_uint(p, &pad)) + return KAE_P_FAIL; + pdhctx->pad = pad ? 1 : 0; + } + + return KAE_P_SUCCESS; +} + +static int kae_keyexch_dh_set_ctx_params(void *dhctx, const OSSL_PARAM params[]) +{ + PROV_DH_KEYEXCH_CTX *pdhctx = (PROV_DH_KEYEXCH_CTX *)dhctx; + int ret = KAE_P_FAIL; + + if (pdhctx == NULL) { + fprintf(stderr, "invalid: dh ctx is NULL\n"); + return ret; + } + + /* If params is NULL, no need to set */ + if (params == NULL) + return KAE_P_SUCCESS; + + // pthread_mutex_lock(&dh_mutex); + ret = prov_dh_locate_kdf_type(pdhctx, params); + if (ret == KAE_P_FAIL) { + fprintf(stderr, "failed to locate kdf type\n"); + goto end; + } + + ret = prov_dh_locate_kdf_digest(pdhctx, params); + if (ret == KAE_P_FAIL) { + fprintf(stderr, "failed to locate kdf digest\n"); + goto end; + } + + ret = prov_dh_locate_kdf_outlen(pdhctx, params); + if (ret == KAE_P_FAIL) { + fprintf(stderr, "failed to locate kdf outlen\n"); + goto end; + } + + ret = prov_dh_locate_kdf_ukm(pdhctx, params); + if (ret == KAE_P_FAIL) { + fprintf(stderr, "failed to locate kdf ukm\n"); + goto end; + } + + ret = prov_dh_locate_kdf_pad(pdhctx, params); + if (ret == KAE_P_FAIL) + fprintf(stderr, "failed to locate kdf pad\n"); + +end: + // pthread_mutex_unlock(&dh_mutex); + return ret; +} + +static int kae_keyexch_dh_init(void *dhctx, void *dh, const OSSL_PARAM params[]) +{ + PROV_DH_KEYEXCH_CTX *pdhctx = (PROV_DH_KEYEXCH_CTX *)dhctx; + + if (pdhctx == NULL) { + fprintf(stderr, "invalid: dhctx is NULL\n"); + return KAE_P_FAIL; + } + + if (dh == NULL || !DH_up_ref(dh)) { + fprintf(stderr, "invalid: dh is NULL\n"); + return KAE_P_FAIL; + } + + // pthread_mutex_lock(&dh_mutex); + if (pdhctx->dh) { + DH_free(pdhctx->dh); + pdhctx->dh = NULL; + } + + pdhctx->dh = dh; + pdhctx->kdf_type = PROV_DH_KDF_NONE; + // pthread_mutex_unlock(&dh_mutex); + + return kae_keyexch_dh_set_ctx_params(pdhctx, params); +} + +static int kae_dh_sw_derive(void *dhctx, unsigned char *secret, size_t *psecretlen, size_t outlen) +{ + if (!get_default_dh_keyexch().derive) + return KAE_P_FAIL; + + fprintf(stderr, "switch to openssl software calculation in dh derivation.\n"); + return get_default_dh_keyexch().derive(dhctx, secret, psecretlen, outlen); +} + +static int dh_compute_key_padded(unsigned char *key, const BIGNUM *pub_key, DH *dh) +{ + size_t dhsize; + int rv, pad; + + /* rv is constant unless compute_key is external */ + rv = hpre_dh_compute_key(key, pub_key, dh); + if (rv <= 0) + return rv; + + dhsize = BN_num_bytes(dh->params.p); + pad = dhsize - rv; + /* pad is constant (zero) unless compute_key is external */ + if (pad > 0) { + memmove(key + pad, key, rv); + memset(key, 0, pad); + } + + if (pad < 0) { + fprintf(stderr, "invalid: recv key size(%d) > dhsize(%zu)", rv, dhsize); + return KAE_P_FAIL; + } + + return rv + pad; +} + +static int prov_dh_plain_derive( + PROV_DH_KEYEXCH_CTX *pdhctx, unsigned char *secret, size_t *secretlen, size_t outlen, unsigned int pad) +{ + const BIGNUM *pubkey = NULL; + size_t dhsize; + int ret; + + /* pdhctx has been checked when the function is called */ + if (pdhctx->dh == NULL) { + fprintf(stderr, "invalid: dh is NULL\n"); + return KAE_P_FAIL; + } + + dhsize = (size_t)DH_size(pdhctx->dh); + if (dhsize == 0) { + fprintf(stderr, "invalid: dhszie is zero\n"); + return KAE_P_FAIL; + } + + if (secret == NULL) { + *secretlen = dhsize; + return KAE_P_SUCCESS; + } + + if (outlen < dhsize) { + fprintf(stderr, "invalid: outlen(%zu) < dhsize(%zu)\n", outlen, dhsize); + return KAE_P_FAIL; + } + + if (pdhctx->dhpeer == NULL) { + fprintf(stderr, "invalid: dhpeer is NULL\n"); + return KAE_P_FAIL; + } + + DH_get0_key(pdhctx->dhpeer, &pubkey, NULL); + + if (pad) + ret = dh_compute_key_padded(secret, pubkey, pdhctx->dh); + else + ret = hpre_dh_compute_key(secret, pubkey, pdhctx->dh); + if (ret <= 0) { + fprintf(stderr, "failed to do dh compute, pad(%u)\n", pad); + return ret; + } + + *secretlen = ret; + + return KAE_P_SUCCESS; +} + +/* Key derivation function from X9.63/SECG */ +static int ossl_dh_kdf_X9_42_asn1( + unsigned char *out, PROV_DH_KEYEXCH_CTX *pdhctx, const unsigned char *z, size_t z_len, const char *propq) +{ + OSSL_LIB_CTX *libctx = pdhctx->libctx; + const char *cek_alg = pdhctx->kdf_cekalg; + const unsigned char *ukm = pdhctx->kdf_ukm; + OSSL_PARAM params[KDF_PARAM_NUM] = {0}; + size_t outlen = pdhctx->kdf_outlen; + size_t ukmlen = pdhctx->kdf_ukmlen; + const EVP_MD *md = pdhctx->kdf_md; + OSSL_PARAM *p = params; + const char *mdname; + EVP_KDF_CTX *kctx; + EVP_KDF *kdf; + int ret = 0; + + kdf = EVP_KDF_fetch(libctx, OSSL_KDF_NAME_X942KDF_ASN1, propq); + if (kdf == NULL) + return 0; + + kctx = EVP_KDF_CTX_new(kdf); + if (kctx == NULL) + goto end; + + mdname = EVP_MD_get0_name(md); + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, (char *)mdname, 0); + *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY, (unsigned char *)z, z_len); + if (ukm != NULL) + *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_UKM, (unsigned char *)ukm, ukmlen); + + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_CEK_ALG, (char *)cek_alg, 0); + *p = OSSL_PARAM_construct_end(); + ret = EVP_KDF_derive(kctx, out, outlen, params) > 0; + +end: + EVP_KDF_CTX_free(kctx); + EVP_KDF_free(kdf); + + return ret; +} + +static int prov_dh_X9_42_kdf_derive( + PROV_DH_KEYEXCH_CTX *pdhctx, unsigned char *secret, size_t *secretlen, size_t outlen) +{ + unsigned char *stmp; + size_t stmplen; + int ret = 0; + + if (secret == NULL) { + *secretlen = pdhctx->kdf_outlen; + return KAE_P_SUCCESS; + } + + if (outlen < pdhctx->kdf_outlen) { + fprintf(stderr, "invalid: outlen(%zu) < kdf_outlen(%zu)\n", outlen, pdhctx->kdf_outlen); + return KAE_P_FAIL; + } + + if (!prov_dh_plain_derive(pdhctx, NULL, &stmplen, 0, 1)) + return KAE_P_FAIL; + + stmp = OPENSSL_secure_malloc(stmplen); + if (stmp == NULL) { + fprintf(stderr, "failed to do OPENSSL_secure_malloc\n"); + return KAE_P_FAIL; + } + + ret = prov_dh_plain_derive(pdhctx, stmp, &stmplen, stmplen, USE_PAD); + if (ret != KAE_P_SUCCESS) + goto end; + + /* Do KDF stuff */ + if (pdhctx->kdf_type == PROV_DH_KDF_X9_42_ASN1) { + if (ossl_dh_kdf_X9_42_asn1(secret, pdhctx, stmp, stmplen, NULL) == KAE_P_FAIL) { + ret = KAE_P_FAIL; + fprintf(stderr, "failed to do ossl_dh_kdf_X9_42_asn1\n"); + goto end; + } + } + + *secretlen = pdhctx->kdf_outlen; + ret = KAE_P_SUCCESS; + +end: + OPENSSL_secure_clear_free(stmp, stmplen); + + return ret; +} + +static int kae_keyexch_dh_derive(void *dhctx, unsigned char *secret, size_t *psecretlen, size_t outlen) +{ + PROV_DH_KEYEXCH_CTX *pdhctx = (PROV_DH_KEYEXCH_CTX *)dhctx; + int ret = KAE_P_FAIL; + + if (pdhctx == NULL) { + fprintf(stderr, "invalid: pdhctx is NULL\n"); + return KAE_P_FAIL; + } + + switch (pdhctx->kdf_type) { + case PROV_DH_KDF_NONE: + ret = prov_dh_plain_derive(pdhctx, secret, psecretlen, outlen, pdhctx->pad); + break; + case PROV_DH_KDF_X9_42_ASN1: + ret = prov_dh_X9_42_kdf_derive(pdhctx, secret, psecretlen, outlen); + break; + default: + fprintf(stderr, "invalid: unsupport kdf type\n"); + ret = KAE_P_FAIL; + break; + } + + if (ret == KAE_P_SUCCESS) + return KAE_P_SUCCESS; + if (ret == KAE_P_FAIL) + return kae_dh_sw_derive(dhctx, secret, psecretlen, outlen); + return KAE_P_FAIL; +} + +/* The 2 parties must share the same domain parameters */ +static int kae_keyexch_dh_match_params(DH *priv, DH *peer) +{ + FFC_PARAMS *dhparams_priv = ossl_dh_get0_params(priv); + FFC_PARAMS *dhparams_peer = ossl_dh_get0_params(peer); + int ret; + + if (dhparams_priv == NULL || dhparams_peer == NULL) { + fprintf(stderr, "failed to get dh params\n"); + return KAE_P_FAIL; + } + + ret = ossl_ffc_params_cmp(dhparams_priv, dhparams_peer, IGNORE_Q); + if (ret == KAE_P_FAIL) + fprintf(stderr, "invalid: domain parameters of both parties do not match\n"); + + return ret; +} + +static int kae_keyexch_dh_set_peer(void *dhctx, void *dh) +{ + PROV_DH_KEYEXCH_CTX *pdhctx = (PROV_DH_KEYEXCH_CTX *)dhctx; + + if (pdhctx == NULL || dh == NULL) { + fprintf(stderr, "invalid: dh ctx or object is NULL\n"); + return KAE_P_FAIL; + } + + if (kae_keyexch_dh_match_params(dh, pdhctx->dh) == KAE_P_FAIL || DH_up_ref(dh) == KAE_P_FAIL) { + fprintf(stderr, "failed to match dh params\n"); + return KAE_P_FAIL; + } + + // pthread_mutex_lock(&dh_mutex); + if (pdhctx->dhpeer) + DH_free(pdhctx->dhpeer); + pdhctx->dhpeer = dh; + // pthread_mutex_unlock(&dh_mutex); + + return KAE_P_SUCCESS; +} + +static void kae_keyexch_dh_freectx(void *dhctx) +{ + PROV_DH_KEYEXCH_CTX *pdhctx = (PROV_DH_KEYEXCH_CTX *)dhctx; + + if (pdhctx == NULL) + return; + + if (pdhctx->kdf_cekalg) { + OPENSSL_free(pdhctx->kdf_cekalg); + pdhctx->kdf_cekalg = NULL; + } + + if (pdhctx->dh) { + DH_free(pdhctx->dh); + pdhctx->dh = NULL; + } + + if (pdhctx->dhpeer) { + DH_free(pdhctx->dhpeer); + pdhctx->dhpeer = NULL; + } + + if (pdhctx->kdf_md) { + EVP_MD_free(pdhctx->kdf_md); + pdhctx->kdf_md = NULL; + } + + if (pdhctx->kdf_ukm) { + OPENSSL_clear_free(pdhctx->kdf_ukm, pdhctx->kdf_ukmlen); + pdhctx->kdf_ukm = NULL; + } + + if (pdhctx->kdf_cekalg) { + OPENSSL_free(pdhctx->kdf_cekalg); + pdhctx->kdf_cekalg = NULL; + } + + OPENSSL_free(pdhctx); +} + +static void *kae_keyexch_dh_dupctx(void *dhctx) +{ + PROV_DH_KEYEXCH_CTX *srcctx = (PROV_DH_KEYEXCH_CTX *)dhctx; + PROV_DH_KEYEXCH_CTX *dstctx; + + if (srcctx == NULL) { + fprintf(stderr, "invalid: src ctx is NULL\n"); + return NULL; + } + + dstctx = OPENSSL_zalloc(sizeof(*dstctx)); + if (dstctx == NULL) { + fprintf(stderr, "failed to alloc dst ctx\n"); + return NULL; + } + + memcpy(dstctx, srcctx, sizeof(PROV_DH_KEYEXCH_CTX)); + dstctx->dh = NULL; + dstctx->dhpeer = NULL; + dstctx->kdf_md = NULL; + dstctx->kdf_ukm = NULL; + dstctx->kdf_cekalg = NULL; + + if (srcctx->dh && !DH_up_ref(srcctx->dh)) + goto err; + else + dstctx->dh = srcctx->dh; + + if (srcctx->dhpeer && !DH_up_ref(srcctx->dhpeer)) + goto err; + else + dstctx->dhpeer = srcctx->dhpeer; + + if (srcctx->kdf_md && !EVP_MD_up_ref(srcctx->kdf_md)) + goto err; + else + dstctx->kdf_md = srcctx->kdf_md; + + /* Duplicate UKM data if present */ + if (srcctx->kdf_ukm && srcctx->kdf_ukmlen > 0) { + dstctx->kdf_ukm = OPENSSL_memdup(srcctx->kdf_ukm, srcctx->kdf_ukmlen); + if (dstctx->kdf_ukm == NULL) + goto err; + } + + if (srcctx->kdf_cekalg != NULL) { + dstctx->kdf_cekalg = OPENSSL_strdup(srcctx->kdf_cekalg); + if (dstctx->kdf_cekalg == NULL) + goto err; + } + + return dstctx; + +err: + kae_keyexch_dh_freectx(dstctx); + + return NULL; +} + +static const OSSL_PARAM known_settable_ctx_params[] = {OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_PAD, NULL), + OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS, NULL, 0), + OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL), + OSSL_PARAM_octet_string(OSSL_EXCHANGE_PARAM_KDF_UKM, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_CEK_ALG, NULL, 0), + OSSL_PARAM_END}; + +static const OSSL_PARAM *kae_keyexch_dh_settable_ctx_params(ossl_unused void *dhctx, ossl_unused void *provctx) +{ + return known_settable_ctx_params; +} + +static int kae_keyexch_dh_get_ctx_params(void *dhctx, OSSL_PARAM params[]) +{ + PROV_DH_KEYEXCH_CTX *pdhctx = (PROV_DH_KEYEXCH_CTX *)dhctx; + const char *kdf_type; + OSSL_PARAM *p; + + if (pdhctx == NULL) { + fprintf(stderr, "invalid: dh ctx is NULL\n"); + return KAE_P_FAIL; + } + + p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_TYPE); + if (p != NULL) { + switch (pdhctx->kdf_type) { + case PROV_DH_KDF_NONE: + kdf_type = ""; + break; + case PROV_DH_KDF_X9_42_ASN1: + kdf_type = OSSL_KDF_NAME_X942KDF_ASN1; + break; + default: + fprintf(stderr, "invalid kdf_type\n"); + return KAE_P_FAIL; + } + + if (!OSSL_PARAM_set_utf8_string(p, kdf_type)) { + fprintf(stderr, "failed to set utf8 string for kdf_type\n"); + return KAE_P_FAIL; + } + } + + p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST); + if (p != NULL && !OSSL_PARAM_set_utf8_string(p, pdhctx->kdf_md == NULL ? "" : EVP_MD_get0_name(pdhctx->kdf_md))) { + fprintf(stderr, "failed to set kdf_md\n"); + return KAE_P_FAIL; + } + + p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN); + if (p != NULL && !OSSL_PARAM_set_size_t(p, pdhctx->kdf_outlen)) { + fprintf(stderr, "failed to set kdf_outlen\n"); + return KAE_P_FAIL; + } + + p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_UKM); + if (p != NULL && !OSSL_PARAM_set_octet_ptr(p, pdhctx->kdf_ukm, pdhctx->kdf_ukmlen)) { + fprintf(stderr, "failed to set kdf_ukm\n"); + return KAE_P_FAIL; + } + + p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_CEK_ALG); + if (p != NULL && !OSSL_PARAM_set_utf8_string(p, pdhctx->kdf_cekalg == NULL ? "" : pdhctx->kdf_cekalg)) { + fprintf(stderr, "failed to set kdf_cekalg\n"); + return KAE_P_FAIL; + } + + return KAE_P_SUCCESS; +} + +static const OSSL_PARAM known_gettable_ctx_params[] = {OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, NULL, 0), + OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL), + OSSL_PARAM_DEFN(OSSL_EXCHANGE_PARAM_KDF_UKM, OSSL_PARAM_OCTET_PTR, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_CEK_ALG, NULL, 0), + OSSL_PARAM_END}; + +static const OSSL_PARAM *kae_keyexch_dh_gettable_ctx_params(ossl_unused void *dhctx, ossl_unused void *provctx) +{ + return known_gettable_ctx_params; +} \ No newline at end of file diff --git a/KAEOpensslProvider/src/provider/prov_nosva/prov_digest.c b/KAEOpensslProvider/src/provider/prov_nosva/prov_digest.c new file mode 100644 index 0000000000000000000000000000000000000000..acdaea6ea44bb4cb8643b332aacaad0a0c217aec --- /dev/null +++ b/KAEOpensslProvider/src/provider/prov_nosva/prov_digest.c @@ -0,0 +1,379 @@ +/* + * Copyright 2025 Huawei Technologies Co.,Ltd.All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#include "prov.h" +#include "prov_digest.h" +#include "../../adapter/common/kae_log.h" + +static int sec_digests_soft_md(sec_digest_priv *priv) +{ + int app_datasize = 0; + + if (priv->soft_md) + return 1; + + switch (priv->e_nid) { + case NID_sm3: + // priv->soft_md = EVP_sm3(); + priv->soft_md = EVP_MD_fetch(NULL, "SM3", "provider=default"); + break; + case NID_md5: + // priv->soft_md = EVP_md5(); + priv->soft_md = EVP_MD_fetch(NULL, "MD5", "provider=default"); + break; + default: + break; + } + + if (unlikely(priv->soft_md == NULL)) + return 0; + + app_datasize = EVP_MD_meth_get_app_datasize(priv->soft_md); + if (app_datasize == 0) { + /* OpenSSL 3.0 has no app_datasize, need set manually + * check crypto/evp/legacy_md5.c: md5_md as example + */ + switch (priv->e_nid) { + case NID_sm3: + app_datasize = sizeof(EVP_MD *) + sizeof(SM3_CTX); + break; + case NID_md5: + app_datasize = sizeof(EVP_MD *) + sizeof(MD5_CTX); + break; + default: + break; + } + } + + if (priv->soft_ctx == NULL) { + EVP_MD_CTX *ctx = EVP_MD_CTX_new(); + + if (ctx == NULL) + return 0; + + ctx->md_data = OPENSSL_malloc(app_datasize); + if (ctx->md_data == NULL) + return 0; + + priv->soft_ctx = ctx; + priv->app_datasize = app_datasize; + } + return 1; +} + +int sec_digests_soft_init(sec_digest_priv *priv) +{ + if (sec_digests_soft_md(priv) == 0) + return 0; + + // return EVP_MD_meth_get_init(priv->soft_md)(priv->soft_ctx); + return EVP_DigestInit_ex(priv->soft_ctx, priv->soft_md, NULL); +} + +int sec_digests_soft_update(sec_digest_priv *priv, const void *data, size_t len) +{ + // return EVP_MD_meth_get_update(priv->soft_md)(priv->soft_ctx, data, len); + + return EVP_DigestUpdate(priv->soft_ctx, data, len); +} + +int sec_digests_soft_final(sec_digest_priv *priv, unsigned char *digest) +{ + // return EVP_MD_meth_get_final(priv->soft_md)(priv->soft_ctx, digest); + + unsigned int digest_length; + + return EVP_DigestFinal_ex(priv->soft_ctx, digest, &digest_length); +} + +void sec_digests_soft_cleanup(sec_digest_priv *priv) +{ + EVP_MD_CTX *ctx = priv->soft_ctx; + // if (priv->copy) + // return; + if (ctx != NULL) { + if (ctx->md_data) { + OPENSSL_free(ctx->md_data); + ctx->md_data = NULL; + } + EVP_MD_CTX_free(ctx); + priv->soft_ctx = NULL; + priv->app_datasize = 0; + } + + if (priv->soft_md) { + EVP_MD_free(priv->soft_md); + priv->soft_md = NULL; + } +} + +int sec_digests_soft_work(sec_digest_priv *md_ctx, int len, unsigned char *digest) +{ + int ret; + ret = sec_digests_soft_init(md_ctx); + if (len != 0) + ret |= sec_digests_soft_update(md_ctx, md_ctx->last_update_buff, len); + ret |= sec_digests_soft_final(md_ctx, digest); + sec_digests_soft_cleanup(md_ctx); + return ret; +} + +int sec_digests_soft_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from) +{ + sec_digest_priv *to_ctx = (sec_digest_priv *)EVP_MD_CTX_md_data(to); + sec_digest_priv *from_ctx = (sec_digest_priv *)EVP_MD_CTX_md_data(from); + int ret; + + if (!to_ctx) + return 1; + + if (!from_ctx) { + US_ERR("priv get from digest ctx is NULL."); + return 0; + } + // 需要重新给目的上下文分配ctx + if (to_ctx->soft_ctx) { + to_ctx->soft_ctx = NULL; + ret = sec_digests_soft_init(to_ctx); + if (ret != OPENSSL_SUCCESS) { + return OPENSSL_FAIL; + } + + memcpy(to_ctx->soft_ctx->md_data, from_ctx->soft_ctx->md_data, to_ctx->app_datasize); + } + + return OPENSSL_SUCCESS; +} + +static int kae_digest_init(void *dctx, const OSSL_PARAM params[]) +{ + sec_digest_priv *priv = (sec_digest_priv *)dctx; + + if (!priv) { + fprintf(stderr, "CTX is NULL.\n"); + return KAE_P_FAIL; + } + + if (!sec_digests_soft_md(priv)) { + return KAE_P_FAIL; + } + + if (!sec_digests_init(priv)) { + return KAE_P_FAIL; + } + priv->switch_flag = 0; + + return OPENSSL_SUCCESS; +} + +static int kae_digest_update(void *dctx, const unsigned char *in, size_t inl) +{ + sec_digest_priv *priv = (sec_digest_priv *)dctx; + int ret; + if (!dctx || !in) { + fprintf(stderr, "CTX or input data is NULL.\n"); + return KAE_P_FAIL; + } + + ret = sec_digests_update(priv, in, inl); + if (ret == KAE_CRYPTO_FAIL) { + goto soft; + } + + return ret; + +soft: + if (sec_digests_soft_init(priv) != OPENSSL_SUCCESS) { + US_ERR("do sec digest soft init failed"); + return OPENSSL_FAIL; + } + + return sec_digests_soft_update(priv, in, inl); +} + +static int kae_digest_final(void *dctx, unsigned char *out, size_t *outl, size_t outsz) +{ + sec_digest_priv *priv = (sec_digest_priv *)dctx; + int ret; + + if (!dctx || !out) { + fprintf(stderr, "CTX or output data is NULL.\n"); + return KAE_P_FAIL; + } + + if (outsz > 0) { + ret = sec_digests_final(priv, out); + + if (ret == KAE_CRYPTO_FAIL) { + if (priv->switch_flag == 1) + goto soft_final; + goto soft; + } + if (!ret) + return ret; + } + + if (outl) + *outl = priv->md_size; + + return KAE_P_SUCCESS; + +soft_final: + ret = sec_digests_soft_final(priv, out); + sec_digests_soft_cleanup(priv); + + if (!ret) { + return ret; + } + if (outl) + *outl = priv->md_size; + + return ret; + +soft: + if (priv->state == SEC_DIGEST_INIT) { + ret = sec_digests_soft_work(priv, priv->last_update_bufflen, out); + if (!ret) + return ret; + } else { + US_ERR("do sec digest failed"); + ret = OPENSSL_FAIL; + } + + if (outl) + *outl = priv->md_size; + return ret; +} + +static int kae_digest_digest( + void *dctx, const unsigned char *in, size_t inl, unsigned char *out, size_t *outl, size_t outsz) +{ + sec_digest_priv *priv = (sec_digest_priv *)dctx; + int ret; + + if (!dctx || !in || !out) { + fprintf(stderr, "CTX or input or output data is NULL.\n"); + return KAE_P_FAIL; + } + + // if (inl > BUF_LEN) { + // fprintf(stderr, "data len(%zu) can not be processed in single digest.\n", + // inl); + // return KAE_DIGEST_FAIL; + // } + + if (outsz > 0) { + ret = kae_digest_init(priv, NULL); + if (!ret) + return ret; + + ret = kae_digest_update(priv, in, inl); + if (!ret) + return ret; + + ret = kae_digest_final(priv, out, outl, outsz); + if (!ret) + return ret; + } + + return KAE_P_SUCCESS; +} + +static void *kae_digest_dupctx(void *dctx) +{ + sec_digest_priv *priv = (sec_digest_priv *)dctx; + sec_digest_priv *dst_ctx; + int ret; + + dst_ctx = OPENSSL_zalloc(sizeof(*dst_ctx)); + dst_ctx->e_nid = priv->e_nid; + dst_ctx->md_size = priv->md_size; + dst_ctx->switch_flag = priv->switch_flag; + + if (!sec_digests_soft_md(dst_ctx)) { + return KAE_P_FAIL; + } + + ret = sec_digests_copy(dst_ctx, priv); + if (!ret) { + return NULL; + } + return dst_ctx; +} + +static void kae_digest_freectx(void *dctx) +{ + sec_digest_priv *priv = (sec_digest_priv *)dctx; + + if (!dctx) { + fprintf(stderr, "the CTX to be free is NULL.\n"); + return; + } + + if (priv->soft_ctx) { + sec_digests_soft_cleanup(priv); + } + + sec_digests_cleanup(priv); + OPENSSL_clear_free(priv, sizeof(*priv)); +} + +/* some params related code is copied from OpenSSL v3.0 prov/digestcommon.h */ +static const OSSL_PARAM kae_digest_default_known_gettable_params[] = { + OSSL_PARAM_size_t(OSSL_DIGEST_PARAM_BLOCK_SIZE, NULL), + OSSL_PARAM_size_t(OSSL_DIGEST_PARAM_SIZE, NULL), + OSSL_PARAM_int(OSSL_DIGEST_PARAM_XOF, NULL), + OSSL_PARAM_int(OSSL_DIGEST_PARAM_ALGID_ABSENT, NULL), + OSSL_PARAM_END}; + +static const OSSL_PARAM *kae_digest_gettable_params(void *provctx) +{ + return kae_digest_default_known_gettable_params; +} + +static int kae_digest_default_get_params(OSSL_PARAM params[], size_t blksz, size_t paramsz) +{ + OSSL_PARAM *p; + + p = OSSL_PARAM_locate(params, OSSL_DIGEST_PARAM_BLOCK_SIZE); + if (p != NULL && !OSSL_PARAM_set_size_t(p, blksz)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return KAE_P_FAIL; + } + p = OSSL_PARAM_locate(params, OSSL_DIGEST_PARAM_SIZE); + if (p != NULL && !OSSL_PARAM_set_size_t(p, paramsz)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return KAE_P_FAIL; + } + p = OSSL_PARAM_locate(params, OSSL_DIGEST_PARAM_XOF); + if (p != NULL && !OSSL_PARAM_set_int(p, 0)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return KAE_P_FAIL; + } + p = OSSL_PARAM_locate(params, OSSL_DIGEST_PARAM_ALGID_ABSENT); + if (p != NULL && !OSSL_PARAM_set_int(p, 0)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return KAE_P_FAIL; + } + + return KAE_P_SUCCESS; +} diff --git a/KAEOpensslProvider/src/provider/prov_nosva/prov_digest.h b/KAEOpensslProvider/src/provider/prov_nosva/prov_digest.h new file mode 100644 index 0000000000000000000000000000000000000000..1eeff1906e1fd2af7c04084683c8fa7f3686e590 --- /dev/null +++ b/KAEOpensslProvider/src/provider/prov_nosva/prov_digest.h @@ -0,0 +1,92 @@ +/* + * Copyright 2025 Huawei Technologies Co.,Ltd.All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef KAE_PROV_PKEY_H +#define KAE_PROV_PKEY_H + +#include "../../adapter/nosva/algorithm/digest/sec_digests.h" + +/* copied form openssl/include/internal/sm3.h + * OpenSSL 3.0 has no + */ +#define SM3_DIGEST_LENGTH 32 +#define SM3_WORD unsigned int +#define SM3_CBLOCK 64 +#define SM3_LBLOCK (SM3_CBLOCK / 4) +typedef struct SM3state_st { + SM3_WORD A, B, C, D, E, F, G, H; + SM3_WORD Nl, Nh; + SM3_WORD data[SM3_LBLOCK]; + unsigned int num; +} SM3_CTX; + +// static OSSL_FUNC_digest_init_fn kae_digest_init; +// static OSSL_FUNC_digest_update_fn kae_digest_update; +// static OSSL_FUNC_digest_final_fn kae_digest_final; +// static OSSL_FUNC_digest_digest_fn kae_digest_digest; +// static OSSL_FUNC_digest_freectx_fn kae_digest_freectx; +// static OSSL_FUNC_digest_dupctx_fn kae_digest_dupctx; +// static OSSL_FUNC_digest_get_params_fn kae_digest_get_params; +// static OSSL_FUNC_digest_set_ctx_params_fn lkae_digest_set_ctx_params; +// static OSSL_FUNC_digest_get_ctx_params_fn kae_digest_get_ctx_params; +// static OSSL_FUNC_digest_gettable_params_fn kae_gettable_params; +// static OSSL_FUNC_digest_settable_ctx_params_fn kae_settable_ctx_params; +// static OSSL_FUNC_digest_gettable_ctx_params_fn kae_gettable_ctx_params; + +static OSSL_FUNC_digest_init_fn kae_digest_init; +static OSSL_FUNC_digest_update_fn kae_digest_update; +static OSSL_FUNC_digest_final_fn kae_digest_final; +static OSSL_FUNC_digest_digest_fn kae_digest_digest; +static OSSL_FUNC_digest_freectx_fn kae_digest_freectx; +static OSSL_FUNC_digest_dupctx_fn kae_digest_dupctx; +static OSSL_FUNC_digest_gettable_params_fn kae_digest_gettable_params; + +static int kae_digest_default_get_params(OSSL_PARAM params[], size_t blksz, size_t paramsz); + +#define KAE_PROVIDER_IMPLEMENTATION(name, nid, mdsize, blksize) \ + static OSSL_FUNC_digest_newctx_fn kae_##name##_newctx; \ + static void *kae_##name##_newctx(void *provctx) \ + { \ + sec_digest_priv *ctx = OPENSSL_zalloc(sizeof(*ctx)); \ + memset((void *)ctx, 0, sizeof(sec_digest_priv)); \ + if (!ctx) \ + return NULL; \ + \ + ctx->e_nid = nid; \ + ctx->md_size = mdsize; \ + ctx->blk_size = blksize; \ + return ctx; \ + } \ + static OSSL_FUNC_digest_get_params_fn kae_##name##_get_params; \ + static int kae_##name##_get_params(OSSL_PARAM params[]) \ + { \ + return kae_digest_default_get_params(params, blksize, mdsize); \ + } \ + const OSSL_DISPATCH kae_##name##_functions[] = {{OSSL_FUNC_DIGEST_NEWCTX, (void (*)(void))kae_##name##_newctx}, \ + {OSSL_FUNC_DIGEST_FREECTX, (void (*)(void))kae_digest_freectx}, \ + {OSSL_FUNC_DIGEST_DUPCTX, (void (*)(void))kae_digest_dupctx}, \ + {OSSL_FUNC_DIGEST_INIT, (void (*)(void))kae_digest_init}, \ + {OSSL_FUNC_DIGEST_UPDATE, (void (*)(void))kae_digest_update}, \ + {OSSL_FUNC_DIGEST_FINAL, (void (*)(void))kae_digest_final}, \ + {OSSL_FUNC_DIGEST_DIGEST, (void (*)(void))kae_digest_digest}, \ + {OSSL_FUNC_DIGEST_GET_PARAMS, (void (*)(void))kae_##name##_get_params}, \ + {OSSL_FUNC_DIGEST_GETTABLE_PARAMS, (void (*)(void))kae_digest_gettable_params}, \ + {0, NULL}} + +KAE_PROVIDER_IMPLEMENTATION(md5, NID_md5, MD5_DIGEST_LENGTH, MD5_CBLOCK); +KAE_PROVIDER_IMPLEMENTATION(sm3, NID_sm3, SM3_DIGEST_LENGTH, SM3_CBLOCK); + +#endif \ No newline at end of file diff --git a/KAEOpensslProvider/src/provider/prov_nosva/prov_pkey.h b/KAEOpensslProvider/src/provider/prov_nosva/prov_pkey.h new file mode 100644 index 0000000000000000000000000000000000000000..6814f58076246e512b91c22d84030e26b785a263 --- /dev/null +++ b/KAEOpensslProvider/src/provider/prov_nosva/prov_pkey.h @@ -0,0 +1,430 @@ +/* + * Copyright 2025 Huawei Technologies Co.,Ltd.All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef KAE_PROV_PKEY_H +#define KAE_PROV_PKEY_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "prov.h" + +#define KAE_ECC_MAX_KEY_BITS 521 +#define KAE_ECC_MAX_KEY_BYTES 66 +#define KAE_ECC_CV_PARAM_NUM 6 +#define KAE_P_INTI_SUCCESS 0 +#define PROV_SEND_MAX_CNT 90000000 +#define PROV_RECV_MAX_CNT 60000000 +#define PROV_ENV_RECV_MAX_CNT 60000 +#define PROV_KEYMGMT_ALG_NUM 7 +// #define ECC_POINT_SIZE(n) ((n) << 1) +#define KAE_OCTET_STRING 0x04 +#define ECC128BITS 128 +#define ECC192BITS 192 +#define ECC224BITS 224 +#define ECC256BITS 256 +#define ECC320BITS 320 +#define ECC384BITS 384 +#define ECC521BITS 521 +#define GET_RAND_MAX_CNT 100 + +enum { + KEYMGMT_SM2 = 0x0, + KEYMGMT_MAX = 0x6 +}; + +enum { + SIGNATURE_SM2 = 0x0, + SIGNATURE_MAX = 0x3 +}; + +struct curve_param { + /* Prime */ + BIGNUM *p; + /* ECC coefficient 'a' */ + BIGNUM *a; + /* ECC coefficient 'b' */ + BIGNUM *b; + /* Base point */ + const EC_POINT *g; + /* Order of base point */ + const BIGNUM *order; +}; + +struct ec_gen_ctx { + OSSL_LIB_CTX *libctx; + char *group_name; + char *encoding; + char *pt_format; + char *group_check; + char *field_type; + BIGNUM *p, *a, *b, *order, *cofactor; + unsigned char *gen, *seed; + size_t gen_len, seed_len; + int selection; + int ecdh_mode; + EC_GROUP *gen_group; +}; + +typedef struct { + /* libcrypto internal */ + int id; + + int name_id; + char *type_name; + const char *description; + OSSL_PROVIDER *prov; + int refcnt; + void *lock; + + /* Constructor(s), destructor, information */ + OSSL_FUNC_keymgmt_new_fn *new_fun; + OSSL_FUNC_keymgmt_free_fn *free; + OSSL_FUNC_keymgmt_get_params_fn *get_params; + OSSL_FUNC_keymgmt_gettable_params_fn *gettable_params; + OSSL_FUNC_keymgmt_set_params_fn *set_params; + OSSL_FUNC_keymgmt_settable_params_fn *settable_params; + + /* Generation, a complex constructor */ + OSSL_FUNC_keymgmt_gen_init_fn *gen_init; + OSSL_FUNC_keymgmt_gen_set_template_fn *gen_set_template; + OSSL_FUNC_keymgmt_gen_set_params_fn *gen_set_params; + OSSL_FUNC_keymgmt_gen_settable_params_fn *gen_settable_params; + OSSL_FUNC_keymgmt_gen_fn *gen; + OSSL_FUNC_keymgmt_gen_cleanup_fn *gen_cleanup; + OSSL_FUNC_keymgmt_load_fn *load; + + /* Key object checking */ + OSSL_FUNC_keymgmt_query_operation_name_fn *query_operation_name; + OSSL_FUNC_keymgmt_has_fn *has; + OSSL_FUNC_keymgmt_validate_fn *validate; + OSSL_FUNC_keymgmt_match_fn *match; + + /* Import and export routines */ + OSSL_FUNC_keymgmt_import_fn *import; + OSSL_FUNC_keymgmt_import_types_fn *import_types; + OSSL_FUNC_keymgmt_export_fn *export_fun; + OSSL_FUNC_keymgmt_export_types_fn *export_types; + OSSL_FUNC_keymgmt_dup_fn *dup; +} KAE_PKEY_KEYMGMT; + +#define KAE_PKEY_KEYMGMT_DESCR(nm, alg) \ + static OSSL_FUNC_keymgmt_new_fn kae_keymgmt_##nm##_new; \ + static OSSL_FUNC_keymgmt_free_fn kae_keymgmt_##nm##_free; \ + static OSSL_FUNC_keymgmt_get_params_fn kae_keymgmt_##nm##_get_params; \ + static OSSL_FUNC_keymgmt_gettable_params_fn kae_keymgmt_##nm##_gettable_params; \ + static OSSL_FUNC_keymgmt_set_params_fn kae_keymgmt_##nm##_set_params; \ + static OSSL_FUNC_keymgmt_settable_params_fn kae_keymgmt_##nm##_settable_params; \ + static OSSL_FUNC_keymgmt_gen_init_fn kae_keymgmt_##nm##_gen_init; \ + static OSSL_FUNC_keymgmt_gen_set_template_fn kae_keymgmt_##nm##_gen_set_template; \ + static OSSL_FUNC_keymgmt_gen_set_params_fn kae_keymgmt_##nm##_gen_set_params; \ + static OSSL_FUNC_keymgmt_gen_settable_params_fn kae_keymgmt_##nm##_gen_settable_params; \ + static OSSL_FUNC_keymgmt_gen_fn kae_keymgmt_##nm##_gen; \ + static OSSL_FUNC_keymgmt_gen_cleanup_fn kae_keymgmt_##nm##_gen_cleanup; \ + static OSSL_FUNC_keymgmt_load_fn kae_keymgmt_##nm##_load; \ + static OSSL_FUNC_keymgmt_has_fn kae_keymgmt_##nm##_has; \ + static OSSL_FUNC_keymgmt_validate_fn kae_keymgmt_##nm##_validate; \ + static OSSL_FUNC_keymgmt_match_fn kae_keymgmt_##nm##_match; \ + static OSSL_FUNC_keymgmt_import_fn kae_keymgmt_##nm##_import; \ + static OSSL_FUNC_keymgmt_import_types_fn kae_keymgmt_##nm##_import_types; \ + static OSSL_FUNC_keymgmt_export_fn kae_keymgmt_##nm##_export; \ + static OSSL_FUNC_keymgmt_export_types_fn kae_keymgmt_##nm##_export_types; \ + static OSSL_FUNC_keymgmt_dup_fn kae_keymgmt_##nm##_dup; \ + static OSSL_FUNC_keymgmt_query_operation_name_fn kae_keymgmt_##nm##_query_operation_name; \ + static KAE_PKEY_KEYMGMT get_default_##nm##_keymgmt(void) \ + { \ + static KAE_PKEY_KEYMGMT s_keymgmt; \ + static int initilazed; \ + \ + if (!initilazed) { \ + KAE_PKEY_KEYMGMT *keymgmt = (KAE_PKEY_KEYMGMT *)EVP_KEYMGMT_fetch(NULL, #alg, "provider=default"); \ + \ + if (keymgmt) { \ + s_keymgmt = *keymgmt; \ + EVP_KEYMGMT_free((EVP_KEYMGMT *)keymgmt); \ + initilazed = 1; \ + } else { \ + fprintf(stderr, "failed to EVP_KEYMGMT_fetch default provider\n"); \ + } \ + } \ + return s_keymgmt; \ + } \ + const OSSL_DISPATCH kae_##nm##_keymgmt_functions[] = { \ + {OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))kae_keymgmt_##nm##_new}, \ + {OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))kae_keymgmt_##nm##_free}, \ + {OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*)(void))kae_keymgmt_##nm##_get_params}, \ + {OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*)(void))kae_keymgmt_##nm##_gettable_params}, \ + {OSSL_FUNC_KEYMGMT_SET_PARAMS, (void (*)(void))kae_keymgmt_##nm##_set_params}, \ + {OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (void (*)(void))kae_keymgmt_##nm##_settable_params}, \ + {OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))kae_keymgmt_##nm##_gen_init}, \ + {OSSL_FUNC_KEYMGMT_GEN_SET_TEMPLATE, (void (*)(void))kae_keymgmt_##nm##_gen_set_template}, \ + {OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, (void (*)(void))kae_keymgmt_##nm##_gen_set_params}, \ + {OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS, (void (*)(void))kae_keymgmt_##nm##_gen_settable_params}, \ + {OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))kae_keymgmt_##nm##_gen}, \ + {OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (void (*)(void))kae_keymgmt_##nm##_gen_cleanup}, \ + {OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))kae_keymgmt_##nm##_load}, \ + {OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))kae_keymgmt_##nm##_has}, \ + {OSSL_FUNC_KEYMGMT_VALIDATE, (void (*)(void))kae_keymgmt_##nm##_validate}, \ + {OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))kae_keymgmt_##nm##_match}, \ + {OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))kae_keymgmt_##nm##_import}, \ + {OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))kae_keymgmt_##nm##_import_types}, \ + {OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))kae_keymgmt_##nm##_export}, \ + {OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))kae_keymgmt_##nm##_export_types}, \ + {OSSL_FUNC_KEYMGMT_DUP, (void (*)(void))kae_keymgmt_##nm##_dup}, \ + {OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME, (void (*)(void))kae_keymgmt_##nm##_query_operation_name}, \ + {0, NULL}} + +typedef struct { + int name_id; + char *type_name; + const char *description; + OSSL_PROVIDER *prov; + int refcnt; + void *lock; + + OSSL_FUNC_asym_cipher_newctx_fn *newctx; + OSSL_FUNC_asym_cipher_encrypt_init_fn *encrypt_init; + OSSL_FUNC_asym_cipher_encrypt_fn *encrypt; + OSSL_FUNC_asym_cipher_decrypt_init_fn *decrypt_init; + OSSL_FUNC_asym_cipher_decrypt_fn *decrypt; + OSSL_FUNC_asym_cipher_freectx_fn *freectx; + OSSL_FUNC_asym_cipher_dupctx_fn *dupctx; + OSSL_FUNC_asym_cipher_get_ctx_params_fn *get_ctx_params; + OSSL_FUNC_asym_cipher_gettable_ctx_params_fn *gettable_ctx_params; + OSSL_FUNC_asym_cipher_set_ctx_params_fn *set_ctx_params; + OSSL_FUNC_asym_cipher_settable_ctx_params_fn *settable_ctx_params; +} KAE_PKEY_ASYM_CIPHER; + +#define KAE_PKEY_ASYM_CIPHER_DESCR(nm, alg) \ + static OSSL_FUNC_asym_cipher_newctx_fn kae_asym_cipher_##nm##_newctx; \ + static OSSL_FUNC_asym_cipher_encrypt_init_fn kae_asym_cipher_##nm##_encrypt_init; \ + static OSSL_FUNC_asym_cipher_encrypt_fn kae_asym_cipher_##nm##_encrypt; \ + static OSSL_FUNC_asym_cipher_decrypt_init_fn kae_asym_cipher_##nm##_decrypt_init; \ + static OSSL_FUNC_asym_cipher_decrypt_fn kae_asym_cipher_##nm##_decrypt; \ + static OSSL_FUNC_asym_cipher_freectx_fn kae_asym_cipher_##nm##_freectx; \ + static OSSL_FUNC_asym_cipher_dupctx_fn kae_asym_cipher_##nm##_dupctx; \ + static OSSL_FUNC_asym_cipher_get_ctx_params_fn kae_asym_cipher_##nm##_get_ctx_params; \ + static OSSL_FUNC_asym_cipher_gettable_ctx_params_fn kae_asym_cipher_##nm##_gettable_ctx_params; \ + static OSSL_FUNC_asym_cipher_set_ctx_params_fn kae_asym_cipher_##nm##_set_ctx_params; \ + static OSSL_FUNC_asym_cipher_settable_ctx_params_fn kae_asym_cipher_##nm##_settable_ctx_params; \ + static KAE_PKEY_ASYM_CIPHER get_default_##nm##_asym_cipher(void) \ + { \ + static KAE_PKEY_ASYM_CIPHER s_asym_cipher; \ + static int initilazed; \ + \ + if (!initilazed) { \ + KAE_PKEY_ASYM_CIPHER *asym_cipher = \ + (KAE_PKEY_ASYM_CIPHER *)EVP_ASYM_CIPHER_fetch(NULL, #alg, "provider=default"); \ + \ + if (asym_cipher) { \ + s_asym_cipher = *asym_cipher; \ + EVP_ASYM_CIPHER_free((EVP_ASYM_CIPHER *)asym_cipher); \ + initilazed = 1; \ + } else { \ + fprintf(stderr, "failed to EVP_ASYM_CIPHER_fetch default provider\n"); \ + } \ + } \ + return s_asym_cipher; \ + } \ + const OSSL_DISPATCH kae_##nm##_asym_cipher_functions[] = { \ + {OSSL_FUNC_ASYM_CIPHER_NEWCTX, (void (*)(void))kae_asym_cipher_##nm##_newctx}, \ + {OSSL_FUNC_ASYM_CIPHER_ENCRYPT_INIT, (void (*)(void))kae_asym_cipher_##nm##_encrypt_init}, \ + {OSSL_FUNC_ASYM_CIPHER_ENCRYPT, (void (*)(void))kae_asym_cipher_##nm##_encrypt}, \ + {OSSL_FUNC_ASYM_CIPHER_DECRYPT_INIT, (void (*)(void))kae_asym_cipher_##nm##_decrypt_init}, \ + {OSSL_FUNC_ASYM_CIPHER_DECRYPT, (void (*)(void))kae_asym_cipher_##nm##_decrypt}, \ + {OSSL_FUNC_ASYM_CIPHER_FREECTX, (void (*)(void))kae_asym_cipher_##nm##_freectx}, \ + {OSSL_FUNC_ASYM_CIPHER_DUPCTX, (void (*)(void))kae_asym_cipher_##nm##_dupctx}, \ + {OSSL_FUNC_ASYM_CIPHER_GET_CTX_PARAMS, (void (*)(void))kae_asym_cipher_##nm##_get_ctx_params}, \ + {OSSL_FUNC_ASYM_CIPHER_GETTABLE_CTX_PARAMS, (void (*)(void))kae_asym_cipher_##nm##_gettable_ctx_params}, \ + {OSSL_FUNC_ASYM_CIPHER_SET_CTX_PARAMS, (void (*)(void))kae_asym_cipher_##nm##_set_ctx_params}, \ + {OSSL_FUNC_ASYM_CIPHER_SETTABLE_CTX_PARAMS, (void (*)(void))kae_asym_cipher_##nm##_settable_ctx_params}, \ + {0, NULL}} + +typedef struct { + int name_id; + char *type_name; + const char *description; + OSSL_PROVIDER *prov; + int refcnt; + void *lock; + + OSSL_FUNC_signature_newctx_fn *newctx; + OSSL_FUNC_signature_sign_init_fn *sign_init; + OSSL_FUNC_signature_sign_fn *sign; + OSSL_FUNC_signature_verify_init_fn *verify_init; + OSSL_FUNC_signature_verify_fn *verify; + OSSL_FUNC_signature_verify_recover_init_fn *verify_recover_init; + OSSL_FUNC_signature_verify_recover_fn *verify_recover; + OSSL_FUNC_signature_digest_sign_init_fn *digest_sign_init; + OSSL_FUNC_signature_digest_sign_update_fn *digest_sign_update; + OSSL_FUNC_signature_digest_sign_final_fn *digest_sign_final; + OSSL_FUNC_signature_digest_sign_fn *digest_sign; + OSSL_FUNC_signature_digest_verify_init_fn *digest_verify_init; + OSSL_FUNC_signature_digest_verify_update_fn *digest_verify_update; + OSSL_FUNC_signature_digest_verify_final_fn *digest_verify_final; + OSSL_FUNC_signature_digest_verify_fn *digest_verify; + OSSL_FUNC_signature_freectx_fn *freectx; + OSSL_FUNC_signature_dupctx_fn *dupctx; + OSSL_FUNC_signature_get_ctx_params_fn *get_ctx_params; + OSSL_FUNC_signature_gettable_ctx_params_fn *gettable_ctx_params; + OSSL_FUNC_signature_set_ctx_params_fn *set_ctx_params; + OSSL_FUNC_signature_settable_ctx_params_fn *settable_ctx_params; + OSSL_FUNC_signature_get_ctx_md_params_fn *get_ctx_md_params; + OSSL_FUNC_signature_gettable_ctx_md_params_fn *gettable_ctx_md_params; + OSSL_FUNC_signature_set_ctx_md_params_fn *set_ctx_md_params; + OSSL_FUNC_signature_settable_ctx_md_params_fn *settable_ctx_md_params; +} KAE_PKEY_SIGNATURE; + +#define KAE_PKEY_SIGNATURE_DESCR(nm, alg) \ + static OSSL_FUNC_signature_newctx_fn kae_signature_##nm##_newctx; \ + static OSSL_FUNC_signature_sign_init_fn kae_signature_##nm##_sign_init; \ + static OSSL_FUNC_signature_verify_init_fn kae_signature_##nm##_verify_init; \ + static OSSL_FUNC_signature_sign_fn kae_signature_##nm##_sign; \ + static OSSL_FUNC_signature_verify_fn kae_signature_##nm##_verify; \ + static OSSL_FUNC_signature_verify_recover_init_fn kae_signature_##nm##_verify_recover_init; \ + static OSSL_FUNC_signature_verify_recover_fn kae_signature_##nm##_verify_recover; \ + static OSSL_FUNC_signature_digest_sign_init_fn kae_signature_##nm##_digest_sign_init; \ + static OSSL_FUNC_signature_digest_sign_update_fn kae_signature_##nm##_digest_sign_update; \ + static OSSL_FUNC_signature_digest_sign_final_fn kae_signature_##nm##_digest_sign_final; \ + static OSSL_FUNC_signature_digest_verify_init_fn kae_signature_##nm##_digest_verify_init; \ + static OSSL_FUNC_signature_digest_verify_update_fn kae_signature_##nm##_digest_verify_update; \ + static OSSL_FUNC_signature_digest_verify_final_fn kae_signature_##nm##_digest_verify_final; \ + static OSSL_FUNC_signature_freectx_fn kae_signature_##nm##_freectx; \ + static OSSL_FUNC_signature_dupctx_fn kae_signature_##nm##_dupctx; \ + static OSSL_FUNC_signature_get_ctx_params_fn kae_signature_##nm##_get_ctx_params; \ + static OSSL_FUNC_signature_gettable_ctx_params_fn kae_signature_##nm##_gettable_ctx_params; \ + static OSSL_FUNC_signature_set_ctx_params_fn kae_signature_##nm##_set_ctx_params; \ + static OSSL_FUNC_signature_settable_ctx_params_fn kae_signature_##nm##_settable_ctx_params; \ + static OSSL_FUNC_signature_get_ctx_md_params_fn kae_signature_##nm##_get_ctx_md_params; \ + static OSSL_FUNC_signature_gettable_ctx_md_params_fn kae_signature_##nm##_gettable_ctx_md_params; \ + static OSSL_FUNC_signature_set_ctx_md_params_fn kae_signature_##nm##_set_ctx_md_params; \ + static OSSL_FUNC_signature_settable_ctx_md_params_fn kae_signature_##nm##_settable_ctx_md_params; \ + static KAE_PKEY_SIGNATURE get_default_##nm##_signature(void) \ + { \ + static KAE_PKEY_SIGNATURE s_signature; \ + static int initilazed; \ + \ + if (!initilazed) { \ + KAE_PKEY_SIGNATURE *signature = (KAE_PKEY_SIGNATURE *)EVP_SIGNATURE_fetch(NULL, #alg, "provider=default"); \ + \ + if (signature) { \ + s_signature = *signature; \ + EVP_SIGNATURE_free((EVP_SIGNATURE *)signature); \ + initilazed = 1; \ + } else { \ + fprintf(stderr, "failed to EVP_SIGNATURE_fetch default provider\n"); \ + } \ + } \ + return s_signature; \ + } \ + const OSSL_DISPATCH kae_##nm##_signature_functions[] = { \ + {OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))kae_signature_##nm##_newctx}, \ + {OSSL_FUNC_SIGNATURE_SIGN_INIT, (void (*)(void))kae_signature_##nm##_sign_init}, \ + {OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))kae_signature_##nm##_sign}, \ + {OSSL_FUNC_SIGNATURE_VERIFY_INIT, (void (*)(void))kae_signature_##nm##_verify_init}, \ + {OSSL_FUNC_SIGNATURE_VERIFY, (void (*)(void))kae_signature_##nm##_verify}, \ + {OSSL_FUNC_SIGNATURE_VERIFY_RECOVER_INIT, (void (*)(void))kae_signature_##nm##_verify_recover_init}, \ + {OSSL_FUNC_SIGNATURE_VERIFY_RECOVER, (void (*)(void))kae_signature_##nm##_verify_recover}, \ + {OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, (void (*)(void))kae_signature_##nm##_digest_sign_init}, \ + {OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE, (void (*)(void))kae_signature_##nm##_digest_sign_update}, \ + {OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL, (void (*)(void))kae_signature_##nm##_digest_sign_final}, \ + {OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT, (void (*)(void))kae_signature_##nm##_digest_verify_init}, \ + {OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_UPDATE, (void (*)(void))kae_signature_##nm##_digest_verify_update}, \ + {OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_FINAL, (void (*)(void))kae_signature_##nm##_digest_verify_final}, \ + {OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))kae_signature_##nm##_freectx}, \ + {OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))kae_signature_##nm##_dupctx}, \ + {OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, (void (*)(void))kae_signature_##nm##_get_ctx_params}, \ + {OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, (void (*)(void))kae_signature_##nm##_gettable_ctx_params}, \ + {OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, (void (*)(void))kae_signature_##nm##_set_ctx_params}, \ + {OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, (void (*)(void))kae_signature_##nm##_settable_ctx_params}, \ + {OSSL_FUNC_SIGNATURE_GET_CTX_MD_PARAMS, (void (*)(void))kae_signature_##nm##_get_ctx_md_params}, \ + {OSSL_FUNC_SIGNATURE_GETTABLE_CTX_MD_PARAMS, (void (*)(void))kae_signature_##nm##_gettable_ctx_md_params}, \ + {OSSL_FUNC_SIGNATURE_SET_CTX_MD_PARAMS, (void (*)(void))kae_signature_##nm##_set_ctx_md_params}, \ + {OSSL_FUNC_SIGNATURE_SETTABLE_CTX_MD_PARAMS, (void (*)(void))kae_signature_##nm##_settable_ctx_md_params}, \ + {0, NULL}} + +typedef struct { + int name_id; + char *type_name; + const char *description; + OSSL_PROVIDER *prov; + int refcnt; + + OSSL_FUNC_keyexch_newctx_fn *newctx; + OSSL_FUNC_keyexch_init_fn *init; + OSSL_FUNC_keyexch_set_peer_fn *set_peer; + OSSL_FUNC_keyexch_derive_fn *derive; + OSSL_FUNC_keyexch_freectx_fn *freectx; + OSSL_FUNC_keyexch_dupctx_fn *dupctx; + OSSL_FUNC_keyexch_set_ctx_params_fn *set_ctx_params; + OSSL_FUNC_keyexch_settable_ctx_params_fn *settable_ctx_params; + OSSL_FUNC_keyexch_get_ctx_params_fn *get_ctx_params; + OSSL_FUNC_keyexch_gettable_ctx_params_fn *gettable_ctx_params; +} KAE_PKEY_KEYEXCH; + +#define KAE_PKEY_KEYEXCH_DESCR(nm, alg) \ + static OSSL_FUNC_keyexch_newctx_fn kae_keyexch_##nm##_newctx; \ + static OSSL_FUNC_keyexch_init_fn kae_keyexch_##nm##_init; \ + static OSSL_FUNC_keyexch_set_peer_fn kae_keyexch_##nm##_set_peer; \ + static OSSL_FUNC_keyexch_derive_fn kae_keyexch_##nm##_derive; \ + static OSSL_FUNC_keyexch_freectx_fn kae_keyexch_##nm##_freectx; \ + static OSSL_FUNC_keyexch_dupctx_fn kae_keyexch_##nm##_dupctx; \ + static OSSL_FUNC_keyexch_set_ctx_params_fn kae_keyexch_##nm##_set_ctx_params; \ + static OSSL_FUNC_keyexch_settable_ctx_params_fn kae_keyexch_##nm##_settable_ctx_params; \ + static OSSL_FUNC_keyexch_get_ctx_params_fn kae_keyexch_##nm##_get_ctx_params; \ + static OSSL_FUNC_keyexch_gettable_ctx_params_fn kae_keyexch_##nm##_gettable_ctx_params; \ + static KAE_PKEY_KEYEXCH get_default_##nm##_keyexch(void) \ + { \ + KAE_PKEY_KEYEXCH s_keyexch; \ + static int initilazed; \ + \ + if (!initilazed) { \ + KAE_PKEY_KEYEXCH *keyexch = (KAE_PKEY_KEYEXCH *)EVP_KEYEXCH_fetch(NULL, #alg, "provider=default"); \ + if (keyexch) { \ + s_keyexch = *keyexch; \ + EVP_KEYEXCH_free((EVP_KEYEXCH *)keyexch); \ + initilazed = 1; \ + } else { \ + fprintf(stderr, "failed to EVP_KEYEXCH_fetch default provider\n"); \ + } \ + } \ + return s_keyexch; \ + } \ + const OSSL_DISPATCH kae_##nm##_keyexch_functions[] = { \ + {OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))kae_keyexch_##nm##_newctx}, \ + {OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS, (void (*)(void))kae_keyexch_##nm##_set_ctx_params}, \ + {OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))kae_keyexch_##nm##_init}, \ + {OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))kae_keyexch_##nm##_derive}, \ + {OSSL_FUNC_KEYEXCH_SET_PEER, (void (*)(void))kae_keyexch_##nm##_set_peer}, \ + {OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))kae_keyexch_##nm##_freectx}, \ + {OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))kae_keyexch_##nm##_dupctx}, \ + {OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS, (void (*)(void))kae_keyexch_##nm##_settable_ctx_params}, \ + {OSSL_FUNC_KEYEXCH_GET_CTX_PARAMS, (void (*)(void))kae_keyexch_##nm##_get_ctx_params}, \ + {OSSL_FUNC_KEYEXCH_GETTABLE_CTX_PARAMS, (void (*)(void))kae_keyexch_##nm##_gettable_ctx_params}, \ + {0, NULL}} + +#endif \ No newline at end of file diff --git a/KAEOpensslProvider/src/provider/prov_nosva/prov_rsa.c b/KAEOpensslProvider/src/provider/prov_nosva/prov_rsa.c new file mode 100644 index 0000000000000000000000000000000000000000..ce284e2afeae130c66852e4194e543baf51ea2c9 --- /dev/null +++ b/KAEOpensslProvider/src/provider/prov_nosva/prov_rsa.c @@ -0,0 +1,1316 @@ +/* + * Copyright 2025 Huawei Technologies Co.,Ltd.All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "prov.h" +#include "prov_pkey.h" +#include "../../adapter/common/kae_log.h" +#include "../../adapter/common/kae_types.h" +#include "../../adapter/nosva/algorithm/pkey/hpre_rsa.h" + +KAE_PKEY_KEYMGMT_DESCR(rsa, RSA); +KAE_PKEY_SIGNATURE_DESCR(rsa, RSA); +KAE_PKEY_ASYM_CIPHER_DESCR(rsa, RSA); + +static void kae_rsa_clear_flags(RSA *r, int flags) +{ + r->flags &= ~flags; +} + +static int kae_rsa_test_flags(const RSA *r, int flags) +{ + return r->flags & flags; +} + +static void kae_rsa_set_flags(RSA *r, int flags) +{ + r->flags |= flags; +} + +static int kae_rsa_size(const RSA *r) +{ + return BN_num_bytes(r->n); +} + +static int setup_tbuf(PROV_RSA_SIG_CTX *ctx) +{ + if (ctx->tbuf != NULL) { + return OPENSSL_SUCCESS; + } + + if ((ctx->tbuf = OPENSSL_malloc(RSA_size(ctx->rsa))) == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return OPENSSL_FAIL; + } + + return OPENSSL_SUCCESS; +} + +static void clean_tbuf(PROV_RSA_SIG_CTX *ctx) +{ + if (ctx->tbuf != NULL) + OPENSSL_cleanse(ctx->tbuf, kae_rsa_size(ctx->rsa)); +} + +static void free_tbuf(PROV_RSA_SIG_CTX *ctx) +{ + clean_tbuf(ctx); + OPENSSL_free(ctx->tbuf); + ctx->tbuf = NULL; +} + +static RSA *ossl_rsa_new_with_ctx(OSSL_LIB_CTX *libctx) +{ + RSA *ret = OPENSSL_zalloc(sizeof(*ret)); + + if (ret == NULL) { + ERR_raise(ERR_LIB_RSA, ERR_R_MALLOC_FAILURE); + return NULL; + } + + ret->references = 1; + ret->lock = CRYPTO_THREAD_lock_new(); + if (ret->lock == NULL) { + ERR_raise(ERR_LIB_RSA, ERR_R_MALLOC_FAILURE); + OPENSSL_free(ret); + return NULL; + } + + ret->libctx = libctx; + + return ret; +} + +static int rsa_gencb(int p, int n, BN_GENCB *cb) +{ + struct rsa_gen_ctx *gctx = BN_GENCB_get_arg(cb); + OSSL_PARAM params[] = {OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END}; + + params[0] = OSSL_PARAM_construct_int(OSSL_GEN_PARAM_POTENTIAL, &p); + params[1] = OSSL_PARAM_construct_int(OSSL_GEN_PARAM_ITERATION, &n); + return gctx->cb(params, gctx->cbarg); +} + +static void *kae_keymgmt_rsa_new(void *provctx) +{ + if (!get_default_rsa_keymgmt().new_fun) + return NULL; + + return get_default_rsa_keymgmt().new_fun(provctx); +} + +static void kae_keymgmt_rsa_free(void *keydata) +{ + if (!get_default_rsa_keymgmt().free) + return; + + get_default_rsa_keymgmt().free(keydata); +} + +static int kae_keymgmt_rsa_get_params(void *key, OSSL_PARAM params[]) +{ + if (!get_default_rsa_keymgmt().get_params) + return KAE_P_FAIL; + + return get_default_rsa_keymgmt().get_params(key, params); +} + +static const OSSL_PARAM *kae_keymgmt_rsa_gettable_params(void *provctx) +{ + if (!get_default_rsa_keymgmt().gettable_params) + return NULL; + + return get_default_rsa_keymgmt().gettable_params(provctx); +} + +static int kae_keymgmt_rsa_set_params(void *key, const OSSL_PARAM params[]) +{ + if (!get_default_rsa_keymgmt().set_params) { + return KAE_P_FAIL; + } + + return get_default_rsa_keymgmt().set_params(key, params); +} + +static const OSSL_PARAM *kae_keymgmt_rsa_settable_params(ossl_unused void *provctx) +{ + if (!get_default_rsa_keymgmt().settable_params) { + return NULL; + } + + return get_default_rsa_keymgmt().settable_params(provctx); +} + +static void *kae_keymgmt_rsa_gen_init(void *provctx, int selection, const OSSL_PARAM params[]) +{ + if (!get_default_rsa_keymgmt().gen_init) + return NULL; + + return get_default_rsa_keymgmt().gen_init(provctx, selection, params); +} + +static int kae_keymgmt_rsa_gen_set_template(void *genctx, void *templates) +{ + if (!get_default_rsa_keymgmt().gen_set_template) { + return KAE_P_FAIL; + } + + return get_default_rsa_keymgmt().gen_set_template(genctx, templates); +} + +static int kae_keymgmt_rsa_gen_set_params(void *genctx, const OSSL_PARAM params[]) +{ + if (!get_default_rsa_keymgmt().gen_set_params) + return KAE_P_FAIL; + + return get_default_rsa_keymgmt().gen_set_params(genctx, params); +} + +static const OSSL_PARAM *kae_keymgmt_rsa_gen_settable_params(ossl_unused void *genctx, ossl_unused void *provctx) +{ + if (!get_default_rsa_keymgmt().gen_settable_params) + return NULL; + + return get_default_rsa_keymgmt().gen_settable_params(genctx, provctx); +} + +static void *kae_keymgmt_rsa_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg) +{ + struct rsa_gen_ctx *gctx = genctx; + RSA *rsa = NULL; + BN_GENCB *gencb = NULL; + int ret; + + if (gctx == NULL) + return NULL; + + rsa = ossl_rsa_new_with_ctx(gctx->libctx); + if (rsa == NULL) + return NULL; + + gctx->cb = osslcb; + gctx->cbarg = cbarg; + gencb = BN_GENCB_new(); + if (gencb != NULL) + BN_GENCB_set(gencb, rsa_gencb, genctx); + + ret = hpre_rsa_keygen(rsa, (int)gctx->nbits, gctx->pub_exp, gencb); + if (ret == KAE_CRYPTO_FAIL) { + BN_GENCB_free(gencb); + kae_keymgmt_rsa_free(rsa); + goto soft; + } + + kae_rsa_clear_flags(rsa, RSA_FLAG_TYPE_MASK); + kae_rsa_set_flags(rsa, gctx->rsa_type); + BN_GENCB_free(gencb); + + return rsa; + +soft: + fprintf(stderr, "switch to execute openssl software calculation.\n"); + if (!get_default_rsa_keymgmt().gen) + return NULL; + return get_default_rsa_keymgmt().gen(genctx, osslcb, cbarg); +} + +static void kae_keymgmt_rsa_gen_cleanup(void *genctx) +{ + if (!get_default_rsa_keymgmt().gen_cleanup) + return; + + get_default_rsa_keymgmt().gen_cleanup(genctx); +} + +static void *kae_keymgmt_rsa_load(const void *reference, size_t reference_sz) +{ + if (!get_default_rsa_keymgmt().load) + return NULL; + + return get_default_rsa_keymgmt().load(reference, reference_sz); +} + +static int kae_keymgmt_rsa_has(const void *keydata, int selection) +{ + if (!get_default_rsa_keymgmt().has) + return KAE_P_FAIL; + + return get_default_rsa_keymgmt().has(keydata, selection); +} + +static int kae_keymgmt_rsa_validate(const void *keydata, int selection, int checktype) +{ + if (!get_default_rsa_keymgmt().validate) + return KAE_P_FAIL; + + return get_default_rsa_keymgmt().validate(keydata, selection, checktype); +} + +static int kae_keymgmt_rsa_match(const void *keydata1, const void *keydata2, int selection) +{ + if (!get_default_rsa_keymgmt().match) + return KAE_P_FAIL; + + return get_default_rsa_keymgmt().match(keydata1, keydata2, selection); +} + +static int kae_keymgmt_rsa_import(void *keydata, int selection, const OSSL_PARAM params[]) +{ + if (!get_default_rsa_keymgmt().import) + return KAE_P_FAIL; + + return get_default_rsa_keymgmt().import(keydata, selection, params); +} + +static const OSSL_PARAM *kae_keymgmt_rsa_import_types(int selection) +{ + if (!get_default_rsa_keymgmt().import_types) + return NULL; + + return get_default_rsa_keymgmt().import_types(selection); +} + +static int kae_keymgmt_rsa_export(void *keydata, int selection, OSSL_CALLBACK *param_callback, void *cbarg) +{ + if (!get_default_rsa_keymgmt().export_fun) + return KAE_P_FAIL; + + return get_default_rsa_keymgmt().export_fun(keydata, selection, param_callback, cbarg); +} + +static const OSSL_PARAM *kae_keymgmt_rsa_export_types(int selection) +{ + if (!get_default_rsa_keymgmt().export_types) + return NULL; + + return get_default_rsa_keymgmt().export_types(selection); +} + +static void *kae_keymgmt_rsa_dup(const void *keydata_from, int selection) +{ + if (!get_default_rsa_keymgmt().dup) + return NULL; + + return get_default_rsa_keymgmt().dup(keydata_from, selection); +} + +static const char *kae_keymgmt_rsa_query_operation_name(int operation_id) +{ + if (!get_default_rsa_keymgmt().query_operation_name) + return NULL; + + return get_default_rsa_keymgmt().query_operation_name(operation_id); +} + +static void *kae_asym_cipher_rsa_newctx(void *provctx) +{ + PROV_RSA_ASYM_CTX *priv = NULL; + + priv = OPENSSL_zalloc(sizeof(*priv)); + if (priv == NULL) + return NULL; + priv->libctx = prov_libctx_of(provctx); + + return priv; +} + +static int kae_rsa_asym_init(void *vprsactx, void *vrsa, const OSSL_PARAM params[], int operation) +{ + PROV_RSA_ASYM_CTX *priv = (PROV_RSA_ASYM_CTX *)vprsactx; + + priv->rsa = vrsa; + priv->operation = operation; + + switch (kae_rsa_test_flags(priv->rsa, RSA_FLAG_TYPE_MASK)) { + case RSA_FLAG_TYPE_RSA: + priv->pad_mode = RSA_PKCS1_PADDING; + break; + case RSA_FLAG_TYPE_RSASSAPSS: + priv->pad_mode = RSA_PKCS1_PSS_PADDING; + break; + default: + ERR_raise(ERR_LIB_RSA, PROV_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return OPENSSL_FAIL; + } + + return OPENSSL_SUCCESS; +} + +static int kae_asym_cipher_rsa_encrypt_init(void *vprsactx, void *vrsa, const OSSL_PARAM params[]) +{ + return kae_rsa_asym_init(vprsactx, vrsa, params, EVP_PKEY_OP_ENCRYPT); +} + +static int kae_asym_cipher_rsa_encrypt( + void *vprsactx, unsigned char *out, size_t *outlen, size_t outsize, const unsigned char *in, size_t inlen) +{ + PROV_RSA_ASYM_CTX *priv = (PROV_RSA_ASYM_CTX *)vprsactx; + size_t len; + int ret; + + if (out == NULL) { + len = kae_rsa_size(priv->rsa); + if (len == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY); + return OPENSSL_FAIL; + } + *outlen = len; + return OPENSSL_SUCCESS; + } + + ret = hpre_rsa_public_encrypt(inlen, in, out, priv->rsa, priv->pad_mode); + if (ret == KAE_CRYPTO_FAIL) { + goto soft; + } + + *outlen = ret; + + return OPENSSL_SUCCESS; + +soft: + fprintf(stderr, "switch to execute openssl software calculation.\n"); + if (!get_default_rsa_asym_cipher().encrypt) + return KAE_P_FAIL; + + return get_default_rsa_asym_cipher().encrypt(vprsactx, out, outlen, outsize, in, inlen); +} + +static int kae_asym_cipher_rsa_decrypt_init(void *vprsactx, void *vrsa, const OSSL_PARAM params[]) +{ + return kae_rsa_asym_init(vprsactx, vrsa, params, EVP_PKEY_OP_DECRYPT); +} + +static int kae_asym_cipher_rsa_decrypt( + void *vprsactx, unsigned char *out, size_t *outlen, size_t outsize, const unsigned char *in, size_t inlen) +{ + PROV_RSA_ASYM_CTX *priv = (PROV_RSA_ASYM_CTX *)vprsactx; + size_t len = kae_rsa_size(priv->rsa); + int ret; + + if (out == NULL) { + if (len == 0) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY); + return OPENSSL_FAIL; + } + *outlen = len; + return OPENSSL_SUCCESS; + } + + if (outsize < len) { + ERR_raise(ERR_LIB_PROV, PROV_R_BAD_LENGTH); + return OPENSSL_FAIL; + } + + ret = hpre_rsa_private_decrypt(inlen, in, out, priv->rsa, priv->pad_mode); + if (ret == KAE_CRYPTO_FAIL) { + goto soft; + } + + *outlen = ret; + + return OPENSSL_SUCCESS; + +soft: + fprintf(stderr, "switch to execute openssl software calculation.\n"); + if (!get_default_rsa_asym_cipher().decrypt) + return KAE_P_FAIL; + + return get_default_rsa_asym_cipher().decrypt(vprsactx, out, outlen, outsize, in, inlen); +} + +static void kae_asym_cipher_rsa_freectx(void *vprsactx) +{ + PROV_RSA_ASYM_CTX *priv = (PROV_RSA_ASYM_CTX *)vprsactx; + + if (priv == NULL) + return; + + OPENSSL_free(priv); +} + +static void *kae_asym_cipher_rsa_dupctx(void *vprsactx) +{ + if (!get_default_rsa_asym_cipher().dupctx) + return KAE_P_FAIL; + return get_default_rsa_asym_cipher().dupctx(vprsactx); +} + +static int kae_asym_cipher_rsa_get_ctx_params(void *vprsactx, OSSL_PARAM *params) +{ + if (!get_default_rsa_asym_cipher().get_ctx_params) + return KAE_P_FAIL; + + return get_default_rsa_asym_cipher().get_ctx_params(vprsactx, params); +} + +static const OSSL_PARAM *kae_asym_cipher_rsa_gettable_ctx_params(void *vprsactx, void *provctx) +{ + if (!get_default_rsa_asym_cipher().gettable_ctx_params) + return KAE_P_FAIL; + + return get_default_rsa_asym_cipher().gettable_ctx_params(vprsactx, provctx); +} + +static int kae_asym_cipher_rsa_set_ctx_params(void *vprsactx, const OSSL_PARAM params[]) +{ + if (!get_default_rsa_asym_cipher().set_ctx_params) + return KAE_P_FAIL; + + return get_default_rsa_asym_cipher().set_ctx_params(vprsactx, params); +} + +static const OSSL_PARAM *kae_asym_cipher_rsa_settable_ctx_params(void *vprsactx, void *provctx) +{ + if (!get_default_rsa_asym_cipher().settable_ctx_params) + return KAE_P_FAIL; + + return get_default_rsa_asym_cipher().settable_ctx_params(vprsactx, provctx); +} + +static void *kae_signature_rsa_newctx(void *provctx, const char *propq) +{ + PROV_RSA_SIG_CTX *priv = OPENSSL_zalloc(sizeof(PROV_RSA_SIG_CTX)); + char *propq_copy = NULL; + + if (priv == NULL) + goto err; + + if (propq != NULL) { + propq_copy = OPENSSL_strdup(propq); + if (propq_copy == NULL) + goto err; + } + + priv->libctx = prov_libctx_of(provctx); + priv->flag_allow_md = 1; + priv->propq = propq_copy; + return priv; + +err: + OPENSSL_free(priv); + fprintf(stderr, "%s failed.\n", __func__); + return NULL; +} + +static int kae_rsa_init(void *vprsactx, void *vrsa, const OSSL_PARAM params[], int operation) +{ + PROV_RSA_SIG_CTX *priv = (PROV_RSA_SIG_CTX *)vprsactx; + + if (priv == NULL || vrsa == NULL) { + return OPENSSL_FAIL; + } + + priv->rsa = vrsa; + priv->operation = operation; + + /* Maximum for sign, auto for verify */ + priv->saltlen = RSA_PSS_SALTLEN_AUTO; + priv->min_saltlen = -1; + + switch (kae_rsa_test_flags(priv->rsa, RSA_FLAG_TYPE_MASK)) { + case RSA_FLAG_TYPE_RSA: + priv->pad_mode = RSA_PKCS1_PADDING; + break; + case RSA_FLAG_TYPE_RSASSAPSS: + priv->pad_mode = RSA_PKCS1_PSS_PADDING; + break; + default: + ERR_raise(ERR_LIB_RSA, PROV_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return OPENSSL_FAIL; + } + + return OPENSSL_SUCCESS; +} + +static int kae_signature_rsa_sign_init(void *vprsactx, void *vrsa, const OSSL_PARAM params[]) +{ + return kae_rsa_init(vprsactx, vrsa, params, EVP_PKEY_OP_SIGN); +} + +static int kae_signature_rsa_verify_init(void *vprsactx, void *vrsa, const OSSL_PARAM params[]) +{ + return kae_rsa_init(vprsactx, vrsa, params, EVP_PKEY_OP_VERIFY); +} + +#define KAE_ASN1_SEQUENCE 0x30 +#define ASN1_OCTET_STRING_ 0x04 +#define ASN1_NULL 0x05 +#define ASN1_OID 0x06 +/* SHA OIDs are of the form: (2 16 840 1 101 3 4 2 |n|) */ +#define ENCODE_DIGESTINFO_SHA(name, n, sz) \ + static const unsigned char digestinfo_##name##_der[] = {KAE_ASN1_SEQUENCE, \ + 0x11 + sz, \ + KAE_ASN1_SEQUENCE, \ + 0x0d, \ + ASN1_OID, \ + 0x09, \ + 2 * 40 + 16, \ + 0x86, \ + 0x48, \ + 1, \ + 101, \ + 3, \ + 4, \ + 2, \ + n, \ + ASN1_NULL, \ + 0x00, \ + ASN1_OCTET_STRING_, \ + sz}; + +/* MD2, MD4 and MD5 OIDs are of the form: (1 2 840 113549 2 |n|) */ +#define ENCODE_DIGESTINFO_MD(name, n, sz) \ + static const unsigned char digestinfo_##name##_der[] = {KAE_ASN1_SEQUENCE, \ + 0x10 + sz, \ + KAE_ASN1_SEQUENCE, \ + 0x0c, \ + ASN1_OID, \ + 0x08, \ + 1 * 40 + 2, \ + 0x86, \ + 0x48, \ + 0x86, \ + 0xf7, \ + 0x0d, \ + 2, \ + n, \ + ASN1_NULL, \ + 0x00, \ + ASN1_OCTET_STRING_, \ + sz}; + +/* SHA-1 (1 3 14 3 2 26) */ +static const unsigned char digestinfo_sha1_der[] = {KAE_ASN1_SEQUENCE, + 0x0d + SHA_DIGEST_LENGTH, + KAE_ASN1_SEQUENCE, + 0x09, + ASN1_OID, + 0x05, + 1 * 40 + 3, + 14, + 3, + 2, + 26, + ASN1_NULL, + 0x00, + ASN1_OCTET_STRING_, + SHA_DIGEST_LENGTH}; +ENCODE_DIGESTINFO_SHA(sha256, 0x01, SHA256_DIGEST_LENGTH) +ENCODE_DIGESTINFO_SHA(sha384, 0x02, SHA384_DIGEST_LENGTH) +ENCODE_DIGESTINFO_SHA(sha512, 0x03, SHA512_DIGEST_LENGTH) +ENCODE_DIGESTINFO_SHA(sha224, 0x04, SHA224_DIGEST_LENGTH) +ENCODE_DIGESTINFO_SHA(sha512_224, 0x05, SHA224_DIGEST_LENGTH) +ENCODE_DIGESTINFO_SHA(sha512_256, 0x06, SHA256_DIGEST_LENGTH) +ENCODE_DIGESTINFO_SHA(sha3_224, 0x07, SHA224_DIGEST_LENGTH) +ENCODE_DIGESTINFO_SHA(sha3_256, 0x08, SHA256_DIGEST_LENGTH) +ENCODE_DIGESTINFO_SHA(sha3_384, 0x09, SHA384_DIGEST_LENGTH) +ENCODE_DIGESTINFO_SHA(sha3_512, 0x0a, SHA512_DIGEST_LENGTH) + +#define MD_CASE(name) \ + case NID_##name: \ + *len = sizeof(digestinfo_##name##_der); \ + return digestinfo_##name##_der; + +#define MD_NID_CASE(name, sz) \ + case NID_##name: \ + return sz; + +const unsigned char *kae_rsa_digestinfo_encoding(int md_nid, size_t *len) +{ + switch (md_nid) { + MD_CASE(sha1) + MD_CASE(sha224) + MD_CASE(sha256) + MD_CASE(sha384) + MD_CASE(sha512) + MD_CASE(sha512_224) + MD_CASE(sha512_256) + MD_CASE(sha3_224) + MD_CASE(sha3_256) + MD_CASE(sha3_384) + MD_CASE(sha3_512) + default: + return NULL; + } +} + +static int digest_sz_from_nid(int nid) +{ + switch (nid) { + MD_NID_CASE(sha1, SHA_DIGEST_LENGTH) + MD_NID_CASE(sha224, SHA224_DIGEST_LENGTH) + MD_NID_CASE(sha256, SHA256_DIGEST_LENGTH) + MD_NID_CASE(sha384, SHA384_DIGEST_LENGTH) + MD_NID_CASE(sha512, SHA512_DIGEST_LENGTH) + MD_NID_CASE(sha512_224, SHA224_DIGEST_LENGTH) + MD_NID_CASE(sha512_256, SHA256_DIGEST_LENGTH) + MD_NID_CASE(sha3_224, SHA224_DIGEST_LENGTH) + MD_NID_CASE(sha3_256, SHA256_DIGEST_LENGTH) + MD_NID_CASE(sha3_384, SHA384_DIGEST_LENGTH) + MD_NID_CASE(sha3_512, SHA512_DIGEST_LENGTH) + default: + return 0; + } +} + +int encode_pkcs1(unsigned char **out, size_t *out_len, int type, const unsigned char *m, size_t m_len) +{ + size_t di_prefix_len, dig_info_len; + const unsigned char *di_prefix; + unsigned char *dig_info; + + if (type == NID_undef) { + + return 0; + } + di_prefix = kae_rsa_digestinfo_encoding(type, &di_prefix_len); + if (di_prefix == NULL) { + + return 0; + } + dig_info_len = di_prefix_len + m_len; + dig_info = OPENSSL_malloc(dig_info_len); + if (dig_info == NULL) { + + return 0; + } + memcpy(dig_info, di_prefix, di_prefix_len); + memcpy(dig_info + di_prefix_len, m, m_len); + + *out = dig_info; + *out_len = dig_info_len; + return 1; +} + +#define SSL_SIG_LENGTH 36 +int KAE_RSA_sign( + int type, const unsigned char *m, unsigned int m_len, unsigned char *sigret, unsigned int *siglen, RSA *rsa) +{ + int encrypt_len, ret = 0; + size_t encoded_len = 0; + unsigned char *tmps = NULL; + const unsigned char *encoded = NULL; + + /* Compute the encoded digest. */ + if (type == NID_md5_sha1) { + /* + * NID_md5_sha1 corresponds to the MD5/SHA1 combination in TLS 1.1 and + * earlier. It has no DigestInfo wrapper but otherwise is + * RSASSA-PKCS1-v1_5. + */ + if (m_len != SSL_SIG_LENGTH) { + + return 0; + } + encoded_len = SSL_SIG_LENGTH; + encoded = m; + } else { + if (!encode_pkcs1(&tmps, &encoded_len, type, m, m_len)) + goto err; + encoded = tmps; + } + + if (encoded_len + RSA_PKCS1_PADDING_SIZE > (size_t)kae_rsa_size(rsa)) { + goto err; + } + encrypt_len = hpre_rsa_private_encrypt((int)encoded_len, encoded, sigret, rsa, RSA_PKCS1_PADDING); + if (encoded_len == KAE_CRYPTO_FAIL) { + ret = KAE_CRYPTO_FAIL; + goto err; + } + if (encrypt_len <= 0) + goto err; + + *siglen = encrypt_len; + ret = 1; + +err: + OPENSSL_clear_free(tmps, encoded_len); + return ret; +} +#define rsa_pss_restricted(prsactx) (prsactx->min_saltlen != -1) + +int KAE_RSA_sign_ASN1_OCTET_STRING( + int type, const unsigned char *m, unsigned int m_len, unsigned char *sigret, unsigned int *siglen, RSA *rsa) +{ + ASN1_OCTET_STRING sig; + int i, j, ret = 1; + unsigned char *p, *s; + + sig.type = V_ASN1_OCTET_STRING; + sig.length = m_len; + sig.data = (unsigned char *)m; + + i = i2d_ASN1_OCTET_STRING(&sig, NULL); + j = kae_rsa_size(rsa); + if (i > (j - RSA_PKCS1_PADDING_SIZE)) { + return OPENSSL_FAIL; + } + s = OPENSSL_malloc((unsigned int)j + 1); + if (s == NULL) { + return OPENSSL_FAIL; + } + p = s; + i2d_ASN1_OCTET_STRING(&sig, &p); + i = hpre_rsa_private_encrypt(i, s, sigret, rsa, RSA_PKCS1_PADDING); + if (i == KAE_CRYPTO_FAIL) { + ret = i; + goto end; + } + + if (i <= 0) + ret = 0; + else + *siglen = i; + +end: + OPENSSL_clear_free(s, (unsigned int)j + 1); + return ret; +} + +static size_t rsa_get_md_size(const PROV_RSA_SIG_CTX *priv) +{ + if (priv->md != NULL) + return EVP_MD_size(priv->md); + return 0; +} + +static int kae_signature_rsa_sign( + void *vprsactx, unsigned char *sig, size_t *siglen, size_t sigsize, const unsigned char *tbs, size_t tbslen) +{ + PROV_RSA_SIG_CTX *priv = (PROV_RSA_SIG_CTX *)vprsactx; + size_t rsasize = kae_rsa_size(priv->rsa); + int ret; + + if (sig == NULL) { + *siglen = rsasize; + return OPENSSL_SUCCESS; + } + + if (sigsize < rsasize) { + ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_SIGNATURE_SIZE, "is %zu, should be at least %zu", sigsize, rsasize); + return OPENSSL_FAIL; + } + + size_t mdsize = rsa_get_md_size(priv); + if (mdsize == 0) { + ret = hpre_rsa_private_encrypt(tbslen, tbs, sig, priv->rsa, priv->pad_mode); + if (ret == KAE_CRYPTO_FAIL) { + goto soft; + } + } else { + if (tbslen != mdsize) { + goto err; + } + if (EVP_MD_is_a(priv->md, OSSL_DIGEST_NAME_MDC2)) { + unsigned int sltmp; + + if (priv->pad_mode != RSA_PKCS1_PADDING) { + + goto err; + } + ret = KAE_RSA_sign_ASN1_OCTET_STRING(0, tbs, tbslen, sig, &sltmp, priv->rsa); + if (ret == KAE_CRYPTO_FAIL) { + goto soft; + } + + if (ret <= 0) { + goto err; + } + ret = sltmp; + goto end; + } + + switch (priv->pad_mode) { + case RSA_X931_PADDING: + if ((size_t)kae_rsa_size(priv->rsa) < tbslen + 1) { + goto err; + } + if (!setup_tbuf(priv)) { + goto err; + } + memcpy(priv->tbuf, tbs, tbslen); + priv->tbuf[tbslen] = RSA_X931_hash_id(priv->mdnid); + ret = hpre_rsa_private_encrypt(tbslen + 1, priv->tbuf, sig, priv->rsa, RSA_X931_PADDING); + clean_tbuf(priv); + if (ret == KAE_CRYPTO_FAIL) { + goto soft; + } + break; + + case RSA_PKCS1_PADDING: { + unsigned int sltmp; + ret = KAE_RSA_sign(priv->mdnid, tbs, tbslen, sig, &sltmp, priv->rsa); + if (ret == KAE_CRYPTO_FAIL) { + goto soft; + } + if (ret <= 0) { + goto err; + } + ret = sltmp; + } break; + + case RSA_PKCS1_PSS_PADDING: + /* Check PSS restrictions */ + if (rsa_pss_restricted(priv)) { + switch (priv->saltlen) { + case RSA_PSS_SALTLEN_DIGEST: + if (priv->min_saltlen > EVP_MD_size(priv->md)) { + + goto err; + } + /* FALLTHRU */ + default: + if (priv->saltlen >= 0 && priv->saltlen < priv->min_saltlen) { + goto err; + } + break; + } + } + if (!setup_tbuf(priv)) + goto err; + if (!RSA_padding_add_PKCS1_PSS_mgf1( + priv->rsa, priv->tbuf, tbs, priv->md, priv->mgf1_md, priv->saltlen)) { + goto err; + } + ret = hpre_rsa_private_encrypt(kae_rsa_size(priv->rsa), priv->tbuf, sig, priv->rsa, RSA_NO_PADDING); + clean_tbuf(priv); + if (ret == KAE_CRYPTO_FAIL) { + goto soft; + } + break; + + default: + + goto err; + } + } + + if (ret == KAE_P_FAIL) { + goto soft; + } + + if (ret < 0) + return ret; + + *siglen = ret; + +end: + return OPENSSL_SUCCESS; + +err: + return OPENSSL_FAIL; + +soft: + fprintf(stderr, "switch to execute openssl software calculation.\n"); + if (!get_default_rsa_signature().sign) + return KAE_P_FAIL; + + return get_default_rsa_signature().sign(vprsactx, sig, siglen, sigsize, tbs, tbslen); +} + +int KAE_RSA_verify(int type, const unsigned char *m, unsigned int m_len, unsigned char *rm, size_t *prm_len, + const unsigned char *sigbuf, size_t siglen, RSA *rsa) +{ + int len, ret = 0; + size_t decrypt_len, encoded_len = 0; + unsigned char *decrypt_buf = NULL, *encoded = NULL; + + if (siglen != (size_t)kae_rsa_size(rsa)) { + return ret; + } + + /* Recover the encoded digest. */ + decrypt_buf = OPENSSL_malloc(siglen); + if (decrypt_buf == NULL) { + goto err; + } + + len = hpre_rsa_public_decrypt((int)siglen, sigbuf, decrypt_buf, rsa, RSA_PKCS1_PADDING); + if (len == KAE_CRYPTO_FAIL) { + OPENSSL_clear_free(decrypt_buf, siglen); + return KAE_CRYPTO_FAIL; + } + if (len <= 0) + goto err; + decrypt_len = len; + + if (type == NID_md5_sha1) { + /* + * NID_md5_sha1 corresponds to the MD5/SHA1 combination in TLS 1.1 and + * earlier. It has no DigestInfo wrapper but otherwise is + * RSASSA-PKCS1-v1_5. + */ + if (decrypt_len != SSL_SIG_LENGTH) { + + goto err; + } + + if (rm != NULL) { + memcpy(rm, decrypt_buf, SSL_SIG_LENGTH); + *prm_len = SSL_SIG_LENGTH; + } else { + if (m_len != SSL_SIG_LENGTH) { + + goto err; + } + + if (memcmp(decrypt_buf, m, SSL_SIG_LENGTH) != 0) { + + goto err; + } + } + } else if (type == NID_mdc2 && decrypt_len == 2 + 16 && decrypt_buf[0] == 0x04 && decrypt_buf[1] == 0x10) { + /* + * Oddball MDC2 case: signature can be OCTET STRING. check for correct + * tag and length octets. + */ + if (rm != NULL) { + memcpy(rm, decrypt_buf + 2, 16); + *prm_len = 16; + } else { + if (m_len != 16) { + + goto err; + } + + if (memcmp(m, decrypt_buf + 2, 16) != 0) { + + goto err; + } + } + } else { + /* + * If recovering the digest, extract a digest-sized output from the end + * of |decrypt_buf| for |encode_pkcs1|, then compare the decryption + * output as in a standard verification. + */ + if (rm != NULL) { + len = digest_sz_from_nid(type); + + if (len <= 0) + goto err; + m_len = (unsigned int)len; + if (m_len > decrypt_len) { + + goto err; + } + m = decrypt_buf + decrypt_len - m_len; + } + + /* Construct the encoded digest and ensure it matches. */ + if (!encode_pkcs1(&encoded, &encoded_len, type, m, m_len)) + goto err; + + if (encoded_len != decrypt_len || memcmp(encoded, decrypt_buf, encoded_len) != 0) { + + goto err; + } + + /* Output the recovered digest. */ + if (rm != NULL) { + memcpy(rm, m, m_len); + *prm_len = m_len; + } + } + + ret = 1; + +err: + OPENSSL_clear_free(encoded, encoded_len); + OPENSSL_clear_free(decrypt_buf, siglen); + return ret; +} + +static int kae_signature_rsa_verify( + void *vprsactx, const unsigned char *sig, size_t siglen, const unsigned char *tbs, size_t tbslen) +{ + PROV_RSA_SIG_CTX *priv = (PROV_RSA_SIG_CTX *)vprsactx; + size_t rslen = 0; + int ret = 0; + + if (priv->md != NULL) { + switch (priv->pad_mode) { + case RSA_PKCS1_PADDING: + ret = KAE_RSA_verify(priv->mdnid, tbs, tbslen, NULL, NULL, sig, siglen, priv->rsa); + if (ret == KAE_CRYPTO_FAIL) { + goto soft; + } + if (!ret) { + return OPENSSL_FAIL; + } + return OPENSSL_SUCCESS; + case RSA_X931_PADDING: + if (!setup_tbuf(priv)) + return OPENSSL_FAIL; + ret = kae_signature_rsa_verify_recover(priv, priv->tbuf, &rslen, 0, sig, siglen); + if (ret <= 0) + return OPENSSL_FAIL; + break; + case RSA_PKCS1_PSS_PADDING: { + size_t mdsize; + + /* + * We need to check this for the RSA_verify_PKCS1_PSS_mgf1() + * call + */ + mdsize = rsa_get_md_size(priv); + if (tbslen != mdsize) { + US_ERR("RSA verify fail, tbslen is not equal to mdsize"); + return OPENSSL_FAIL; + } + if (!setup_tbuf(priv)) + return OPENSSL_FAIL; + + ret = hpre_rsa_public_decrypt(siglen, sig, priv->tbuf, priv->rsa, RSA_NO_PADDING); + if (ret == KAE_CRYPTO_FAIL) { + goto soft; + } + if (ret <= 0) { + return OPENSSL_FAIL; + } + ret = + RSA_padding_add_PKCS1_PSS_mgf1(priv->rsa, priv->tbuf, tbs, priv->md, priv->mgf1_md, priv->saltlen); + if (ret <= 0) { + return OPENSSL_FAIL; + } + return OPENSSL_SUCCESS; + } + default: + US_ERR("RSA verify fail, only X.931, PKCS#1 v1.5 or PSS padding allowed"); + return OPENSSL_FAIL; + } + } else { + if (!setup_tbuf(priv)) + return OPENSSL_FAIL; + ret = hpre_rsa_public_decrypt(siglen, sig, priv->tbuf, priv->rsa, priv->pad_mode); + if (ret == KAE_CRYPTO_FAIL) { + goto soft; + } + if (ret <= 0) { + return OPENSSL_FAIL; + } + rslen = (size_t)ret; + } + + if ((rslen != tbslen) || memcmp(tbs, priv->tbuf, rslen)) + return OPENSSL_FAIL; + + return OPENSSL_SUCCESS; + +soft: + US_DEBUG("RSA verify fail, switch to execute openssl software calculation"); + if (!get_default_rsa_signature().verify) + return KAE_P_FAIL; + + return get_default_rsa_signature().verify(vprsactx, sig, siglen, tbs, tbslen); +} + +static int kae_signature_rsa_verify_recover_init(void *vprsactx, void *vrsa, const OSSL_PARAM params[]) +{ + if (!get_default_rsa_signature().verify_recover_init) + return KAE_P_FAIL; + + return get_default_rsa_signature().verify_recover_init(vprsactx, vrsa, params); +} + +static int kae_signature_rsa_verify_recover( + void *vprsactx, unsigned char *rout, size_t *routlen, size_t routsize, const unsigned char *sig, size_t siglen) +{ + if (!get_default_rsa_signature().verify_recover) + return KAE_P_FAIL; + + return get_default_rsa_signature().verify_recover(vprsactx, rout, routlen, routsize, sig, siglen); +} + +static int kae_signature_rsa_digest_sign_init(void *vprsactx, const char *mdname, void *vrsa, const OSSL_PARAM params[]) +{ + if (!get_default_rsa_signature().digest_sign_init) + return KAE_P_FAIL; + + return get_default_rsa_signature().digest_sign_init(vprsactx, mdname, vrsa, params); +} + +static int kae_signature_rsa_digest_sign_update(void *vprsactx, const unsigned char *data, size_t datalen) +{ + PROV_RSA_SIG_CTX *priv = (PROV_RSA_SIG_CTX *)vprsactx; + + if (priv == NULL || priv->mdctx == NULL) + return OPENSSL_FAIL; + + return EVP_DigestUpdate(priv->mdctx, data, datalen); +} + +static int kae_signature_rsa_digest_sign_final(void *vprsactx, unsigned char *sig, size_t *siglen, size_t sigsize) +{ + PROV_RSA_SIG_CTX *priv = (PROV_RSA_SIG_CTX *)vprsactx; + unsigned char digest[EVP_MAX_MD_SIZE]; + unsigned int dlen = 0; + + if (priv == NULL) + return OPENSSL_FAIL; + priv->flag_allow_md = 1; + + if (priv->mdctx == NULL) + return OPENSSL_FAIL; + /* + * If sig is NULL then we're just finding out the sig size. Other fields + * are ignored. Defer to rsa_sign. + */ + if (sig != NULL) { + /* + * The digests used here are all known (see rsa_get_md_nid()), so they + * should not exceed the internal buffer size of EVP_MAX_MD_SIZE. + */ + if (!EVP_DigestFinal_ex(priv->mdctx, digest, &dlen)) + return OPENSSL_FAIL; + } + + return kae_signature_rsa_sign(vprsactx, sig, siglen, sigsize, digest, (size_t)dlen); +} + +static int kae_signature_rsa_digest_verify_init( + void *vprsactx, const char *mdname, void *vrsa, const OSSL_PARAM params[]) +{ + if (!get_default_rsa_signature().digest_verify_init) + return KAE_P_FAIL; + + return get_default_rsa_signature().digest_verify_init(vprsactx, mdname, vrsa, params); +} + +static int kae_signature_rsa_digest_verify_update(void *vprsactx, const unsigned char *data, size_t datalen) +{ + if (!get_default_rsa_signature().digest_verify_update) + return KAE_P_FAIL; + + return get_default_rsa_signature().digest_verify_update(vprsactx, data, datalen); +} + +static int kae_signature_rsa_digest_verify_final(void *vprsactx, const unsigned char *sig, size_t siglen) +{ + PROV_RSA_SIG_CTX *priv = (PROV_RSA_SIG_CTX *)vprsactx; + unsigned char digest[EVP_MAX_MD_SIZE]; + unsigned int dlen = 0; + + if (priv == NULL) + return OPENSSL_FAIL; + + priv->flag_allow_md = 1; + if (priv->mdctx == NULL) + return OPENSSL_FAIL; + + /* + * The digests used here are all known (see rsa_get_md_nid()), so they + * should not exceed the internal buffer size of EVP_MAX_MD_SIZE. + */ + if (!EVP_DigestFinal_ex(priv->mdctx, digest, &dlen)) + return OPENSSL_FAIL; + + return kae_signature_rsa_verify(vprsactx, sig, siglen, digest, (size_t)dlen); +} + +static void kae_signature_rsa_freectx(void *vprsactx) +{ + PROV_RSA_SIG_CTX *priv = (PROV_RSA_SIG_CTX *)vprsactx; + + if (priv == NULL) + return; + + free_tbuf(priv); + OPENSSL_clear_free(priv, sizeof(*priv)); +} + +static void *kae_signature_rsa_dupctx(void *vprsactx) +{ + if (!get_default_rsa_signature().dupctx) + return NULL; + + return get_default_rsa_signature().dupctx(vprsactx); +} + +static int kae_signature_rsa_get_ctx_params(void *vprsactx, OSSL_PARAM *params) +{ + if (!get_default_rsa_signature().get_ctx_params) + return KAE_P_FAIL; + + return get_default_rsa_signature().get_ctx_params(vprsactx, params); +} + +static const OSSL_PARAM *kae_signature_rsa_gettable_ctx_params(ossl_unused void *vprsactx, ossl_unused void *provctx) +{ + if (!get_default_rsa_signature().gettable_ctx_params) + return NULL; + + return get_default_rsa_signature().gettable_ctx_params(vprsactx, provctx); +} + +static int kae_signature_rsa_set_ctx_params(void *vprsactx, const OSSL_PARAM params[]) +{ + + if (!get_default_rsa_signature().set_ctx_params) + return KAE_P_FAIL; + + return get_default_rsa_signature().set_ctx_params(vprsactx, params); +} + +static const OSSL_PARAM *kae_signature_rsa_settable_ctx_params(void *vprsactx, void *provctx) +{ + if (!get_default_rsa_signature().settable_ctx_params) + return NULL; + + return get_default_rsa_signature().settable_ctx_params(vprsactx, provctx); +} + +static int kae_signature_rsa_get_ctx_md_params(void *vprsactx, OSSL_PARAM *params) +{ + if (!get_default_rsa_signature().get_ctx_md_params) + return KAE_P_FAIL; + + return get_default_rsa_signature().get_ctx_md_params(vprsactx, params); +} + +static const OSSL_PARAM *kae_signature_rsa_gettable_ctx_md_params(void *vprsactx) +{ + if (!get_default_rsa_signature().gettable_ctx_md_params) + return NULL; + + return get_default_rsa_signature().gettable_ctx_md_params(vprsactx); +} + +static int kae_signature_rsa_set_ctx_md_params(void *vprsactx, const OSSL_PARAM params[]) +{ + if (!get_default_rsa_signature().set_ctx_md_params) + return KAE_P_FAIL; + + return get_default_rsa_signature().set_ctx_md_params(vprsactx, params); +} + +static const OSSL_PARAM *kae_signature_rsa_settable_ctx_md_params(void *vprsactx) +{ + if (!get_default_rsa_signature().settable_ctx_md_params) + return NULL; + + return get_default_rsa_signature().settable_ctx_md_params(vprsactx); +} \ No newline at end of file diff --git a/KAEOpensslProvider/src/provider/prov_nosva/prov_sm2.c b/KAEOpensslProvider/src/provider/prov_nosva/prov_sm2.c new file mode 100644 index 0000000000000000000000000000000000000000..0dcdc2c392f36b35928eacafcc3599307b71d4cf --- /dev/null +++ b/KAEOpensslProvider/src/provider/prov_nosva/prov_sm2.c @@ -0,0 +1,1801 @@ +/* + * Copyright 2025 Huawei Technologies Co.,Ltd.All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "prov.h" +#include "prov_pkey.h" +#include "internal/prov_packet.h" +#include "internal/prov_der_writer.h" +#include "../../adapter/nosva/algorithm/pkey/hpre_sm2.h" + +#define SM2_KEY_BYTES 32 +#define SM2_GET_SIGNLEN 1 +#define SM3_DIGEST_LENGTH 32 + +KAE_PKEY_KEYMGMT_DESCR(sm2, SM2); +KAE_PKEY_SIGNATURE_DESCR(sm2, SM2); +KAE_PKEY_ASYM_CIPHER_DESCR(sm2, SM2); + +static const OSSL_PARAM sm2_asym_cipher_known_settable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_ENGINE, NULL, 0), + OSSL_PARAM_END}; + +static const OSSL_PARAM sm2_asym_cipher_known_gettable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_DIGEST, NULL, 0), OSSL_PARAM_END}; + +static const OSSL_PARAM sm2_sig_known_settable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_SIGNATURE_PARAM_DIGEST_SIZE, NULL), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_DIST_ID, NULL, 0), + OSSL_PARAM_END}; + +static const OSSL_PARAM sm2_sig_known_gettable_ctx_params[] = { + OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_ALGORITHM_ID, NULL, 0), + OSSL_PARAM_size_t(OSSL_SIGNATURE_PARAM_DIGEST_SIZE, NULL), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_END}; + +enum { CTX_INIT_FAIL = -1, CTX_UNINIT, CTX_INIT_SUCC }; + +static void *kae_keymgmt_sm2_new(void *provctx) +{ + if (!get_default_sm2_keymgmt().new_fun) { + fprintf(stderr, "failed to get keymgmt new function\n"); + return NULL; + } + + return get_default_sm2_keymgmt().new_fun(provctx); +} + +static void kae_keymgmt_sm2_free(void *keydata) +{ + if (!get_default_sm2_keymgmt().free) { + fprintf(stderr, "failed to get keymgmt free function\n"); + return; + } + + get_default_sm2_keymgmt().free(keydata); +} + +static int kae_keymgmt_sm2_get_params(void *key, OSSL_PARAM params[]) +{ + if (!get_default_sm2_keymgmt().get_params) { + fprintf(stderr, "failed to get keymgmt get_params function\n"); + return KAE_P_FAIL; + } + + return get_default_sm2_keymgmt().get_params(key, params); +} + +static const OSSL_PARAM *kae_keymgmt_sm2_gettable_params(void *provctx) +{ + if (!get_default_sm2_keymgmt().gettable_params) { + fprintf(stderr, "failed to get keymgmt gettable_params function\n"); + return NULL; + } + + return get_default_sm2_keymgmt().gettable_params(provctx); +} + +static int kae_keymgmt_sm2_set_params(void *key, const OSSL_PARAM params[]) +{ + if (!get_default_sm2_keymgmt().set_params) { + fprintf(stderr, "failed to get keymgmt set_params function\n"); + return KAE_P_FAIL; + } + + return get_default_sm2_keymgmt().set_params(key, params); +} + +static const OSSL_PARAM *kae_keymgmt_sm2_settable_params(ossl_unused void *provctx) +{ + if (!get_default_sm2_keymgmt().settable_params) { + fprintf(stderr, "failed to get keymgmt settable_params function\n"); + return NULL; + } + + return get_default_sm2_keymgmt().settable_params(provctx); +} + +static void *kae_keymgmt_sm2_gen_init(void *provctx, int selection, const OSSL_PARAM params[]) +{ + if (!get_default_sm2_keymgmt().gen_init) { + fprintf(stderr, "failed to get keymgmt gen_init function\n"); + return NULL; + } + + return get_default_sm2_keymgmt().gen_init(provctx, selection, params); +} + +static int kae_keymgmt_sm2_gen_set_template(void *genctx, void *templates) +{ + if (!get_default_sm2_keymgmt().gen_set_template) { + fprintf(stderr, "failed to get keymgmt gen_set_template function\n"); + return KAE_P_FAIL; + } + + return get_default_sm2_keymgmt().gen_set_template(genctx, templates); +} + +static int kae_keymgmt_sm2_gen_set_params(void *genctx, const OSSL_PARAM params[]) +{ + if (!get_default_sm2_keymgmt().gen_set_params) { + fprintf(stderr, "failed to get keymgmt gen_set_params function\n"); + return KAE_P_FAIL; + } + + return get_default_sm2_keymgmt().gen_set_params(genctx, params); +} + +static const OSSL_PARAM *kae_keymgmt_sm2_gen_settable_params(ossl_unused void *genctx, ossl_unused void *provctx) +{ + if (!get_default_sm2_keymgmt().gen_settable_params) { + fprintf(stderr, "failed to get keymgmt gen_settable_params function\n"); + return NULL; + } + + return get_default_sm2_keymgmt().gen_settable_params(genctx, provctx); +} + +static void *kae_keymgmt_sm2_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg) +{ + // todo; use hardware? + if (!get_default_sm2_keymgmt().gen) { + fprintf(stderr, "failed to get keymgmt gen function\n"); + return NULL; + } + + return get_default_sm2_keymgmt().gen(genctx, osslcb, cbarg); +} + +static void kae_keymgmt_sm2_gen_cleanup(void *genctx) +{ + if (!get_default_sm2_keymgmt().gen_cleanup) { + fprintf(stderr, "failed to get keymgmt gen_cleanup function\n"); + return; + } + + get_default_sm2_keymgmt().gen_cleanup(genctx); +} + +static void *kae_keymgmt_sm2_load(const void *reference, size_t reference_sz) +{ + if (!get_default_sm2_keymgmt().load) { + fprintf(stderr, "failed to get keymgmt load function\n"); + return NULL; + } + + return get_default_sm2_keymgmt().load(reference, reference_sz); +} + +static int kae_keymgmt_sm2_has(const void *keydata, int selection) +{ + if (!get_default_sm2_keymgmt().has) { + fprintf(stderr, "failed to get keymgmt has function\n"); + return KAE_P_FAIL; + } + + return get_default_sm2_keymgmt().has(keydata, selection); +} + +static int kae_keymgmt_sm2_validate(const void *keydata, int selection, int checktype) +{ + if (!get_default_sm2_keymgmt().validate) { + fprintf(stderr, "failed to get keymgmt validate function\n"); + return KAE_P_FAIL; + } + + return get_default_sm2_keymgmt().validate(keydata, selection, checktype); +} + +static int kae_keymgmt_sm2_match(const void *keydata1, const void *keydata2, int selection) +{ + if (!get_default_sm2_keymgmt().match) { + fprintf(stderr, "failed to get keymgmt validate function\n"); + return KAE_P_FAIL; + } + + return get_default_sm2_keymgmt().match(keydata1, keydata2, selection); +} + +static int kae_keymgmt_sm2_import(void *keydata, int selection, const OSSL_PARAM params[]) +{ + if (!get_default_sm2_keymgmt().import) { + fprintf(stderr, "failed to get keymgmt import function\n"); + return KAE_P_FAIL; + } + + return get_default_sm2_keymgmt().import(keydata, selection, params); +} + +static const OSSL_PARAM *kae_keymgmt_sm2_import_types(int selection) +{ + if (!get_default_sm2_keymgmt().import_types) { + fprintf(stderr, "failed to get keymgmt import_types function\n"); + return NULL; + } + + return get_default_sm2_keymgmt().import_types(selection); +} + +static int kae_keymgmt_sm2_export(void *keydata, int selection, OSSL_CALLBACK *param_callback, void *cbarg) +{ + if (!get_default_sm2_keymgmt().export_fun) { + fprintf(stderr, "failed to get keymgmt export function\n"); + return KAE_P_FAIL; + } + + return get_default_sm2_keymgmt().export_fun(keydata, selection, param_callback, cbarg); +} + +static const OSSL_PARAM *kae_keymgmt_sm2_export_types(int selection) +{ + if (!get_default_sm2_keymgmt().export_types) { + fprintf(stderr, "failed to get keymgmt export_types function\n"); + return NULL; + } + + return get_default_sm2_keymgmt().export_types(selection); +} + +static void *kae_keymgmt_sm2_dup(const void *keydata_from, int selection) +{ + if (!get_default_sm2_keymgmt().dup) { + fprintf(stderr, "failed to get keymgmt dup function\n"); + return NULL; + } + + return get_default_sm2_keymgmt().dup(keydata_from, selection); +} + +static const char *kae_keymgmt_sm2_query_operation_name(int operation_id) +{ + if (!get_default_sm2_keymgmt().query_operation_name) { + fprintf(stderr, "failed to get keymgmt query_operation_name function\n"); + return NULL; + } + + return get_default_sm2_keymgmt().query_operation_name(operation_id); +} + +static void *kae_asym_cipher_sm2_newctx(void *provctx) +{ + PROV_SM2_ASYM_CTX *psm2ctx = OPENSSL_zalloc(sizeof(PROV_SM2_ASYM_CTX)); + SM2_PROV_CTX *smctx; + + if (psm2ctx == NULL) { + fprintf(stderr, "failed to alloc PROV_SM2_ASYM_CTX\n"); + return NULL; + } + + psm2ctx->libctx = prov_libctx_of(provctx); + + smctx = OPENSSL_zalloc(sizeof(SM2_PROV_CTX)); + if (smctx == NULL) { + fprintf(stderr, "failed to alloc sm2 prov ctx\n"); + goto free_psm2ctx; + } + + smctx->sm2_md = OPENSSL_zalloc(sizeof(SM2_MD_DATA)); + if (smctx->sm2_md == NULL) { + fprintf(stderr, "failed to alloc sm2 md data\n"); + goto free_smctx; + } + + /* Use SM3 in default, other digest can be set with set_ctx_params API. */ + smctx->sm2_md->mdsize = SM3_DIGEST_LENGTH; + + smctx->sm2_pd = OPENSSL_zalloc(sizeof(SM2_PKEY_DATA)); + if (smctx->sm2_pd == NULL) { + fprintf(stderr, "failed to alloc sm2 pkey data\n"); + goto free_sm2_md; + } + + smctx->do_soft = 0; + // smctx->hsmctx = OPENSSL_malloc(sizeof(hpre_sm2_priv_ctx)); + psm2ctx->sm2_pctx = smctx; + + return psm2ctx; + +free_sm2_md: + OPENSSL_free(smctx->sm2_md); +free_smctx: + OPENSSL_free(smctx); +free_psm2ctx: + OPENSSL_free(psm2ctx); + + return NULL; +} + +static void kae_prov_sm2_set_default_md(PROV_SM2_ASYM_CTX *psm2ctx) +{ + SM2_PROV_CTX *smctx = psm2ctx->sm2_pctx; + SM2_MD_DATA *smd = smctx->sm2_md; + + /* Set SM3 as default digest method */ + if (smd->alloc_md) + EVP_MD_free(smd->alloc_md); + smd->md = smd->alloc_md = EVP_MD_fetch(psm2ctx->libctx, "SM3", NULL); + smd->md_nid = NID_sm3; +} + +static int kae_asym_cipher_sm2_encrypt_init_sw(void *vpsm2ctx, void *vkey, const OSSL_PARAM params[]) +{ + if (!get_default_sm2_asym_cipher().encrypt_init) { + fprintf(stderr, "failed to get keymgmt encrypt init function\n"); + return KAE_P_FAIL; + } + + return get_default_sm2_asym_cipher().encrypt_init(vpsm2ctx, vkey, params); +} + +static int kae_asym_cipher_sm2_encrypt_init(void *vpsm2ctx, void *vkey, const OSSL_PARAM params[]) +{ + PROV_SM2_ASYM_CTX *psm2ctx = (PROV_SM2_ASYM_CTX *)vpsm2ctx; + SM2_PROV_CTX *smctx; + int ret; + + if (psm2ctx == NULL) { + fprintf(stderr, "invalid: psm2ctx is NULL\n"); + return KAE_P_FAIL; + } + + smctx = psm2ctx->sm2_pctx; + if (smctx == NULL) { + fprintf(stderr, "invalid: smctx is NULL\n"); + return KAE_P_FAIL; + } + + if (vkey == NULL || !EC_KEY_up_ref(vkey)) { + fprintf(stderr, "invalid: vkey is NULL\n"); + return KAE_P_FAIL; + } + EC_KEY_free(psm2ctx->ec_key); + psm2ctx->ec_key = vkey; + + /* Set default digest method as SM3 */ + kae_prov_sm2_set_default_md(psm2ctx); + + ret = kae_asym_cipher_sm2_set_ctx_params(psm2ctx, params); + if (ret == KAE_P_FAIL) { + fprintf(stderr, "failed to set_ctx_params\n"); + goto do_soft; + } + + // ret = kae_prov_asym_cipher_get_support_state(SIGNATURE_SM2); + // if (ret == KAE_P_FAIL) { + // fprintf(stderr, "failed to get hardware sm2 signature support\n"); + // goto do_soft; + // } + + // /* Init with KAE */ + // ret = kae_prov_ecc_init("sm2"); + // if (ret == KAE_P_FAIL) { + // fprintf(stderr, "failed to init sm2\n"); + // goto do_soft; + // } + + // smctx->hsmctx = calloc(1, sizeof(smctx->hsmctx)); // 不同于cipher的自动申请和回收pkey需要自己申请的 + if (!smctx->hsmctx) { + fprintf(stderr, "failed to alloc sm2 ctx\n"); + return OPENSSL_FAIL; + } + + ret = hpre_sm2_update_sess(smctx); + if (ret == KAE_P_FAIL) { + fprintf(stderr, "failed to update sess\n"); + goto do_soft; + } + + smctx->init_status = CTX_INIT_SUCC; + smctx->hsmctx->init_status = HPRE_SM2_INIT_SUCC; + return KAE_P_SUCCESS; + +do_soft: + return kae_asym_cipher_sm2_encrypt_init_sw(vpsm2ctx, vkey, params); +} + +static int kae_prov_sm2_encrypt_check( + PROV_SM2_ASYM_CTX *psm2ctx, unsigned char *out, size_t *outlen, const unsigned char *in, size_t inlen) +{ + SM2_PROV_CTX *smctx = psm2ctx->sm2_pctx; + const EVP_MD *md; + + if (smctx == NULL || smctx->hsmctx == NULL) { + fprintf(stderr, "smctx or hsmctx NULL\n"); + return KAE_P_FAIL; + } + + if (smctx->init_status != CTX_INIT_SUCC) { + fprintf(stderr, "sm2 ctx init failed\n"); + return KAE_P_FAIL; + } + + /* + * As we have already set md method in init, if not set, will use default digest. + * The md is unlikey to be NULL here, so if the md is still NULL when encrypt start, + * just return fail. + */ + md = smctx->sm2_md->md; + if (md == NULL) { + fprintf(stderr, "failed to get md method\n"); + return KAE_P_FAIL; + } + + // c3_size = EVP_MD_size(md); + // if (c3_size <= 0) { + // fprintf(stderr, "c3 size error\n"); + // return KAE_P_FAIL; + // } + + // if (inlen > UINT_MAX) { + // fprintf(stderr, "invalid: inlen is out of range\n"); + // return KAE_P_FAIL; + // } + + return KAE_P_SUCCESS; +} + +static int kae_prov_sm2_encrypt_sw( + PROV_SM2_ASYM_CTX *vpsm2ctx, unsigned char *out, size_t *outlen, const unsigned char *in, size_t inlen) +{ + if (!get_default_sm2_asym_cipher().encrypt) { + fprintf(stderr, "fail to get sm2 asym encrypt function.\n"); + return KAE_P_FAIL; + } + + return get_default_sm2_asym_cipher().encrypt(vpsm2ctx, out, outlen, 0, in, inlen); +} + +static int kae_asym_cipher_sm2_encrypt( + void *vpsm2ctx, unsigned char *out, size_t *outlen, size_t outsize, const unsigned char *in, size_t inlen) +{ + PROV_SM2_ASYM_CTX *psm2ctx = (PROV_SM2_ASYM_CTX *)vpsm2ctx; + int ret; + + if (psm2ctx == NULL) { + fprintf(stderr, "invalid: psm2ctx is NULL\n"); + return KAE_P_FAIL; + } + + ret = kae_prov_sm2_encrypt_check(psm2ctx, out, outlen, in, inlen); + if (ret == KAE_P_FAIL) + return ret; + + // /* If out is NULL, compute outlen size and return */ + // if (out == NULL) { + // smctx = psm2ctx->sm2_pctx; + // smd = smctx->sm2_md; + // md = (const EVP_MD *)smd->md; + // if (!kae_prov_sm2_ciphertext_size(psm2ctx->ec_key, md, inlen, outlen)) + // return KAE_P_FAIL; + // else + // return KAE_P_SUCCESS; + // } + + ret = hpre_sm2_encrypt(psm2ctx, out, outlen, in, inlen); + if (ret == OPENSSL_FAIL && psm2ctx->sm2_pctx->do_soft == 1) { + return kae_prov_sm2_encrypt_sw(psm2ctx, out, outlen, in, inlen); + } + return OPENSSL_SUCCESS; +} + +static int kae_asym_cipher_sm2_decrypt_init(void *vpsm2ctx, void *vkey, const OSSL_PARAM params[]) +{ + return kae_asym_cipher_sm2_encrypt_init(vpsm2ctx, vkey, params); +} + +static int kae_prov_sm2_decrypt_check( + SM2_PROV_CTX *smctx, unsigned char *out, size_t *outlen, const unsigned char *in, size_t inlen) +{ + if (smctx == NULL || smctx->hsmctx == NULL) { + fprintf(stderr, "smctx or sess NULL\n"); + return KAE_P_FAIL; + } + + if (smctx->init_status != CTX_INIT_SUCC) { + fprintf(stderr, "sm2 ctx init failed\n"); + return KAE_P_FAIL; + } + + // /* + // * As we have already set md method in init, if not set, will use default digest. + // * The md is unlikey to be NULL here, so if the md is still NULL when encrypt start, + // * just return fail. + // */ + // md = smctx->sm2_md->md; + // if (md == NULL) { + // fprintf(stderr, "failed to get md method\n"); + // return KAE_P_FAIL; + // } + + // hash_size = EVP_MD_size(md); + // if (hash_size <= 0) { + // fprintf(stderr, "hash size = %d error\n", hash_size); + // return KAE_P_FAIL; + // } + + return KAE_P_SUCCESS; +} + +static int kae_asym_cipher_sm2_decrypt( + void *vpsm2ctx, unsigned char *out, size_t *outlen, size_t outsize, const unsigned char *in, size_t inlen) +{ + PROV_SM2_ASYM_CTX *psm2ctx = (PROV_SM2_ASYM_CTX *)vpsm2ctx; + SM2_PROV_CTX *smctx; + int ret; + + if (psm2ctx == NULL) { + fprintf(stderr, "invalid: psm2ctx is NULL\n"); + return KAE_P_FAIL; + } + + smctx = psm2ctx->sm2_pctx; + ret = kae_prov_sm2_decrypt_check(smctx, out, outlen, in, inlen); + if (ret == KAE_P_FAIL) + return ret; + + // if (out == NULL) { + // if (!kae_prov_sm2_plaintext_size(in, inlen, outlen)) + // return KAE_P_FAIL; + // else + // return KAE_P_SUCCESS; + // } + + return hpre_sm2_decrypt(psm2ctx, out, outlen, in, inlen); +} + +static void kae_asym_cipher_sm2_freectx(void *vpsm2ctx) +{ + PROV_SM2_ASYM_CTX *psm2ctx = (PROV_SM2_ASYM_CTX *)vpsm2ctx; + SM2_PROV_CTX *smctx; + + if (psm2ctx == NULL) + return; + + smctx = psm2ctx->sm2_pctx; + if (smctx) { + if (smctx->sm2_md) + OPENSSL_free(smctx->sm2_md); + + if (smctx->sm2_pd) + OPENSSL_free(smctx->sm2_pd); + OPENSSL_free(smctx); + + if (smctx->sm2_md->mdctx) + EVP_MD_CTX_free(smctx->sm2_md->mdctx); + } + + if (psm2ctx->ec_key) + EC_KEY_free(psm2ctx->ec_key); + + OPENSSL_free(psm2ctx); +} + +static void *kae_asym_cipher_sm2_dupctx(void *vpsm2ctx) +{ + PROV_SM2_ASYM_CTX *srcctx = (PROV_SM2_ASYM_CTX *)vpsm2ctx; + SM2_PROV_CTX *dst_smctx, *src_smctx; + PROV_SM2_ASYM_CTX *dstctx; + + if (srcctx == NULL) { + fprintf(stderr, "src ctx is NULL\n"); + return NULL; + } + + src_smctx = srcctx->sm2_pctx; + if (src_smctx == NULL) { + fprintf(stderr, "src_smctx is NULL\n"); + return NULL; + } + + if (src_smctx->sm2_md == NULL) { + fprintf(stderr, "src_smctx is NULL\n"); + return NULL; + } + + dstctx = OPENSSL_zalloc(sizeof(PROV_SM2_ASYM_CTX)); + if (dstctx == NULL) { + fprintf(stderr, "failed to alloc dst ctx\n"); + return NULL; + } + *dstctx = *srcctx; + + dst_smctx = OPENSSL_zalloc(sizeof(SM2_PROV_CTX)); + if (dst_smctx == NULL) { + fprintf(stderr, "failed to alloc dst_smctx\n"); + goto free; + } + + dst_smctx->sm2_md = OPENSSL_zalloc(sizeof(SM2_MD_DATA)); + if (dst_smctx->sm2_md == NULL) { + fprintf(stderr, "failed to alloc dst_smd\n"); + goto free; + } + + if (dstctx->ec_key != NULL && !EC_KEY_up_ref(dstctx->ec_key)) { + fprintf(stderr, "failed to check dstctx key reference\n"); + goto free; + } + + if (dst_smctx->sm2_md->alloc_md && !EVP_MD_up_ref(dst_smctx->sm2_md->alloc_md)) { + fprintf(stderr, "failed to check alloc_md reference\n"); + goto free; + } + + dst_smctx->sm2_md->md = src_smctx->sm2_md->md; + dst_smctx->sm2_md->alloc_md = src_smctx->sm2_md->alloc_md; + + dstctx->sm2_pctx = dst_smctx; + + return dstctx; + +free: + kae_asym_cipher_sm2_freectx(dstctx); + return NULL; +} + +static int kae_asym_cipher_sm2_get_ctx_params(void *vpsm2ctx, OSSL_PARAM *params) +{ + PROV_SM2_ASYM_CTX *psm2ctx = (PROV_SM2_ASYM_CTX *)vpsm2ctx; + SM2_PROV_CTX *smctx; + SM2_MD_DATA *smd; + OSSL_PARAM *p; + EVP_MD *md; + + if (psm2ctx == NULL) { + fprintf(stderr, "failed to get psm2ctx\n"); + return KAE_P_FAIL; + } + + smctx = psm2ctx->sm2_pctx; + if (smctx == NULL) { + fprintf(stderr, "failed to get smctx\n"); + return KAE_P_FAIL; + } + + smd = smctx->sm2_md; + if (smd == NULL) { + fprintf(stderr, "failed to get sm2 md\n"); + return KAE_P_FAIL; + } + + if (params == NULL) { + fprintf(stderr, "params is NULL\n"); + return KAE_P_FAIL; + } + + p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_DIGEST); + if (p != NULL) { + md = smd->md; + if (!OSSL_PARAM_set_utf8_string(p, md == NULL ? "" : EVP_MD_get0_name(md))) { + fprintf(stderr, "failed to set utf8 string\n"); + return KAE_P_FAIL; + } + smd->md_nid = EVP_MD_type(md); + } else { + return KAE_P_FAIL; + } + + return KAE_P_SUCCESS; +} + +static const OSSL_PARAM *kae_asym_cipher_sm2_gettable_ctx_params(ossl_unused void *vpsm2ctx, ossl_unused void *provctx) +{ + return sm2_asym_cipher_known_gettable_ctx_params; +} + +static EVP_MD *kae_prov_load_digest_from_params(SM2_MD_DATA *smd, const OSSL_PARAM params[], OSSL_LIB_CTX *ctx) +{ + const char *propquery = NULL; + const OSSL_PARAM *p; + + /* Load common param properties, p can be NULL */ + p = OSSL_PARAM_locate_const(params, OSSL_ALG_PARAM_PROPERTIES); + if (p) { + if (p->data_type != OSSL_PARAM_UTF8_STRING) { + fprintf(stderr, "data_type != OSSL_PARAM_UTF8_STRING\n"); + return NULL; + } + propquery = p->data; + } + + /* Load digest related params */ + p = OSSL_PARAM_locate_const(params, OSSL_ALG_PARAM_DIGEST); + if (p) { + if (p->data_type != OSSL_PARAM_UTF8_STRING) { + fprintf(stderr, "data_type != OSSL_PARAM_UTF8_STRING\n"); + return NULL; + } + } else { + /* If digest related params is NULL, no need to set digest */ + return NULL; + } + + /* Fetch digest */ + EVP_MD_free(smd->alloc_md); + smd->md = smd->alloc_md = EVP_MD_fetch(ctx, p->data, propquery); + if (smd->md == NULL) { + fprintf(stderr, "failed to fetch MD method\n"); + return NULL; + } + + return smd->md; +} + +static int kae_asym_cipher_sm2_set_ctx_params_sw(void *vpsm2ctx, const OSSL_PARAM params[]) +{ + if (!get_default_sm2_asym_cipher().set_ctx_params) { + fprintf(stderr, "fail to get sm2 asym set_ctx_params function.\n"); + return KAE_P_FAIL; + } + return get_default_sm2_asym_cipher().set_ctx_params(vpsm2ctx, params); +} + +static int kae_asym_cipher_sm2_set_ctx_params(void *vpsm2ctx, const OSSL_PARAM params[]) +{ + PROV_SM2_ASYM_CTX *psm2ctx = (PROV_SM2_ASYM_CTX *)vpsm2ctx; + SM2_PROV_CTX *smctx; + SM2_MD_DATA *smd; + int ret; + + if (psm2ctx == NULL) { + fprintf(stderr, "invalid: sm2 ctx is NULL\n"); + return KAE_P_FAIL; + } + + /* No need to set */ + if (params == NULL) + return KAE_P_SUCCESS; + + smctx = psm2ctx->sm2_pctx; + if (smctx == NULL) { + fprintf(stderr, "invalid: smctx is NULL\n"); + return KAE_P_FAIL; + } + + /* Set digest method */ + smd = smctx->sm2_md; + if (smd == NULL) { + fprintf(stderr, "invalid: sm2 md is NULL\n"); + return KAE_P_FAIL; + } + + smd->md = kae_prov_load_digest_from_params(smctx->sm2_md, params, psm2ctx->libctx); + if (smd->md == NULL) { + fprintf(stderr, "failed to set digest with set_ctx_params\n"); + return KAE_P_FAIL; + } + smd->md_nid = EVP_MD_type(smd->md); + + /* If not init, do not need to update session, just set the data before */ + if (smctx->init_status == CTX_INIT_SUCC) { + ret = hpre_sm2_update_sess(smctx); + if (ret == KAE_P_FAIL) { + fprintf(stderr, "failed to update sess\n"); + goto do_soft; + } + } + + return KAE_P_SUCCESS; + +do_soft: + return kae_asym_cipher_sm2_set_ctx_params_sw(vpsm2ctx, params); +} + +static const OSSL_PARAM *kae_asym_cipher_sm2_settable_ctx_params(ossl_unused void *vpsm2ctx, ossl_unused void *provctx) +{ + return sm2_asym_cipher_known_settable_ctx_params; +} + +static void *kae_signature_sm2_newctx(void *provctx, const char *propq) +{ + PROV_SM2_SIGN_CTX *psm2ctx = OPENSSL_zalloc(sizeof(PROV_SM2_SIGN_CTX)); + SM2_PROV_CTX *smctx; + + if (psm2ctx == NULL) { + fprintf(stderr, "failed to alloc sm2 signature ctx\n"); + return NULL; + } + /* The libctx maybe NULL, if libctx is NULL, will use default ctx. */ + psm2ctx->libctx = prov_libctx_of(provctx); + + smctx = OPENSSL_zalloc(sizeof(SM2_PROV_CTX)); + if (smctx == NULL) { + fprintf(stderr, "failed to alloc sm2 prov ctx\n"); + goto free_ctx; + } + + smctx->sm2_pd = OPENSSL_zalloc(sizeof(SM2_PKEY_DATA)); + if (smctx->sm2_pd == NULL) { + fprintf(stderr, "failed to alloc sm2 pkey data\n"); + goto free_smctx; + } + + smctx->sm2_md = OPENSSL_zalloc(sizeof(SM2_MD_DATA)); + if (smctx->sm2_md == NULL) { + fprintf(stderr, "failed to alloc sm2 md data\n"); + goto free_pd; + } + + /* + * Use SM3 for digest method in default, other digest algs + * can be set with set_ctx_params API. + */ + smctx->sm2_md->mdsize = SM3_DIGEST_LENGTH; + smctx->sm2_md->md_nid = NID_sm3; + strcpy(psm2ctx->mdname, OSSL_DIGEST_NAME_SM3); + smctx->sm2_md->mdctx = EVP_MD_CTX_new(); + if (smctx->sm2_md->mdctx == NULL) { + fprintf(stderr, "failed to alloc sm2 mdctx\n"); + goto free_md; + } + + smctx->do_soft = 0; + // smctx->hsmctx = OPENSSL_malloc(sizeof(hpre_sm2_priv_ctx)); + psm2ctx->sm2_pctx = smctx; + + if (propq) { + psm2ctx->propq = OPENSSL_strdup(propq); + if (psm2ctx->propq == NULL) { + fprintf(stderr, "failed to dup propq\n"); + goto free_mdctx; + } + } + + return psm2ctx; + +free_mdctx: + EVP_MD_CTX_free(smctx->sm2_md->mdctx); +free_md: + OPENSSL_free(smctx->sm2_md); +free_pd: + OPENSSL_free(smctx->sm2_pd); +free_smctx: + OPENSSL_free(smctx); +free_ctx: + OPENSSL_free(psm2ctx); + return NULL; +} + +static int kae_signature_sm2_sign_init_sw(void *vpsm2ctx, void *ec, const OSSL_PARAM params[]) +{ + if (!get_default_sm2_signature().sign_init) { + fprintf(stderr, "fail to get sm2 sign_init function.\n"); + return KAE_P_FAIL; + } + return get_default_sm2_signature().sign_init(vpsm2ctx, ec, params); +} + +static int kae_signature_sm2_sign_init(void *vpsm2ctx, void *ec, const OSSL_PARAM params[]) +{ + PROV_SM2_SIGN_CTX *psm2ctx = (PROV_SM2_SIGN_CTX *)vpsm2ctx; + int ret; + + if (psm2ctx == NULL) { + fprintf(stderr, "invalid: vpsm2ctx is NULL\n"); + return KAE_P_FAIL; + } + + if (ec == NULL && psm2ctx->ec_key == NULL) { + fprintf(stderr, "invalid: sm2 key is NULL\n"); + return KAE_P_FAIL; + } + + if (ec) { + if (!EC_KEY_up_ref(ec)) { + fprintf(stderr, "failed to EC_KEY_up_ref\n"); + return KAE_P_FAIL; + } + EC_KEY_free(psm2ctx->ec_key); + psm2ctx->ec_key = (EC_KEY *)ec; + } + + if (psm2ctx->sm2_pctx == NULL) { + fprintf(stderr, "failed to get smctx\n"); + return KAE_P_FAIL; + } + + /* openssl dgst tool will call sign_init twice, avoid repeated initialization */ + if (psm2ctx->sm2_pctx->init_status == CTX_INIT_SUCC) + return KAE_P_SUCCESS; + + ret = kae_signature_sm2_set_ctx_params((void *)psm2ctx, params); + if (ret == KAE_P_FAIL) { + fprintf(stderr, "failed to set sm2 sig ctx params\n"); + goto do_soft; + } + + // ret = kae_prov_signature_get_support_state(SIGNATURE_SM2); + // if (ret == KAE_P_FAIL) { + // fprintf(stderr, "failed to get hardware sm2 signature support\n"); + // goto do_soft; + // } + + // /* Init with KAE */ + // ret = kae_prov_ecc_init("sm2"); + // if (ret == KAE_P_FAIL) { + // fprintf(stderr, "failed to init sm2\n"); + // goto do_soft; + // } + + ret = hpre_sm2_update_sess(psm2ctx->sm2_pctx); + + if (ret == KAE_P_FAIL) { + fprintf(stderr, "failed to update sess in sign init\n"); + goto do_soft; + } + + psm2ctx->sm2_pctx->init_status = CTX_INIT_SUCC; + psm2ctx->sm2_pctx->hsmctx->init_status = HPRE_SM2_INIT_SUCC; + return KAE_P_SUCCESS; + +do_soft: + return kae_signature_sm2_sign_init_sw(vpsm2ctx, ec, params); +} + +static int kae_signature_sm2_verify_init(void *vpsm2ctx, void *ec, const OSSL_PARAM params[]) +{ + return kae_signature_sm2_sign_init(vpsm2ctx, ec, params); +} + +static int kae_prov_sm2_check_tbs_params(PROV_SM2_SIGN_CTX *psm2ctx, const unsigned char *tbs, size_t tbslen) +{ + SM2_PROV_CTX *smctx = psm2ctx->sm2_pctx; + + if (smctx == NULL) { + fprintf(stderr, "invalid: ctx is NULL\n"); + return KAE_P_FAIL; + } + + if (smctx->hsmctx == NULL) { + fprintf(stderr, "invalid: smctx->sess is NULL\n"); + return KAE_P_FAIL; + } + + if (smctx->init_status != CTX_INIT_SUCC) { + fprintf(stderr, "sm2 ctx init did not init\n"); + return KAE_P_FAIL; + } + + if (smctx->sm2_md == NULL) { + fprintf(stderr, "invalid: sm2_md is NULL\n"); + return KAE_P_FAIL; + } + + if (smctx->sm2_md->mdsize != 0 && tbslen != smctx->sm2_md->mdsize) { + fprintf(stderr, "invalid: tbslen(%zu) != mdsize(%zu)\n", tbslen, smctx->sm2_md->mdsize); + return KAE_P_FAIL; + } + + // if (tbslen > SM2_KEY_BYTES) { + // fprintf(stderr, "invalid: tbslen(%zu) > SM2_KEY_BYTES(32)\n", tbslen); + // return KAE_P_FAIL; + // } + + // if (kae_prov_is_all_zero(tbs, tbslen)) { + // fprintf(stderr, "invalid: tbs all zero\n"); + // return KAE_P_FAIL; + // } + + return KAE_P_SUCCESS; +} + +static int kae_signature_sm2_sign_sw( + void *vpsm2ctx, unsigned char *sig, size_t *siglen, size_t sigsize, const unsigned char *tbs, size_t tbslen) +{ + if (!get_default_sm2_signature().sign) { + fprintf(stderr, "fail to get sm2 sign function.\n"); + return KAE_P_FAIL; + } + + return get_default_sm2_signature().sign(vpsm2ctx, sig, siglen, sigsize, tbs, tbslen); +} + +static int kae_signature_sm2_sign( + void *vpsm2ctx, unsigned char *sig, size_t *siglen, size_t sigsize, const unsigned char *tbs, size_t tbslen) +{ + PROV_SM2_SIGN_CTX *psm2ctx = (PROV_SM2_SIGN_CTX *)vpsm2ctx; + int ret, ecsize; + size_t sltmp; + + if (psm2ctx == NULL) { + fprintf(stderr, "invalid: psm2ctx is NULL\n"); + return KAE_P_FAIL; + } + + if (psm2ctx->ec_key == NULL) { + fprintf(stderr, "invalid: sm2 ec is NULL\n"); + return KAE_P_FAIL; + } + + ecsize = ECDSA_size(psm2ctx->ec_key); + if (ecsize <= 0) { + fprintf(stderr, "ecsize error %d\n", ecsize); + return KAE_P_FAIL; + } + + /* + * If 'sig' is NULL, users can use sm2_decrypt API to obtain the valid 'siglen' first, + * then users use the value of 'signlen' to alloc the memory of 'sig' and call the + * sm2_decrypt API a second time to do the decryption task. + */ + if (sig == NULL) { + *siglen = (size_t)ecsize; + return SM2_GET_SIGNLEN; + } + + if (sigsize < (size_t)ecsize) { + fprintf(stderr, "sigsize(%zu) < ecsize(%d)\n", sigsize, ecsize); + goto do_soft; + } + + ret = kae_prov_sm2_check_tbs_params(psm2ctx, tbs, tbslen); + if (ret == KAE_P_FAIL) { + fprintf(stderr, "failed to check sm2 signature params\n"); + goto do_soft; + } + + ret = hpre_sm2_sign(psm2ctx, sig, &sltmp, tbs, tbslen); + if (ret == OPENSSL_FAIL && psm2ctx->sm2_pctx->do_soft == 1) { + fprintf(stderr, "failed to do sm2 sign\n"); + goto do_soft; + } + + *siglen = sltmp; + + return KAE_P_SUCCESS; + +do_soft: + + return kae_signature_sm2_sign_sw(vpsm2ctx, sig, siglen, sigsize, tbs, tbslen); +} + +static int kae_signature_sm2_verify_sw( + void *vpsm2ctx, const unsigned char *sig, size_t siglen, const unsigned char *tbs, size_t tbslen) +{ + if (!get_default_sm2_signature().verify) { + fprintf(stderr, "fail to get sm2 verify function.\n"); + return KAE_P_FAIL; + } + return get_default_sm2_signature().verify(vpsm2ctx, sig, siglen, tbs, tbslen); +} + +static int kae_signature_sm2_verify( + void *vpsm2ctx, const unsigned char *sig, size_t siglen, const unsigned char *tbs, size_t tbslen) +{ + PROV_SM2_SIGN_CTX *psm2ctx = (PROV_SM2_SIGN_CTX *)vpsm2ctx; + int ret; + + if (psm2ctx == NULL) { + fprintf(stderr, "invalid: psm2ctx is NULL\n"); + return KAE_P_FAIL; + } + + ret = kae_prov_sm2_check_tbs_params(psm2ctx, tbs, tbslen); + if (ret == KAE_P_FAIL) { + fprintf(stderr, "failed to check sm2 verify params\n"); + goto do_soft; + } + + ret = hpre_sm2_verify(psm2ctx, sig, siglen, tbs, tbslen); + if (ret == KAE_P_FAIL) { + fprintf(stderr, "failed to do sm2 verify\n"); + goto do_soft; + } + + return KAE_P_SUCCESS; + +do_soft: + return kae_signature_sm2_verify_sw(vpsm2ctx, sig, siglen, tbs, tbslen); +} + +static int kae_signature_sm2_verify_recover_init(void *vpsm2ctx, void *vsm2, const OSSL_PARAM params[]) +{ + // 软算的也没有实现 + return KAE_P_SUCCESS; +} + +static int kae_signature_sm2_verify_recover( + void *vpsm2ctx, unsigned char *rout, size_t *routlen, size_t routsize, const unsigned char *sig, size_t siglen) +{ + return KAE_P_SUCCESS; +} + +static int kae_prov_sm2_sig_set_mdname(PROV_SM2_SIGN_CTX *psm2ctx, const char *mdname) +{ + SM2_PROV_CTX *smctx; + + /* If mdname is NULL, no need to set, just return */ + if (mdname == NULL) + return KAE_P_SUCCESS; + + /* 'psm2ctx' has already been checked when call this function, no need to check again */ + smctx = psm2ctx->sm2_pctx; + if (smctx == NULL) { + fprintf(stderr, "invalid: smctx is NULL\n"); + return KAE_P_FAIL; + } + + if (smctx->sm2_md == NULL) { + fprintf(stderr, "invalid: smctx->sm2_md is NULL\n"); + return KAE_P_FAIL; + } + + if (smctx->sm2_md->md == NULL) { + smctx->sm2_md->md = EVP_MD_fetch(psm2ctx->libctx, psm2ctx->mdname, psm2ctx->propq); + if (smctx->sm2_md->md == NULL) { + fprintf(stderr, "failed to fetch digest method\n"); + return KAE_P_FAIL; + } + } + + if (strlen(mdname) >= sizeof(psm2ctx->mdname) || !EVP_MD_is_a(smctx->sm2_md->md, mdname)) { + fprintf(stderr, "failed to check mdname, digest=%s\n", mdname); + return KAE_P_FAIL; + } + + OPENSSL_strlcpy(psm2ctx->mdname, mdname, sizeof(psm2ctx->mdname)); + + return KAE_P_SUCCESS; +} + +static int kae_signature_sm2_digest_sign_init(void *vpsm2ctx, const char *mdname, void *ec, const OSSL_PARAM params[]) +{ + PROV_SM2_SIGN_CTX *psm2ctx = (PROV_SM2_SIGN_CTX *)vpsm2ctx; + SM2_PROV_CTX *smctx; + int md_nid; + WPACKET pkt; + + if (!kae_signature_sm2_sign_init(vpsm2ctx, ec, params) || !kae_prov_sm2_sig_set_mdname(psm2ctx, mdname)) + return KAE_P_FAIL; + + smctx = psm2ctx->sm2_pctx; + + if (smctx->sm2_md->mdctx == NULL) { + smctx->sm2_md->mdctx = EVP_MD_CTX_new(); + if (unlikely(smctx->sm2_md->mdctx == NULL)) { + fprintf(stderr, "failed to EVP_MD_CTX_new\n"); + return KAE_P_FAIL; + } + } + + /* + * We do not care about DER writing errors. + * All it really means is that for some reason, there's no + * AlgorithmIdentifier to be had, but the operation itself is + * still valid, just as long as it's not used to construct + * anything that needs an AlgorithmIdentifier. + */ + md_nid = EVP_MD_get_type(smctx->sm2_md->md); + smctx->sm2_md->md_nid = md_nid; + psm2ctx->aid_len = 0; + if (WPACKET_init_der(&pkt, psm2ctx->aid_buf, sizeof(psm2ctx->aid_buf)) && + ossl_DER_w_algorithmIdentifier_SM2_with_MD(&pkt, -1, psm2ctx->ec_key, md_nid) && WPACKET_finish(&pkt)) { + WPACKET_get_total_written(&pkt, &psm2ctx->aid_len); + psm2ctx->aid = WPACKET_get_curr(&pkt); + } + WPACKET_cleanup(&pkt); + + if (!EVP_DigestInit_ex2(smctx->sm2_md->mdctx, smctx->sm2_md->md, params)) { + fprintf(stderr, "failed to do digest init\n"); + EVP_MD_CTX_free(smctx->sm2_md->mdctx); + return KAE_P_FAIL; + } + + psm2ctx->flag_compute_z_digest = 1; + + return KAE_P_SUCCESS; +} + +static int kae_prov_sm2_check_md_params(SM2_PROV_CTX *smctx) +{ + if (smctx->sm2_md == NULL) { + fprintf(stderr, "invalid: sm2_md is NULL\n"); + return KAE_P_FAIL; + } + + if (smctx->sm2_md->md == NULL) { + fprintf(stderr, "invalid: md is NULL\n"); + return KAE_P_FAIL; + } + + if (smctx->sm2_md->mdctx == NULL) { + fprintf(stderr, "invalid: mdctx is NULL\n"); + return KAE_P_FAIL; + } + + return KAE_P_SUCCESS; +} + +static int sm2_sig_compute_z_digest(PROV_SM2_SIGN_CTX *psm2ctx) +{ + SM2_PROV_CTX *smctx = psm2ctx->sm2_pctx; + uint8_t *z = NULL; + int ret; + + if (psm2ctx->flag_compute_z_digest) { + /* Only do this once */ + psm2ctx->flag_compute_z_digest = 0; + + z = OPENSSL_zalloc(smctx->sm2_md->mdsize); + if (z == NULL) { + fprintf(stderr, "failed to alloc z\n"); + return KAE_P_FAIL; + } + + /* get hashed prefix 'z' of tbs message */ + ret = hpre_sm2_compute_z_digest(z, smctx->sm2_md->md, psm2ctx->id, psm2ctx->id_len, psm2ctx->ec_key); + if (ret == KAE_P_FAIL) { + fprintf(stderr, "failed to kae_prov_sm2_compute_z_digest\n"); + goto free_z; + } + + ret = EVP_DigestUpdate(smctx->sm2_md->mdctx, z, smctx->sm2_md->mdsize); + if (ret == KAE_P_FAIL) { + fprintf(stderr, "failed to EVP_DigestUpdate\n"); + goto free_z; + } + OPENSSL_free(z); + } + + return KAE_P_SUCCESS; + +free_z: + OPENSSL_free(z); + return KAE_P_FAIL; +} + +static int kae_signature_sm2_digest_sign_update(void *vpsm2ctx, const unsigned char *data, size_t datalen) +{ + PROV_SM2_SIGN_CTX *psm2ctx = (PROV_SM2_SIGN_CTX *)vpsm2ctx; + SM2_PROV_CTX *smctx; + int ret; + + if (psm2ctx == NULL) { + fprintf(stderr, "invalid: psm2ctx is NULL in digest sign update\n"); + return KAE_P_FAIL; + } + + smctx = psm2ctx->sm2_pctx; + if (smctx == NULL) { + fprintf(stderr, "invalid: smctx is NULL in compute z digest\n"); + return KAE_P_FAIL; + } + + ret = kae_prov_sm2_check_md_params(smctx); + if (ret == KAE_P_FAIL) + return ret; + + ret = sm2_sig_compute_z_digest(psm2ctx); + if (ret == KAE_P_FAIL) { + fprintf(stderr, "failed to compute z digest\n"); + return ret; + } + + ret = EVP_DigestUpdate(smctx->sm2_md->mdctx, data, datalen); + if (ret == KAE_P_FAIL) { + fprintf(stderr, "failed to EVP_DigestUpdate\n"); + return ret; + } + + return KAE_P_SUCCESS; +} + +static int kae_signature_sm2_digest_sign_final(void *vpsm2ctx, unsigned char *sig, size_t *siglen, size_t sigsize) +{ + PROV_SM2_SIGN_CTX *psm2ctx = (PROV_SM2_SIGN_CTX *)vpsm2ctx; + unsigned char digest[EVP_MAX_MD_SIZE]; + unsigned int dlen = 0; + SM2_PROV_CTX *smctx; + int ret; + + if (psm2ctx == NULL) { + fprintf(stderr, "invalid: psm2ctx is NULL\n"); + return KAE_P_FAIL; + } + + smctx = psm2ctx->sm2_pctx; + if (smctx == NULL) { + fprintf(stderr, "invalid: smctx is NULL\n"); + return KAE_P_FAIL; + } + + ret = kae_prov_sm2_check_md_params(smctx); + if (ret == KAE_P_FAIL) + return ret; + + /* + * If sig is NULL then we're just finding out the sig size. Other fields + * are ignored. Defer to sm2sig_sign. + */ + if (sig != NULL) { + ret = sm2_sig_compute_z_digest(psm2ctx); + if (ret == KAE_P_FAIL) + return ret; + + ret = EVP_DigestFinal_ex(smctx->sm2_md->mdctx, digest, &dlen); + if (ret == KAE_P_FAIL) { + fprintf(stderr, "failed to do EVP_DigestFinal_ex\n"); + return ret; + } + } + + return kae_signature_sm2_sign(vpsm2ctx, sig, siglen, sigsize, digest, (size_t)dlen); +} + +static int kae_signature_sm2_digest_verify_init(void *vpsm2ctx, const char *mdname, void *ec, const OSSL_PARAM params[]) +{ + return kae_signature_sm2_digest_sign_init(vpsm2ctx, mdname, ec, params); +} + +static int kae_signature_sm2_digest_verify_update(void *vpsm2ctx, const unsigned char *data, size_t datalen) +{ + return kae_signature_sm2_digest_sign_update(vpsm2ctx, data, datalen); +} + +static int kae_signature_sm2_digest_verify_final(void *vpsm2ctx, const unsigned char *sig, size_t siglen) +{ + PROV_SM2_SIGN_CTX *psm2ctx = (PROV_SM2_SIGN_CTX *)vpsm2ctx; + unsigned char digest[EVP_MAX_MD_SIZE]; + unsigned int dlen = 0; + SM2_PROV_CTX *smctx; + int ret, size; + + if (psm2ctx == NULL) { + fprintf(stderr, "invalid: psm2ctx is NULL\n"); + return KAE_P_FAIL; + } + + smctx = psm2ctx->sm2_pctx; + if (smctx == NULL) { + fprintf(stderr, "invalid: smctx is NULL\n"); + return KAE_P_FAIL; + } + + ret = kae_prov_sm2_check_md_params(smctx); + if (ret == KAE_P_FAIL) + return ret; + + size = EVP_MD_get_size(smctx->sm2_md->md); + if (size > EVP_MAX_MD_SIZE) { + fprintf(stderr, "invalid: md size(%d) > %d\n", size, EVP_MAX_MD_SIZE); + return KAE_P_FAIL; + } + + ret = sm2_sig_compute_z_digest(psm2ctx); + if (ret == KAE_P_FAIL) { + fprintf(stderr, "failed to do sm2_sig_compute_z_digest\n"); + return ret; + } + + ret = EVP_DigestFinal_ex(smctx->sm2_md->mdctx, digest, &dlen); + if (ret == KAE_P_FAIL) { + fprintf(stderr, "failed to do EVP_DigestFinal_ex, dlen = %u\n", dlen); + return ret; + } + + return kae_signature_sm2_verify(vpsm2ctx, sig, siglen, digest, (size_t)dlen); +} + +static void kae_signature_sm2_freectx(void *vpsm2ctx) +{ + PROV_SM2_SIGN_CTX *psm2ctx = (PROV_SM2_SIGN_CTX *)vpsm2ctx; + SM2_PROV_CTX *smctx; + + if (psm2ctx == NULL) + return; + + smctx = psm2ctx->sm2_pctx; + if (smctx == NULL) + goto free_psm2ctx; + + /* + * Pkey and md related data in smctx->sm2_md and smctx->sm2_pd will + * release by some openssl tools, such as dgst, after call freectx. + * Free pkey and md related data in our provider will cause double-free + * with openssl dgst tool, maybe it is an openssl bug, fix it later. + */ + + if (smctx->sm2_md->mdctx) + EVP_MD_CTX_free(smctx->sm2_md->mdctx); + OPENSSL_free(smctx); + +free_psm2ctx: + if (psm2ctx->propq) + OPENSSL_free(psm2ctx->propq); + if (psm2ctx->ec_key) + EC_KEY_free(psm2ctx->ec_key); + if (psm2ctx->id) + OPENSSL_free(psm2ctx->id); + + OPENSSL_free(psm2ctx); + return; +} + +static int check_signature_src_ctx(PROV_SM2_SIGN_CTX *srcctx) +{ + SM2_PROV_CTX *src_smctx; + + if (srcctx == NULL) { + fprintf(stderr, "invalid: src ctx is NULL\n"); + return KAE_P_FAIL; + } + + if (srcctx->ec_key != NULL && !EC_KEY_up_ref(srcctx->ec_key)) { + fprintf(stderr, "failed to check srcctx key reference\n"); + return KAE_P_FAIL; + } + + src_smctx = srcctx->sm2_pctx; + if (src_smctx == NULL) { + fprintf(stderr, "invalid: src_smctx is NULL\n"); + return KAE_P_FAIL; + } + + if (src_smctx->sm2_md == NULL) { + fprintf(stderr, "invalid: sm2_md is NULL\n"); + return KAE_P_FAIL; + } + + if (src_smctx->sm2_md->md != NULL && !EVP_MD_up_ref(src_smctx->sm2_md->md)) { + fprintf(stderr, "failed to check srcctx md reference\n"); + return KAE_P_FAIL; + } + + return KAE_P_SUCCESS; +} + +static int create_dst_ctx_data(SM2_PROV_CTX *dst_smctx) +{ + dst_smctx->sm2_md = OPENSSL_zalloc(sizeof(SM2_MD_DATA)); + if (dst_smctx->sm2_md == NULL) { + fprintf(stderr, "failed to alloc dst_smctx->sm2_md\n"); + return KAE_P_FAIL; + } + + dst_smctx->sm2_pd = OPENSSL_zalloc(sizeof(SM2_PKEY_DATA)); + if (dst_smctx->sm2_pd == NULL) { + fprintf(stderr, "failed to alloc dst_smctx->sm2_pd\n"); + OPENSSL_free(dst_smctx->sm2_md); + return KAE_P_FAIL; + } + + return KAE_P_SUCCESS; +} + +static void copy_ctx_data(SM2_PROV_CTX *dst_smctx, SM2_PROV_CTX *src_smctx) +{ + dst_smctx->sm2_md->md = src_smctx->sm2_md->md; + dst_smctx->sm2_md->mdsize = src_smctx->sm2_md->mdsize; + dst_smctx->sm2_md->md_nid = src_smctx->sm2_md->md_nid; + dst_smctx->sm2_pd = src_smctx->sm2_pd; + dst_smctx->hsmctx = src_smctx->hsmctx; + dst_smctx->init_status = src_smctx->init_status; +} + +static void release_dst_ctx_data(SM2_PROV_CTX *dst_smctx) +{ + if (dst_smctx->sm2_md) + OPENSSL_free(dst_smctx->sm2_md); + + if (dst_smctx->sm2_pd) + OPENSSL_free(dst_smctx->sm2_pd); +} + +static void *kae_signature_sm2_dupctx(void *vpsm2ctx) +{ + PROV_SM2_SIGN_CTX *srcctx = (PROV_SM2_SIGN_CTX *)vpsm2ctx; + SM2_PROV_CTX *dst_smctx, *src_smctx; + PROV_SM2_SIGN_CTX *dstctx; + + if (check_signature_src_ctx(srcctx) == KAE_P_FAIL) + return NULL; + src_smctx = srcctx->sm2_pctx; + + dstctx = OPENSSL_zalloc(sizeof(PROV_SM2_SIGN_CTX)); + if (dstctx == NULL) { + fprintf(stderr, "failed to alloc dst ctx\n"); + return NULL; + } + + memcpy(dstctx, srcctx, sizeof(PROV_SM2_SIGN_CTX)); + dstctx->ec_key = srcctx->ec_key; + + dst_smctx = OPENSSL_zalloc(sizeof(SM2_PROV_CTX)); + if (dst_smctx == NULL) { + fprintf(stderr, "failed to alloc dst_smctx\n"); + goto free_dstctx; + } + dstctx->sm2_pctx = dst_smctx; + + if (create_dst_ctx_data(dst_smctx) == KAE_P_FAIL) + goto free_dst_smctx; + + if (src_smctx->sm2_md->mdctx != NULL) { + dst_smctx->sm2_md->mdctx = EVP_MD_CTX_new(); + if (dst_smctx->sm2_md->mdctx == NULL || + EVP_MD_CTX_copy_ex(dst_smctx->sm2_md->mdctx, src_smctx->sm2_md->mdctx) == 0) { + fprintf(stderr, "failed to new dst mdctx or copy src mdctx\n"); + goto free_dst_ctx_data; + } + } + + copy_ctx_data(dst_smctx, src_smctx); + + if (srcctx->id != NULL) { + dstctx->id = OPENSSL_malloc(srcctx->id_len); + if (dstctx->id == NULL) { + fprintf(stderr, "failed to alloc id\n"); + goto free_dst_mdctx; + } + dstctx->id_len = srcctx->id_len; + memcpy(dstctx->id, srcctx->id, srcctx->id_len); + } + + return dstctx; + +free_dst_mdctx: + EVP_MD_CTX_free(dst_smctx->sm2_md->mdctx); +free_dst_ctx_data: + release_dst_ctx_data(dst_smctx); +free_dst_smctx: + OPENSSL_free(dst_smctx); +free_dstctx: + OPENSSL_free(dstctx); + return NULL; +} + +static int kae_signature_sm2_get_ctx_params(void *vpsm2ctx, OSSL_PARAM *params) +{ + PROV_SM2_SIGN_CTX *psm2ctx = (PROV_SM2_SIGN_CTX *)vpsm2ctx; + OSSL_PARAM *p; + + if (psm2ctx == NULL) { + fprintf(stderr, "invalid: psm2ctx is NULL\n"); + return KAE_P_FAIL; + } + + p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_ALGORITHM_ID); + if (p != NULL && !OSSL_PARAM_set_octet_string(p, psm2ctx->aid, psm2ctx->aid_len)) { + fprintf(stderr, "failed to locate algorithm id\n"); + return KAE_P_FAIL; + } + + p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST_SIZE); + if (p != NULL && !OSSL_PARAM_set_size_t(p, psm2ctx->sm2_pctx->sm2_md->mdsize)) { + fprintf(stderr, "failed to locate digest size\n"); + return KAE_P_FAIL; + } + + p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST); + if (p != NULL && !OSSL_PARAM_set_utf8_string(p, + psm2ctx->sm2_pctx->sm2_md->md == NULL ? psm2ctx->mdname + : EVP_MD_get0_name(psm2ctx->sm2_pctx->sm2_md->md))) { + fprintf(stderr, "failed to locate digest\n"); + return KAE_P_FAIL; + } + + return KAE_P_SUCCESS; +} + +static const OSSL_PARAM *kae_signature_sm2_gettable_ctx_params(ossl_unused void *vpsm2ctx, ossl_unused void *provctx) +{ + return sm2_sig_known_gettable_ctx_params; +} + +static int kae_prov_sm2_locate_id_digest(PROV_SM2_SIGN_CTX *psm2ctx, const OSSL_PARAM params[]) +{ + size_t tmp_idlen = 0; + const OSSL_PARAM *p; + void *tmp_id = NULL; + char *mdname = NULL; + size_t mdsize; + + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DIST_ID); + if (p) { + /*If the 'z' digest has already been computed, the ID is set too late */ + if (psm2ctx->flag_compute_z_digest == 0) { + fprintf(stderr, "invalid: should set ID param before z digest\n"); + return KAE_P_FAIL; + } + + if (p->data_size != 0 && !OSSL_PARAM_get_octet_string(p, &tmp_id, 0, &tmp_idlen)) { + fprintf(stderr, "failed to OSSL_PARAM_get_octet_string\n"); + return KAE_P_FAIL; + } + if (psm2ctx->id != NULL) + OPENSSL_free(psm2ctx->id); + psm2ctx->id = tmp_id; + psm2ctx->id_len = tmp_idlen; + } + + /* + * The following code checks that the size is the same as the SM3 digest + * size returning an error otherwise. + * If there is ever any different digest algorithm allowed with SM2 + * this needs to be adjusted accordingly. + */ + p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST_SIZE); + if (p != NULL && (!OSSL_PARAM_get_size_t(p, &mdsize) || mdsize != psm2ctx->sm2_pctx->sm2_md->mdsize)) { + fprintf(stderr, "failed to locate digest size\n"); + return KAE_P_FAIL; + } + + p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST); + if (p) { + if (!OSSL_PARAM_get_utf8_string(p, &mdname, 0)) { + fprintf(stderr, "failed to OSSL_PARAM_get_utf8_string\n"); + return KAE_P_FAIL; + } + + if (!kae_prov_sm2_sig_set_mdname(psm2ctx, mdname)) { + OPENSSL_free(mdname); + fprintf(stderr, "failed to OSSL_PARAM_get_utf8_string\n"); + return KAE_P_FAIL; + } + + if (mdname != NULL) + OPENSSL_free(mdname); + } + + return KAE_P_SUCCESS; +} + +static int kae_signature_sm2_set_ctx_params_sw(void *vpsm2ctx, const OSSL_PARAM params[]) +{ + if (!get_default_sm2_signature().set_ctx_params) { + fprintf(stderr, "fail to get sm2 set_ctx_params function.\n"); + return KAE_P_FAIL; + } + + return get_default_sm2_signature().set_ctx_params(vpsm2ctx, params); +} + +static int kae_signature_sm2_set_ctx_params(void *vpsm2ctx, const OSSL_PARAM params[]) +{ + PROV_SM2_SIGN_CTX *psm2ctx = (PROV_SM2_SIGN_CTX *)vpsm2ctx; + SM2_PROV_CTX *smctx; + int ret; + + /* + * 'set_ctx_param' function can be called independently, + * so check 'psm2ctx' again here. + */ + if (psm2ctx == NULL) { + fprintf(stderr, "invalid: sm2 ctx is NULL\n"); + return KAE_P_FAIL; + } + + /* If params is NULL, no need to set ctx params, just return */ + if (params == NULL) + return KAE_P_SUCCESS; + + smctx = psm2ctx->sm2_pctx; + if (smctx == NULL) { + fprintf(stderr, "invalid: smctx is NULL\n"); + return KAE_P_FAIL; + } + + ret = kae_prov_sm2_locate_id_digest(psm2ctx, params); + if (ret == KAE_P_FAIL) + return ret; + + /* If not init, do not need to update session, just set the data before */ + if (smctx->init_status == CTX_INIT_SUCC) { + ret = hpre_sm2_update_sess(psm2ctx->sm2_pctx); + if (ret == KAE_P_FAIL) { + fprintf(stderr, "failed to update sess in set_ctx\n"); + goto do_soft; + } + } + + return KAE_P_SUCCESS; + +do_soft: + return kae_signature_sm2_set_ctx_params_sw(vpsm2ctx, params); +} + +static const OSSL_PARAM *kae_signature_sm2_settable_ctx_params(ossl_unused void *vpsm2ctx, ossl_unused void *provctx) +{ + return sm2_sig_known_settable_ctx_params; +} + +static int kae_signature_sm2_get_ctx_md_params(void *vpsm2ctx, OSSL_PARAM *params) +{ + PROV_SM2_SIGN_CTX *psm2ctx = (PROV_SM2_SIGN_CTX *)vpsm2ctx; + SM2_PROV_CTX *smctx; + + smctx = psm2ctx->sm2_pctx; + if (smctx == NULL) { + fprintf(stderr, "invalid: smctx is NULL\n"); + return KAE_P_FAIL; + } + + if (smctx->sm2_md->mdctx == NULL) { + fprintf(stderr, "invalid: mdctx is NULL\n"); + return KAE_P_FAIL; + } + + return EVP_MD_CTX_get_params(smctx->sm2_md->mdctx, params); +} + +static const OSSL_PARAM *kae_signature_sm2_gettable_ctx_md_params(void *vpsm2ctx) +{ + PROV_SM2_SIGN_CTX *psm2ctx = (PROV_SM2_SIGN_CTX *)vpsm2ctx; + SM2_PROV_CTX *smctx; + + smctx = psm2ctx->sm2_pctx; + if (smctx == NULL) { + fprintf(stderr, "invalid: smctx is NULL\n"); + return KAE_P_FAIL; + } + + if (smctx->sm2_md->md == NULL) { + fprintf(stderr, "invalid: md is NULL\n"); + return KAE_P_FAIL; + } + + return EVP_MD_gettable_ctx_params(smctx->sm2_md->md); +} + +static int kae_signature_sm2_set_ctx_md_params(void *vpsm2ctx, const OSSL_PARAM params[]) +{ + PROV_SM2_SIGN_CTX *psm2ctx = (PROV_SM2_SIGN_CTX *)vpsm2ctx; + SM2_PROV_CTX *smctx; + + smctx = psm2ctx->sm2_pctx; + if (smctx == NULL) { + fprintf(stderr, "invalid: smctx is NULL\n"); + return KAE_P_FAIL; + } + + if (smctx->sm2_md->mdctx == NULL) { + fprintf(stderr, "invalid: mdctx is NULL\n"); + return KAE_P_FAIL; + } + + return EVP_MD_CTX_set_params(smctx->sm2_md->mdctx, params); +} + +static const OSSL_PARAM *kae_signature_sm2_settable_ctx_md_params(void *vpsm2ctx) +{ + PROV_SM2_SIGN_CTX *psm2ctx = (PROV_SM2_SIGN_CTX *)vpsm2ctx; + SM2_PROV_CTX *smctx; + + smctx = psm2ctx->sm2_pctx; + if (smctx == NULL) { + fprintf(stderr, "invalid: smctx is NULL\n"); + return KAE_P_FAIL; + } + + if (smctx->sm2_md->md == NULL) { + fprintf(stderr, "invalid: md is NULL\n"); + return KAE_P_FAIL; + } + + return EVP_MD_settable_ctx_params(smctx->sm2_md->md); +} \ No newline at end of file diff --git a/KAEOpensslProvider/test/func/.keep b/KAEOpensslProvider/test/func/.keep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/KAEOpensslProvider/test/perf/bandwidth.sh b/KAEOpensslProvider/test/perf/bandwidth.sh new file mode 100644 index 0000000000000000000000000000000000000000..e90439aff9078c26ed4bc03aa9ec65ff884a797f --- /dev/null +++ b/KAEOpensslProvider/test/perf/bandwidth.sh @@ -0,0 +1,273 @@ +#!/bin/bash +RESFILE="bwidth.txt" +ENV="" +EXE="openssl" +PROVIDER_DIR="/usr/local/lib/ossl-modules" +PROVIDER="-provider kae_provider" +RUN_TIMES=1 +TIME_SEC="20" + +# 获取 CPU 核心数 +all_cores=$(nproc) +half_cores=$(($all_cores *1 / 2)) + +CORES_NUM=($all_cores) +CORES_NUM+=($(($all_cores * 7 / 8))) #作为扩展吧,想确认硬算是否达到带宽就删除注释 +# CORES_NUM+=($(($all_cores * 6 / 8))) +# CORES_NUM+=($(($all_cores * 5 / 8))) + +echo "CORES_NUM: ${CORES_NUM[@]}" + +function check_enviroment() +{ + IMPLEMENTER=$(cat /proc/cpuinfo | grep "CPU implementer" | awk 'NR==1{printf $4}') + CPUPAET=$(cat /proc/cpuinfo | grep "CPU part" | awk 'NR==1{printf $4}') + if [ "${IMPLEMENTER}-${CPUPAET}" == "0x48-0xd01" ];then + ENV="920" + elif [ "${IMPLEMENTER}-${CPUPAET}" == "0x48-0xd02" ];then + ENV="920B" + elif [ $(arch) == "x86_64" ];then + ENV="X86" + PROVIDER="-provider qat_provider" + else + ENV="UNKNOW CPU" + fi +} + +########################################## +# general alg perf # +########################################## + +function DO_OPENSSL_SYNC(){ + local ALG=$1 + local MULTI=$2 + local HALF_MULTI=$(($2 / 2)) + local BYTES=$3 + + local half_combined="0-$(($half_cores-1))" + local all_combined="0-$(($MULTI / 2 - 1)),$half_cores-$(($MULTI / 2 - 1 + $half_cores))" + + local SPEED_H + local SPEED_S + local SPEED_TMP + local TOTAL_SPEED_S=0 + local TOTAL_SPEED_H=0 + + for i in $(seq 1 $RUN_TIMES); do + # 单P + SPEED_TMP=`taskset -c $half_combined $EXE speed -elapsed -evp $ALG -multi $HALF_MULTI -bytes $BYTES -seconds $TIME_SEC | tail -n 1 | awk '{print $NF}'` #soft + SPEED_TMP=${SPEED_TMP/k/} + TOTAL_SPEED_S=$(echo "$TOTAL_SPEED_S + $SPEED_TMP" | bc) + + SPEED_TMP=`taskset -c $half_combined $EXE speed $PROVIDER -elapsed -evp $ALG -multi $HALF_MULTI -bytes $BYTES -seconds $TIME_SEC | tail -n 1 | awk '{print $NF}'` #hard + SPEED_TMP=${SPEED_TMP/k/} + TOTAL_SPEED_H=$(echo "$TOTAL_SPEED_H + $SPEED_TMP" | bc) + done + + SPEED_S=$(echo "scale=2; $TOTAL_SPEED_S / $RUN_TIMES" | bc) + SPEED_H=$(echo "scale=2; $TOTAL_SPEED_H / $RUN_TIMES" | bc) + echo "$ENV , $ALG , SYNC , $HALF_MULTI , $BYTES , $SPEED_S , $SPEED_H , $(echo "scale=3; $SPEED_H/$SPEED_S" | bc | awk '{printf "%.3f\n", $0}') " >> $RESFILE + + + TOTAL_SPEED_S=0 + TOTAL_SPEED_H=0 + for i in $(seq 1 $RUN_TIMES); do + # 整机 + SPEED_TMP=`taskset -c $all_combined $EXE speed -elapsed -evp $ALG -multi $MULTI -bytes $BYTES -seconds $TIME_SEC | tail -n 1 | awk '{print $NF}'` #soft + SPEED_TMP=${SPEED_TMP/k/} + TOTAL_SPEED_S=$(echo "$TOTAL_SPEED_S + $SPEED_TMP" | bc) + + SPEED_TMP=`taskset -c $all_combined $EXE speed $PROVIDER -elapsed -evp $ALG -multi $MULTI -bytes $BYTES -seconds $TIME_SEC | tail -n 1 | awk '{print $NF}'` #hard + SPEED_TMP=${SPEED_TMP/k/} + TOTAL_SPEED_H=$(echo "$TOTAL_SPEED_H + $SPEED_TMP" | bc) + done + + SPEED_S=$(echo "scale=2; $TOTAL_SPEED_S / $RUN_TIMES" | bc) + SPEED_H=$(echo "scale=2; $TOTAL_SPEED_H / $RUN_TIMES" | bc) + echo "$ENV , $ALG , SYNC , $MULTI , $BYTES , $SPEED_S , $SPEED_H , $(echo "scale=3; $SPEED_H/$SPEED_S" | bc | awk '{printf "%.3f\n", $0}') " >> $RESFILE +} + + +function DO_EVP_BD(){ + local ALGES=$1 + local BYTES=$2 + #AES + for alg in $ALGES + do + for sync_nulti in ${CORES_NUM[@]} + do + for aes_bytes in $BYTES + do + DO_OPENSSL_SYNC $alg $sync_nulti $aes_bytes + done + done + done +} + +########################################## +# RSA perf # +########################################## + +function RSA_SYNC(){ + local ALG=$1 + local MULTI=$2 + + local HALF_MULTI=$(($2 / 2)) + local half_combined="0-$(($half_cores-1))" + local all_combined="0-$(($MULTI / 2 - 1)),$half_cores-$(($MULTI / 2 - 1 + $half_cores))" + + local SPEED_TMP + local SPEED_verify_S + local SPEED_sign_S + local SPEED_verify_H + local SPEED_sign_H + + local TOTAL_SPEED_SIGN_S=0 + local TOTAL_SPEED_VERIFY_S=0 + local TOTAL_SPEED_SIGN_H=0 + local TOTAL_SPEED_VERIFY_H=0 + + for i in $(seq 1 $RUN_TIMES); do + #单P + SPEED_TMP=`taskset -c $half_combined $EXE speed -elapsed -multi $HALF_MULTI -seconds $TIME_SEC $ALG | tail -n 1` #soft + TOTAL_SPEED_SIGN_S=$(echo "$TOTAL_SPEED_SIGN_S + $(echo $SPEED_TMP | awk '{print $(NF-1)}')" | bc) + TOTAL_SPEED_VERIFY_S=$(echo "$TOTAL_SPEED_VERIFY_S + $(echo $SPEED_TMP | awk '{print $(NF-0)}')" | bc) + + SPEED_TMP=`taskset -c $half_combined $EXE speed $PROVIDER -elapsed -multi $HALF_MULTI -seconds $TIME_SEC $ALG | tail -n 1 ` #hard + TOTAL_SPEED_SIGN_H=$(echo "$TOTAL_SPEED_SIGN_H + $(echo $SPEED_TMP | awk '{print $(NF-1)}')" | bc) + TOTAL_SPEED_VERIFY_H=$(echo "$TOTAL_SPEED_VERIFY_H + $(echo $SPEED_TMP | awk '{print $(NF-0)}')" | bc) + done + + SPEED_sign_S=$(echo "scale=2; $TOTAL_SPEED_SIGN_S / $RUN_TIMES" | bc) + SPEED_verify_S=$(echo "scale=2; $TOTAL_SPEED_VERIFY_S / $RUN_TIMES" | bc) + SPEED_sign_H=$(echo "scale=2; $TOTAL_SPEED_SIGN_H / $RUN_TIMES" | bc) + SPEED_verify_H=$(echo "scale=2; $TOTAL_SPEED_VERIFY_H / $RUN_TIMES" | bc) + echo "$ENV , $ALG-sign , SYNC , $HALF_MULTI , ${ALG#rsa} , $SPEED_sign_S , $SPEED_sign_H , $(echo "scale=3; $SPEED_sign_H/$SPEED_sign_S" | bc | awk '{printf "%.3f\n", $0}') " >> $RESFILE + echo "$ENV , $ALG-verify , SYNC , $HALF_MULTI , ${ALG#rsa} , $SPEED_verify_S , $SPEED_verify_H , $(echo "scale=3; $SPEED_verify_H/$SPEED_verify_S" | bc | awk '{printf "%.3f\n", $0}') " >> $RESFILE + + + TOTAL_SPEED_SIGN_S=0 + TOTAL_SPEED_VERIFY_S=0 + TOTAL_SPEED_SIGN_H=0 + TOTAL_SPEED_VERIFY_H=0 + for i in $(seq 1 $RUN_TIMES); do + #整机 + SPEED_TMP=`taskset -c $all_combined $EXE speed -elapsed -multi $MULTI -seconds $TIME_SEC $ALG | tail -n 1` #soft + TOTAL_SPEED_SIGN_S=$(echo "$TOTAL_SPEED_SIGN_S + $(echo $SPEED_TMP | awk '{print $(NF-1)}')" | bc) + TOTAL_SPEED_VERIFY_S=$(echo "$TOTAL_SPEED_VERIFY_S + $(echo $SPEED_TMP | awk '{print $(NF-0)}')" | bc) + + SPEED_TMP=`taskset -c $all_combined $EXE speed $PROVIDER -elapsed -multi $MULTI -seconds $TIME_SEC $ALG | tail -n 1 ` #hard + TOTAL_SPEED_SIGN_H=$(echo "$TOTAL_SPEED_SIGN_H + $(echo $SPEED_TMP | awk '{print $(NF-1)}')" | bc) + TOTAL_SPEED_VERIFY_H=$(echo "$TOTAL_SPEED_VERIFY_H + $(echo $SPEED_TMP | awk '{print $(NF-0)}')" | bc) + done + + SPEED_sign_S=$(echo "scale=2; $TOTAL_SPEED_SIGN_S / $RUN_TIMES" | bc) + SPEED_verify_S=$(echo "scale=2; $TOTAL_SPEED_VERIFY_S / $RUN_TIMES" | bc) + SPEED_sign_H=$(echo "scale=2; $TOTAL_SPEED_SIGN_H / $RUN_TIMES" | bc) + SPEED_verify_H=$(echo "scale=2; $TOTAL_SPEED_VERIFY_H / $RUN_TIMES" | bc) + echo "$ENV , $ALG-sign , SYNC , $MULTI , ${ALG#rsa} , $SPEED_sign_S , $SPEED_sign_H , $(echo "scale=3; $SPEED_sign_H/$SPEED_sign_S" | bc | awk '{printf "%.3f\n", $0}') " >> $RESFILE + echo "$ENV , $ALG-verify , SYNC , $MULTI , ${ALG#rsa} , $SPEED_verify_S , $SPEED_verify_H , $(echo "scale=3; $SPEED_verify_H/$SPEED_verify_S" | bc | awk '{printf "%.3f\n", $0}') " >> $RESFILE +} + + +function DO_RSA_BD(){ + local ALGES=$1 + #AES-同步 + for alg in $ALGES + do + for sync_nulti in ${CORES_NUM[@]} + do + RSA_SYNC $alg $sync_nulti + done + done +} + +########################################## +# DH perf # +########################################## +function DH_SYNC(){ + local ALG=$1 + local MULTI=$2 + + local HALF_MULTI=$(($2 / 2)) + local half_combined="0-$(($half_cores-1))" + local all_combined="0-$(($MULTI / 2 - 1)),$half_cores-$(($MULTI / 2 - 1 + $half_cores))" + + local SPEED_S + local SPEED_H + local SPEED_TMP + local TOTAL_SPEED_S=0 + local TOTAL_SPEED_H=0 + + for i in $(seq 1 $RUN_TIMES); do + #单P + SPEED_TMP=`taskset -c $half_combined $EXE speed -elapsed -multi $HALF_MULTI -seconds $TIME_SEC $ALG | tail -n 1 | awk '{print $(NF-0)}'` #soft + TOTAL_SPEED_S=$(echo "$TOTAL_SPEED_S + $SPEED_TMP" | bc) + + SPEED_TMP=`taskset -c $half_combined $EXE speed $PROVIDER -elapsed -multi $HALF_MULTI -seconds $TIME_SEC $ALG | tail -n 1 | awk '{print $(NF-0)}' ` #hard + TOTAL_SPEED_H=$(echo "$TOTAL_SPEED_H + $SPEED_TMP" | bc) + done + + SPEED_S=$(echo "scale=2; $TOTAL_SPEED_S / $RUN_TIMES" | bc) + SPEED_H=$(echo "scale=2; $TOTAL_SPEED_H / $RUN_TIMES" | bc) + echo "$ENV , $ALG , SYNC , $HALF_MULTI , ${ALG#ffdh} , $SPEED_S , $SPEED_H , $(echo "scale=3; $SPEED_H/$SPEED_S" | bc | awk '{printf "%.3f\n", $0}') " >> $RESFILE + + + TOTAL_SPEED_S=0 + TOTAL_SPEED_H=0 + for i in $(seq 1 $RUN_TIMES); do + #整机 + SPEED_TMP=`taskset -c $all_combined $EXE speed -elapsed -multi $MULTI -seconds $TIME_SEC $ALG | tail -n 1 | awk '{print $(NF-0)}'` #soft + TOTAL_SPEED_S=$(echo "$TOTAL_SPEED_S + $SPEED_TMP" | bc) + + SPEED_TMP=`taskset -c $all_combined $EXE speed $PROVIDER -elapsed -multi $MULTI -seconds $TIME_SEC $ALG | tail -n 1 | awk '{print $(NF-0)}' ` #hard + TOTAL_SPEED_H=$(echo "$TOTAL_SPEED_H + $SPEED_TMP" | bc) + done + + SPEED_S=$(echo "scale=2; $TOTAL_SPEED_S / $RUN_TIMES" | bc) + SPEED_H=$(echo "scale=2; $TOTAL_SPEED_H / $RUN_TIMES" | bc) + echo "$ENV , $ALG , SYNC , $MULTI , ${ALG#ffdh} , $SPEED_S , $SPEED_H , $(echo "scale=3; $SPEED_H/$SPEED_S" | bc | awk '{printf "%.3f\n", $0}') " >> $RESFILE +} + +function DO_DH_BD(){ + local ALGES=$1 + #AES-同步 + for alg in $ALGES + do + for sync_nulti in ${CORES_NUM[@]} + do + DH_SYNC $alg $sync_nulti + done + done +} + +function main(){ + check_enviroment + export OPENSSL_MODULES=$PROVIDER_DIR + echo "测试环境 , 算法 , 同步异步 , 进程数量 , 包长 , 软算速度 KB/s , 硬算速度 KB/s , 硬软比 " > $RESFILE + + #AES + DO_EVP_BD "aes-256-cbc aes-256-ctr aes-256-ecb aes-256-xts aes-256-ofb aes-256-cfb" "1048576" + + #SM4 + DO_EVP_BD "sm4-cbc sm4-ctr sm4-ecb sm4-ofb sm4-cfb" "1048576" + + #SM3 + DO_EVP_BD "sm3" "1048576" + + #MD5 + DO_EVP_BD "md5" "1048576" + + #RSA + DO_RSA_BD "rsa2048 rsa4096" + + #SM2 + DO_RSA_BD "sm2" + + #DH + DO_DH_BD "ffdh2048 ffdh4096" + +} + +main "$@" +exit $? diff --git a/KAEOpensslProvider/test/perf/convert.py b/KAEOpensslProvider/test/perf/convert.py new file mode 100644 index 0000000000000000000000000000000000000000..f5828baff6028872153b83a89442d8196d0f0e9d --- /dev/null +++ b/KAEOpensslProvider/test/perf/convert.py @@ -0,0 +1,73 @@ +import os +import csv + +# 获取当前目录 +current_directory = os.getcwd() + +# 定义输出文件夹路径 +output_folder = os.path.join(current_directory, 'output') # 存放转换后的 CSV 文件 + +# 创建输出文件夹(如果不存在) +os.makedirs(output_folder, exist_ok=True) + +# 定义表头 +columns_header = [ + '测试环境', '算法', '同步异步', '进程数量', '包长', + '软算速度 KB/s', '硬算速度 KB/s', '硬软比', + '软算速度 Gbps', '硬算速度 Gbps' +] + +# 遍历当前目录下的所有 .txt 文件 +for filename in os.listdir(current_directory): + # 判断文件是否为 .txt 文件 + if filename.endswith('.txt'): + input_file = os.path.join(current_directory, filename) + + # 创建一个新的 CSV 文件 + output_file = os.path.join(output_folder, f"{os.path.splitext(filename)[0]}.csv") + + with open(input_file, 'r', encoding='utf-8') as infile, open(output_file, 'w', newline='', encoding='utf-8-sig') as outfile: + reader = infile.readlines() + writer = csv.writer(outfile) + + # 写入表头 + writer.writerow(columns_header) + + # 跳过第一行(表头) + for i, line in enumerate(reader): + if i == 0: + continue # 跳过第一行 + + line = line.strip() # 去掉前后的空白字符 + if line: + columns = line.split(',') + + # 如果数据不足,填充0 + columns = [col.strip() if col.strip() else '0' for col in columns] + + # 获取软算和硬算速度(单位:KB/s) + try: + soft_speed = float(columns[5]) + hard_speed = float(columns[6]) + except ValueError: + soft_speed = 0 + hard_speed = 0 + + # 转换为带宽(单位:Gbps/s),注意1KB = 8Kb + soft_bandwidth = (soft_speed * 8) / 1e6 # KB/s 转 Gbps/s + hard_bandwidth = (hard_speed * 8) / 1e6 # KB/s 转 Gbps/s + + # 保留两位小数 + soft_bandwidth = round(soft_bandwidth, 2) + hard_bandwidth = round(hard_bandwidth, 2) + + # 添加带宽到数据列表 + columns.append(soft_bandwidth) # 软算带宽 Gbps/s + columns.append(hard_bandwidth) # 硬算带宽 Gbps/s + + # 写入数据到 CSV 文件 + writer.writerow(columns) + + print(f"文件 {filename} 已成功转换为 {output_file}") + +print("所有文件已转换完成!") diff --git a/KAEOpensslProvider/test/perf/multi_perf.sh b/KAEOpensslProvider/test/perf/multi_perf.sh new file mode 100644 index 0000000000000000000000000000000000000000..32182f5f2c0300839d217f62da364146a0c69301 --- /dev/null +++ b/KAEOpensslProvider/test/perf/multi_perf.sh @@ -0,0 +1,350 @@ +#!/bin/bash +RESFILE="multi.txt" +ENV="" +SYNC_MULTIS="1 4 16 32 64" +ASYNC_MULTIS="1 2 4 8 16" +EXE="openssl" +PROVIDER_DIR="/usr/local/lib/ossl-modules" +PROVIDER="-provider kae_provider" +RUN_TIMES=3 + +#均匀绑单P的核。因为920B单P就有2个加速器。。也为了较少开超线程带来的影响 +all_cores=$(nproc) +quarter_cores=$(($all_cores *1 / 4)) + +function check_enviroment() +{ + IMPLEMENTER=$(cat /proc/cpuinfo | grep "CPU implementer" | awk 'NR==1{printf $4}') + CPUPAET=$(cat /proc/cpuinfo | grep "CPU part" | awk 'NR==1{printf $4}') + if [ "${IMPLEMENTER}-${CPUPAET}" == "0x48-0xd01" ];then + ENV="920" + elif [ "${IMPLEMENTER}-${CPUPAET}" == "0x48-0xd02" ];then + ENV="920B" + elif [ $(arch) == "x86_64" ];then + ENV="X86" + PROVIDER="-provider kae_provider" + else + ENV="UNKNOW CPU" + fi +} + +########################################## +# general alg perf # +########################################## + +function DO_OPENSSL_SYNC(){ + local ALG=$1 + local MULTI=$2 + local BYTES=$3 + local avg_combined + if [ "$2" = "1" ]; then + avg_combined="0" + else + avg_combined="0-$(($MULTI / 2 - 1)),$quarter_cores-$(($MULTI / 2 - 1 + $quarter_cores))" + fi + + local SPEED_H + local SPEED_S + local SPEED_TMP + local TOTAL_SPEED_S=0 + local TOTAL_SPEED_H=0 + + #同步模式 + for i in $(seq 1 $RUN_TIMES); do + SPEED_TMP=`taskset -c $avg_combined $EXE speed -elapsed -evp $ALG -multi $MULTI -bytes $BYTES | tail -n 1 | awk '{print $NF}'` #soft + SPEED_TMP=${SPEED_TMP/k/} + TOTAL_SPEED_S=$(echo "$TOTAL_SPEED_S + $SPEED_TMP" | bc) + + SPEED_TMP=`taskset -c $avg_combined $EXE speed $PROVIDER -elapsed -evp $ALG -multi $MULTI -bytes $BYTES | tail -n 1 | awk '{print $NF}'` #hard + SPEED_TMP=${SPEED_TMP/k/} + TOTAL_SPEED_H=$(echo "$TOTAL_SPEED_H + $SPEED_TMP" | bc) + done + + SPEED_S=$(echo "scale=2; $TOTAL_SPEED_S / $RUN_TIMES" | bc) + SPEED_H=$(echo "scale=2; $TOTAL_SPEED_H / $RUN_TIMES" | bc) + echo "$ENV , $ALG , SYNC , $MULTI , $BYTES , $SPEED_S , $SPEED_H , $(echo "scale=3; $SPEED_H/$SPEED_S" | bc | awk '{printf "%.3f\n", $0}') " >> $RESFILE +} + +function DO_OPENSSL_ASYNC(){ + local ALG=$1 + local MULTI=$2 + local BYTES=$3 + local avg_combined + if [ "$2" = "1" ]; then + avg_combined="0" + else + avg_combined="0-$(($MULTI / 2 - 1)),$quarter_cores-$(($MULTI / 2 - 1 + $quarter_cores))" + fi + + local SPEED_H + local SPEED_S + local SPEED_TMP + local TOTAL_SPEED_S=0 + local TOTAL_SPEED_H=0 + + #异步模式 + for i in $(seq 1 $RUN_TIMES); do + SPEED_TMP=`taskset -c $avg_combined $EXE speed -elapsed -async_jobs 16 -multi $MULTI -evp $ALG -bytes $BYTES | tail -n 1 | awk '{print $NF}'` #soft + SPEED_TMP=${SPEED_TMP/k/} + TOTAL_SPEED_S=$(echo "$TOTAL_SPEED_S + $SPEED_TMP" | bc) + + SPEED_TMP=`taskset -c $avg_combined $EXE speed $PROVIDER -elapsed -async_jobs 16 -multi $MULTI -evp $ALG -bytes $BYTES | tail -n 1 | awk '{print $NF}'` #hard + SPEED_TMP=${SPEED_TMP/k/} + TOTAL_SPEED_H=$(echo "$TOTAL_SPEED_H + $SPEED_TMP" | bc) + done + + SPEED_S=$(echo "scale=2; $TOTAL_SPEED_S / $RUN_TIMES" | bc) + SPEED_H=$(echo "scale=2; $TOTAL_SPEED_H / $RUN_TIMES" | bc) + echo "$ENV , $ALG , ASYNC , 16x$MULTI , $BYTES , $SPEED_S , $SPEED_H , $(echo "scale=3; $SPEED_H/$SPEED_S" | bc | awk '{printf "%.3f\n", $0}') " >> $RESFILE +} + +function DO_ALG(){ + local ALGES=$1 + local BYTES=$2 + #AES-同步 + for alg in $ALGES + do + for sync_nulti in $SYNC_MULTIS + do + for aes_bytes in $BYTES + do + DO_OPENSSL_SYNC $alg $sync_nulti $aes_bytes + done + done + done + + #AES-异步 + for alg in $ALGES + do + for sync_nulti in $ASYNC_MULTIS + do + for aes_bytes in $BYTES + do + DO_OPENSSL_ASYNC $alg $sync_nulti $aes_bytes + done + done + done +} + +########################################## +# RSA perf # +########################################## + +function RSA_SYNC(){ + local ALG=$1 + local MULTI=$2 + local avg_combined + if [ "$2" = "1" ]; then + avg_combined="0" + else + avg_combined="0-$(($MULTI / 2 - 1)),$quarter_cores-$(($MULTI / 2 - 1 + $quarter_cores))" + fi + + local SPEED_TMP + local SPEED_sign_S + local SPEED_verify_S + local SPEED_sign_H + local SPEED_verify_H + + local TOTAL_SPEED_SIGN_S=0 + local TOTAL_SPEED_VERIFY_S=0 + local TOTAL_SPEED_SIGN_H=0 + local TOTAL_SPEED_VERIFY_H=0 + + #同步模式 + for i in $(seq 1 $RUN_TIMES); do + SPEED_TMP=`taskset -c $avg_combined $EXE speed -elapsed -multi $MULTI $ALG | tail -n 1` #soft + TOTAL_SPEED_SIGN_S=$(echo "$TOTAL_SPEED_SIGN_S + $(echo $SPEED_TMP | awk '{print $(NF-1)}')" | bc) + TOTAL_SPEED_VERIFY_S=$(echo "$TOTAL_SPEED_VERIFY_S + $(echo $SPEED_TMP | awk '{print $(NF-0)}')" | bc) + + SPEED_TMP=`taskset -c $avg_combined $EXE speed $PROVIDER -elapsed -multi $MULTI $ALG | tail -n 1 ` #hard + TOTAL_SPEED_SIGN_H=$(echo "$TOTAL_SPEED_SIGN_H + $(echo $SPEED_TMP | awk '{print $(NF-1)}')" | bc) + TOTAL_SPEED_VERIFY_H=$(echo "$TOTAL_SPEED_VERIFY_H + $(echo $SPEED_TMP | awk '{print $(NF-0)}')" | bc) + done + + SPEED_sign_S=$(echo "scale=2; $TOTAL_SPEED_SIGN_S / $RUN_TIMES" | bc) + SPEED_verify_S=$(echo "scale=2; $TOTAL_SPEED_VERIFY_S / $RUN_TIMES" | bc) + SPEED_sign_H=$(echo "scale=2; $TOTAL_SPEED_SIGN_H / $RUN_TIMES" | bc) + SPEED_verify_H=$(echo "scale=2; $TOTAL_SPEED_VERIFY_H / $RUN_TIMES" | bc) + + echo "$ENV , $ALG-sign , SYNC , $MULTI , ${ALG#rsa} , $SPEED_sign_S , $SPEED_sign_H , $(echo "scale=3; $SPEED_sign_H/$SPEED_sign_S" | bc | awk '{printf "%.3f\n", $0}') " >> $RESFILE + echo "$ENV , $ALG-verify , SYNC , $MULTI , ${ALG#rsa} , $SPEED_verify_S , $SPEED_verify_H , $(echo "scale=3; $SPEED_verify_H/$SPEED_verify_S" | bc | awk '{printf "%.3f\n", $0}') " >> $RESFILE +} + +function RSA_ASYNC(){ + local ALG=$1 + local MULTI=$2 + local avg_combined + if [ "$2" = "1" ]; then + avg_combined="0" + else + avg_combined="0-$(($MULTI / 2 - 1)),$quarter_cores-$(($MULTI / 2 - 1 + $quarter_cores))" + fi + + local SPEED + local SPEED_sign_S + local SPEED_verify_S + local SPEED_sign_H + local SPEED_verify_H + + local SPEED_TMP + local TOTAL_SPEED_SIGN_S=0 + local TOTAL_SPEED_VERIFY_S=0 + local TOTAL_SPEED_SIGN_H=0 + local TOTAL_SPEED_VERIFY_H=0 + + #异步模式 + for i in $(seq 1 $RUN_TIMES); do + SPEED_TMP=`taskset -c $avg_combined $EXE speed -elapsed -async_jobs 16 -multi $MULTI $ALG | tail -n 1 ` #soft + TOTAL_SPEED_SIGN_S=$(echo "$TOTAL_SPEED_SIGN_S + $(echo $SPEED_TMP | awk '{print $(NF-1)}')" | bc) + TOTAL_SPEED_VERIFY_S=$(echo "$TOTAL_SPEED_VERIFY_S + $(echo $SPEED_TMP | awk '{print $(NF-0)}')" | bc) + + SPEED_TMP=`taskset -c $avg_combined $EXE speed $PROVIDER -elapsed -async_jobs 16 -multi $MULTI $ALG | tail -n 1 ` #hard + TOTAL_SPEED_SIGN_H=$(echo "$TOTAL_SPEED_SIGN_H + $(echo $SPEED_TMP | awk '{print $(NF-1)}')" | bc) + TOTAL_SPEED_VERIFY_H=$(echo "$TOTAL_SPEED_VERIFY_H + $(echo $SPEED_TMP | awk '{print $(NF-0)}')" | bc) + done + + SPEED_sign_S=$(echo "scale=2; $TOTAL_SPEED_SIGN_S / $RUN_TIMES" | bc) + SPEED_verify_S=$(echo "scale=2; $TOTAL_SPEED_VERIFY_S / $RUN_TIMES" | bc) + SPEED_sign_H=$(echo "scale=2; $TOTAL_SPEED_SIGN_H / $RUN_TIMES" | bc) + SPEED_verify_H=$(echo "scale=2; $TOTAL_SPEED_VERIFY_H / $RUN_TIMES" | bc) + echo "$ENV , $ALG-sign , ASYNC , 16x$MULTI , ${ALG#rsa} , $SPEED_sign_S , $SPEED_sign_H , $(echo "scale=3; $SPEED_sign_H/$SPEED_sign_S" | bc | awk '{printf "%.3f\n", $0}') " >> $RESFILE + echo "$ENV , $ALG-verify , ASYNC , 16x$MULTI , ${ALG#rsa} , $SPEED_verify_S , $SPEED_verify_H , $(echo "scale=3; $SPEED_verify_H/$SPEED_verify_S" | bc | awk '{printf "%.3f\n", $0}') " >> $RESFILE +} + +function DO_RSA(){ + local ALGES=$1 + #AES-同步 + for alg in $ALGES + do + for sync_nulti in $SYNC_MULTIS + do + RSA_SYNC $alg $sync_nulti + done + done + + #AES-异步 + for alg in $ALGES + do + for sync_nulti in $ASYNC_MULTIS + do + RSA_ASYNC $alg $sync_nulti + done + done +} + +########################################## +# DH perf # +########################################## +function DH_SYNC(){ + local ALG=$1 + local MULTI=$2 + local avg_combined + if [ "$2" = "1" ]; then + avg_combined="0" + else + avg_combined="0-$(($MULTI / 2 - 1)),$quarter_cores-$(($MULTI / 2 - 1 + $quarter_cores))" + fi + + local SPEED_S + local SPEED_H + local SPEED_TMP + local TOTAL_SPEED_S=0 + local TOTAL_SPEED_H=0 + + #同步模式 + for i in $(seq 1 $RUN_TIMES); do + SPEED_TMP=`taskset -c $avg_combined $EXE speed -elapsed -multi $MULTI $ALG | tail -n 1 | awk '{print $(NF-0)}'` #soft + TOTAL_SPEED_S=$(echo "$TOTAL_SPEED_S + $SPEED_TMP" | bc) + + SPEED_TMP=`taskset -c $avg_combined $EXE speed $PROVIDER -elapsed -multi $MULTI $ALG | tail -n 1 | awk '{print $(NF-0)}' ` #hard + TOTAL_SPEED_H=$(echo "$TOTAL_SPEED_H + $SPEED_TMP" | bc) + done + + SPEED_S=$(echo "scale=2; $TOTAL_SPEED_S / $RUN_TIMES" | bc) + SPEED_H=$(echo "scale=2; $TOTAL_SPEED_H / $RUN_TIMES" | bc) + echo "$ENV , $ALG , SYNC , $MULTI , ${ALG#ffdh} , $SPEED_S , $SPEED_H , $(echo "scale=3; $SPEED_H/$SPEED_S" | bc | awk '{printf "%.3f\n", $0}') " >> $RESFILE +} + +function DH_ASYNC(){ + local ALG=$1 + local MULTI=$2 + local avg_combined + if [ "$2" = "1" ]; then + avg_combined="0" + else + avg_combined="0-$(($MULTI / 2 - 1)),$quarter_cores-$(($MULTI / 2 - 1 + $quarter_cores))" + fi + + local SPEED_S + local SPEED_H + local SPEED_TMP + local TOTAL_SPEED_S=0 + local TOTAL_SPEED_H=0 + + #异步模式 + for i in $(seq 1 $RUN_TIMES); do + SPEED_TMP=`taskset -c $avg_combined $EXE speed -elapsed -async_jobs 16 -multi $MULTI $ALG | tail -n 1 | awk '{print $(NF-0)}'` #soft + TOTAL_SPEED_S=$(echo "$TOTAL_SPEED_S + $SPEED_TMP" | bc) + + SPEED_TMP=`taskset -c $avg_combined $EXE speed $PROVIDER -elapsed -async_jobs 16 -multi $MULTI $ALG | tail -n 1 | awk '{print $(NF-0)}'` #hard + TOTAL_SPEED_H=$(echo "$TOTAL_SPEED_H + $SPEED_TMP" | bc) + done + + SPEED_S=$(echo "scale=2; $TOTAL_SPEED_S / $RUN_TIMES" | bc) + SPEED_H=$(echo "scale=2; $TOTAL_SPEED_H / $RUN_TIMES" | bc) + echo "$ENV , $ALG , ASYNC , 16x$MULTI , ${ALG#ffdh} , $SPEED_S , $SPEED_H , $(echo "scale=3; $SPEED_H/$SPEED_S" | bc | awk '{printf "%.3f\n", $0}') " >> $RESFILE +} + +function DO_DH(){ + local ALGES=$1 + #AES-同步 + for alg in $ALGES + do + for sync_nulti in $SYNC_MULTIS + do + DH_SYNC $alg $sync_nulti + done + done + + #AES-异步 + for alg in $ALGES + do + for sync_nulti in $ASYNC_MULTIS + do + DH_ASYNC $alg $sync_nulti + done + done +} + + +function main(){ + check_enviroment + export OPENSSL_MODULES=$PROVIDER_DIR + echo "测试环境 , 算法 , 同步异步 , 进程数量 , 包长 , 软算速度 KB/s , 硬算速度 KB/s , 硬软比 " > $RESFILE + + #AES + DO_ALG "aes-256-cbc aes-256-ctr aes-256-ecb aes-256-xts aes-256-ofb aes-256-cfb" "64 256 512 1024 4096 16384 262144 1048576" + + #SM4 + DO_ALG "sm4-cbc sm4-ctr sm4-ecb sm4-ofb sm4-cfb" "64 256 512 1024 4096 16384 262144 1048576" + + #SM3 + DO_ALG "sm3" "64 256 512 1024 4096 16384 262144 1048576" + + #MD5 + DO_ALG "md5" "64 512 4096 16384 262144 1048576" + + #RSA + DO_RSA "rsa2048 rsa4096" + + #SM2 + DO_RSA "sm2" + + #DH + DO_DH "ffdh2048 ffdh4096" + +} + +main "$@" +exit $? diff --git a/KAEOpensslProvider/test/perf/run_perf.sh b/KAEOpensslProvider/test/perf/run_perf.sh new file mode 100644 index 0000000000000000000000000000000000000000..2ca003da31872c60553511dba04185d7c95c090d --- /dev/null +++ b/KAEOpensslProvider/test/perf/run_perf.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +echo "start openssl perf test." + +chmod +x bandwidth.sh +chmod +x multi_perf.sh +sh bandwidth.sh +sh multi_perf.sh +python convert.py + +echo "All openssl perf scripts have been executed." \ No newline at end of file diff --git a/build.sh b/build.sh index 6cc57d28400397094890d1a848630b08b5a74cad..a6fb3d7ac9eb06efdf6c123276c4089faa745e40 100644 --- a/build.sh +++ b/build.sh @@ -474,6 +474,46 @@ function engine_clean_openssl3() # engine_log_clean } +function build_ossl_provider() +{ + openssl3_install_path=$1 + if [ "$1" = "" ];then + openssl3_install_path=$(which openssl | awk -F'/bin' '{print $1}') + fi + cd ${SRC_PATH}/KAEOpensslProvider + export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig + autoreconf -i + + if [ ! -f "$openssl3_install_path/include/openssl/opensslv.h" ]; then + echo "openssl3 install path is wrong, $openssl3_install_path/include/openssl/opensslv.h is not exist." + exit 1 + else + if $openssl3_install_path/bin/openssl version | grep -q "OpenSSL 3."; then + echo "OpenSSL version is 3.x." + elif $openssl3_install_path/bin/openssl version | grep -q "OpenSSL 1."; then + $openssl3_install_path/bin/openssl version + echo "OpenSSL version is 1.x, please use openssl3.0 install path" + exit 1 + else + $openssl3_install_path/bin/openssl version + echo "OpenSSL version is not support" + exit 1 + fi + fi + + ./configure --libdir=/usr/local/lib/ossl-modules --enable-kae --enable-provider --with-openssl_install_dir=$openssl3_install_path #/usr/local/ssl3 + make -j + make install +} + +function clean_ossl_provider() +{ + cd ${SRC_PATH}/KAEOpensslProvider + make uninstall + make clean + rm -rf /usr/local/lib/ossl-modules +} + function build_engine_gmssl() { gmssl_install_path=$1 @@ -757,6 +797,13 @@ main() { build_engine_openssl3_asm $2 fi ;; + "ossl_provider") + if [ "$2" = "clean" ]; then + clean_ossl_provider + else + build_ossl_provider $2 + fi + ;; "engine_gmssl") if [ "$2" = "clean" ]; then engine_clean_gmssl