162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright(c) 2016-20 Intel Corporation. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#define _GNU_SOURCE 562306a36Sopenharmony_ci#include <assert.h> 662306a36Sopenharmony_ci#include <getopt.h> 762306a36Sopenharmony_ci#include <stdbool.h> 862306a36Sopenharmony_ci#include <stdint.h> 962306a36Sopenharmony_ci#include <stdio.h> 1062306a36Sopenharmony_ci#include <stdlib.h> 1162306a36Sopenharmony_ci#include <string.h> 1262306a36Sopenharmony_ci#include <sys/stat.h> 1362306a36Sopenharmony_ci#include <sys/types.h> 1462306a36Sopenharmony_ci#include <unistd.h> 1562306a36Sopenharmony_ci#include <openssl/err.h> 1662306a36Sopenharmony_ci#include <openssl/pem.h> 1762306a36Sopenharmony_ci#include "defines.h" 1862306a36Sopenharmony_ci#include "main.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* 2162306a36Sopenharmony_ci * FIXME: OpenSSL 3.0 has deprecated some functions. For now just ignore 2262306a36Sopenharmony_ci * the warnings. 2362306a36Sopenharmony_ci */ 2462306a36Sopenharmony_ci#pragma GCC diagnostic ignored "-Wdeprecated-declarations" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistruct q1q2_ctx { 2762306a36Sopenharmony_ci BN_CTX *bn_ctx; 2862306a36Sopenharmony_ci BIGNUM *m; 2962306a36Sopenharmony_ci BIGNUM *s; 3062306a36Sopenharmony_ci BIGNUM *q1; 3162306a36Sopenharmony_ci BIGNUM *qr; 3262306a36Sopenharmony_ci BIGNUM *q2; 3362306a36Sopenharmony_ci}; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic void free_q1q2_ctx(struct q1q2_ctx *ctx) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci BN_CTX_free(ctx->bn_ctx); 3862306a36Sopenharmony_ci BN_free(ctx->m); 3962306a36Sopenharmony_ci BN_free(ctx->s); 4062306a36Sopenharmony_ci BN_free(ctx->q1); 4162306a36Sopenharmony_ci BN_free(ctx->qr); 4262306a36Sopenharmony_ci BN_free(ctx->q2); 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic bool alloc_q1q2_ctx(const uint8_t *s, const uint8_t *m, 4662306a36Sopenharmony_ci struct q1q2_ctx *ctx) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci ctx->bn_ctx = BN_CTX_new(); 4962306a36Sopenharmony_ci ctx->s = BN_bin2bn(s, SGX_MODULUS_SIZE, NULL); 5062306a36Sopenharmony_ci ctx->m = BN_bin2bn(m, SGX_MODULUS_SIZE, NULL); 5162306a36Sopenharmony_ci ctx->q1 = BN_new(); 5262306a36Sopenharmony_ci ctx->qr = BN_new(); 5362306a36Sopenharmony_ci ctx->q2 = BN_new(); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci if (!ctx->bn_ctx || !ctx->s || !ctx->m || !ctx->q1 || !ctx->qr || 5662306a36Sopenharmony_ci !ctx->q2) { 5762306a36Sopenharmony_ci free_q1q2_ctx(ctx); 5862306a36Sopenharmony_ci return false; 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci return true; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic void reverse_bytes(void *data, int length) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci int i = 0; 6762306a36Sopenharmony_ci int j = length - 1; 6862306a36Sopenharmony_ci uint8_t temp; 6962306a36Sopenharmony_ci uint8_t *ptr = data; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci while (i < j) { 7262306a36Sopenharmony_ci temp = ptr[i]; 7362306a36Sopenharmony_ci ptr[i] = ptr[j]; 7462306a36Sopenharmony_ci ptr[j] = temp; 7562306a36Sopenharmony_ci i++; 7662306a36Sopenharmony_ci j--; 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic bool calc_q1q2(const uint8_t *s, const uint8_t *m, uint8_t *q1, 8162306a36Sopenharmony_ci uint8_t *q2) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci struct q1q2_ctx ctx; 8462306a36Sopenharmony_ci int len; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci if (!alloc_q1q2_ctx(s, m, &ctx)) { 8762306a36Sopenharmony_ci fprintf(stderr, "Not enough memory for Q1Q2 calculation\n"); 8862306a36Sopenharmony_ci return false; 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (!BN_mul(ctx.q1, ctx.s, ctx.s, ctx.bn_ctx)) 9262306a36Sopenharmony_ci goto out; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci if (!BN_div(ctx.q1, ctx.qr, ctx.q1, ctx.m, ctx.bn_ctx)) 9562306a36Sopenharmony_ci goto out; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci if (BN_num_bytes(ctx.q1) > SGX_MODULUS_SIZE) { 9862306a36Sopenharmony_ci fprintf(stderr, "Too large Q1 %d bytes\n", 9962306a36Sopenharmony_ci BN_num_bytes(ctx.q1)); 10062306a36Sopenharmony_ci goto out; 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci if (!BN_mul(ctx.q2, ctx.s, ctx.qr, ctx.bn_ctx)) 10462306a36Sopenharmony_ci goto out; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (!BN_div(ctx.q2, NULL, ctx.q2, ctx.m, ctx.bn_ctx)) 10762306a36Sopenharmony_ci goto out; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci if (BN_num_bytes(ctx.q2) > SGX_MODULUS_SIZE) { 11062306a36Sopenharmony_ci fprintf(stderr, "Too large Q2 %d bytes\n", 11162306a36Sopenharmony_ci BN_num_bytes(ctx.q2)); 11262306a36Sopenharmony_ci goto out; 11362306a36Sopenharmony_ci } 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci len = BN_bn2bin(ctx.q1, q1); 11662306a36Sopenharmony_ci reverse_bytes(q1, len); 11762306a36Sopenharmony_ci len = BN_bn2bin(ctx.q2, q2); 11862306a36Sopenharmony_ci reverse_bytes(q2, len); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci free_q1q2_ctx(&ctx); 12162306a36Sopenharmony_ci return true; 12262306a36Sopenharmony_ciout: 12362306a36Sopenharmony_ci free_q1q2_ctx(&ctx); 12462306a36Sopenharmony_ci return false; 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistruct sgx_sigstruct_payload { 12862306a36Sopenharmony_ci struct sgx_sigstruct_header header; 12962306a36Sopenharmony_ci struct sgx_sigstruct_body body; 13062306a36Sopenharmony_ci}; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic bool check_crypto_errors(void) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci int err; 13562306a36Sopenharmony_ci bool had_errors = false; 13662306a36Sopenharmony_ci const char *filename; 13762306a36Sopenharmony_ci int line; 13862306a36Sopenharmony_ci char str[256]; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci for ( ; ; ) { 14162306a36Sopenharmony_ci if (ERR_peek_error() == 0) 14262306a36Sopenharmony_ci break; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci had_errors = true; 14562306a36Sopenharmony_ci err = ERR_get_error_line(&filename, &line); 14662306a36Sopenharmony_ci ERR_error_string_n(err, str, sizeof(str)); 14762306a36Sopenharmony_ci fprintf(stderr, "crypto: %s: %s:%d\n", str, filename, line); 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci return had_errors; 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic inline const BIGNUM *get_modulus(RSA *key) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci const BIGNUM *n; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci RSA_get0_key(key, &n, NULL, NULL); 15862306a36Sopenharmony_ci return n; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic RSA *gen_sign_key(void) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci unsigned long sign_key_length; 16462306a36Sopenharmony_ci BIO *bio; 16562306a36Sopenharmony_ci RSA *key; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci sign_key_length = (unsigned long)&sign_key_end - 16862306a36Sopenharmony_ci (unsigned long)&sign_key; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci bio = BIO_new_mem_buf(&sign_key, sign_key_length); 17162306a36Sopenharmony_ci if (!bio) 17262306a36Sopenharmony_ci return NULL; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci key = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL); 17562306a36Sopenharmony_ci BIO_free(bio); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci return key; 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cienum mrtags { 18162306a36Sopenharmony_ci MRECREATE = 0x0045544145524345, 18262306a36Sopenharmony_ci MREADD = 0x0000000044444145, 18362306a36Sopenharmony_ci MREEXTEND = 0x00444E4554584545, 18462306a36Sopenharmony_ci}; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cistatic bool mrenclave_update(EVP_MD_CTX *ctx, const void *data) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci if (!EVP_DigestUpdate(ctx, data, 64)) { 18962306a36Sopenharmony_ci fprintf(stderr, "digest update failed\n"); 19062306a36Sopenharmony_ci return false; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci return true; 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic bool mrenclave_commit(EVP_MD_CTX *ctx, uint8_t *mrenclave) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci unsigned int size; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (!EVP_DigestFinal_ex(ctx, (unsigned char *)mrenclave, &size)) { 20162306a36Sopenharmony_ci fprintf(stderr, "digest commit failed\n"); 20262306a36Sopenharmony_ci return false; 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci if (size != 32) { 20662306a36Sopenharmony_ci fprintf(stderr, "invalid digest size = %u\n", size); 20762306a36Sopenharmony_ci return false; 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci return true; 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistruct mrecreate { 21462306a36Sopenharmony_ci uint64_t tag; 21562306a36Sopenharmony_ci uint32_t ssaframesize; 21662306a36Sopenharmony_ci uint64_t size; 21762306a36Sopenharmony_ci uint8_t reserved[44]; 21862306a36Sopenharmony_ci} __attribute__((__packed__)); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic bool mrenclave_ecreate(EVP_MD_CTX *ctx, uint64_t blob_size) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci struct mrecreate mrecreate; 22462306a36Sopenharmony_ci uint64_t encl_size; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci for (encl_size = 0x1000; encl_size < blob_size; ) 22762306a36Sopenharmony_ci encl_size <<= 1; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci memset(&mrecreate, 0, sizeof(mrecreate)); 23062306a36Sopenharmony_ci mrecreate.tag = MRECREATE; 23162306a36Sopenharmony_ci mrecreate.ssaframesize = 1; 23262306a36Sopenharmony_ci mrecreate.size = encl_size; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (!EVP_DigestInit_ex(ctx, EVP_sha256(), NULL)) 23562306a36Sopenharmony_ci return false; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci return mrenclave_update(ctx, &mrecreate); 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cistruct mreadd { 24162306a36Sopenharmony_ci uint64_t tag; 24262306a36Sopenharmony_ci uint64_t offset; 24362306a36Sopenharmony_ci uint64_t flags; /* SECINFO flags */ 24462306a36Sopenharmony_ci uint8_t reserved[40]; 24562306a36Sopenharmony_ci} __attribute__((__packed__)); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic bool mrenclave_eadd(EVP_MD_CTX *ctx, uint64_t offset, uint64_t flags) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci struct mreadd mreadd; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci memset(&mreadd, 0, sizeof(mreadd)); 25262306a36Sopenharmony_ci mreadd.tag = MREADD; 25362306a36Sopenharmony_ci mreadd.offset = offset; 25462306a36Sopenharmony_ci mreadd.flags = flags; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci return mrenclave_update(ctx, &mreadd); 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistruct mreextend { 26062306a36Sopenharmony_ci uint64_t tag; 26162306a36Sopenharmony_ci uint64_t offset; 26262306a36Sopenharmony_ci uint8_t reserved[48]; 26362306a36Sopenharmony_ci} __attribute__((__packed__)); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistatic bool mrenclave_eextend(EVP_MD_CTX *ctx, uint64_t offset, 26662306a36Sopenharmony_ci const uint8_t *data) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci struct mreextend mreextend; 26962306a36Sopenharmony_ci int i; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci for (i = 0; i < 0x1000; i += 0x100) { 27262306a36Sopenharmony_ci memset(&mreextend, 0, sizeof(mreextend)); 27362306a36Sopenharmony_ci mreextend.tag = MREEXTEND; 27462306a36Sopenharmony_ci mreextend.offset = offset + i; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci if (!mrenclave_update(ctx, &mreextend)) 27762306a36Sopenharmony_ci return false; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci if (!mrenclave_update(ctx, &data[i + 0x00])) 28062306a36Sopenharmony_ci return false; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci if (!mrenclave_update(ctx, &data[i + 0x40])) 28362306a36Sopenharmony_ci return false; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci if (!mrenclave_update(ctx, &data[i + 0x80])) 28662306a36Sopenharmony_ci return false; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci if (!mrenclave_update(ctx, &data[i + 0xC0])) 28962306a36Sopenharmony_ci return false; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci return true; 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_cistatic bool mrenclave_segment(EVP_MD_CTX *ctx, struct encl *encl, 29662306a36Sopenharmony_ci struct encl_segment *seg) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci uint64_t end = seg->size; 29962306a36Sopenharmony_ci uint64_t offset; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci for (offset = 0; offset < end; offset += PAGE_SIZE) { 30262306a36Sopenharmony_ci if (!mrenclave_eadd(ctx, seg->offset + offset, seg->flags)) 30362306a36Sopenharmony_ci return false; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci if (seg->measure) { 30662306a36Sopenharmony_ci if (!mrenclave_eextend(ctx, seg->offset + offset, seg->src + offset)) 30762306a36Sopenharmony_ci return false; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci return true; 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cibool encl_measure(struct encl *encl) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci uint64_t header1[2] = {0x000000E100000006, 0x0000000000010000}; 31762306a36Sopenharmony_ci uint64_t header2[2] = {0x0000006000000101, 0x0000000100000060}; 31862306a36Sopenharmony_ci struct sgx_sigstruct *sigstruct = &encl->sigstruct; 31962306a36Sopenharmony_ci struct sgx_sigstruct_payload payload; 32062306a36Sopenharmony_ci uint8_t digest[SHA256_DIGEST_LENGTH]; 32162306a36Sopenharmony_ci EVP_MD_CTX *ctx = NULL; 32262306a36Sopenharmony_ci unsigned int siglen; 32362306a36Sopenharmony_ci RSA *key = NULL; 32462306a36Sopenharmony_ci int i; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci memset(sigstruct, 0, sizeof(*sigstruct)); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci sigstruct->header.header1[0] = header1[0]; 32962306a36Sopenharmony_ci sigstruct->header.header1[1] = header1[1]; 33062306a36Sopenharmony_ci sigstruct->header.header2[0] = header2[0]; 33162306a36Sopenharmony_ci sigstruct->header.header2[1] = header2[1]; 33262306a36Sopenharmony_ci sigstruct->exponent = 3; 33362306a36Sopenharmony_ci sigstruct->body.attributes = SGX_ATTR_MODE64BIT; 33462306a36Sopenharmony_ci sigstruct->body.xfrm = 3; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci /* sanity check */ 33762306a36Sopenharmony_ci if (check_crypto_errors()) 33862306a36Sopenharmony_ci goto err; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci key = gen_sign_key(); 34162306a36Sopenharmony_ci if (!key) { 34262306a36Sopenharmony_ci ERR_print_errors_fp(stdout); 34362306a36Sopenharmony_ci goto err; 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci BN_bn2bin(get_modulus(key), sigstruct->modulus); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci ctx = EVP_MD_CTX_create(); 34962306a36Sopenharmony_ci if (!ctx) 35062306a36Sopenharmony_ci goto err; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci if (!mrenclave_ecreate(ctx, encl->src_size)) 35362306a36Sopenharmony_ci goto err; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci for (i = 0; i < encl->nr_segments; i++) { 35662306a36Sopenharmony_ci struct encl_segment *seg = &encl->segment_tbl[i]; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (!mrenclave_segment(ctx, encl, seg)) 35962306a36Sopenharmony_ci goto err; 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci if (!mrenclave_commit(ctx, sigstruct->body.mrenclave)) 36362306a36Sopenharmony_ci goto err; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci memcpy(&payload.header, &sigstruct->header, sizeof(sigstruct->header)); 36662306a36Sopenharmony_ci memcpy(&payload.body, &sigstruct->body, sizeof(sigstruct->body)); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci SHA256((unsigned char *)&payload, sizeof(payload), digest); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci if (!RSA_sign(NID_sha256, digest, SHA256_DIGEST_LENGTH, 37162306a36Sopenharmony_ci sigstruct->signature, &siglen, key)) 37262306a36Sopenharmony_ci goto err; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci if (!calc_q1q2(sigstruct->signature, sigstruct->modulus, sigstruct->q1, 37562306a36Sopenharmony_ci sigstruct->q2)) 37662306a36Sopenharmony_ci goto err; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci /* BE -> LE */ 37962306a36Sopenharmony_ci reverse_bytes(sigstruct->signature, SGX_MODULUS_SIZE); 38062306a36Sopenharmony_ci reverse_bytes(sigstruct->modulus, SGX_MODULUS_SIZE); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci EVP_MD_CTX_destroy(ctx); 38362306a36Sopenharmony_ci RSA_free(key); 38462306a36Sopenharmony_ci return true; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_cierr: 38762306a36Sopenharmony_ci if (ctx) 38862306a36Sopenharmony_ci EVP_MD_CTX_destroy(ctx); 38962306a36Sopenharmony_ci RSA_free(key); 39062306a36Sopenharmony_ci return false; 39162306a36Sopenharmony_ci} 392