189ed30d1SJens Wiklander // SPDX-License-Identifier: BSD-2-Clause 289ed30d1SJens Wiklander /* 38f6ac972SJens Wiklander * Copyright (c) 2014-2019, 2022 Linaro Limited 489ed30d1SJens Wiklander */ 589ed30d1SJens Wiklander 689ed30d1SJens Wiklander #include <crypto/crypto.h> 7c2c27539SJorge Ramirez-Ortiz #include <crypto/crypto_impl.h> 88f6ac972SJens Wiklander #include <fault_mitigation.h> 9*d71c4cd4SJens Wiklander #include <mempool.h> 1089ed30d1SJens Wiklander #include <stdlib.h> 1189ed30d1SJens Wiklander #include <string.h> 1289ed30d1SJens Wiklander #include <tee_api_defines_extensions.h> 138f6ac972SJens Wiklander #include <tee_api_types.h> 1489ed30d1SJens Wiklander #include <tee/tee_cryp_utl.h> 1589ed30d1SJens Wiklander #include <trace.h> 1689ed30d1SJens Wiklander #include <utee_defines.h> 1789ed30d1SJens Wiklander 1889ed30d1SJens Wiklander #include "acipher_helpers.h" 1989ed30d1SJens Wiklander 2089ed30d1SJens Wiklander 2189ed30d1SJens Wiklander /* 2289ed30d1SJens Wiklander * Compute the LibTomCrypt "hashindex" given a TEE Algorithm "algo" 2389ed30d1SJens Wiklander * Return 2489ed30d1SJens Wiklander * - TEE_SUCCESS in case of success, 2589ed30d1SJens Wiklander * - TEE_ERROR_BAD_PARAMETERS in case algo is not a valid algo 2689ed30d1SJens Wiklander * - TEE_ERROR_NOT_SUPPORTED in case algo is not supported by LTC 2789ed30d1SJens Wiklander * Return -1 in case of error 2889ed30d1SJens Wiklander */ 2989ed30d1SJens Wiklander static TEE_Result tee_algo_to_ltc_hashindex(uint32_t algo, int *ltc_hashindex) 3089ed30d1SJens Wiklander { 3189ed30d1SJens Wiklander switch (algo) { 32a1cbb728SJens Wiklander #if defined(_CFG_CORE_LTC_SHA1) 3389ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_V1_5_SHA1: 3489ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA1: 3589ed30d1SJens Wiklander case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA1: 3689ed30d1SJens Wiklander *ltc_hashindex = find_hash("sha1"); 3789ed30d1SJens Wiklander break; 3889ed30d1SJens Wiklander #endif 39a1cbb728SJens Wiklander #if defined(_CFG_CORE_LTC_MD5) 4089ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_V1_5_MD5: 4189ed30d1SJens Wiklander *ltc_hashindex = find_hash("md5"); 4289ed30d1SJens Wiklander break; 4389ed30d1SJens Wiklander #endif 44a1cbb728SJens Wiklander #if defined(_CFG_CORE_LTC_SHA224) 4589ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_V1_5_SHA224: 4689ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA224: 4789ed30d1SJens Wiklander case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA224: 4889ed30d1SJens Wiklander *ltc_hashindex = find_hash("sha224"); 4989ed30d1SJens Wiklander break; 5089ed30d1SJens Wiklander #endif 51a1cbb728SJens Wiklander #if defined(_CFG_CORE_LTC_SHA256) 5289ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_V1_5_SHA256: 5389ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256: 5489ed30d1SJens Wiklander case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA256: 5589ed30d1SJens Wiklander *ltc_hashindex = find_hash("sha256"); 5689ed30d1SJens Wiklander break; 5789ed30d1SJens Wiklander #endif 58a1cbb728SJens Wiklander #if defined(_CFG_CORE_LTC_SHA384) 5989ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_V1_5_SHA384: 6089ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA384: 6189ed30d1SJens Wiklander case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA384: 6289ed30d1SJens Wiklander *ltc_hashindex = find_hash("sha384"); 6389ed30d1SJens Wiklander break; 6489ed30d1SJens Wiklander #endif 65a1cbb728SJens Wiklander #if defined(_CFG_CORE_LTC_SHA512) 6689ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_V1_5_SHA512: 6789ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA512: 6889ed30d1SJens Wiklander case TEE_ALG_RSAES_PKCS1_OAEP_MGF1_SHA512: 6989ed30d1SJens Wiklander *ltc_hashindex = find_hash("sha512"); 7089ed30d1SJens Wiklander break; 7189ed30d1SJens Wiklander #endif 7289ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_V1_5: 7389ed30d1SJens Wiklander case TEE_ALG_RSAES_PKCS1_V1_5: 7489ed30d1SJens Wiklander /* invalid one. but it should not be used anyway */ 7589ed30d1SJens Wiklander *ltc_hashindex = -1; 7689ed30d1SJens Wiklander return TEE_SUCCESS; 7789ed30d1SJens Wiklander 7889ed30d1SJens Wiklander default: 7989ed30d1SJens Wiklander return TEE_ERROR_BAD_PARAMETERS; 8089ed30d1SJens Wiklander } 8189ed30d1SJens Wiklander 8289ed30d1SJens Wiklander if (*ltc_hashindex < 0) 8389ed30d1SJens Wiklander return TEE_ERROR_NOT_SUPPORTED; 8489ed30d1SJens Wiklander else 8589ed30d1SJens Wiklander return TEE_SUCCESS; 8689ed30d1SJens Wiklander } 8789ed30d1SJens Wiklander 8889ed30d1SJens Wiklander TEE_Result crypto_acipher_alloc_rsa_keypair(struct rsa_keypair *s, 8989ed30d1SJens Wiklander size_t key_size_bits __unused) 90c2c27539SJorge Ramirez-Ortiz __weak __alias("sw_crypto_acipher_alloc_rsa_keypair"); 91c2c27539SJorge Ramirez-Ortiz 92c2c27539SJorge Ramirez-Ortiz TEE_Result sw_crypto_acipher_alloc_rsa_keypair(struct rsa_keypair *s, 93c2c27539SJorge Ramirez-Ortiz size_t key_size_bits __unused) 9489ed30d1SJens Wiklander { 9589ed30d1SJens Wiklander memset(s, 0, sizeof(*s)); 9689ed30d1SJens Wiklander if (!bn_alloc_max(&s->e)) 9789ed30d1SJens Wiklander return TEE_ERROR_OUT_OF_MEMORY; 9889ed30d1SJens Wiklander if (!bn_alloc_max(&s->d)) 9989ed30d1SJens Wiklander goto err; 10089ed30d1SJens Wiklander if (!bn_alloc_max(&s->n)) 10189ed30d1SJens Wiklander goto err; 10289ed30d1SJens Wiklander if (!bn_alloc_max(&s->p)) 10389ed30d1SJens Wiklander goto err; 10489ed30d1SJens Wiklander if (!bn_alloc_max(&s->q)) 10589ed30d1SJens Wiklander goto err; 10689ed30d1SJens Wiklander if (!bn_alloc_max(&s->qp)) 10789ed30d1SJens Wiklander goto err; 10889ed30d1SJens Wiklander if (!bn_alloc_max(&s->dp)) 10989ed30d1SJens Wiklander goto err; 11089ed30d1SJens Wiklander if (!bn_alloc_max(&s->dq)) 11189ed30d1SJens Wiklander goto err; 11289ed30d1SJens Wiklander 11389ed30d1SJens Wiklander return TEE_SUCCESS; 11489ed30d1SJens Wiklander err: 11592e38694SJerome Forissier crypto_acipher_free_rsa_keypair(s); 11689ed30d1SJens Wiklander return TEE_ERROR_OUT_OF_MEMORY; 11789ed30d1SJens Wiklander } 11889ed30d1SJens Wiklander 119c2c27539SJorge Ramirez-Ortiz 12089ed30d1SJens Wiklander TEE_Result crypto_acipher_alloc_rsa_public_key(struct rsa_public_key *s, 12189ed30d1SJens Wiklander size_t key_size_bits __unused) 122c2c27539SJorge Ramirez-Ortiz __weak __alias("sw_crypto_acipher_alloc_rsa_public_key"); 123c2c27539SJorge Ramirez-Ortiz 124c2c27539SJorge Ramirez-Ortiz TEE_Result sw_crypto_acipher_alloc_rsa_public_key(struct rsa_public_key *s, 125c2c27539SJorge Ramirez-Ortiz size_t key_size_bits __unused) 12689ed30d1SJens Wiklander { 12789ed30d1SJens Wiklander memset(s, 0, sizeof(*s)); 12889ed30d1SJens Wiklander if (!bn_alloc_max(&s->e)) 12989ed30d1SJens Wiklander return TEE_ERROR_OUT_OF_MEMORY; 13089ed30d1SJens Wiklander if (!bn_alloc_max(&s->n)) 13189ed30d1SJens Wiklander goto err; 13289ed30d1SJens Wiklander return TEE_SUCCESS; 13389ed30d1SJens Wiklander err: 13489ed30d1SJens Wiklander crypto_bignum_free(s->e); 13589ed30d1SJens Wiklander return TEE_ERROR_OUT_OF_MEMORY; 13689ed30d1SJens Wiklander } 13789ed30d1SJens Wiklander 138c2c27539SJorge Ramirez-Ortiz 13989ed30d1SJens Wiklander void crypto_acipher_free_rsa_public_key(struct rsa_public_key *s) 140c2c27539SJorge Ramirez-Ortiz __weak __alias("sw_crypto_acipher_free_rsa_public_key"); 141c2c27539SJorge Ramirez-Ortiz 142c2c27539SJorge Ramirez-Ortiz void sw_crypto_acipher_free_rsa_public_key(struct rsa_public_key *s) 14389ed30d1SJens Wiklander { 14489ed30d1SJens Wiklander if (!s) 14589ed30d1SJens Wiklander return; 14689ed30d1SJens Wiklander crypto_bignum_free(s->n); 14789ed30d1SJens Wiklander crypto_bignum_free(s->e); 14889ed30d1SJens Wiklander } 14989ed30d1SJens Wiklander 150c2c27539SJorge Ramirez-Ortiz 151a1d5c81fSElias von Däniken void crypto_acipher_free_rsa_keypair(struct rsa_keypair *s) 152c2c27539SJorge Ramirez-Ortiz __weak __alias("sw_crypto_acipher_free_rsa_keypair"); 153c2c27539SJorge Ramirez-Ortiz 154c2c27539SJorge Ramirez-Ortiz void sw_crypto_acipher_free_rsa_keypair(struct rsa_keypair *s) 155a1d5c81fSElias von Däniken { 156a1d5c81fSElias von Däniken if (!s) 157a1d5c81fSElias von Däniken return; 158a1d5c81fSElias von Däniken crypto_bignum_free(s->e); 159a1d5c81fSElias von Däniken crypto_bignum_free(s->d); 160a1d5c81fSElias von Däniken crypto_bignum_free(s->n); 161a1d5c81fSElias von Däniken crypto_bignum_free(s->p); 162a1d5c81fSElias von Däniken crypto_bignum_free(s->q); 163a1d5c81fSElias von Däniken crypto_bignum_free(s->qp); 164a1d5c81fSElias von Däniken crypto_bignum_free(s->dp); 16585f7c554SJerome Forissier crypto_bignum_free(s->dq); 166a1d5c81fSElias von Däniken } 167a1d5c81fSElias von Däniken 168c2c27539SJorge Ramirez-Ortiz TEE_Result crypto_acipher_gen_rsa_key(struct rsa_keypair *key, 169c2c27539SJorge Ramirez-Ortiz size_t key_size) 170c2c27539SJorge Ramirez-Ortiz __weak __alias("sw_crypto_acipher_gen_rsa_key"); 171c2c27539SJorge Ramirez-Ortiz 172c2c27539SJorge Ramirez-Ortiz TEE_Result sw_crypto_acipher_gen_rsa_key(struct rsa_keypair *key, 173c2c27539SJorge Ramirez-Ortiz size_t key_size) 17489ed30d1SJens Wiklander { 17589ed30d1SJens Wiklander TEE_Result res; 17689ed30d1SJens Wiklander rsa_key ltc_tmp_key; 17789ed30d1SJens Wiklander int ltc_res; 17889ed30d1SJens Wiklander 17989ed30d1SJens Wiklander /* Generate a temporary RSA key */ 18074524a75SCedric Neveux ltc_res = rsa_make_key_bn_e(NULL, find_prng("prng_crypto"), 18174524a75SCedric Neveux key_size / 8, key->e, <c_tmp_key); 18289ed30d1SJens Wiklander if (ltc_res != CRYPT_OK) { 18389ed30d1SJens Wiklander res = TEE_ERROR_BAD_PARAMETERS; 18489ed30d1SJens Wiklander } else if ((size_t)mp_count_bits(ltc_tmp_key.N) != key_size) { 18589ed30d1SJens Wiklander rsa_free(<c_tmp_key); 18689ed30d1SJens Wiklander res = TEE_ERROR_BAD_PARAMETERS; 18789ed30d1SJens Wiklander } else { 18889ed30d1SJens Wiklander /* Copy the key */ 18989ed30d1SJens Wiklander ltc_mp.copy(ltc_tmp_key.d, key->d); 19089ed30d1SJens Wiklander ltc_mp.copy(ltc_tmp_key.N, key->n); 19189ed30d1SJens Wiklander ltc_mp.copy(ltc_tmp_key.p, key->p); 19289ed30d1SJens Wiklander ltc_mp.copy(ltc_tmp_key.q, key->q); 19389ed30d1SJens Wiklander ltc_mp.copy(ltc_tmp_key.qP, key->qp); 19489ed30d1SJens Wiklander ltc_mp.copy(ltc_tmp_key.dP, key->dp); 19589ed30d1SJens Wiklander ltc_mp.copy(ltc_tmp_key.dQ, key->dq); 19689ed30d1SJens Wiklander 19789ed30d1SJens Wiklander /* Free the temporary key */ 19889ed30d1SJens Wiklander rsa_free(<c_tmp_key); 19989ed30d1SJens Wiklander res = TEE_SUCCESS; 20089ed30d1SJens Wiklander } 20189ed30d1SJens Wiklander 20289ed30d1SJens Wiklander return res; 20389ed30d1SJens Wiklander } 20489ed30d1SJens Wiklander 20589ed30d1SJens Wiklander static TEE_Result rsadorep(rsa_key *ltc_key, const uint8_t *src, 20689ed30d1SJens Wiklander size_t src_len, uint8_t *dst, size_t *dst_len) 20789ed30d1SJens Wiklander { 20889ed30d1SJens Wiklander TEE_Result res = TEE_SUCCESS; 20989ed30d1SJens Wiklander uint8_t *buf = NULL; 21089ed30d1SJens Wiklander unsigned long blen, offset; 21189ed30d1SJens Wiklander int ltc_res; 21289ed30d1SJens Wiklander 21389ed30d1SJens Wiklander /* 21489ed30d1SJens Wiklander * Use a temporary buffer since we don't know exactly how large the 21589ed30d1SJens Wiklander * required size of the out buffer without doing a partial decrypt. 21689ed30d1SJens Wiklander * We know the upper bound though. 21789ed30d1SJens Wiklander */ 218a1cbb728SJens Wiklander blen = _CFG_CORE_LTC_BIGNUM_MAX_BITS / sizeof(uint8_t); 219*d71c4cd4SJens Wiklander buf = mempool_alloc(mempool_default, blen); 22089ed30d1SJens Wiklander if (!buf) { 22189ed30d1SJens Wiklander res = TEE_ERROR_OUT_OF_MEMORY; 22289ed30d1SJens Wiklander goto out; 22389ed30d1SJens Wiklander } 22489ed30d1SJens Wiklander 22589ed30d1SJens Wiklander ltc_res = rsa_exptmod(src, src_len, buf, &blen, ltc_key->type, 22689ed30d1SJens Wiklander ltc_key); 22789ed30d1SJens Wiklander switch (ltc_res) { 22889ed30d1SJens Wiklander case CRYPT_PK_NOT_PRIVATE: 22989ed30d1SJens Wiklander case CRYPT_PK_INVALID_TYPE: 23089ed30d1SJens Wiklander case CRYPT_PK_INVALID_SIZE: 23189ed30d1SJens Wiklander case CRYPT_INVALID_PACKET: 23289ed30d1SJens Wiklander EMSG("rsa_exptmod() returned %d", ltc_res); 23389ed30d1SJens Wiklander res = TEE_ERROR_BAD_PARAMETERS; 23489ed30d1SJens Wiklander goto out; 23589ed30d1SJens Wiklander case CRYPT_OK: 23689ed30d1SJens Wiklander break; 23789ed30d1SJens Wiklander default: 23889ed30d1SJens Wiklander /* This will result in a panic */ 23989ed30d1SJens Wiklander EMSG("rsa_exptmod() returned %d", ltc_res); 24089ed30d1SJens Wiklander res = TEE_ERROR_GENERIC; 24189ed30d1SJens Wiklander goto out; 24289ed30d1SJens Wiklander } 24389ed30d1SJens Wiklander 24489ed30d1SJens Wiklander /* Remove the zero-padding (leave one zero if buff is all zeroes) */ 24589ed30d1SJens Wiklander offset = 0; 24689ed30d1SJens Wiklander while ((offset < blen - 1) && (buf[offset] == 0)) 24789ed30d1SJens Wiklander offset++; 24889ed30d1SJens Wiklander 24989ed30d1SJens Wiklander if (*dst_len < blen - offset) { 25089ed30d1SJens Wiklander *dst_len = blen - offset; 25189ed30d1SJens Wiklander res = TEE_ERROR_SHORT_BUFFER; 25289ed30d1SJens Wiklander goto out; 25389ed30d1SJens Wiklander } 25489ed30d1SJens Wiklander 25589ed30d1SJens Wiklander res = TEE_SUCCESS; 25689ed30d1SJens Wiklander *dst_len = blen - offset; 25789ed30d1SJens Wiklander memcpy(dst, (char *)buf + offset, *dst_len); 25889ed30d1SJens Wiklander 25989ed30d1SJens Wiklander out: 260*d71c4cd4SJens Wiklander mempool_free(mempool_default, buf); 26189ed30d1SJens Wiklander 26289ed30d1SJens Wiklander return res; 26389ed30d1SJens Wiklander } 26489ed30d1SJens Wiklander 26589ed30d1SJens Wiklander TEE_Result crypto_acipher_rsanopad_encrypt(struct rsa_public_key *key, 266c2c27539SJorge Ramirez-Ortiz const uint8_t *src, 267c2c27539SJorge Ramirez-Ortiz size_t src_len, uint8_t *dst, 268c2c27539SJorge Ramirez-Ortiz size_t *dst_len) 269c2c27539SJorge Ramirez-Ortiz __weak __alias("sw_crypto_acipher_rsanopad_encrypt"); 270c2c27539SJorge Ramirez-Ortiz 271c2c27539SJorge Ramirez-Ortiz TEE_Result sw_crypto_acipher_rsanopad_encrypt(struct rsa_public_key *key, 272c2c27539SJorge Ramirez-Ortiz const uint8_t *src, 273c2c27539SJorge Ramirez-Ortiz size_t src_len, uint8_t *dst, 274c2c27539SJorge Ramirez-Ortiz size_t *dst_len) 27589ed30d1SJens Wiklander { 27689ed30d1SJens Wiklander TEE_Result res; 27789ed30d1SJens Wiklander rsa_key ltc_key = { 0, }; 27889ed30d1SJens Wiklander 27989ed30d1SJens Wiklander ltc_key.type = PK_PUBLIC; 28089ed30d1SJens Wiklander ltc_key.e = key->e; 28189ed30d1SJens Wiklander ltc_key.N = key->n; 28289ed30d1SJens Wiklander 28389ed30d1SJens Wiklander res = rsadorep(<c_key, src, src_len, dst, dst_len); 28489ed30d1SJens Wiklander return res; 28589ed30d1SJens Wiklander } 28689ed30d1SJens Wiklander 28789ed30d1SJens Wiklander TEE_Result crypto_acipher_rsanopad_decrypt(struct rsa_keypair *key, 288c2c27539SJorge Ramirez-Ortiz const uint8_t *src, 289c2c27539SJorge Ramirez-Ortiz size_t src_len, uint8_t *dst, 290c2c27539SJorge Ramirez-Ortiz size_t *dst_len) 291c2c27539SJorge Ramirez-Ortiz __weak __alias("sw_crypto_acipher_rsanopad_decrypt"); 292c2c27539SJorge Ramirez-Ortiz 293c2c27539SJorge Ramirez-Ortiz TEE_Result sw_crypto_acipher_rsanopad_decrypt(struct rsa_keypair *key, 294c2c27539SJorge Ramirez-Ortiz const uint8_t *src, 295c2c27539SJorge Ramirez-Ortiz size_t src_len, uint8_t *dst, 296c2c27539SJorge Ramirez-Ortiz size_t *dst_len) 29789ed30d1SJens Wiklander { 29889ed30d1SJens Wiklander TEE_Result res; 29989ed30d1SJens Wiklander rsa_key ltc_key = { 0, }; 30089ed30d1SJens Wiklander 30189ed30d1SJens Wiklander ltc_key.type = PK_PRIVATE; 30289ed30d1SJens Wiklander ltc_key.e = key->e; 30389ed30d1SJens Wiklander ltc_key.N = key->n; 30489ed30d1SJens Wiklander ltc_key.d = key->d; 30589ed30d1SJens Wiklander if (key->p && crypto_bignum_num_bytes(key->p)) { 30689ed30d1SJens Wiklander ltc_key.p = key->p; 30789ed30d1SJens Wiklander ltc_key.q = key->q; 30889ed30d1SJens Wiklander ltc_key.qP = key->qp; 30989ed30d1SJens Wiklander ltc_key.dP = key->dp; 31089ed30d1SJens Wiklander ltc_key.dQ = key->dq; 31189ed30d1SJens Wiklander } 31289ed30d1SJens Wiklander 31389ed30d1SJens Wiklander res = rsadorep(<c_key, src, src_len, dst, dst_len); 31489ed30d1SJens Wiklander return res; 31589ed30d1SJens Wiklander } 31689ed30d1SJens Wiklander 317c2c27539SJorge Ramirez-Ortiz TEE_Result crypto_acipher_rsaes_decrypt(uint32_t algo, 318c2c27539SJorge Ramirez-Ortiz struct rsa_keypair *key, 319c2c27539SJorge Ramirez-Ortiz const uint8_t *label, 320c2c27539SJorge Ramirez-Ortiz size_t label_len, const uint8_t *src, 321c2c27539SJorge Ramirez-Ortiz size_t src_len, uint8_t *dst, 322c2c27539SJorge Ramirez-Ortiz size_t *dst_len) 323c2c27539SJorge Ramirez-Ortiz __weak __alias("sw_crypto_acipher_rsaes_decrypt"); 324c2c27539SJorge Ramirez-Ortiz 325c2c27539SJorge Ramirez-Ortiz TEE_Result sw_crypto_acipher_rsaes_decrypt(uint32_t algo, 326c2c27539SJorge Ramirez-Ortiz struct rsa_keypair *key, 327c2c27539SJorge Ramirez-Ortiz const uint8_t *label, 328c2c27539SJorge Ramirez-Ortiz size_t label_len, const uint8_t *src, 329c2c27539SJorge Ramirez-Ortiz size_t src_len, uint8_t *dst, 330c2c27539SJorge Ramirez-Ortiz size_t *dst_len) 33189ed30d1SJens Wiklander { 33289ed30d1SJens Wiklander TEE_Result res = TEE_SUCCESS; 33389ed30d1SJens Wiklander void *buf = NULL; 33489ed30d1SJens Wiklander unsigned long blen; 33589ed30d1SJens Wiklander int ltc_hashindex, ltc_res, ltc_stat, ltc_rsa_algo; 33689ed30d1SJens Wiklander size_t mod_size; 33789ed30d1SJens Wiklander rsa_key ltc_key = { 0, }; 33889ed30d1SJens Wiklander 33989ed30d1SJens Wiklander ltc_key.type = PK_PRIVATE; 34089ed30d1SJens Wiklander ltc_key.e = key->e; 34189ed30d1SJens Wiklander ltc_key.d = key->d; 34289ed30d1SJens Wiklander ltc_key.N = key->n; 34389ed30d1SJens Wiklander if (key->p && crypto_bignum_num_bytes(key->p)) { 34489ed30d1SJens Wiklander ltc_key.p = key->p; 34589ed30d1SJens Wiklander ltc_key.q = key->q; 34689ed30d1SJens Wiklander ltc_key.qP = key->qp; 34789ed30d1SJens Wiklander ltc_key.dP = key->dp; 34889ed30d1SJens Wiklander ltc_key.dQ = key->dq; 34989ed30d1SJens Wiklander } 35089ed30d1SJens Wiklander 35189ed30d1SJens Wiklander /* Get the algorithm */ 35289ed30d1SJens Wiklander res = tee_algo_to_ltc_hashindex(algo, <c_hashindex); 35389ed30d1SJens Wiklander if (res != TEE_SUCCESS) { 35489ed30d1SJens Wiklander EMSG("tee_algo_to_ltc_hashindex() returned %d", (int)res); 35589ed30d1SJens Wiklander goto out; 35689ed30d1SJens Wiklander } 35789ed30d1SJens Wiklander 35889ed30d1SJens Wiklander /* 35989ed30d1SJens Wiklander * Use a temporary buffer since we don't know exactly how large 36089ed30d1SJens Wiklander * the required size of the out buffer without doing a partial 36189ed30d1SJens Wiklander * decrypt. We know the upper bound though. 36289ed30d1SJens Wiklander */ 36389ed30d1SJens Wiklander if (algo == TEE_ALG_RSAES_PKCS1_V1_5) { 36489ed30d1SJens Wiklander mod_size = ltc_mp.unsigned_size((void *)(ltc_key.N)); 36589ed30d1SJens Wiklander blen = mod_size - 11; 36689ed30d1SJens Wiklander ltc_rsa_algo = LTC_PKCS_1_V1_5; 36789ed30d1SJens Wiklander } else { 36889ed30d1SJens Wiklander /* Decoded message is always shorter than encrypted message */ 36989ed30d1SJens Wiklander blen = src_len; 37089ed30d1SJens Wiklander ltc_rsa_algo = LTC_PKCS_1_OAEP; 37189ed30d1SJens Wiklander } 37289ed30d1SJens Wiklander 373*d71c4cd4SJens Wiklander buf = mempool_alloc(mempool_default, blen); 37489ed30d1SJens Wiklander if (!buf) { 37589ed30d1SJens Wiklander res = TEE_ERROR_OUT_OF_MEMORY; 37689ed30d1SJens Wiklander goto out; 37789ed30d1SJens Wiklander } 37889ed30d1SJens Wiklander 37989ed30d1SJens Wiklander ltc_res = rsa_decrypt_key_ex(src, src_len, buf, &blen, 38089ed30d1SJens Wiklander ((label_len == 0) ? 0 : label), label_len, 38189ed30d1SJens Wiklander ltc_hashindex, ltc_rsa_algo, <c_stat, 38289ed30d1SJens Wiklander <c_key); 38389ed30d1SJens Wiklander switch (ltc_res) { 38489ed30d1SJens Wiklander case CRYPT_PK_INVALID_PADDING: 38589ed30d1SJens Wiklander case CRYPT_INVALID_PACKET: 38689ed30d1SJens Wiklander case CRYPT_PK_INVALID_SIZE: 38789ed30d1SJens Wiklander EMSG("rsa_decrypt_key_ex() returned %d", ltc_res); 38889ed30d1SJens Wiklander res = TEE_ERROR_BAD_PARAMETERS; 38989ed30d1SJens Wiklander goto out; 39089ed30d1SJens Wiklander case CRYPT_OK: 39189ed30d1SJens Wiklander break; 39289ed30d1SJens Wiklander default: 39389ed30d1SJens Wiklander /* This will result in a panic */ 39489ed30d1SJens Wiklander EMSG("rsa_decrypt_key_ex() returned %d", ltc_res); 39589ed30d1SJens Wiklander res = TEE_ERROR_GENERIC; 39689ed30d1SJens Wiklander goto out; 39789ed30d1SJens Wiklander } 39889ed30d1SJens Wiklander if (ltc_stat != 1) { 39989ed30d1SJens Wiklander /* This will result in a panic */ 40089ed30d1SJens Wiklander EMSG("rsa_decrypt_key_ex() returned %d and %d", 40189ed30d1SJens Wiklander ltc_res, ltc_stat); 40289ed30d1SJens Wiklander res = TEE_ERROR_GENERIC; 40389ed30d1SJens Wiklander goto out; 40489ed30d1SJens Wiklander } 40589ed30d1SJens Wiklander 40689ed30d1SJens Wiklander if (*dst_len < blen) { 40789ed30d1SJens Wiklander *dst_len = blen; 40889ed30d1SJens Wiklander res = TEE_ERROR_SHORT_BUFFER; 40989ed30d1SJens Wiklander goto out; 41089ed30d1SJens Wiklander } 41189ed30d1SJens Wiklander 41289ed30d1SJens Wiklander res = TEE_SUCCESS; 41389ed30d1SJens Wiklander *dst_len = blen; 41489ed30d1SJens Wiklander memcpy(dst, buf, blen); 41589ed30d1SJens Wiklander 41689ed30d1SJens Wiklander out: 417*d71c4cd4SJens Wiklander mempool_free(mempool_default, buf); 41889ed30d1SJens Wiklander 41989ed30d1SJens Wiklander return res; 42089ed30d1SJens Wiklander } 42189ed30d1SJens Wiklander 42289ed30d1SJens Wiklander TEE_Result crypto_acipher_rsaes_encrypt(uint32_t algo, 42389ed30d1SJens Wiklander struct rsa_public_key *key, 424c2c27539SJorge Ramirez-Ortiz const uint8_t *label, 425c2c27539SJorge Ramirez-Ortiz size_t label_len, const uint8_t *src, 426c2c27539SJorge Ramirez-Ortiz size_t src_len, uint8_t *dst, 427c2c27539SJorge Ramirez-Ortiz size_t *dst_len) 428c2c27539SJorge Ramirez-Ortiz __weak __alias("sw_crypto_acipher_rsaes_encrypt"); 429c2c27539SJorge Ramirez-Ortiz 430c2c27539SJorge Ramirez-Ortiz TEE_Result sw_crypto_acipher_rsaes_encrypt(uint32_t algo, 431c2c27539SJorge Ramirez-Ortiz struct rsa_public_key *key, 432c2c27539SJorge Ramirez-Ortiz const uint8_t *label, 433c2c27539SJorge Ramirez-Ortiz size_t label_len, const uint8_t *src, 434c2c27539SJorge Ramirez-Ortiz size_t src_len, uint8_t *dst, 435c2c27539SJorge Ramirez-Ortiz size_t *dst_len) 43689ed30d1SJens Wiklander { 43789ed30d1SJens Wiklander TEE_Result res; 43889ed30d1SJens Wiklander uint32_t mod_size; 43989ed30d1SJens Wiklander int ltc_hashindex, ltc_res, ltc_rsa_algo; 44089ed30d1SJens Wiklander rsa_key ltc_key = { 44189ed30d1SJens Wiklander .type = PK_PUBLIC, 44289ed30d1SJens Wiklander .e = key->e, 44389ed30d1SJens Wiklander .N = key->n 44489ed30d1SJens Wiklander }; 44589ed30d1SJens Wiklander 44689ed30d1SJens Wiklander mod_size = ltc_mp.unsigned_size((void *)(ltc_key.N)); 44789ed30d1SJens Wiklander if (*dst_len < mod_size) { 44889ed30d1SJens Wiklander *dst_len = mod_size; 44989ed30d1SJens Wiklander res = TEE_ERROR_SHORT_BUFFER; 45089ed30d1SJens Wiklander goto out; 45189ed30d1SJens Wiklander } 45289ed30d1SJens Wiklander *dst_len = mod_size; 45389ed30d1SJens Wiklander 45489ed30d1SJens Wiklander /* Get the algorithm */ 45589ed30d1SJens Wiklander res = tee_algo_to_ltc_hashindex(algo, <c_hashindex); 45689ed30d1SJens Wiklander if (res != TEE_SUCCESS) 45789ed30d1SJens Wiklander goto out; 45889ed30d1SJens Wiklander 45989ed30d1SJens Wiklander if (algo == TEE_ALG_RSAES_PKCS1_V1_5) 46089ed30d1SJens Wiklander ltc_rsa_algo = LTC_PKCS_1_V1_5; 46189ed30d1SJens Wiklander else 46289ed30d1SJens Wiklander ltc_rsa_algo = LTC_PKCS_1_OAEP; 46389ed30d1SJens Wiklander 46489ed30d1SJens Wiklander ltc_res = rsa_encrypt_key_ex(src, src_len, dst, 46589ed30d1SJens Wiklander (unsigned long *)(dst_len), label, 4661f3b1115SJens Wiklander label_len, NULL, find_prng("prng_crypto"), 46789ed30d1SJens Wiklander ltc_hashindex, ltc_rsa_algo, <c_key); 46889ed30d1SJens Wiklander switch (ltc_res) { 46989ed30d1SJens Wiklander case CRYPT_PK_INVALID_PADDING: 47089ed30d1SJens Wiklander case CRYPT_INVALID_PACKET: 47189ed30d1SJens Wiklander case CRYPT_PK_INVALID_SIZE: 47289ed30d1SJens Wiklander EMSG("rsa_encrypt_key_ex() returned %d", ltc_res); 47389ed30d1SJens Wiklander res = TEE_ERROR_BAD_PARAMETERS; 47489ed30d1SJens Wiklander goto out; 47589ed30d1SJens Wiklander case CRYPT_OK: 47689ed30d1SJens Wiklander break; 47789ed30d1SJens Wiklander default: 47889ed30d1SJens Wiklander /* This will result in a panic */ 47989ed30d1SJens Wiklander res = TEE_ERROR_GENERIC; 48089ed30d1SJens Wiklander goto out; 48189ed30d1SJens Wiklander } 48289ed30d1SJens Wiklander res = TEE_SUCCESS; 48389ed30d1SJens Wiklander 48489ed30d1SJens Wiklander out: 48589ed30d1SJens Wiklander return res; 48689ed30d1SJens Wiklander } 48789ed30d1SJens Wiklander 48889ed30d1SJens Wiklander TEE_Result crypto_acipher_rsassa_sign(uint32_t algo, struct rsa_keypair *key, 48989ed30d1SJens Wiklander int salt_len, const uint8_t *msg, 49089ed30d1SJens Wiklander size_t msg_len, uint8_t *sig, 49189ed30d1SJens Wiklander size_t *sig_len) 492c2c27539SJorge Ramirez-Ortiz __weak __alias("sw_crypto_acipher_rsassa_sign"); 493c2c27539SJorge Ramirez-Ortiz 494c2c27539SJorge Ramirez-Ortiz TEE_Result sw_crypto_acipher_rsassa_sign(uint32_t algo, struct rsa_keypair *key, 495c2c27539SJorge Ramirez-Ortiz int salt_len, const uint8_t *msg, 496c2c27539SJorge Ramirez-Ortiz size_t msg_len, uint8_t *sig, 497c2c27539SJorge Ramirez-Ortiz size_t *sig_len) 49889ed30d1SJens Wiklander { 49989ed30d1SJens Wiklander TEE_Result res; 50089ed30d1SJens Wiklander size_t hash_size, mod_size; 50189ed30d1SJens Wiklander int ltc_res, ltc_rsa_algo, ltc_hashindex; 50289ed30d1SJens Wiklander unsigned long ltc_sig_len; 50389ed30d1SJens Wiklander rsa_key ltc_key = { 0, }; 50489ed30d1SJens Wiklander 50589ed30d1SJens Wiklander ltc_key.type = PK_PRIVATE; 50689ed30d1SJens Wiklander ltc_key.e = key->e; 50789ed30d1SJens Wiklander ltc_key.N = key->n; 50889ed30d1SJens Wiklander ltc_key.d = key->d; 50989ed30d1SJens Wiklander if (key->p && crypto_bignum_num_bytes(key->p)) { 51089ed30d1SJens Wiklander ltc_key.p = key->p; 51189ed30d1SJens Wiklander ltc_key.q = key->q; 51289ed30d1SJens Wiklander ltc_key.qP = key->qp; 51389ed30d1SJens Wiklander ltc_key.dP = key->dp; 51489ed30d1SJens Wiklander ltc_key.dQ = key->dq; 51589ed30d1SJens Wiklander } 51689ed30d1SJens Wiklander 51789ed30d1SJens Wiklander switch (algo) { 51889ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_V1_5: 51989ed30d1SJens Wiklander ltc_rsa_algo = LTC_PKCS_1_V1_5_NA1; 52089ed30d1SJens Wiklander break; 52189ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_V1_5_MD5: 52289ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_V1_5_SHA1: 52389ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_V1_5_SHA224: 52489ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_V1_5_SHA256: 52589ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_V1_5_SHA384: 52689ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_V1_5_SHA512: 52789ed30d1SJens Wiklander ltc_rsa_algo = LTC_PKCS_1_V1_5; 52889ed30d1SJens Wiklander break; 52989ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA1: 53089ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA224: 53189ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256: 53289ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA384: 53389ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA512: 53489ed30d1SJens Wiklander ltc_rsa_algo = LTC_PKCS_1_PSS; 53589ed30d1SJens Wiklander break; 53689ed30d1SJens Wiklander default: 53789ed30d1SJens Wiklander res = TEE_ERROR_BAD_PARAMETERS; 53889ed30d1SJens Wiklander goto err; 53989ed30d1SJens Wiklander } 54089ed30d1SJens Wiklander 54189ed30d1SJens Wiklander if (ltc_rsa_algo != LTC_PKCS_1_V1_5_NA1) { 54289ed30d1SJens Wiklander ltc_res = tee_algo_to_ltc_hashindex(algo, <c_hashindex); 54389ed30d1SJens Wiklander if (ltc_res != CRYPT_OK) { 54489ed30d1SJens Wiklander res = TEE_ERROR_BAD_PARAMETERS; 54589ed30d1SJens Wiklander goto err; 54689ed30d1SJens Wiklander } 54789ed30d1SJens Wiklander 5487c767434SAlbert Schwarzkopf res = tee_alg_get_digest_size(TEE_DIGEST_HASH_TO_ALGO(algo), 54989ed30d1SJens Wiklander &hash_size); 55089ed30d1SJens Wiklander if (res != TEE_SUCCESS) 55189ed30d1SJens Wiklander goto err; 55289ed30d1SJens Wiklander 55389ed30d1SJens Wiklander if (msg_len != hash_size) { 55489ed30d1SJens Wiklander res = TEE_ERROR_BAD_PARAMETERS; 55589ed30d1SJens Wiklander goto err; 55689ed30d1SJens Wiklander } 55789ed30d1SJens Wiklander } 55889ed30d1SJens Wiklander 55989ed30d1SJens Wiklander mod_size = ltc_mp.unsigned_size((void *)(ltc_key.N)); 56089ed30d1SJens Wiklander 56189ed30d1SJens Wiklander if (*sig_len < mod_size) { 56289ed30d1SJens Wiklander *sig_len = mod_size; 56389ed30d1SJens Wiklander res = TEE_ERROR_SHORT_BUFFER; 56489ed30d1SJens Wiklander goto err; 56589ed30d1SJens Wiklander } 56689ed30d1SJens Wiklander 56789ed30d1SJens Wiklander ltc_sig_len = mod_size; 56889ed30d1SJens Wiklander 56989ed30d1SJens Wiklander ltc_res = rsa_sign_hash_ex(msg, msg_len, sig, <c_sig_len, 5701f3b1115SJens Wiklander ltc_rsa_algo, NULL, find_prng("prng_crypto"), 57189ed30d1SJens Wiklander ltc_hashindex, salt_len, <c_key); 57289ed30d1SJens Wiklander 57389ed30d1SJens Wiklander *sig_len = ltc_sig_len; 57489ed30d1SJens Wiklander 57589ed30d1SJens Wiklander if (ltc_res != CRYPT_OK) { 57689ed30d1SJens Wiklander res = TEE_ERROR_BAD_PARAMETERS; 57789ed30d1SJens Wiklander goto err; 57889ed30d1SJens Wiklander } 57989ed30d1SJens Wiklander res = TEE_SUCCESS; 58089ed30d1SJens Wiklander 58189ed30d1SJens Wiklander err: 58289ed30d1SJens Wiklander return res; 58389ed30d1SJens Wiklander } 58489ed30d1SJens Wiklander 58589ed30d1SJens Wiklander TEE_Result crypto_acipher_rsassa_verify(uint32_t algo, 58689ed30d1SJens Wiklander struct rsa_public_key *key, 58789ed30d1SJens Wiklander int salt_len, const uint8_t *msg, 58889ed30d1SJens Wiklander size_t msg_len, const uint8_t *sig, 58989ed30d1SJens Wiklander size_t sig_len) 590c2c27539SJorge Ramirez-Ortiz __weak __alias("sw_crypto_acipher_rsassa_verify"); 591c2c27539SJorge Ramirez-Ortiz 592c2c27539SJorge Ramirez-Ortiz TEE_Result sw_crypto_acipher_rsassa_verify(uint32_t algo, 593c2c27539SJorge Ramirez-Ortiz struct rsa_public_key *key, 594c2c27539SJorge Ramirez-Ortiz int salt_len, const uint8_t *msg, 595c2c27539SJorge Ramirez-Ortiz size_t msg_len, const uint8_t *sig, 596c2c27539SJorge Ramirez-Ortiz size_t sig_len) 59789ed30d1SJens Wiklander { 59889ed30d1SJens Wiklander TEE_Result res; 59989ed30d1SJens Wiklander uint32_t bigint_size; 60089ed30d1SJens Wiklander size_t hash_size; 60189ed30d1SJens Wiklander int stat, ltc_hashindex, ltc_res, ltc_rsa_algo; 60289ed30d1SJens Wiklander rsa_key ltc_key = { 60389ed30d1SJens Wiklander .type = PK_PUBLIC, 60489ed30d1SJens Wiklander .e = key->e, 60589ed30d1SJens Wiklander .N = key->n 60689ed30d1SJens Wiklander }; 6078f6ac972SJens Wiklander struct ftmn ftmn = { }; 6088f6ac972SJens Wiklander 6098f6ac972SJens Wiklander /* 6108f6ac972SJens Wiklander * The caller expects to call crypto_acipher_rsassa_verify(), 6118f6ac972SJens Wiklander * update the hash as needed. 6128f6ac972SJens Wiklander */ 6138f6ac972SJens Wiklander FTMN_CALLEE_SWAP_HASH(FTMN_FUNC_HASH("crypto_acipher_rsassa_verify")); 61489ed30d1SJens Wiklander 61589ed30d1SJens Wiklander if (algo != TEE_ALG_RSASSA_PKCS1_V1_5) { 6167c767434SAlbert Schwarzkopf res = tee_alg_get_digest_size(TEE_DIGEST_HASH_TO_ALGO(algo), 61789ed30d1SJens Wiklander &hash_size); 61889ed30d1SJens Wiklander if (res != TEE_SUCCESS) 61989ed30d1SJens Wiklander goto err; 62089ed30d1SJens Wiklander 62189ed30d1SJens Wiklander if (msg_len != hash_size) { 62289ed30d1SJens Wiklander res = TEE_ERROR_BAD_PARAMETERS; 62389ed30d1SJens Wiklander goto err; 62489ed30d1SJens Wiklander } 62589ed30d1SJens Wiklander } 62689ed30d1SJens Wiklander 62789ed30d1SJens Wiklander bigint_size = ltc_mp.unsigned_size(ltc_key.N); 62889ed30d1SJens Wiklander if (sig_len < bigint_size) { 62989ed30d1SJens Wiklander res = TEE_ERROR_SIGNATURE_INVALID; 63089ed30d1SJens Wiklander goto err; 63189ed30d1SJens Wiklander } 63289ed30d1SJens Wiklander 63389ed30d1SJens Wiklander /* Get the algorithm */ 63489ed30d1SJens Wiklander if (algo != TEE_ALG_RSASSA_PKCS1_V1_5) { 63589ed30d1SJens Wiklander res = tee_algo_to_ltc_hashindex(algo, <c_hashindex); 63689ed30d1SJens Wiklander if (res != TEE_SUCCESS) 63789ed30d1SJens Wiklander goto err; 63889ed30d1SJens Wiklander } 63989ed30d1SJens Wiklander 64089ed30d1SJens Wiklander switch (algo) { 64189ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_V1_5: 64289ed30d1SJens Wiklander ltc_rsa_algo = LTC_PKCS_1_V1_5_NA1; 64389ed30d1SJens Wiklander break; 64489ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_V1_5_MD5: 64589ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_V1_5_SHA1: 64689ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_V1_5_SHA224: 64789ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_V1_5_SHA256: 64889ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_V1_5_SHA384: 64989ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_V1_5_SHA512: 65089ed30d1SJens Wiklander ltc_rsa_algo = LTC_PKCS_1_V1_5; 65189ed30d1SJens Wiklander break; 65289ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA1: 65389ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA224: 65489ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256: 65589ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA384: 65689ed30d1SJens Wiklander case TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA512: 65789ed30d1SJens Wiklander ltc_rsa_algo = LTC_PKCS_1_PSS; 65889ed30d1SJens Wiklander break; 65989ed30d1SJens Wiklander default: 66089ed30d1SJens Wiklander res = TEE_ERROR_BAD_PARAMETERS; 66189ed30d1SJens Wiklander goto err; 66289ed30d1SJens Wiklander } 66389ed30d1SJens Wiklander 6648f6ac972SJens Wiklander FTMN_PUSH_LINKED_CALL(&ftmn, FTMN_FUNC_HASH("rsa_verify_hash_ex")); 66589ed30d1SJens Wiklander ltc_res = rsa_verify_hash_ex(sig, sig_len, msg, msg_len, ltc_rsa_algo, 66689ed30d1SJens Wiklander ltc_hashindex, salt_len, &stat, <c_key); 66789ed30d1SJens Wiklander res = convert_ltc_verify_status(ltc_res, stat); 6688f6ac972SJens Wiklander if (res) 6698f6ac972SJens Wiklander FTMN_SET_CHECK_RES_NOT_ZERO(&ftmn, FTMN_INCR0, res); 6708f6ac972SJens Wiklander else 6718f6ac972SJens Wiklander FTMN_SET_CHECK_RES_FROM_CALL(&ftmn, FTMN_INCR0, 0); 6728f6ac972SJens Wiklander FTMN_POP_LINKED_CALL(&ftmn); 6738f6ac972SJens Wiklander FTMN_CALLEE_DONE_CHECK(&ftmn, FTMN_INCR0, FTMN_STEP_COUNT(1), res); 6748f6ac972SJens Wiklander return res; 67589ed30d1SJens Wiklander err: 6768f6ac972SJens Wiklander FTMN_CALLEE_DONE_NOT_ZERO(res); 67789ed30d1SJens Wiklander return res; 67889ed30d1SJens Wiklander } 679