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