1*b077aed3SPierre Pronchery /* 2*b077aed3SPierre Pronchery * Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved. 3*b077aed3SPierre Pronchery * 4*b077aed3SPierre Pronchery * Licensed under the Apache License 2.0 (the "License"). You may not use 5*b077aed3SPierre Pronchery * this file except in compliance with the License. You can obtain a copy 6*b077aed3SPierre Pronchery * in the file LICENSE in the source distribution or at 7*b077aed3SPierre Pronchery * https://www.openssl.org/source/license.html 8*b077aed3SPierre Pronchery */ 9*b077aed3SPierre Pronchery 10*b077aed3SPierre Pronchery #include <openssl/crypto.h> 11*b077aed3SPierre Pronchery #include <openssl/core_dispatch.h> 12*b077aed3SPierre Pronchery #include <openssl/core_names.h> 13*b077aed3SPierre Pronchery #include <openssl/params.h> 14*b077aed3SPierre Pronchery #include <openssl/err.h> 15*b077aed3SPierre Pronchery #include <openssl/proverr.h> 16*b077aed3SPierre Pronchery #include "internal/cryptlib.h" 17*b077aed3SPierre Pronchery #include "crypto/ecx.h" 18*b077aed3SPierre Pronchery #include "prov/implementations.h" 19*b077aed3SPierre Pronchery #include "prov/providercommon.h" 20*b077aed3SPierre Pronchery #ifdef S390X_EC_ASM 21*b077aed3SPierre Pronchery # include "s390x_arch.h" 22*b077aed3SPierre Pronchery #endif 23*b077aed3SPierre Pronchery 24*b077aed3SPierre Pronchery static OSSL_FUNC_keyexch_newctx_fn x25519_newctx; 25*b077aed3SPierre Pronchery static OSSL_FUNC_keyexch_newctx_fn x448_newctx; 26*b077aed3SPierre Pronchery static OSSL_FUNC_keyexch_init_fn ecx_init; 27*b077aed3SPierre Pronchery static OSSL_FUNC_keyexch_set_peer_fn ecx_set_peer; 28*b077aed3SPierre Pronchery static OSSL_FUNC_keyexch_derive_fn ecx_derive; 29*b077aed3SPierre Pronchery static OSSL_FUNC_keyexch_freectx_fn ecx_freectx; 30*b077aed3SPierre Pronchery static OSSL_FUNC_keyexch_dupctx_fn ecx_dupctx; 31*b077aed3SPierre Pronchery 32*b077aed3SPierre Pronchery /* 33*b077aed3SPierre Pronchery * What's passed as an actual key is defined by the KEYMGMT interface. 34*b077aed3SPierre Pronchery * We happen to know that our KEYMGMT simply passes ECX_KEY structures, so 35*b077aed3SPierre Pronchery * we use that here too. 36*b077aed3SPierre Pronchery */ 37*b077aed3SPierre Pronchery 38*b077aed3SPierre Pronchery typedef struct { 39*b077aed3SPierre Pronchery size_t keylen; 40*b077aed3SPierre Pronchery ECX_KEY *key; 41*b077aed3SPierre Pronchery ECX_KEY *peerkey; 42*b077aed3SPierre Pronchery } PROV_ECX_CTX; 43*b077aed3SPierre Pronchery 44*b077aed3SPierre Pronchery static void *ecx_newctx(void *provctx, size_t keylen) 45*b077aed3SPierre Pronchery { 46*b077aed3SPierre Pronchery PROV_ECX_CTX *ctx; 47*b077aed3SPierre Pronchery 48*b077aed3SPierre Pronchery if (!ossl_prov_is_running()) 49*b077aed3SPierre Pronchery return NULL; 50*b077aed3SPierre Pronchery 51*b077aed3SPierre Pronchery ctx = OPENSSL_zalloc(sizeof(PROV_ECX_CTX)); 52*b077aed3SPierre Pronchery if (ctx == NULL) { 53*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); 54*b077aed3SPierre Pronchery return NULL; 55*b077aed3SPierre Pronchery } 56*b077aed3SPierre Pronchery 57*b077aed3SPierre Pronchery ctx->keylen = keylen; 58*b077aed3SPierre Pronchery 59*b077aed3SPierre Pronchery return ctx; 60*b077aed3SPierre Pronchery } 61*b077aed3SPierre Pronchery 62*b077aed3SPierre Pronchery static void *x25519_newctx(void *provctx) 63*b077aed3SPierre Pronchery { 64*b077aed3SPierre Pronchery return ecx_newctx(provctx, X25519_KEYLEN); 65*b077aed3SPierre Pronchery } 66*b077aed3SPierre Pronchery 67*b077aed3SPierre Pronchery static void *x448_newctx(void *provctx) 68*b077aed3SPierre Pronchery { 69*b077aed3SPierre Pronchery return ecx_newctx(provctx, X448_KEYLEN); 70*b077aed3SPierre Pronchery } 71*b077aed3SPierre Pronchery 72*b077aed3SPierre Pronchery static int ecx_init(void *vecxctx, void *vkey, 73*b077aed3SPierre Pronchery ossl_unused const OSSL_PARAM params[]) 74*b077aed3SPierre Pronchery { 75*b077aed3SPierre Pronchery PROV_ECX_CTX *ecxctx = (PROV_ECX_CTX *)vecxctx; 76*b077aed3SPierre Pronchery ECX_KEY *key = vkey; 77*b077aed3SPierre Pronchery 78*b077aed3SPierre Pronchery if (!ossl_prov_is_running()) 79*b077aed3SPierre Pronchery return 0; 80*b077aed3SPierre Pronchery 81*b077aed3SPierre Pronchery if (ecxctx == NULL 82*b077aed3SPierre Pronchery || key == NULL 83*b077aed3SPierre Pronchery || key->keylen != ecxctx->keylen 84*b077aed3SPierre Pronchery || !ossl_ecx_key_up_ref(key)) { 85*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); 86*b077aed3SPierre Pronchery return 0; 87*b077aed3SPierre Pronchery } 88*b077aed3SPierre Pronchery 89*b077aed3SPierre Pronchery ossl_ecx_key_free(ecxctx->key); 90*b077aed3SPierre Pronchery ecxctx->key = key; 91*b077aed3SPierre Pronchery 92*b077aed3SPierre Pronchery return 1; 93*b077aed3SPierre Pronchery } 94*b077aed3SPierre Pronchery 95*b077aed3SPierre Pronchery static int ecx_set_peer(void *vecxctx, void *vkey) 96*b077aed3SPierre Pronchery { 97*b077aed3SPierre Pronchery PROV_ECX_CTX *ecxctx = (PROV_ECX_CTX *)vecxctx; 98*b077aed3SPierre Pronchery ECX_KEY *key = vkey; 99*b077aed3SPierre Pronchery 100*b077aed3SPierre Pronchery if (!ossl_prov_is_running()) 101*b077aed3SPierre Pronchery return 0; 102*b077aed3SPierre Pronchery 103*b077aed3SPierre Pronchery if (ecxctx == NULL 104*b077aed3SPierre Pronchery || key == NULL 105*b077aed3SPierre Pronchery || key->keylen != ecxctx->keylen 106*b077aed3SPierre Pronchery || !ossl_ecx_key_up_ref(key)) { 107*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); 108*b077aed3SPierre Pronchery return 0; 109*b077aed3SPierre Pronchery } 110*b077aed3SPierre Pronchery ossl_ecx_key_free(ecxctx->peerkey); 111*b077aed3SPierre Pronchery ecxctx->peerkey = key; 112*b077aed3SPierre Pronchery 113*b077aed3SPierre Pronchery return 1; 114*b077aed3SPierre Pronchery } 115*b077aed3SPierre Pronchery 116*b077aed3SPierre Pronchery static int ecx_derive(void *vecxctx, unsigned char *secret, size_t *secretlen, 117*b077aed3SPierre Pronchery size_t outlen) 118*b077aed3SPierre Pronchery { 119*b077aed3SPierre Pronchery PROV_ECX_CTX *ecxctx = (PROV_ECX_CTX *)vecxctx; 120*b077aed3SPierre Pronchery 121*b077aed3SPierre Pronchery if (!ossl_prov_is_running()) 122*b077aed3SPierre Pronchery return 0; 123*b077aed3SPierre Pronchery 124*b077aed3SPierre Pronchery if (ecxctx->key == NULL 125*b077aed3SPierre Pronchery || ecxctx->key->privkey == NULL 126*b077aed3SPierre Pronchery || ecxctx->peerkey == NULL) { 127*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY); 128*b077aed3SPierre Pronchery return 0; 129*b077aed3SPierre Pronchery } 130*b077aed3SPierre Pronchery 131*b077aed3SPierre Pronchery if (!ossl_assert(ecxctx->keylen == X25519_KEYLEN 132*b077aed3SPierre Pronchery || ecxctx->keylen == X448_KEYLEN)) { 133*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); 134*b077aed3SPierre Pronchery return 0; 135*b077aed3SPierre Pronchery } 136*b077aed3SPierre Pronchery 137*b077aed3SPierre Pronchery if (secret == NULL) { 138*b077aed3SPierre Pronchery *secretlen = ecxctx->keylen; 139*b077aed3SPierre Pronchery return 1; 140*b077aed3SPierre Pronchery } 141*b077aed3SPierre Pronchery if (outlen < ecxctx->keylen) { 142*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); 143*b077aed3SPierre Pronchery return 0; 144*b077aed3SPierre Pronchery } 145*b077aed3SPierre Pronchery 146*b077aed3SPierre Pronchery if (ecxctx->keylen == X25519_KEYLEN) { 147*b077aed3SPierre Pronchery #ifdef S390X_EC_ASM 148*b077aed3SPierre Pronchery if (OPENSSL_s390xcap_P.pcc[1] 149*b077aed3SPierre Pronchery & S390X_CAPBIT(S390X_SCALAR_MULTIPLY_X25519)) { 150*b077aed3SPierre Pronchery if (s390x_x25519_mul(secret, ecxctx->peerkey->pubkey, 151*b077aed3SPierre Pronchery ecxctx->key->privkey) == 0) { 152*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_DURING_DERIVATION); 153*b077aed3SPierre Pronchery return 0; 154*b077aed3SPierre Pronchery } 155*b077aed3SPierre Pronchery } else 156*b077aed3SPierre Pronchery #endif 157*b077aed3SPierre Pronchery if (ossl_x25519(secret, ecxctx->key->privkey, 158*b077aed3SPierre Pronchery ecxctx->peerkey->pubkey) == 0) { 159*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_DURING_DERIVATION); 160*b077aed3SPierre Pronchery return 0; 161*b077aed3SPierre Pronchery } 162*b077aed3SPierre Pronchery } else { 163*b077aed3SPierre Pronchery #ifdef S390X_EC_ASM 164*b077aed3SPierre Pronchery if (OPENSSL_s390xcap_P.pcc[1] 165*b077aed3SPierre Pronchery & S390X_CAPBIT(S390X_SCALAR_MULTIPLY_X448)) { 166*b077aed3SPierre Pronchery if (s390x_x448_mul(secret, ecxctx->peerkey->pubkey, 167*b077aed3SPierre Pronchery ecxctx->key->privkey) == 0) { 168*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_DURING_DERIVATION); 169*b077aed3SPierre Pronchery return 0; 170*b077aed3SPierre Pronchery } 171*b077aed3SPierre Pronchery } else 172*b077aed3SPierre Pronchery #endif 173*b077aed3SPierre Pronchery if (ossl_x448(secret, ecxctx->key->privkey, 174*b077aed3SPierre Pronchery ecxctx->peerkey->pubkey) == 0) { 175*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_DURING_DERIVATION); 176*b077aed3SPierre Pronchery return 0; 177*b077aed3SPierre Pronchery } 178*b077aed3SPierre Pronchery } 179*b077aed3SPierre Pronchery 180*b077aed3SPierre Pronchery *secretlen = ecxctx->keylen; 181*b077aed3SPierre Pronchery return 1; 182*b077aed3SPierre Pronchery } 183*b077aed3SPierre Pronchery 184*b077aed3SPierre Pronchery static void ecx_freectx(void *vecxctx) 185*b077aed3SPierre Pronchery { 186*b077aed3SPierre Pronchery PROV_ECX_CTX *ecxctx = (PROV_ECX_CTX *)vecxctx; 187*b077aed3SPierre Pronchery 188*b077aed3SPierre Pronchery ossl_ecx_key_free(ecxctx->key); 189*b077aed3SPierre Pronchery ossl_ecx_key_free(ecxctx->peerkey); 190*b077aed3SPierre Pronchery 191*b077aed3SPierre Pronchery OPENSSL_free(ecxctx); 192*b077aed3SPierre Pronchery } 193*b077aed3SPierre Pronchery 194*b077aed3SPierre Pronchery static void *ecx_dupctx(void *vecxctx) 195*b077aed3SPierre Pronchery { 196*b077aed3SPierre Pronchery PROV_ECX_CTX *srcctx = (PROV_ECX_CTX *)vecxctx; 197*b077aed3SPierre Pronchery PROV_ECX_CTX *dstctx; 198*b077aed3SPierre Pronchery 199*b077aed3SPierre Pronchery if (!ossl_prov_is_running()) 200*b077aed3SPierre Pronchery return NULL; 201*b077aed3SPierre Pronchery 202*b077aed3SPierre Pronchery dstctx = OPENSSL_zalloc(sizeof(*srcctx)); 203*b077aed3SPierre Pronchery if (dstctx == NULL) { 204*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); 205*b077aed3SPierre Pronchery return NULL; 206*b077aed3SPierre Pronchery } 207*b077aed3SPierre Pronchery 208*b077aed3SPierre Pronchery *dstctx = *srcctx; 209*b077aed3SPierre Pronchery if (dstctx->key != NULL && !ossl_ecx_key_up_ref(dstctx->key)) { 210*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); 211*b077aed3SPierre Pronchery OPENSSL_free(dstctx); 212*b077aed3SPierre Pronchery return NULL; 213*b077aed3SPierre Pronchery } 214*b077aed3SPierre Pronchery 215*b077aed3SPierre Pronchery if (dstctx->peerkey != NULL && !ossl_ecx_key_up_ref(dstctx->peerkey)) { 216*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR); 217*b077aed3SPierre Pronchery ossl_ecx_key_free(dstctx->key); 218*b077aed3SPierre Pronchery OPENSSL_free(dstctx); 219*b077aed3SPierre Pronchery return NULL; 220*b077aed3SPierre Pronchery } 221*b077aed3SPierre Pronchery 222*b077aed3SPierre Pronchery return dstctx; 223*b077aed3SPierre Pronchery } 224*b077aed3SPierre Pronchery 225*b077aed3SPierre Pronchery const OSSL_DISPATCH ossl_x25519_keyexch_functions[] = { 226*b077aed3SPierre Pronchery { OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))x25519_newctx }, 227*b077aed3SPierre Pronchery { OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))ecx_init }, 228*b077aed3SPierre Pronchery { OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))ecx_derive }, 229*b077aed3SPierre Pronchery { OSSL_FUNC_KEYEXCH_SET_PEER, (void (*)(void))ecx_set_peer }, 230*b077aed3SPierre Pronchery { OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))ecx_freectx }, 231*b077aed3SPierre Pronchery { OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))ecx_dupctx }, 232*b077aed3SPierre Pronchery { 0, NULL } 233*b077aed3SPierre Pronchery }; 234*b077aed3SPierre Pronchery 235*b077aed3SPierre Pronchery const OSSL_DISPATCH ossl_x448_keyexch_functions[] = { 236*b077aed3SPierre Pronchery { OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))x448_newctx }, 237*b077aed3SPierre Pronchery { OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))ecx_init }, 238*b077aed3SPierre Pronchery { OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))ecx_derive }, 239*b077aed3SPierre Pronchery { OSSL_FUNC_KEYEXCH_SET_PEER, (void (*)(void))ecx_set_peer }, 240*b077aed3SPierre Pronchery { OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))ecx_freectx }, 241*b077aed3SPierre Pronchery { OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))ecx_dupctx }, 242*b077aed3SPierre Pronchery { 0, NULL } 243*b077aed3SPierre Pronchery }; 244