/* * Copyright 2020 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 */ /* * RSA low level APIs are deprecated for public use, but still ok for * internal use. */ #include "internal/deprecated.h" #include "e_os.h" /* strcasecmp */ #include #include #include #include #include #include #include #include #include #include "prov/provider_ctx.h" #include "prov/implementations.h" #include "prov/securitycheck.h" static OSSL_FUNC_kem_newctx_fn rsakem_newctx; static OSSL_FUNC_kem_encapsulate_init_fn rsakem_encapsulate_init; static OSSL_FUNC_kem_encapsulate_fn rsakem_generate; static OSSL_FUNC_kem_decapsulate_init_fn rsakem_decapsulate_init; static OSSL_FUNC_kem_decapsulate_fn rsakem_recover; static OSSL_FUNC_kem_freectx_fn rsakem_freectx; static OSSL_FUNC_kem_dupctx_fn rsakem_dupctx; static OSSL_FUNC_kem_get_ctx_params_fn rsakem_get_ctx_params; static OSSL_FUNC_kem_gettable_ctx_params_fn rsakem_gettable_ctx_params; static OSSL_FUNC_kem_set_ctx_params_fn rsakem_set_ctx_params; static OSSL_FUNC_kem_settable_ctx_params_fn rsakem_settable_ctx_params; /* * Only the KEM for RSASVE as defined in SP800-56b r2 is implemented * currently. */ #define KEM_OP_UNDEFINED -1 #define KEM_OP_RSASVE 0 /* * What's passed as an actual key is defined by the KEYMGMT interface. * We happen to know that our KEYMGMT simply passes RSA structures, so * we use that here too. */ typedef struct { OSSL_LIB_CTX *libctx; RSA *rsa; int op; } PROV_RSA_CTX; static const OSSL_ITEM rsakem_opname_id_map[] = { { KEM_OP_RSASVE, OSSL_KEM_PARAM_OPERATION_RSASVE }, }; static int name2id(const char *name, const OSSL_ITEM *map, size_t sz) { size_t i; if (name == NULL) return -1; for (i = 0; i < sz; ++i) { if (strcasecmp(map[i].ptr, name) == 0) return map[i].id; } return -1; } static int rsakem_opname2id(const char *name) { return name2id(name, rsakem_opname_id_map, OSSL_NELEM(rsakem_opname_id_map)); } static void *rsakem_newctx(void *provctx) { PROV_RSA_CTX *prsactx = OPENSSL_zalloc(sizeof(PROV_RSA_CTX)); if (prsactx == NULL) return NULL; prsactx->libctx = PROV_LIBCTX_OF(provctx); prsactx->op = KEM_OP_UNDEFINED; return prsactx; } static void rsakem_freectx(void *vprsactx) { PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; RSA_free(prsactx->rsa); OPENSSL_free(prsactx); } static void *rsakem_dupctx(void *vprsactx) { PROV_RSA_CTX *srcctx = (PROV_RSA_CTX *)vprsactx; PROV_RSA_CTX *dstctx; dstctx = OPENSSL_zalloc(sizeof(*srcctx)); if (dstctx == NULL) return NULL; *dstctx = *srcctx; if (dstctx->rsa != NULL && !RSA_up_ref(dstctx->rsa)) { OPENSSL_free(dstctx); return NULL; } return dstctx; } static int rsakem_init(void *vprsactx, void *vrsa, int operation) { PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; if (prsactx == NULL || vrsa == NULL || !RSA_up_ref(vrsa)) return 0; RSA_free(prsactx->rsa); prsactx->rsa = vrsa; if (!ossl_rsa_check_key(vrsa, operation == EVP_PKEY_OP_ENCAPSULATE)) { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); return 0; } return 1; } static int rsakem_encapsulate_init(void *vprsactx, void *vrsa) { return rsakem_init(vprsactx, vrsa, EVP_PKEY_OP_ENCAPSULATE); } static int rsakem_decapsulate_init(void *vprsactx, void *vrsa) { return rsakem_init(vprsactx, vrsa, EVP_PKEY_OP_DECAPSULATE); } static int rsakem_get_ctx_params(void *vprsactx, OSSL_PARAM *params) { PROV_RSA_CTX *ctx = (PROV_RSA_CTX *)vprsactx; if (ctx == NULL || params == NULL) return 0; return 1; } static const OSSL_PARAM known_gettable_rsakem_ctx_params[] = { OSSL_PARAM_END }; static const OSSL_PARAM *rsakem_gettable_ctx_params(ossl_unused void *provctx) { return known_gettable_rsakem_ctx_params; } static int rsakem_set_ctx_params(void *vprsactx, const OSSL_PARAM params[]) { PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; const OSSL_PARAM *p; int op; if (prsactx == NULL || params == NULL) return 0; p = OSSL_PARAM_locate_const(params, OSSL_KEM_PARAM_OPERATION); if (p != NULL) { if (p->data_type != OSSL_PARAM_UTF8_STRING) return 0; op = rsakem_opname2id(p->data); if (op < 0) return 0; prsactx->op = op; } return 1; } static const OSSL_PARAM known_settable_rsakem_ctx_params[] = { OSSL_PARAM_utf8_string(OSSL_KEM_PARAM_OPERATION, NULL, 0), OSSL_PARAM_END }; static const OSSL_PARAM *rsakem_settable_ctx_params(ossl_unused void *provctx) { return known_settable_rsakem_ctx_params; } /* * NIST.SP.800-56Br2 * 7.2.1.2 RSASVE Generate Operation (RSASVE.GENERATE). * * Generate a random in the range 1 < z < (n – 1) */ static int rsasve_gen_rand_bytes(RSA *rsa_pub, unsigned char *out, int outlen) { int ret = 0; BN_CTX *bnctx; BIGNUM *z, *nminus3; bnctx = BN_CTX_secure_new_ex(ossl_rsa_get0_libctx(rsa_pub)); if (bnctx == NULL) return 0; /* * Generate a random in the range 1 < z < (n – 1). * Since BN_priv_rand_range_ex() returns a value in range 0 <= r < max * We can achieve this by adding 2.. but then we need to subtract 3 from * the upper bound i.e: 2 + (0 <= r < (n - 3)) */ BN_CTX_start(bnctx); nminus3 = BN_CTX_get(bnctx); z = BN_CTX_get(bnctx); ret = (z != NULL && (BN_copy(nminus3, RSA_get0_n(rsa_pub)) != NULL) && BN_sub_word(nminus3, 3) && BN_priv_rand_range_ex(z, nminus3, bnctx) && BN_add_word(z, 2) && (BN_bn2binpad(z, out, outlen) == outlen)); BN_CTX_end(bnctx); BN_CTX_free(bnctx); return ret; } /* * NIST.SP.800-56Br2 * 7.2.1.2 RSASVE Generate Operation (RSASVE.GENERATE). */ static int rsasve_generate(PROV_RSA_CTX *prsactx, unsigned char *out, size_t *outlen, unsigned char *secret, size_t *secretlen) { int ret; size_t nlen; /* Step (1): nlen = Ceil(len(n)/8) */ nlen = RSA_size(prsactx->rsa); if (out == NULL) { if (nlen == 0) { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY); return 0; } if (outlen == NULL && secretlen == NULL) return 0; if (outlen != NULL) *outlen = nlen; if (secretlen != NULL) *secretlen = nlen; return 1; } /* * Step (2): Generate a random byte string z of nlen bytes where * 1 < z < n - 1 */ if (!rsasve_gen_rand_bytes(prsactx->rsa, secret, nlen)) return 0; /* Step(3): out = RSAEP((n,e), z) */ ret = RSA_public_encrypt(nlen, secret, out, prsactx->rsa, RSA_NO_PADDING); if (ret) { ret = 1; if (outlen != NULL) *outlen = nlen; if (secretlen != NULL) *secretlen = nlen; } else { OPENSSL_cleanse(secret, nlen); } return ret; } /* * NIST.SP.800-56Br2 * 7.2.1.3 RSASVE Recovery Operation (RSASVE.RECOVER). */ static int rsasve_recover(PROV_RSA_CTX *prsactx, unsigned char *out, size_t *outlen, const unsigned char *in, size_t inlen) { size_t nlen; /* Step (1): get the byte length of n */ nlen = RSA_size(prsactx->rsa); if (out == NULL) { if (nlen == 0) { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY); return 0; } *outlen = nlen; return 1; } /* Step (2): check the input ciphertext 'inlen' matches the nlen */ if (inlen != nlen) { ERR_raise(ERR_LIB_PROV, PROV_R_BAD_LENGTH); return 0; } /* Step (3): out = RSADP((n,d), in) */ return (RSA_private_decrypt(inlen, in, out, prsactx->rsa, RSA_NO_PADDING) > 0); } static int rsakem_generate(void *vprsactx, unsigned char *out, size_t *outlen, unsigned char *secret, size_t *secretlen) { PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; switch (prsactx->op) { case KEM_OP_RSASVE: return rsasve_generate(prsactx, out, outlen, secret, secretlen); default: return -2; } } static int rsakem_recover(void *vprsactx, unsigned char *out, size_t *outlen, const unsigned char *in, size_t inlen) { PROV_RSA_CTX *prsactx = (PROV_RSA_CTX *)vprsactx; switch (prsactx->op) { case KEM_OP_RSASVE: return rsasve_recover(prsactx, out, outlen, in, inlen); default: return -2; } } const OSSL_DISPATCH ossl_rsa_asym_kem_functions[] = { { OSSL_FUNC_KEM_NEWCTX, (void (*)(void))rsakem_newctx }, { OSSL_FUNC_KEM_ENCAPSULATE_INIT, (void (*)(void))rsakem_encapsulate_init }, { OSSL_FUNC_KEM_ENCAPSULATE, (void (*)(void))rsakem_generate }, { OSSL_FUNC_KEM_DECAPSULATE_INIT, (void (*)(void))rsakem_decapsulate_init }, { OSSL_FUNC_KEM_DECAPSULATE, (void (*)(void))rsakem_recover }, { OSSL_FUNC_KEM_FREECTX, (void (*)(void))rsakem_freectx }, { OSSL_FUNC_KEM_DUPCTX, (void (*)(void))rsakem_dupctx }, { OSSL_FUNC_KEM_GET_CTX_PARAMS, (void (*)(void))rsakem_get_ctx_params }, { OSSL_FUNC_KEM_GETTABLE_CTX_PARAMS, (void (*)(void))rsakem_gettable_ctx_params }, { OSSL_FUNC_KEM_SET_CTX_PARAMS, (void (*)(void))rsakem_set_ctx_params }, { OSSL_FUNC_KEM_SETTABLE_CTX_PARAMS, (void (*)(void))rsakem_settable_ctx_params }, { 0, NULL } };