text: // SPDX-License-Identifier: BSD-2-Clause
  /*
   * Copyright 2018-2021 NXP
   *
   * Crypto DSA interface implementation to enable HW driver.
   */
  #include <crypto/crypto.h>
  #include <drvcrypt.h>
  #include <drvcrypt_acipher.h>
  
  /*
   * Get the recommended L and N bits parameters corresponding
   * respectively to the size of the Primes P and G (and so
   * the Public Key and Private Key).
   *
   * Refer the NIST.FIPS 186-4 section 4.2
   *
   * @size_bits   Maximum key size bits
   * @l_bits      [out] L size in bits
   * @n_bits      [out] N size in bits
   */
  static TEE_Result get_keys_size(size_t size_bits, size_t *l_bits,
  				size_t *n_bits)
  {
  	if (size_bits <= 1024)
  		*n_bits = 160;
  	else if (size_bits <= 3072)
  		*n_bits = 256;
  	else
  		return TEE_ERROR_NOT_IMPLEMENTED;
  
  	*l_bits = size_bits;
  
  	return TEE_SUCCESS;
  }
  
  TEE_Result crypto_acipher_alloc_dsa_keypair(struct dsa_keypair *key,
  					    size_t size_bits)
  {
  	TEE_Result ret = TEE_ERROR_NOT_IMPLEMENTED;
  	struct drvcrypt_dsa *dsa = NULL;
  	size_t l_bits = 0;
  	size_t n_bits = 0;
  
  	if (!key || !size_bits) {
  		CRYPTO_TRACE("Param error key @0x%" PRIxPTR " size %zu bits",
  			     (uintptr_t)key, size_bits);
  		return TEE_ERROR_BAD_PARAMETERS;
  	}
  
  	ret = get_keys_size(size_bits, &l_bits, &n_bits);
  	if (ret == TEE_SUCCESS) {
  		dsa = drvcrypt_get_ops(CRYPTO_DSA);
  		if (dsa)
  			ret = dsa->alloc_keypair(key, l_bits, n_bits);
  		else
  			ret = TEE_ERROR_NOT_IMPLEMENTED;
  	}
  
  	CRYPTO_TRACE("DSA Keypair (%zu bits) alloc ret = 0x%" PRIx32, size_bits,
  		     ret);
  	return ret;
  }
  
  TEE_Result crypto_acipher_alloc_dsa_public_key(struct dsa_public_key *key,
  					       size_t size_bits)
  {
  	TEE_Result ret = TEE_ERROR_NOT_IMPLEMENTED;
  	struct drvcrypt_dsa *dsa = NULL;
  	size_t l_bits = 0;
  	size_t n_bits = 0;
  
  	if (!key || !size_bits) {
  		CRYPTO_TRACE("Param error key @0x%" PRIxPTR " size %zu bits",
  			     (uintptr_t)key, size_bits);
  		return TEE_ERROR_BAD_PARAMETERS;
  	}
  
  	ret = get_keys_size(size_bits, &l_bits, &n_bits);
  	if (ret == TEE_SUCCESS) {
  		dsa = drvcrypt_get_ops(CRYPTO_DSA);
  		if (dsa)
  			ret = dsa->alloc_publickey(key, l_bits, n_bits);
  		else
  			ret = TEE_ERROR_NOT_IMPLEMENTED;
  	}
  
  	CRYPTO_TRACE("DSA Public Key (%zu bits) alloc ret = 0x%" PRIx32,
  		     size_bits, ret);
  	return ret;
  }
  
  TEE_Result crypto_acipher_gen_dsa_key(struct dsa_keypair *key, size_t key_size)
  {
  	TEE_Result ret = TEE_ERROR_NOT_IMPLEMENTED;
  	struct drvcrypt_dsa *dsa = NULL;
  	size_t l_bits = 0;
  	size_t n_bits = 0;
  
  	if (!key || !key_size) {
  		CRYPTO_TRACE("Param error key @0x%" PRIxPTR " size %zu bits",
  			     (uintptr_t)key, key_size);
  		return TEE_ERROR_BAD_PARAMETERS;
  	}
  
  	ret = get_keys_size(key_size, &l_bits, &n_bits);
  	if (ret == TEE_SUCCESS) {
  		dsa = drvcrypt_get_ops(CRYPTO_DSA);
  		if (dsa)
  			ret = dsa->gen_keypair(key, l_bits, n_bits);
  		else
  			ret = TEE_ERROR_NOT_IMPLEMENTED;
  	}
  
  	CRYPTO_TRACE("DSA Keypair (%zu bits) generate ret = 0x%" PRIx32,
  		     key_size, ret);
  
  	return ret;
  }
  
  TEE_Result crypto_acipher_dsa_sign(uint32_t algo, struct dsa_keypair *key,
  				   const uint8_t *msg, size_t msg_len,
  				   uint8_t *sig, size_t *sig_len)
  {
  	TEE_Result ret = TEE_ERROR_BAD_PARAMETERS;
  	struct drvcrypt_dsa *dsa = NULL;
  	struct drvcrypt_sign_data sdata = { };
  	size_t l_bytes = 0;
  	size_t n_bytes = 0;
  
  	if (!key || !msg || !sig_len) {
  		CRYPTO_TRACE("Input parameters reference error");
  		return TEE_ERROR_BAD_PARAMETERS;
  	}
  
  	/*
  	 * Verify the signature length function of the key size
  	 *
  	 * Prime number sizes are not stored but deducted from bignum size.
  	 * This requires prime numbers p and q to have their MSB set otherwise
  	 * crypto_bignum_num_bytes() will return a wrong size.
  	 */
  	n_bytes = crypto_bignum_num_bytes(key->q);
  	l_bytes = crypto_bignum_num_bytes(key->p);
  	if (*sig_len < 2 * n_bytes) {
  		CRYPTO_TRACE("Length (%zu) too short expected %zu bytes",
  			     *sig_len, 2 * n_bytes);
  		*sig_len = 2 * n_bytes;
  		return TEE_ERROR_SHORT_BUFFER;
  	}
  
  	if (!sig) {
  		CRYPTO_TRACE("Parameter \"sig\" reference error");
  		return TEE_ERROR_BAD_PARAMETERS;
  	}
  
  	dsa = drvcrypt_get_ops(CRYPTO_DSA);
  	if (dsa) {
  		sdata.algo = algo;
  		sdata.key = key;
  		sdata.size_sec = n_bytes;
  		sdata.message.data = (uint8_t *)msg;
  		sdata.message.length = msg_len;
  		sdata.signature.data = sig;
  		sdata.signature.length = *sig_len;
  
  		ret = dsa->sign(&sdata, l_bytes, n_bytes);
  
  		/* Set the signature length */
  		*sig_len = sdata.signature.length;
  	} else {
  		ret = TEE_ERROR_NOT_IMPLEMENTED;
  	}
  
  	CRYPTO_TRACE("Sign algo (0x%" PRIx32 ") returned 0x%" PRIx32, algo,
  		     ret);
  
  	return ret;
  }
  
  TEE_Result crypto_acipher_dsa_verify(uint32_t algo, struct dsa_public_key *key,
  				     const uint8_t *msg, size_t msg_len,
  				     const uint8_t *sig, size_t sig_len)
  {
  	TEE_Result ret = TEE_ERROR_BAD_PARAMETERS;
  	struct drvcrypt_dsa *dsa = NULL;
  	struct drvcrypt_sign_data sdata = { };
  	size_t l_bytes = 0;
  	size_t n_bytes = 0;
  
  	if (!key || !msg || !sig) {
  		CRYPTO_TRACE("Input parameters reference error");
  		return TEE_ERROR_BAD_PARAMETERS;
  	}
  
  	/*
  	 * Verify the signature length function of the key size
  	 *
  	 * Prime number sizes are not stored but deducted from bignum size.
  	 * This requires prime numbers p and q to have their MSB set otherwise
  	 * crypto_bignum_num_bytes() will return a wrong size.
  	 */
  	n_bytes = crypto_bignum_num_bytes(key->q);
  	l_bytes = crypto_bignum_num_bytes(key->p);
  	if (sig_len != 2 * n_bytes) {
  		CRYPTO_TRACE("Length (%zu) is invalid expected %zu bytes",
  			     sig_len, 2 * n_bytes);
  		return TEE_ERROR_SIGNATURE_INVALID;
  	}
  
  	dsa = drvcrypt_get_ops(CRYPTO_DSA);
  	if (dsa) {
  		sdata.algo = algo;
  		sdata.key = key;
  		sdata.size_sec = n_bytes;
  		sdata.message.data = (uint8_t *)msg;
  		sdata.message.length = msg_len;
  		sdata.signature.data = (uint8_t *)sig;
  		sdata.signature.length = sig_len;
  
  		ret = dsa->verify(&sdata, l_bytes, n_bytes);
  	} else {
  		ret = TEE_ERROR_NOT_IMPLEMENTED;
  	}
  
  	CRYPTO_TRACE("Verify algo (0x%" PRIx32 ") returned 0x%" PRIx32, algo,
  		     ret);
  
  	return ret;
  }
  