Linux cryptographic layer development
 help / color / mirror / Atom feed
* Re: [PATCH 3/3 v4] crypto: kpp - Add ECDH software support
From: Stephan Mueller @ 2016-05-06 12:02 UTC (permalink / raw)
  To: Salvatore Benedetto; +Cc: herbert, linux-crypto
In-Reply-To: <1462439857-93895-4-git-send-email-salvatore.benedetto@intel.com>

Am Donnerstag, 5. Mai 2016, 10:17:37 schrieb Salvatore Benedetto:

Hi Salvatore,

>  * Implement ECDH under kpp API
>  * Provide ECC software support for curve P-192 and
>    P-256.
>  * Add kpp test for ECDH with data generated by OpenSSL
> 
> Signed-off-by: Salvatore Benedetto <salvatore.benedetto@intel.com>
> ---
>  crypto/Kconfig          |    5 +
>  crypto/Makefile         |    3 +
>  crypto/ecc.c            | 1038
> +++++++++++++++++++++++++++++++++++++++++++++++ crypto/ecc.h            |  
> 70 ++++
>  crypto/ecc_curve_defs.h |   57 +++
>  crypto/ecdh.c           |  171 ++++++++
>  crypto/testmgr.c        |  136 ++++++-
>  crypto/testmgr.h        |   73 ++++
>  include/crypto/ecdh.h   |   24 ++
>  9 files changed, 1568 insertions(+), 9 deletions(-)
>  create mode 100644 crypto/ecc.c
>  create mode 100644 crypto/ecc.h
>  create mode 100644 crypto/ecc_curve_defs.h
>  create mode 100644 crypto/ecdh.c
>  create mode 100644 include/crypto/ecdh.h
> 
> diff --git a/crypto/Kconfig b/crypto/Kconfig
> index 89db25c..08a1a3b 100644
> --- a/crypto/Kconfig
> +++ b/crypto/Kconfig
> @@ -117,6 +117,11 @@ config CRYPTO_DH
>  	help
>  	  Generic implementation of the Diffie-Hellman algorithm.
> 
> +config CRYPTO_ECDH
> +	tristate "ECDH algorithm"
> +	select CRYTPO_KPP
> +	help
> +	  Generic implementation of the ECDH algorithm
> 
>  config CRYPTO_MANAGER
>  	tristate "Cryptographic algorithm manager"
> diff --git a/crypto/Makefile b/crypto/Makefile
> index 101f8fd..ba03079 100644
> --- a/crypto/Makefile
> +++ b/crypto/Makefile
> @@ -33,6 +33,9 @@ obj-$(CONFIG_CRYPTO_AKCIPHER2) += akcipher.o
>  obj-$(CONFIG_CRYPTO_KPP2) += kpp.o
> 
>  obj-$(CONFIG_CRYPTO_DH) += dh.o
> +ecdh_generic-y := ecc.o
> +ecdh_generic-y += ecdh.o
> +obj-$(CONFIG_CRYPTO_ECDH) += ecdh_generic.o
> 
>  $(obj)/rsapubkey-asn1.o: $(obj)/rsapubkey-asn1.c $(obj)/rsapubkey-asn1.h
>  $(obj)/rsaprivkey-asn1.o: $(obj)/rsaprivkey-asn1.c $(obj)/rsaprivkey-asn1.h
> diff --git a/crypto/ecc.c b/crypto/ecc.c
> new file mode 100644
> index 0000000..c50f9c8
> --- /dev/null
> +++ b/crypto/ecc.c
> @@ -0,0 +1,1038 @@
> +/*
> + * Copyright (c) 2013, Kenneth MacKay
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions are
> + * met:
> + *  * Redistributions of source code must retain the above copyright
> + *   notice, this list of conditions and the following disclaimer.
> + *  * Redistributions in binary form must reproduce the above copyright
> + *    notice, this list of conditions and the following disclaimer in the
> + *    documentation and/or other materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + */
> +
> +#include <linux/random.h>
> +#include <linux/slab.h>
> +#include <linux/swab.h>
> +#include <crypto/ecdh.h>
> +
> +#include "ecc.h"
> +#include "ecc_curve_defs.h"
> +
> +#define MAX_TRIES 16
> +
> +typedef struct {
> +	u64 m_low;
> +	u64 m_high;
> +} uint128_t;
> +
> +static inline const struct ecc_curve *ecc_get_curve(unsigned int curve_id)
> +{
> +	switch (curve_id) {
> +	case ECC_CURVE_NIST_P192: return &nist_p192;
> +	case ECC_CURVE_NIST_P256: return &nist_p256;
> +	default: return NULL;
> +	}
> +}
> +
> +static u64 *ecc_alloc_digits_space(unsigned int ndigits)
> +{
> +	size_t len = ndigits * sizeof(u64);
> +
> +	if (!len)
> +		return NULL;
> +
> +	return kmalloc(len, GFP_KERNEL);
> +}
> +
> +static void ecc_free_digits_space(u64 *space)
> +{
> +	kzfree(space);
> +}
> +
> +static struct ecc_point *ecc_alloc_point(unsigned int ndigits)
> +{
> +	struct ecc_point *p = kmalloc(sizeof(*p), GFP_KERNEL);
> +
> +	if (!p)
> +		return NULL;
> +
> +	p->x = ecc_alloc_digits_space(ndigits);
> +	if (!p->x)
> +		goto err_alloc_x;
> +
> +	p->y = ecc_alloc_digits_space(ndigits);
> +	if (!p->y)
> +		goto err_alloc_y;
> +
> +	p->ndigits = ndigits;
> +
> +	return p;
> +
> +err_alloc_y:
> +	ecc_free_digits_space(p->x);
> +err_alloc_x:
> +	kfree(p);
> +	return NULL;
> +}
> +
> +static void ecc_free_point(struct ecc_point *p)
> +{
> +	if (!p)
> +		return;
> +
> +	kzfree(p->x);
> +	kzfree(p->y);
> +	kzfree(p);
> +}
> +
> +static void vli_clear(u64 *vli, unsigned int ndigits)
> +{
> +	int i;
> +
> +	for (i = 0; i < ndigits; i++)
> +		vli[i] = 0;
> +}
> +
> +/* Returns true if vli == 0, false otherwise. */
> +static bool vli_is_zero(const u64 *vli, unsigned int ndigits)
> +{
> +	int i;
> +
> +	for (i = 0; i < ndigits; i++) {
> +		if (vli[i])
> +			return false;
> +	}
> +
> +	return true;
> +}
> +
> +/* Returns nonzero if bit bit of vli is set. */
> +static u64 vli_test_bit(const u64 *vli, unsigned int bit)
> +{
> +	return (vli[bit / 64] & ((u64)1 << (bit % 64)));
> +}
> +
> +/* Counts the number of 64-bit "digits" in vli. */
> +static unsigned int vli_num_digits(const u64 *vli, unsigned int ndigits)
> +{
> +	int i;
> +
> +	/* Search from the end until we find a non-zero digit.
> +	 * We do it in reverse because we expect that most digits will
> +	 * be nonzero.
> +	 */
> +	for (i = ndigits - 1; i >= 0 && vli[i] == 0; i--);
> +
> +	return (i + 1);
> +}
> +
> +/* Counts the number of bits required for vli. */
> +static unsigned int vli_num_bits(const u64 *vli, unsigned int ndigits)
> +{
> +	unsigned int i, num_digits;
> +	u64 digit;
> +
> +	num_digits = vli_num_digits(vli, ndigits);
> +	if (num_digits == 0)
> +		return 0;
> +
> +	digit = vli[num_digits - 1];
> +	for (i = 0; digit; i++)
> +		digit >>= 1;
> +
> +	return ((num_digits - 1) * 64 + i);
> +}
> +
> +/* Sets dest = src. */
> +static void vli_set(u64 *dest, const u64 *src, unsigned int ndigits)
> +{
> +	int i;
> +
> +	for (i = 0; i < ndigits; i++)
> +		dest[i] = src[i];
> +}
> +
> +/* Returns sign of left - right. */
> +static int vli_cmp(const u64 *left, const u64 *right, unsigned int ndigits)
> +{
> +	int i;
> +
> +	for (i = ndigits - 1; i >= 0; i--) {
> +		if (left[i] > right[i])
> +			return 1;
> +		else if (left[i] < right[i])
> +			return -1;
> +	}
> +
> +	return 0;
> +}
> +
> +/* Computes result = in << c, returning carry. Can modify in place
> + * (if result == in). 0 < shift < 64.
> + */
> +static u64 vli_lshift(u64 *result, const u64 *in, unsigned int shift,
> +		      unsigned int ndigits)
> +{
> +	u64 carry = 0;
> +	int i;
> +
> +	for (i = 0; i < ndigits; i++) {
> +		u64 temp = in[i];
> +
> +		result[i] = (temp << shift) | carry;
> +		carry = temp >> (64 - shift);
> +	}
> +
> +	return carry;
> +}
> +
> +/* Computes vli = vli >> 1. */
> +static void vli_rshift1(u64 *vli, unsigned int ndigits)
> +{
> +	u64 *end = vli;
> +	u64 carry = 0;
> +
> +	vli += ndigits;
> +
> +	while (vli-- > end) {
> +		u64 temp = *vli;
> +		*vli = (temp >> 1) | carry;
> +		carry = temp << 63;
> +	}
> +}
> +
> +/* Computes result = left + right, returning carry. Can modify in place. */
> +static u64 vli_add(u64 *result, const u64 *left, const u64 *right, +		
  
> unsigned int ndigits)
> +{
> +	u64 carry = 0;
> +	int i;
> +
> +	for (i = 0; i < ndigits; i++) {
> +		u64 sum;
> +
> +		sum = left[i] + right[i] + carry;
> +		if (sum != left[i])
> +			carry = (sum < left[i]);
> +
> +		result[i] = sum;
> +	}
> +
> +	return carry;
> +}
> +
> +/* Computes result = left - right, returning borrow. Can modify in place.
> */ +static u64 vli_sub(u64 *result, const u64 *left, const u64 *right, +	
	 
>  unsigned int ndigits)
> +{
> +	u64 borrow = 0;
> +	int i;
> +
> +	for (i = 0; i < ndigits; i++) {
> +		u64 diff;
> +
> +		diff = left[i] - right[i] - borrow;
> +		if (diff != left[i])
> +			borrow = (diff > left[i]);
> +
> +		result[i] = diff;
> +	}
> +
> +	return borrow;
> +}
> +
> +static uint128_t mul_64_64(u64 left, u64 right)
> +{
> +	u64 a0 = left & 0xffffffffull;
> +	u64 a1 = left >> 32;
> +	u64 b0 = right & 0xffffffffull;
> +	u64 b1 = right >> 32;
> +	u64 m0 = a0 * b0;
> +	u64 m1 = a0 * b1;
> +	u64 m2 = a1 * b0;
> +	u64 m3 = a1 * b1;
> +	uint128_t result;
> +
> +	m2 += (m0 >> 32);
> +	m2 += m1;
> +
> +	/* Overflow */
> +	if (m2 < m1)
> +		m3 += 0x100000000ull;
> +
> +	result.m_low = (m0 & 0xffffffffull) | (m2 << 32);
> +	result.m_high = m3 + (m2 >> 32);
> +
> +	return result;
> +}
> +
> +static uint128_t add_128_128(uint128_t a, uint128_t b)
> +{
> +	uint128_t result;
> +
> +	result.m_low = a.m_low + b.m_low;
> +	result.m_high = a.m_high + b.m_high + (result.m_low < a.m_low);
> +
> +	return result;
> +}
> +
> +static void vli_mult(u64 *result, const u64 *left, const u64 *right,
> +		     unsigned int ndigits)
> +{
> +	uint128_t r01 = { 0, 0 };
> +	u64 r2 = 0;
> +	unsigned int i, k;
> +
> +	/* Compute each digit of result in sequence, maintaining the
> +	 * carries.
> +	 */
> +	for (k = 0; k < ndigits * 2 - 1; k++) {
> +		unsigned int min;
> +
> +		if (k < ndigits)
> +			min = 0;
> +		else
> +			min = (k + 1) - ndigits;
> +
> +		for (i = min; i <= k && i < ndigits; i++) {
> +			uint128_t product;
> +
> +			product = mul_64_64(left[i], right[k - i]);
> +
> +			r01 = add_128_128(r01, product);
> +			r2 += (r01.m_high < product.m_high);
> +		}
> +
> +		result[k] = r01.m_low;
> +		r01.m_low = r01.m_high;
> +		r01.m_high = r2;
> +		r2 = 0;
> +	}
> +
> +	result[ndigits * 2 - 1] = r01.m_low;
> +}
> +
> +static void vli_square(u64 *result, const u64 *left, unsigned int ndigits)
> +{
> +	uint128_t r01 = { 0, 0 };
> +	u64 r2 = 0;
> +	int i, k;
> +
> +	for (k = 0; k < ndigits * 2 - 1; k++) {
> +		unsigned int min;
> +
> +		if (k < ndigits)
> +			min = 0;
> +		else
> +			min = (k + 1) - ndigits;
> +
> +		for (i = min; i <= k && i <= k - i; i++) {
> +			uint128_t product;
> +
> +			product = mul_64_64(left[i], left[k - i]);
> +
> +			if (i < k - i) {
> +				r2 += product.m_high >> 63;
> +				product.m_high = (product.m_high << 1) |
> +						 (product.m_low >> 63);
> +				product.m_low <<= 1;
> +			}
> +
> +			r01 = add_128_128(r01, product);
> +			r2 += (r01.m_high < product.m_high);
> +		}
> +
> +		result[k] = r01.m_low;
> +		r01.m_low = r01.m_high;
> +		r01.m_high = r2;
> +		r2 = 0;
> +	}
> +
> +	result[ndigits * 2 - 1] = r01.m_low;
> +}
> +
> +/* Computes result = (left + right) % mod.
> + * Assumes that left < mod and right < mod, result != mod.
> + */
> +static void vli_mod_add(u64 *result, const u64 *left, const u64 *right,
> +			const u64 *mod, unsigned int ndigits)
> +{
> +	u64 carry;
> +
> +	carry = vli_add(result, left, right, ndigits);
> +
> +	/* result > mod (result = mod + remainder), so subtract mod to
> +	 * get remainder.
> +	 */
> +	if (carry || vli_cmp(result, mod, ndigits) >= 0)
> +		vli_sub(result, result, mod, ndigits);
> +}
> +
> +/* Computes result = (left - right) % mod.
> + * Assumes that left < mod and right < mod, result != mod.
> + */
> +static void vli_mod_sub(u64 *result, const u64 *left, const u64 *right,
> +			const u64 *mod, unsigned int ndigits)
> +{
> +	u64 borrow = vli_sub(result, left, right, ndigits);
> +
> +	/* In this case, p_result == -diff == (max int) - diff.
> +	 * Since -x % d == d - x, we can get the correct result from
> +	 * result + mod (with overflow).
> +	 */
> +	if (borrow)
> +		vli_add(result, result, mod, ndigits);
> +}
> +
> +/* Computes p_result = p_product % curve_p.
> + * See algorithm 5 and 6 from
> + * http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf
> + */
> +static void vli_mmod_fast_192(u64 *result, const u64 *product,
> +			      const u64 *curve_prime, u64 *tmp)
> +{
> +	const unsigned int ndigits = 3;
> +	int carry;
> +
> +	vli_set(result, product, ndigits);
> +
> +	vli_set(tmp, &product[3], ndigits);
> +	carry = vli_add(result, result, tmp, ndigits);
> +
> +	tmp[0] = 0;
> +	tmp[1] = product[3];
> +	tmp[2] = product[4];
> +	carry += vli_add(result, result, tmp, ndigits);
> +
> +	tmp[0] = tmp[1] = product[5];
> +	tmp[2] = 0;
> +	carry += vli_add(result, result, tmp, ndigits);
> +
> +	while (carry || vli_cmp(curve_prime, result, ndigits) != 1)
> +		carry -= vli_sub(result, result, curve_prime, ndigits);
> +}
> +
> +/* Computes result = product % curve_prime
> + * from http://www.nsa.gov/ia/_files/nist-routines.pdf
> + */
> +static void vli_mmod_fast_256(u64 *result, const u64 *product,
> +			      const u64 *curve_prime, u64 *tmp)
> +{
> +	int carry;
> +	const unsigned int ndigits = 4;
> +
> +	/* t */
> +	vli_set(result, product, ndigits);
> +
> +	/* s1 */
> +	tmp[0] = 0;
> +	tmp[1] = product[5] & 0xffffffff00000000ull;
> +	tmp[2] = product[6];
> +	tmp[3] = product[7];
> +	carry = vli_lshift(tmp, tmp, 1, ndigits);
> +	carry += vli_add(result, result, tmp, ndigits);
> +
> +	/* s2 */
> +	tmp[1] = product[6] << 32;
> +	tmp[2] = (product[6] >> 32) | (product[7] << 32);
> +	tmp[3] = product[7] >> 32;
> +	carry += vli_lshift(tmp, tmp, 1, ndigits);
> +	carry += vli_add(result, result, tmp, ndigits);
> +
> +	/* s3 */
> +	tmp[0] = product[4];
> +	tmp[1] = product[5] & 0xffffffff;
> +	tmp[2] = 0;
> +	tmp[3] = product[7];
> +	carry += vli_add(result, result, tmp, ndigits);
> +
> +	/* s4 */
> +	tmp[0] = (product[4] >> 32) | (product[5] << 32);
> +	tmp[1] = (product[5] >> 32) | (product[6] & 0xffffffff00000000ull);
> +	tmp[2] = product[7];
> +	tmp[3] = (product[6] >> 32) | (product[4] << 32);
> +	carry += vli_add(result, result, tmp, ndigits);
> +
> +	/* d1 */
> +	tmp[0] = (product[5] >> 32) | (product[6] << 32);
> +	tmp[1] = (product[6] >> 32);
> +	tmp[2] = 0;
> +	tmp[3] = (product[4] & 0xffffffff) | (product[5] << 32);
> +	carry -= vli_sub(result, result, tmp, ndigits);
> +
> +	/* d2 */
> +	tmp[0] = product[6];
> +	tmp[1] = product[7];
> +	tmp[2] = 0;
> +	tmp[3] = (product[4] >> 32) | (product[5] & 0xffffffff00000000ull);
> +	carry -= vli_sub(result, result, tmp, ndigits);
> +
> +	/* d3 */
> +	tmp[0] = (product[6] >> 32) | (product[7] << 32);
> +	tmp[1] = (product[7] >> 32) | (product[4] << 32);
> +	tmp[2] = (product[4] >> 32) | (product[5] << 32);
> +	tmp[3] = (product[6] << 32);
> +	carry -= vli_sub(result, result, tmp, ndigits);
> +
> +	/* d4 */
> +	tmp[0] = product[7];
> +	tmp[1] = product[4] & 0xffffffff00000000ull;
> +	tmp[2] = product[5];
> +	tmp[3] = product[6] & 0xffffffff00000000ull;
> +	carry -= vli_sub(result, result, tmp, ndigits);
> +
> +	if (carry < 0) {
> +		do {
> +			carry += vli_add(result, result, curve_prime, 
ndigits);
> +		} while (carry < 0);
> +	} else {
> +		while (carry || vli_cmp(curve_prime, result, ndigits) != 1)
> +			carry -= vli_sub(result, result, curve_prime, 
ndigits);
> +	}
> +}
> +
> +/* Computes result = product % curve_prime
> + *  from http://www.nsa.gov/ia/_files/nist-routines.pdf
> +*/
> +static bool vli_mmod_fast(u64 *result, u64 *product,
> +			  const u64 *curve_prime, unsigned int ndigits)
> +{
> +	u64 tmp[2 * ndigits];
> +
> +	switch (ndigits) {
> +	case 3:
> +		vli_mmod_fast_192(result, product, curve_prime, tmp);
> +		break;
> +	case 4:
> +		vli_mmod_fast_256(result, product, curve_prime, tmp);
> +		break;
> +	default:
> +		pr_err("unsupports digits size!\n");
> +		return false;
> +	}
> +
> +	return true;
> +}
> +
> +/* Computes result = (left * right) % curve_prime. */
> +static void vli_mod_mult_fast(u64 *result, const u64 *left, const u64
> *right, +			      const u64 *curve_prime, unsigned int 
ndigits)
> +{
> +	u64 product[2 * ndigits];
> +
> +	vli_mult(product, left, right, ndigits);
> +	vli_mmod_fast(result, product, curve_prime, ndigits);
> +}
> +
> +/* Computes result = left^2 % curve_prime. */
> +static void vli_mod_square_fast(u64 *result, const u64 *left,
> +				const u64 *curve_prime, unsigned int ndigits)
> +{
> +	u64 product[2 * ndigits];
> +
> +	vli_square(product, left, ndigits);
> +	vli_mmod_fast(result, product, curve_prime, ndigits);
> +}
> +
> +#define EVEN(vli) (!(vli[0] & 1))
> +/* Computes result = (1 / p_input) % mod. All VLIs are the same size.
> + * See "From Euclid's GCD to Montgomery Multiplication to the Great Divide"
> + * https://labs.oracle.com/techrep/2001/smli_tr-2001-95.pdf
> + */
> +static void vli_mod_inv(u64 *result, const u64 *input, const u64 *mod,
> +			unsigned int ndigits)
> +{
> +	u64 a[ndigits], b[ndigits];
> +	u64 u[ndigits], v[ndigits];
> +	u64 carry;
> +	int cmp_result;
> +
> +	if (vli_is_zero(input, ndigits)) {
> +		vli_clear(result, ndigits);
> +		return;
> +	}
> +
> +	vli_set(a, input, ndigits);
> +	vli_set(b, mod, ndigits);
> +	vli_clear(u, ndigits);
> +	u[0] = 1;
> +	vli_clear(v, ndigits);
> +
> +	while ((cmp_result = vli_cmp(a, b, ndigits)) != 0) {
> +		carry = 0;
> +
> +		if (EVEN(a)) {
> +			vli_rshift1(a, ndigits);
> +
> +			if (!EVEN(u))
> +				carry = vli_add(u, u, mod, ndigits);
> +
> +			vli_rshift1(u, ndigits);
> +			if (carry)
> +				u[ndigits - 1] |= 0x8000000000000000ull;
> +		} else if (EVEN(b)) {
> +			vli_rshift1(b, ndigits);
> +
> +			if (!EVEN(v))
> +				carry = vli_add(v, v, mod, ndigits);
> +
> +			vli_rshift1(v, ndigits);
> +			if (carry)
> +				v[ndigits - 1] |= 0x8000000000000000ull;
> +		} else if (cmp_result > 0) {
> +			vli_sub(a, a, b, ndigits);
> +			vli_rshift1(a, ndigits);
> +
> +			if (vli_cmp(u, v, ndigits) < 0)
> +				vli_add(u, u, mod, ndigits);
> +
> +			vli_sub(u, u, v, ndigits);
> +			if (!EVEN(u))
> +				carry = vli_add(u, u, mod, ndigits);
> +
> +			vli_rshift1(u, ndigits);
> +			if (carry)
> +				u[ndigits - 1] |= 0x8000000000000000ull;
> +		} else {
> +			vli_sub(b, b, a, ndigits);
> +			vli_rshift1(b, ndigits);
> +
> +			if (vli_cmp(v, u, ndigits) < 0)
> +				vli_add(v, v, mod, ndigits);
> +
> +			vli_sub(v, v, u, ndigits);
> +			if (!EVEN(v))
> +				carry = vli_add(v, v, mod, ndigits);
> +
> +			vli_rshift1(v, ndigits);
> +			if (carry)
> +				v[ndigits - 1] |= 0x8000000000000000ull;
> +		}
> +	}
> +
> +	vli_set(result, u, ndigits);
> +}
> +
> +/* ------ Point operations ------ */
> +
> +/* Returns true if p_point is the point at infinity, false otherwise. */
> +static bool ecc_point_is_zero(const struct ecc_point *point)
> +{
> +	return (vli_is_zero(point->x, point->ndigits) &&
> +		vli_is_zero(point->y, point->ndigits));
> +}
> +
> +/* Point multiplication algorithm using Montgomery's ladder with co-Z
> + * coordinates. From http://eprint.iacr.org/2011/338.pdf
> + */
> +
> +/* Double in place */
> +static void ecc_point_double_jacobian(u64 *x1, u64 *y1, u64 *z1,
> +				      u64 *curve_prime, unsigned int ndigits)
> +{
> +	/* t1 = x, t2 = y, t3 = z */
> +	u64 t4[ndigits];
> +	u64 t5[ndigits];
> +
> +	if (vli_is_zero(z1, ndigits))
> +		return;
> +
> +	/* t4 = y1^2 */
> +	vli_mod_square_fast(t4, y1, curve_prime, ndigits);
> +	/* t5 = x1*y1^2 = A */
> +	vli_mod_mult_fast(t5, x1, t4, curve_prime, ndigits);
> +	/* t4 = y1^4 */
> +	vli_mod_square_fast(t4, t4, curve_prime, ndigits);
> +	/* t2 = y1*z1 = z3 */
> +	vli_mod_mult_fast(y1, y1, z1, curve_prime, ndigits);
> +	/* t3 = z1^2 */
> +	vli_mod_square_fast(z1, z1, curve_prime, ndigits);
> +
> +	/* t1 = x1 + z1^2 */
> +	vli_mod_add(x1, x1, z1, curve_prime, ndigits);
> +	/* t3 = 2*z1^2 */
> +	vli_mod_add(z1, z1, z1, curve_prime, ndigits);
> +	/* t3 = x1 - z1^2 */
> +	vli_mod_sub(z1, x1, z1, curve_prime, ndigits);
> +	/* t1 = x1^2 - z1^4 */
> +	vli_mod_mult_fast(x1, x1, z1, curve_prime, ndigits);
> +
> +	/* t3 = 2*(x1^2 - z1^4) */
> +	vli_mod_add(z1, x1, x1, curve_prime, ndigits);
> +	/* t1 = 3*(x1^2 - z1^4) */
> +	vli_mod_add(x1, x1, z1, curve_prime, ndigits);
> +	if (vli_test_bit(x1, 0)) {
> +		u64 carry = vli_add(x1, x1, curve_prime, ndigits);
> +
> +		vli_rshift1(x1, ndigits);
> +		x1[ndigits - 1] |= carry << 63;
> +	} else {
> +		vli_rshift1(x1, ndigits);
> +	}
> +	/* t1 = 3/2*(x1^2 - z1^4) = B */
> +
> +	/* t3 = B^2 */
> +	vli_mod_square_fast(z1, x1, curve_prime, ndigits);
> +	/* t3 = B^2 - A */
> +	vli_mod_sub(z1, z1, t5, curve_prime, ndigits);
> +	/* t3 = B^2 - 2A = x3 */
> +	vli_mod_sub(z1, z1, t5, curve_prime, ndigits);
> +	/* t5 = A - x3 */
> +	vli_mod_sub(t5, t5, z1, curve_prime, ndigits);
> +	/* t1 = B * (A - x3) */
> +	vli_mod_mult_fast(x1, x1, t5, curve_prime, ndigits);
> +	/* t4 = B * (A - x3) - y1^4 = y3 */
> +	vli_mod_sub(t4, x1, t4, curve_prime, ndigits);
> +
> +	vli_set(x1, z1, ndigits);
> +	vli_set(z1, y1, ndigits);
> +	vli_set(y1, t4, ndigits);
> +}
> +
> +/* Modify (x1, y1) => (x1 * z^2, y1 * z^3) */
> +static void apply_z(u64 *x1, u64 *y1, u64 *z, u64 *curve_prime,
> +		    unsigned int ndigits)
> +{
> +	u64 t1[ndigits];
> +
> +	vli_mod_square_fast(t1, z, curve_prime, ndigits);    /* z^2 */
> +	vli_mod_mult_fast(x1, x1, t1, curve_prime, ndigits); /* x1 * z^2 */
> +	vli_mod_mult_fast(t1, t1, z, curve_prime, ndigits);  /* z^3 */
> +	vli_mod_mult_fast(y1, y1, t1, curve_prime, ndigits); /* y1 * z^3 */
> +}
> +
> +/* P = (x1, y1) => 2P, (x2, y2) => P' */
> +static void xycz_initial_double(u64 *x1, u64 *y1, u64 *x2, u64 *y2,
> +				u64 *p_initial_z, u64 *curve_prime,
> +				unsigned int ndigits)
> +{
> +	u64 z[ndigits];
> +
> +	vli_set(x2, x1, ndigits);
> +	vli_set(y2, y1, ndigits);
> +
> +	vli_clear(z, ndigits);
> +	z[0] = 1;
> +
> +	if (p_initial_z)
> +		vli_set(z, p_initial_z, ndigits);
> +
> +	apply_z(x1, y1, z, curve_prime, ndigits);
> +
> +	ecc_point_double_jacobian(x1, y1, z, curve_prime, ndigits);
> +
> +	apply_z(x2, y2, z, curve_prime, ndigits);
> +}
> +
> +/* Input P = (x1, y1, Z), Q = (x2, y2, Z)
> + * Output P' = (x1', y1', Z3), P + Q = (x3, y3, Z3)
> + * or P => P', Q => P + Q
> + */
> +static void xycz_add(u64 *x1, u64 *y1, u64 *x2, u64 *y2, u64 *curve_prime,
> +		     unsigned int ndigits)
> +{
> +	/* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
> +	u64 t5[ndigits];
> +
> +	/* t5 = x2 - x1 */
> +	vli_mod_sub(t5, x2, x1, curve_prime, ndigits);
> +	/* t5 = (x2 - x1)^2 = A */
> +	vli_mod_square_fast(t5, t5, curve_prime, ndigits);
> +	/* t1 = x1*A = B */
> +	vli_mod_mult_fast(x1, x1, t5, curve_prime, ndigits);
> +	/* t3 = x2*A = C */
> +	vli_mod_mult_fast(x2, x2, t5, curve_prime, ndigits);
> +	/* t4 = y2 - y1 */
> +	vli_mod_sub(y2, y2, y1, curve_prime, ndigits);
> +	/* t5 = (y2 - y1)^2 = D */
> +	vli_mod_square_fast(t5, y2, curve_prime, ndigits);
> +
> +	/* t5 = D - B */
> +	vli_mod_sub(t5, t5, x1, curve_prime, ndigits);
> +	/* t5 = D - B - C = x3 */
> +	vli_mod_sub(t5, t5, x2, curve_prime, ndigits);
> +	/* t3 = C - B */
> +	vli_mod_sub(x2, x2, x1, curve_prime, ndigits);
> +	/* t2 = y1*(C - B) */
> +	vli_mod_mult_fast(y1, y1, x2, curve_prime, ndigits);
> +	/* t3 = B - x3 */
> +	vli_mod_sub(x2, x1, t5, curve_prime, ndigits);
> +	/* t4 = (y2 - y1)*(B - x3) */
> +	vli_mod_mult_fast(y2, y2, x2, curve_prime, ndigits);
> +	/* t4 = y3 */
> +	vli_mod_sub(y2, y2, y1, curve_prime, ndigits);
> +
> +	vli_set(x2, t5, ndigits);
> +}
> +
> +/* Input P = (x1, y1, Z), Q = (x2, y2, Z)
> + * Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3)
> + * or P => P - Q, Q => P + Q
> + */
> +static void xycz_add_c(u64 *x1, u64 *y1, u64 *x2, u64 *y2, u64
> *curve_prime, +		       unsigned int ndigits)
> +{
> +	/* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
> +	u64 t5[ndigits];
> +	u64 t6[ndigits];
> +	u64 t7[ndigits];
> +
> +	/* t5 = x2 - x1 */
> +	vli_mod_sub(t5, x2, x1, curve_prime, ndigits);
> +	/* t5 = (x2 - x1)^2 = A */
> +	vli_mod_square_fast(t5, t5, curve_prime, ndigits);
> +	/* t1 = x1*A = B */
> +	vli_mod_mult_fast(x1, x1, t5, curve_prime, ndigits);
> +	/* t3 = x2*A = C */
> +	vli_mod_mult_fast(x2, x2, t5, curve_prime, ndigits);
> +	/* t4 = y2 + y1 */
> +	vli_mod_add(t5, y2, y1, curve_prime, ndigits);
> +	/* t4 = y2 - y1 */
> +	vli_mod_sub(y2, y2, y1, curve_prime, ndigits);
> +
> +	/* t6 = C - B */
> +	vli_mod_sub(t6, x2, x1, curve_prime, ndigits);
> +	/* t2 = y1 * (C - B) */
> +	vli_mod_mult_fast(y1, y1, t6, curve_prime, ndigits);
> +	/* t6 = B + C */
> +	vli_mod_add(t6, x1, x2, curve_prime, ndigits);
> +	/* t3 = (y2 - y1)^2 */
> +	vli_mod_square_fast(x2, y2, curve_prime, ndigits);
> +	/* t3 = x3 */
> +	vli_mod_sub(x2, x2, t6, curve_prime, ndigits);
> +
> +	/* t7 = B - x3 */
> +	vli_mod_sub(t7, x1, x2, curve_prime, ndigits);
> +	/* t4 = (y2 - y1)*(B - x3) */
> +	vli_mod_mult_fast(y2, y2, t7, curve_prime, ndigits);
> +	/* t4 = y3 */
> +	vli_mod_sub(y2, y2, y1, curve_prime, ndigits);
> +
> +	/* t7 = (y2 + y1)^2 = F */
> +	vli_mod_square_fast(t7, t5, curve_prime, ndigits);
> +	/* t7 = x3' */
> +	vli_mod_sub(t7, t7, t6, curve_prime, ndigits);
> +	/* t6 = x3' - B */
> +	vli_mod_sub(t6, t7, x1, curve_prime, ndigits);
> +	/* t6 = (y2 + y1)*(x3' - B) */
> +	vli_mod_mult_fast(t6, t6, t5, curve_prime, ndigits);
> +	/* t2 = y3' */
> +	vli_mod_sub(y1, t6, y1, curve_prime, ndigits);
> +
> +	vli_set(x1, t7, ndigits);
> +}
> +
> +static void ecc_point_mult(struct ecc_point *result,
> +			   const struct ecc_point *point, const u64 *scalar,
> +			   u64 *initial_z, u64 *curve_prime,
> +			   unsigned int ndigits)
> +{
> +	/* R0 and R1 */
> +	u64 rx[2][ndigits];
> +	u64 ry[2][ndigits];
> +	u64 z[ndigits];
> +	int i, nb;
> +	int num_bits = vli_num_bits(scalar, ndigits);
> +
> +	vli_set(rx[1], point->x, ndigits);
> +	vli_set(ry[1], point->y, ndigits);
> +
> +	xycz_initial_double(rx[1], ry[1], rx[0], ry[0], initial_z, 
curve_prime,
> +			    ndigits);
> +
> +	for (i = num_bits - 2; i > 0; i--) {
> +		nb = !vli_test_bit(scalar, i);
> +		xycz_add_c(rx[1 - nb], ry[1 - nb], rx[nb], ry[nb], 
curve_prime,
> +			   ndigits);
> +		xycz_add(rx[nb], ry[nb], rx[1 - nb], ry[1 - nb], curve_prime,
> +			 ndigits);
> +	}
> +
> +	nb = !vli_test_bit(scalar, 0);
> +	xycz_add_c(rx[1 - nb], ry[1 - nb], rx[nb], ry[nb], curve_prime,
> +		   ndigits);
> +
> +	/* Find final 1/Z value. */
> +	/* X1 - X0 */
> +	vli_mod_sub(z, rx[1], rx[0], curve_prime, ndigits);
> +	/* Yb * (X1 - X0) */
> +	vli_mod_mult_fast(z, z, ry[1 - nb], curve_prime, ndigits);
> +	/* xP * Yb * (X1 - X0) */
> +	vli_mod_mult_fast(z, z, point->x, curve_prime, ndigits);
> +
> +	/* 1 / (xP * Yb * (X1 - X0)) */
> +	vli_mod_inv(z, z, curve_prime, point->ndigits);
> +
> +	/* yP / (xP * Yb * (X1 - X0)) */
> +	vli_mod_mult_fast(z, z, point->y, curve_prime, ndigits);
> +	/* Xb * yP / (xP * Yb * (X1 - X0)) */
> +	vli_mod_mult_fast(z, z, rx[1 - nb], curve_prime, ndigits);
> +	/* End 1/Z calculation */
> +
> +	xycz_add(rx[nb], ry[nb], rx[1 - nb], ry[1 - nb], curve_prime, 
ndigits);
> +
> +	apply_z(rx[0], ry[0], z, curve_prime, ndigits);
> +
> +	vli_set(result->x, rx[0], ndigits);
> +	vli_set(result->y, ry[0], ndigits);
> +}
> +
> +static inline void ecc_swap_digits(const u64 *in, u64 *out,
> +				   unsigned int ndigits)
> +{
> +	int i;
> +
> +	for (i = 0; i < ndigits; i++)
> +		out[i] = __swab64(in[ndigits - 1 - i]);
> +}
> +
> +int ecdh_make_pub_key(unsigned int curve_id,
> +		      const u8 *private_key, unsigned int private_key_len,
> +		      u8 *public_key, unsigned int public_key_len)
> +{
> +	int ret = 0;
> +	struct ecc_point *pk;
> +	unsigned int tries = 0;
> +	u64 *priv = NULL;
> +	unsigned int ndigits;
> +	unsigned int nbytes;
> +	const struct ecc_curve *curve = ecc_get_curve(curve_id);
> +
> +	if (!private_key || !curve) {
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	ndigits = curve->g.ndigits;
> +	nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
> +
> +	if (private_key_len != nbytes) {
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	if (vli_is_zero((const u64 *)&private_key[0], ndigits)) {
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	/* Make sure the private key is in the range [1, n-1]. */
> +	if (vli_cmp(curve->n, (const u64 *)&private_key[0], ndigits) != 1) {
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	priv = ecc_alloc_digits_space(ndigits);
> +	if (!priv) {
> +		ret = -ENOMEM;
> +		goto out;
> +	}
> +
> +	ecc_swap_digits((const u64 *)private_key, priv, ndigits);
> +
> +	pk = ecc_alloc_point(ndigits);
> +	if (!pk) {
> +		ret = -ENOMEM;
> +		goto err_alloc_pk;
> +	}
> +
> +	do {
> +		if (tries++ >= MAX_TRIES)
> +			goto err_retries;
> +
> +		ecc_point_mult(pk, &curve->g, priv, NULL, curve->p, ndigits);
> +
> +	} while (ecc_point_is_zero(pk));
> +
> +	ecc_swap_digits(pk->x, (u64 *)public_key, ndigits);
> +	ecc_swap_digits(pk->y, (u64 *)&public_key[nbytes], ndigits);
> +
> +err_retries:
> +	ecc_free_point(pk);
> +err_alloc_pk:
> +	ecc_free_digits_space(priv);
> +out:
> +	return ret;
> +}
> +
> +int ecdh_shared_secret(unsigned int curve_id,
> +		       const u8 *private_key, unsigned int private_key_len,
> +		       const u8 *public_key, unsigned int public_key_len,
> +		       u8 *secret, unsigned int secret_len)
> +{
> +	int ret = 0;
> +	struct ecc_point *product, *pk;
> +	u64 *priv, *rand_z;
> +	unsigned int ndigits;
> +	unsigned int nbytes;
> +	const struct ecc_curve *curve = ecc_get_curve(curve_id);
> +
> +	if (!private_key || !public_key) {
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	ndigits = curve->g.ndigits;
> +	nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
> +
> +	rand_z = ecc_alloc_digits_space(ndigits);
> +	if (!rand_z) {
> +		ret = -ENOMEM;
> +		goto out;
> +	}
> +
> +	priv = ecc_alloc_digits_space(ndigits);
> +	if (!priv) {
> +		ret = -ENOMEM;
> +		goto err_alloc_priv;
> +	}
> +
> +	get_random_bytes(rand_z, nbytes);
> +
> +	pk = ecc_alloc_point(ndigits);
> +	if (!pk) {
> +		ret = -ENOMEM;
> +		goto err_alloc_pk;
> +	}
> +
> +	product = ecc_alloc_point(ndigits);
> +	if (!product) {
> +		ret = -ENOMEM;
> +		goto err_alloc_product;
> +	}
> +
> +	ecc_swap_digits((const u64 *)public_key, pk->x, ndigits);
> +	ecc_swap_digits((const u64 *)&public_key[nbytes], pk->y, ndigits);
> +	ecc_swap_digits((const u64 *)private_key, priv, ndigits);
> +
> +	ecc_point_mult(product, pk, priv, rand_z, curve->p, ndigits);
> +
> +	ecc_swap_digits(product->x, (u64 *)secret, ndigits);
> +
> +	if (ecc_point_is_zero(product))
> +		ret = -EFAULT;
> +
> +	ecc_free_point(product);
> +err_alloc_product:
> +	ecc_free_point(pk);
> +err_alloc_pk:
> +	ecc_free_digits_space(priv);
> +err_alloc_priv:
> +	ecc_free_digits_space(rand_z);
> +out:
> +	return ret;
> +}
> diff --git a/crypto/ecc.h b/crypto/ecc.h
> new file mode 100644
> index 0000000..7889410
> --- /dev/null
> +++ b/crypto/ecc.h
> @@ -0,0 +1,70 @@
> +/*
> + * Copyright (c) 2013, Kenneth MacKay
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions are
> + * met:
> + *  * Redistributions of source code must retain the above copyright
> + *   notice, this list of conditions and the following disclaimer.
> + *  * Redistributions in binary form must reproduce the above copyright
> + *    notice, this list of conditions and the following disclaimer in the
> + *    documentation and/or other materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
> + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
> + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> + */
> +#ifndef _CRYPTO_ECC_H
> +#define _CRYPTO_ECC_H
> +
> +#define ECC_MAX_DIGITS	4 /* 256 */
> +
> +#define ECC_DIGITS_TO_BYTES_SHIFT 3
> +
> +/**
> + * ecdh_make_pub_key() - Compute an ECC public key
> + *
> + * @curve_id:		id representing the curve to use
> + * @private_key:	pregenerated private key for the given curve
> + * @private_key_len:	length of private_key
> + * @public_key:		buffer for storing the public key generated
> + * @public_key_len:	length of the public_key buffer
> + *
> + * Returns 0 if the public key was generated successfully, a negative value
> + * if an error occurred.
> + */
> +int ecdh_make_pub_key(const unsigned int curve_id,
> +		      const u8 *private_key, unsigned int private_key_len,
> +		      u8 *public_key, unsigned int public_key_len);
> +
> +/**
> + * ecdh_shared_secret() - Compute a shared secret
> + *
> + * @curve_id:		id representing the curve to use
> + * @private_key:	private key of part A
> + * @private_key_len:	length of private_key
> + * @public_key:		public key of counterpart B
> + * @public_key_len:	length of public_key
> + * @secret:		buffer for storing the calculated shared secret
> + * @secret_len:		length of the secret buffer
> + *
> + * Note: It is recommended that you hash the result of ecdh_shared_secret
> + * before using it for symmetric encryption or HMAC.
> + *
> + * Returns 0 if the shared secret was generated successfully, a negative
> value + * if an error occurred.
> + */
> +int ecdh_shared_secret(unsigned int curve_id,
> +		       const u8 *private_key, unsigned int private_key_len,
> +		       const u8 *public_key, unsigned int public_key_len,
> +		       u8 *secret, unsigned int secret_len);
> +#endif
> diff --git a/crypto/ecc_curve_defs.h b/crypto/ecc_curve_defs.h
> new file mode 100644
> index 0000000..03ae5f7
> --- /dev/null
> +++ b/crypto/ecc_curve_defs.h
> @@ -0,0 +1,57 @@
> +#ifndef _CRYTO_ECC_CURVE_DEFS_H
> +#define _CRYTO_ECC_CURVE_DEFS_H
> +
> +struct ecc_point {
> +	u64 *x;
> +	u64 *y;
> +	u8 ndigits;
> +};
> +
> +struct ecc_curve {
> +	char *name;
> +	struct ecc_point g;
> +	u64 *p;
> +	u64 *n;
> +};
> +
> +/* NIST P-192 */
> +static u64 nist_p192_g_x[] = { 0xF4FF0AFD82FF1012ull,
> 0x7CBF20EB43A18800ull, +				0x188DA80EB03090F6ull 
};
> +static u64 nist_p192_g_y[] = { 0x73F977A11E794811ull,
> 0x631011ED6B24CDD5ull, +				0x07192B95FFC8DA78ull 
};
> +static u64 nist_p192_p[] = { 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFEull,
> +				0xFFFFFFFFFFFFFFFFull };
> +static u64 nist_p192_n[] = { 0x146BC9B1B4D22831ull, 0xFFFFFFFF99DEF836ull,
> +				0xFFFFFFFFFFFFFFFFull };
> +static struct ecc_curve nist_p192 = {
> +	.name = "nist_192",
> +	.g = {
> +		.x = nist_p192_g_x,
> +		.y = nist_p192_g_y,
> +		.ndigits = 3,
> +	},
> +	.p = nist_p192_p,
> +	.n = nist_p192_n
> +};
> +
> +/* NIST P-256 */
> +static u64 nist_p256_g_x[] = { 0xF4A13945D898C296ull,
> 0x77037D812DEB33A0ull, +				0xF8BCE6E563A440F2ull, 
0x6B17D1F2E12C4247ull };
> +static u64 nist_p256_g_y[] = { 0xCBB6406837BF51F5ull,
> 0x2BCE33576B315ECEull, +				0x8EE7EB4A7C0F9E16ull, 
0x4FE342E2FE1A7F9Bull };
> +static u64 nist_p256_p[] = { 0xFFFFFFFFFFFFFFFFull, 0x00000000FFFFFFFFull,
> +				0x0000000000000000ull, 0xFFFFFFFF00000001ull 
};
> +static u64 nist_p256_n[] = { 0xF3B9CAC2FC632551ull, 0xBCE6FAADA7179E84ull,
> +				0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFF00000000ull 
};
> +static struct ecc_curve nist_p256 = {
> +	.name = "nist_256",
> +	.g = {
> +		.x = nist_p256_g_x,
> +		.y = nist_p256_g_y,
> +		.ndigits = 4,
> +	},
> +	.p = nist_p256_p,
> +	.n = nist_p256_n
> +};
> +
> +#endif
> diff --git a/crypto/ecdh.c b/crypto/ecdh.c
> new file mode 100644
> index 0000000..828aa14
> --- /dev/null
> +++ b/crypto/ecdh.c
> @@ -0,0 +1,171 @@
> +/* ECDH key-agreement protocol
> + *
> + * Copyright (c) 2016, Intel Corporation
> + * Authors: Salvator Benedetto <salvatore.benedetto@intel.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public Licence
> + * as published by the Free Software Foundation; either version
> + * 2 of the Licence, or (at your option) any later version.
> + */
> +
> +#include <linux/module.h>
> +#include <crypto/internal/kpp.h>
> +#include <crypto/kpp.h>
> +#include <crypto/ecdh.h>
> +#include <linux/scatterlist.h>
> +#include "ecc.h"
> +
> +struct ecdh_ctx {
> +	unsigned int curve_id;
> +	unsigned int ndigits;
> +	u64 private_key[ECC_MAX_DIGITS];
> +	u64 public_key[2 * ECC_MAX_DIGITS];
> +	u64 shared_secret[ECC_MAX_DIGITS];
> +};
> +
> +static inline struct ecdh_ctx *ecdh_get_ctx(struct crypto_kpp *tfm)
> +{
> +	return kpp_tfm_ctx(tfm);
> +}
> +
> +static unsigned int ecdh_supported_curve(unsigned int curve_id)
> +{
> +	switch (curve_id) {
> +	case ECC_CURVE_NIST_P192: return 3;
> +	case ECC_CURVE_NIST_P256: return 4;

Sorry for the late review:

As we have fips_allowed=1 for the entire system, I would ask for a change 
here: Only allow P256 in FIPS mode (or P384 or P521). All other curves are not 
supported in FIPS mode.

> +	default: return 0;
> +	}
> +}
> +
> +static int ecdh_set_params(struct crypto_kpp *tfm, void *buffer,
> +			   unsigned int len)
> +{
> +	struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
> +	struct ecdh_params *params = (struct ecdh_params *)buffer;
> +
> +	if (unlikely(!buffer || !len))
> +		return -EINVAL;
> +
> +	ctx->ndigits = ecdh_supported_curve(params->curve_id);
> +	if (unlikely(!ctx->ndigits))
> +		return -EINVAL;
> +
> +	ctx->curve_id = params->curve_id;
> +
> +	return 0;
> +}
> +
> +static int ecdh_set_secret(struct crypto_kpp *tfm, void *buffer,
> +			   unsigned int len)
> +{
> +	struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
> +
> +	if (unlikely(!buffer || !len))
> +		return -EINVAL;
> +
> +	if (unlikely(ctx->ndigits != (len >> ECC_DIGITS_TO_BYTES_SHIFT)))
> +		return -EINVAL;
> +
> +	memcpy(ctx->private_key, buffer, len);
> +
> +	return 0;
> +}
> +
> +static int ecdh_generate_public_key(struct kpp_request *req)
> +{
> +	int ret = 0;
> +	struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
> +	const struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
> +	size_t copied, nbytes;
> +
> +	nbytes = ctx->ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
> +
> +	ret = ecdh_make_pub_key(ctx->curve_id,
> +				(const u8 *)ctx->private_key, nbytes,
> +				(u8 *)ctx->public_key, sizeof(ctx-
>public_key));
> +	if (ret < 0)
> +		return ret;
> +
> +	/* Public part is a point thus it has both coordinates */
> +	copied = sg_copy_from_buffer(req->dst, 1, ctx->public_key,
> +				     nbytes * 2);
> +
> +	if (copied != 2 * nbytes)
> +		return -EINVAL;
> +
> +	return ret;
> +}
> +
> +static int ecdh_compute_shared_secret(struct kpp_request *req)
> +{
> +	int ret = 0;
> +	struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
> +	struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
> +	size_t copied, nbytes;
> +
> +	nbytes = ctx->ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
> +
> +	copied = sg_copy_to_buffer(req->src, 1, ctx->public_key, 2 * nbytes);
> +	if (copied != 2 * nbytes)
> +		return -EINVAL;
> +
> +	ret = ecdh_shared_secret(ctx->curve_id,
> +				 (const u8 *)ctx->private_key, nbytes,
> +				 (const u8 *)ctx->public_key, 2 * nbytes,
> +				 (u8 *)ctx->shared_secret, nbytes);
> +	if (ret < 0)
> +		return ret;
> +
> +	copied = sg_copy_from_buffer(req->dst, 1, ctx->shared_secret, nbytes);
> +	if (copied != nbytes)
> +		return -EINVAL;
> +
> +	return ret;
> +}
> +
> +static int ecdh_max_size(struct crypto_kpp *tfm)
> +{
> +	struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
> +	int nbytes = ctx->ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
> +
> +	/* Public key is made of two coordinates */
> +	return 2 * nbytes;
> +}
> +
> +static void no_exit_tfm(struct crypto_kpp *tfm)
> +{
> +	return;
> +}
> +
> +static struct kpp_alg ecdh = {
> +	.set_params = ecdh_set_params,
> +	.set_secret = ecdh_set_secret,
> +	.generate_public_key = ecdh_generate_public_key,
> +	.compute_shared_secret = ecdh_compute_shared_secret,
> +	.max_size = ecdh_max_size,
> +	.exit = no_exit_tfm,
> +	.base = {
> +		.cra_name = "ecdh",
> +		.cra_driver_name = "ecdh-generic",
> +		.cra_priority = 100,
> +		.cra_module = THIS_MODULE,
> +		.cra_ctxsize = sizeof(struct ecdh_ctx),
> +	},
> +};
> +
> +static int ecdh_init(void)
> +{
> +	return crypto_register_kpp(&ecdh);
> +}
> +
> +static void ecdh_exit(void)
> +{
> +	crypto_unregister_kpp(&ecdh);
> +}
> +
> +module_init(ecdh_init);
> +module_exit(ecdh_exit);
> +MODULE_ALIAS_CRYPTO("ecdh");
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("ECDH generic algorithm");
> diff --git a/crypto/testmgr.c b/crypto/testmgr.c
> index d68fa58..6d7b30c 100644
> --- a/crypto/testmgr.c
> +++ b/crypto/testmgr.c
> @@ -34,6 +34,7 @@
>  #include <crypto/akcipher.h>
>  #include <crypto/kpp.h>
>  #include <crypto/dh.h>
> +#include <crypto/ecdh.h>
> 
>  #include "internal.h"
> 
> @@ -119,7 +120,10 @@ struct akcipher_test_suite {
>  };
> 
>  struct kpp_test_suite {
> -	struct kpp_testvec_dh *vecs;
> +	union {
> +		struct kpp_testvec_dh *dh;
> +		struct kpp_testvec_ecdh *ecdh;
> +	} vecs;
>  	unsigned int count;
>  };
> 
> @@ -1891,12 +1895,113 @@ static int test_dh(struct crypto_kpp *tfm, struct
> kpp_testvec_dh *vecs, return 0;
>  }
> 
> -static int test_kpp(struct crypto_kpp *tfm, const char *alg,
> -		    struct kpp_testvec_dh *vecs, unsigned int tcount)
> +static int do_test_ecdh(struct crypto_kpp *tfm, struct kpp_testvec_ecdh
> *vec) +{
> +	struct kpp_request *req;
> +	void *input_buf = NULL;
> +	void *output_buf = NULL;
> +	struct tcrypt_result result;
> +	unsigned int out_len_max;
> +	int err = -ENOMEM;
> +	struct scatterlist src, dst;
> +	struct ecdh_params p;
> +	unsigned int nbytes = vec->ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
> +
> +	req = kpp_request_alloc(tfm, GFP_KERNEL);
> +	if (!req)
> +		return err;
> +
> +	init_completion(&result.completion);
> +
> +	/* Set curve_id */
> +	p.curve_id = vec->curve_id;
> +	err = crypto_kpp_set_params(tfm, (void *)&p, sizeof(p));
> +	if (err)
> +		goto free_req;
> +
> +	/* Set A private Key */
> +	err = crypto_kpp_set_secret(tfm, vec->private_a, nbytes);
> +	if (err)
> +		goto free_req;
> +
> +	out_len_max = crypto_kpp_maxsize(tfm);
> +	output_buf = kzalloc(out_len_max, GFP_KERNEL);
> +	if (!output_buf) {
> +		err = -ENOMEM;
> +		goto free_req;
> +	}
> +
> +	sg_init_one(&dst, output_buf, out_len_max);
> +	kpp_request_set_output(req, &dst, out_len_max);
> +	kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
> +				 tcrypt_complete, &result);
> +
> +	/* Compute A public key = aG mod p */
> +	err = wait_async_op(&result, crypto_kpp_generate_public_key(req));
> +	if (err) {
> +		pr_err("alg: ecdh: generate public key test failed. err %d\n",
> +		       err);
> +		goto free_output;
> +	}
> +	/* Verify calculated public key */
> +	if (memcmp(vec->expected_pub_a, sg_virt(req->dst), 2 * nbytes)) {
> +		pr_err("alg: ecdh: generate public key test failed. Invalid 
output\n");
> +		err = -EINVAL;
> +		goto free_output;
> +	}
> +
> +	/* Calculate shared secret key by using counter part public key. */
> +	input_buf = kzalloc(2 * nbytes, GFP_KERNEL);
> +	if (!input_buf) {
> +		err = -ENOMEM;
> +		goto free_output;
> +	}
> +
> +	memcpy(input_buf, vec->public_b, 2 * nbytes);
> +	sg_init_one(&src, input_buf, 2 * nbytes);
> +	sg_init_one(&dst, output_buf, out_len_max);
> +	kpp_request_set_input(req, &src, 2 * nbytes);
> +	kpp_request_set_output(req, &dst, out_len_max);
> +	kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
> +				 tcrypt_complete, &result);
> +	err = wait_async_op(&result, crypto_kpp_compute_shared_secret(req));
> +	if (err) {
> +		pr_err("alg: ecdh: compute shard secret test failed. err 
%d\n",
> +		       err);
> +		goto free_all;
> +	}
> +
> +	/*
> +	 * verify shared secret from which the user will derive
> +	 * secret key by executing whatever hash it has chosen
> +	 */
> +	if (memcmp(vec->expected_ss, sg_virt(req->dst), nbytes)) {
> +		pr_err("alg: ecdh: compute shared secret test failed. Invalid 
output\n");
> +		err = -EINVAL;
> +	}
> +
> +free_all:
> +	kfree(input_buf);
> +free_output:
> +	kfree(output_buf);
> +free_req:
> +	kpp_request_free(req);
> +	return err;
> +}
> +
> +static int test_ecdh(struct crypto_kpp *tfm, struct kpp_testvec_ecdh *vecs,
> +		     unsigned int tcount)
>  {
> -	if (strncmp(alg, "dh", 2) == 0)
> -		return test_dh(tfm, vecs, tcount);
> +	int ret, i;
> 
> +	for (i = 0; i < tcount; i++) {
> +		ret = do_test_ecdh(tfm, vecs++);
> +		if (ret) {
> +			pr_err("alg: ecdh: test failed on vector %d, 
err=%d\n",
> +			       i + 1, ret);
> +			return ret;
> +		}
> +	}
>  	return 0;
>  }
> 
> @@ -1912,9 +2017,12 @@ static int alg_test_kpp(const struct alg_test_desc
> *desc, const char *driver, driver, PTR_ERR(tfm));
>  		return PTR_ERR(tfm);
>  	}
> -	if (desc->suite.kpp.vecs)
> -		err = test_kpp(tfm, desc->alg, desc->suite.kpp.vecs,
> -			       desc->suite.kpp.count);
> +	if (!strncmp(desc->alg, "dh", 2) && desc->suite.kpp.vecs.dh)
> +		err = test_dh(tfm, desc->suite.kpp.vecs.dh,
> +			      desc->suite.kpp.count);
> +	else if (!strncmp(desc->alg, "ecdh", 4) && desc->suite.kpp.vecs.ecdh)
> +		err = test_ecdh(tfm, desc->suite.kpp.vecs.ecdh,
> +				desc->suite.kpp.count);
> 
>  	crypto_free_kpp(tfm);
>  	return err;
> @@ -2860,7 +2968,7 @@ static const struct alg_test_desc alg_test_descs[] = {
> .fips_allowed = 1,
>  		.suite = {
>  			.kpp = {
> -				.vecs = dh_tv_template,
> +				.vecs.dh = dh_tv_template,
>  				.count = DH_TEST_VECTORS
>  			}
>  		}
> @@ -3293,6 +3401,16 @@ static const struct alg_test_desc alg_test_descs[] =
> { }
>  		}
>  	}, {
> +		.alg = "ecdh",
> +		.test = alg_test_kpp,
> +		.fips_allowed = 1,
> +		.suite = {
> +			.kpp = {
> +				.vecs.ecdh = ecdh_tv_template,
> +				.count = ECDH_TEST_VECTORS
> +			}
> +		}
> +	}, {
>  		.alg = "gcm(aes)",
>  		.test = alg_test_aead,
>  		.fips_allowed = 1,
> diff --git a/crypto/testmgr.h b/crypto/testmgr.h
> index e9c34c7..74b3080 100644
> --- a/crypto/testmgr.h
> +++ b/crypto/testmgr.h
> @@ -26,6 +26,8 @@
> 
>  #include <linux/netlink.h>
> 
> +#include "ecc.h"
> +
>  #define MAX_DIGEST_SIZE		64
>  #define MAX_TAP			8
> 
> @@ -148,6 +150,15 @@ struct kpp_testvec_dh {
>  	unsigned short expected_ss_size;
>  };
> 
> +struct kpp_testvec_ecdh {
> +	unsigned int curve_id;
> +	char *private_a;
> +	char *expected_pub_a;
> +	char *public_b;
> +	char *expected_ss;
> +	unsigned short ndigits;
> +};
> +
>  static char zeroed_string[48];
> 
>  /*
> @@ -538,6 +549,68 @@ struct kpp_testvec_dh dh_tv_template[] = {
>  	}
>  };
> 
> +#define ECDH_TEST_VECTORS 2
> +
> +struct kpp_testvec_ecdh ecdh_tv_template[] = {
> +	{
> +	.curve_id = ECC_CURVE_NIST_P192,
> +	.private_a =
> +	"\xb5\x05\xb1\x71\x1e\xbf\x8c\xda"
> +	"\x4e\x19\x1e\x62\x1f\x23\x23\x31"
> +	"\x36\x1e\xd3\x84\x2f\xcc\x21\x72",
> +	.expected_pub_a =
> +	"\x1a\x04\xdb\xa5\xe1\xdd\x4e\x79"
> +	"\xa3\xe6\xef\x0e\x5c\x80\x49\x85"
> +	"\xfa\x78\xb4\xef\x49\xbd\x4c\x7c"
> +	"\x22\x90\x21\x02\xf9\x1b\x81\x5d"
> +	"\x0c\x8a\xa8\x98\xd6\x27\x69\x88"
> +	"\x5e\xbc\x94\xd8\x15\x9e\x21\xce",
> +	.public_b =
> +	"\xc3\xba\x67\x4b\x71\xec\xd0\x76"
> +	"\x7a\x99\x75\x64\x36\x13\x9a\x94"
> +	"\x5d\x8b\xdc\x60\x90\x91\xfd\x3f"
> +	"\xb0\x1f\x8a\x0a\x68\xc6\x88\x6e"
> +	"\x83\x87\xdd\x67\x09\xf8\x8d\x96"
> +	"\x07\xd6\xbd\x1c\xe6\x8d\x9d\x67",
> +	.expected_ss =
> +	"\xf4\x57\xcc\x4f\x1f\x4e\x31\xcc"
> +	"\xe3\x40\x60\xc8\x06\x93\xc6\x2e"
> +	"\x99\x80\x81\x28\xaf\xc5\x51\x74",
> +	.ndigits = 3,
> +	}, {
> +	.curve_id = ECC_CURVE_NIST_P256,
> +	.private_a =
> +	"\x24\xd1\x21\xeb\xe5\xcf\x2d\x83"
> +	"\xf6\x62\x1b\x6e\x43\x84\x3a\xa3"
> +	"\x8b\xe0\x86\xc3\x20\x19\xda\x92"
> +	"\x50\x53\x03\xe1\xc0\xea\xb8\x82",
> +	.expected_pub_a =
> +	"\x1a\x7f\xeb\x52\x00\xbd\x3c\x31"
> +	"\x7d\xb6\x70\xc1\x86\xa6\xc7\xc4"
> +	"\x3b\xc5\x5f\x6c\x6f\x58\x3c\xf5"
> +	"\xb6\x63\x82\x77\x33\x24\xa1\x5f"
> +	"\x6a\xca\x43\x6f\xf7\x7e\xff\x02"
> +	"\x37\x08\xcc\x40\x5e\x7a\xfd\x6a"
> +	"\x6a\x02\x6e\x41\x87\x68\x38\x77"
> +	"\xfa\xa9\x44\x43\x2d\xef\x09\xdf",
> +	.public_b =
> +	"\xcc\xb4\xda\x74\xb1\x47\x3f\xea"
> +	"\x6c\x70\x9e\x38\x2d\xc7\xaa\xb7"
> +	"\x29\xb2\x47\x03\x19\xab\xdd\x34"
> +	"\xbd\xa8\x2c\x93\xe1\xa4\x74\xd9"
> +	"\x64\x63\xf7\x70\x20\x2f\xa4\xe6"
> +	"\x9f\x4a\x38\xcc\xc0\x2c\x49\x2f"
> +	"\xb1\x32\xbb\xaf\x22\x61\xda\xcb"
> +	"\x6f\xdb\xa9\xaa\xfc\x77\x81\xf3",
> +	.expected_ss =
> +	"\xea\x17\x6f\x7e\x6e\x57\x26\x38"
> +	"\x8b\xfb\x41\xeb\xba\xc8\x6d\xa5"
> +	"\xa8\x72\xd1\xff\xc9\x47\x3d\xaa"
> +	"\x58\x43\x9f\x34\x0f\x8c\xf3\xc9",
> +	.ndigits = 4,
> +	}
> +};
> +
>  /*
>   * MD4 test vectors from RFC1320
>   */
> diff --git a/include/crypto/ecdh.h b/include/crypto/ecdh.h
> new file mode 100644
> index 0000000..438214b
> --- /dev/null
> +++ b/include/crypto/ecdh.h
> @@ -0,0 +1,24 @@
> +/*
> + * ECDH params to be used with kpp API
> + *
> + * Copyright (c) 2016, Intel Corporation
> + * Authors: Salvatore Benedetto <salvatore.benedetto@intel.com>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> Free + * Software Foundation; either version 2 of the License, or (at your
> option) + * any later version.
> + *
> + */
> +#ifndef _CRYPTO_ECDH_
> +#define _CRYPTO_ECDH_
> +
> +/* Curves IDs */
> +#define ECC_CURVE_NIST_P192	0x0001
> +#define ECC_CURVE_NIST_P256	0x0002
> +
> +struct ecdh_params {
> +	unsigned int curve_id;
> +};
> +
> +#endif


Ciao
Stephan

^ permalink raw reply

* [PATCH] crypto: caam: fix caam_jr_alloc() ret code
From: Catalin Vasile @ 2016-05-06 13:18 UTC (permalink / raw)
  To: linux-crypto
  Cc: linux-crypto-owner, horia.geanta, alexandru.porosanu, scott.wood,
	Catalin Vasile
In-Reply-To: <1462540733-2170-1-git-send-email-cata.vasile@nxp.com>

caam_jr_alloc() used to return NULL if a JR device could not be
allocated for a session. In turn, every user of this function used
IS_ERR() function to verify if anything went wrong, which does NOT look
for NULL values. This made the kernel crash if the sanity check failed,
because the driver continued to think it had allocated a valid JR dev
instance to the session and at some point it tries to do a caam_jr_free()
on a NULL JR dev pointer.
This patch is a fix for this issue.

Signed-off-by: Catalin Vasile <cata.vasile@nxp.com>
---
 drivers/crypto/caam/jr.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c
index 6fd63a6..5ef4be2 100644
--- a/drivers/crypto/caam/jr.c
+++ b/drivers/crypto/caam/jr.c
@@ -248,7 +248,7 @@ static void caam_jr_dequeue(unsigned long devarg)
 struct device *caam_jr_alloc(void)
 {
 	struct caam_drv_private_jr *jrpriv, *min_jrpriv = NULL;
-	struct device *dev = NULL;
+	struct device *dev = ERR_PTR(-ENODEV);
 	int min_tfm_cnt	= INT_MAX;
 	int tfm_cnt;
 
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH] crypto: caam: add backlogging support
From: Catalin Vasile @ 2016-05-06 13:18 UTC (permalink / raw)
  To: linux-crypto
  Cc: linux-crypto-owner, horia.geanta, alexandru.porosanu, scott.wood,
	Catalin Vasile

caam_jr_enqueue() function returns -EBUSY once there are no more slots
available in the JR, but it doesn't actually save the current request.
This breaks the functionality of users that expect that even if there is
no more space for the request, it is at least queued for later
execution. In other words, all crypto transformations that request
backlogging (i.e. have CRYPTO_TFM_REQ_MAY_BACKLOG set), will hang. Such
an example is dm-crypt. The current patch solves this issue by setting a
threshold after which caam_jr_enqueue() returns -EBUSY, but since the HW
job ring isn't actually full, the job is enqueued.

Signed-off-by: Alexandru Porosanu <alexandru.porosanu@nxp.com>
Tested-by: Catalin Vasile <cata.vasile@nxp.com>
---
 drivers/crypto/caam/caamalg.c  |  88 ++++++++++++++++--
 drivers/crypto/caam/caamhash.c | 101 +++++++++++++++++++--
 drivers/crypto/caam/intern.h   |   7 ++
 drivers/crypto/caam/jr.c       | 196 +++++++++++++++++++++++++++++++++--------
 drivers/crypto/caam/jr.h       |   5 ++
 5 files changed, 343 insertions(+), 54 deletions(-)

diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c
index ea8189f..62bce17 100644
--- a/drivers/crypto/caam/caamalg.c
+++ b/drivers/crypto/caam/caamalg.c
@@ -1921,6 +1921,9 @@ static void aead_encrypt_done(struct device *jrdev, u32 *desc, u32 err,
 
 	edesc = container_of(desc, struct aead_edesc, hw_desc[0]);
 
+	if (err == -EINPROGRESS)
+		goto out_bklogged;
+
 	if (err)
 		caam_jr_strstatus(jrdev, err);
 
@@ -1928,6 +1931,7 @@ static void aead_encrypt_done(struct device *jrdev, u32 *desc, u32 err,
 
 	kfree(edesc);
 
+out_bklogged:
 	aead_request_complete(req, err);
 }
 
@@ -1943,6 +1947,9 @@ static void aead_decrypt_done(struct device *jrdev, u32 *desc, u32 err,
 
 	edesc = container_of(desc, struct aead_edesc, hw_desc[0]);
 
+	if (err == -EINPROGRESS)
+		goto out_bklogged;
+
 	if (err)
 		caam_jr_strstatus(jrdev, err);
 
@@ -1956,6 +1963,7 @@ static void aead_decrypt_done(struct device *jrdev, u32 *desc, u32 err,
 
 	kfree(edesc);
 
+out_bklogged:
 	aead_request_complete(req, err);
 }
 
@@ -1974,6 +1982,9 @@ static void ablkcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err,
 	edesc = (struct ablkcipher_edesc *)((char *)desc -
 		 offsetof(struct ablkcipher_edesc, hw_desc));
 
+	if (err == -EINPROGRESS)
+		goto out_bklogged;
+
 	if (err)
 		caam_jr_strstatus(jrdev, err);
 
@@ -1989,6 +2000,7 @@ static void ablkcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err,
 	ablkcipher_unmap(jrdev, edesc, req);
 	kfree(edesc);
 
+out_bklogged:
 	ablkcipher_request_complete(req, err);
 }
 
@@ -2006,6 +2018,10 @@ static void ablkcipher_decrypt_done(struct device *jrdev, u32 *desc, u32 err,
 
 	edesc = (struct ablkcipher_edesc *)((char *)desc -
 		 offsetof(struct ablkcipher_edesc, hw_desc));
+
+	if (err == -EINPROGRESS)
+		goto out_bklogged;
+
 	if (err)
 		caam_jr_strstatus(jrdev, err);
 
@@ -2021,6 +2037,7 @@ static void ablkcipher_decrypt_done(struct device *jrdev, u32 *desc, u32 err,
 	ablkcipher_unmap(jrdev, edesc, req);
 	kfree(edesc);
 
+out_bklogged:
 	ablkcipher_request_complete(req, err);
 }
 
@@ -2394,7 +2411,15 @@ static int gcm_encrypt(struct aead_request *req)
 #endif
 
 	desc = edesc->hw_desc;
-	ret = caam_jr_enqueue(jrdev, desc, aead_encrypt_done, req);
+	if (req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG) {
+		ret = caam_jr_enqueue_bklog(jrdev, desc, aead_encrypt_done,
+					    req);
+		if (ret == -EBUSY)
+			return ret;
+	} else {
+		ret = caam_jr_enqueue(jrdev, desc, aead_encrypt_done, req);
+	}
+
 	if (!ret) {
 		ret = -EINPROGRESS;
 	} else {
@@ -2438,7 +2463,15 @@ static int aead_encrypt(struct aead_request *req)
 #endif
 
 	desc = edesc->hw_desc;
-	ret = caam_jr_enqueue(jrdev, desc, aead_encrypt_done, req);
+	if (req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG) {
+		ret = caam_jr_enqueue_bklog(jrdev, desc, aead_encrypt_done,
+					    req);
+		if (ret == -EBUSY)
+			return ret;
+	} else {
+		ret = caam_jr_enqueue(jrdev, desc, aead_encrypt_done, req);
+	}
+
 	if (!ret) {
 		ret = -EINPROGRESS;
 	} else {
@@ -2473,7 +2506,15 @@ static int gcm_decrypt(struct aead_request *req)
 #endif
 
 	desc = edesc->hw_desc;
-	ret = caam_jr_enqueue(jrdev, desc, aead_decrypt_done, req);
+	if (req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG) {
+		ret = caam_jr_enqueue_bklog(jrdev, desc, aead_decrypt_done,
+					    req);
+		if (ret == -EBUSY)
+			return ret;
+	} else {
+		ret = caam_jr_enqueue(jrdev, desc, aead_decrypt_done, req);
+	}
+
 	if (!ret) {
 		ret = -EINPROGRESS;
 	} else {
@@ -2523,7 +2564,15 @@ static int aead_decrypt(struct aead_request *req)
 #endif
 
 	desc = edesc->hw_desc;
-	ret = caam_jr_enqueue(jrdev, desc, aead_decrypt_done, req);
+	if (req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG) {
+		ret = caam_jr_enqueue_bklog(jrdev, desc, aead_decrypt_done,
+					    req);
+		if (ret == -EBUSY)
+			return ret;
+	} else {
+		ret = caam_jr_enqueue(jrdev, desc, aead_decrypt_done, req);
+	}
+
 	if (!ret) {
 		ret = -EINPROGRESS;
 	} else {
@@ -2672,7 +2721,15 @@ static int ablkcipher_encrypt(struct ablkcipher_request *req)
 		       desc_bytes(edesc->hw_desc), 1);
 #endif
 	desc = edesc->hw_desc;
-	ret = caam_jr_enqueue(jrdev, desc, ablkcipher_encrypt_done, req);
+	if (req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG) {
+		ret = caam_jr_enqueue_bklog(jrdev, desc,
+					    ablkcipher_encrypt_done, req);
+		if (ret == -EBUSY)
+			return ret;
+	} else {
+		ret = caam_jr_enqueue(jrdev, desc, ablkcipher_encrypt_done,
+				      req);
+	}
 
 	if (!ret) {
 		ret = -EINPROGRESS;
@@ -2710,7 +2767,16 @@ static int ablkcipher_decrypt(struct ablkcipher_request *req)
 		       desc_bytes(edesc->hw_desc), 1);
 #endif
 
-	ret = caam_jr_enqueue(jrdev, desc, ablkcipher_decrypt_done, req);
+	if (req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG) {
+		ret = caam_jr_enqueue_bklog(jrdev, desc,
+					    ablkcipher_decrypt_done, req);
+		if (ret == -EBUSY)
+			return ret;
+	} else {
+		ret = caam_jr_enqueue(jrdev, desc, ablkcipher_decrypt_done,
+				      req);
+	}
+
 	if (!ret) {
 		ret = -EINPROGRESS;
 	} else {
@@ -2851,7 +2917,15 @@ static int ablkcipher_givencrypt(struct skcipher_givcrypt_request *creq)
 		       desc_bytes(edesc->hw_desc), 1);
 #endif
 	desc = edesc->hw_desc;
-	ret = caam_jr_enqueue(jrdev, desc, ablkcipher_encrypt_done, req);
+	if (req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG) {
+		ret = caam_jr_enqueue_bklog(jrdev, desc,
+					    ablkcipher_encrypt_done, req);
+		if (ret == -EBUSY)
+			return ret;
+	} else {
+		ret = caam_jr_enqueue(jrdev, desc, ablkcipher_encrypt_done,
+				      req);
+	}
 
 	if (!ret) {
 		ret = -EINPROGRESS;
diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c
index 5845d4a..910a350 100644
--- a/drivers/crypto/caam/caamhash.c
+++ b/drivers/crypto/caam/caamhash.c
@@ -650,6 +650,10 @@ static void ahash_done(struct device *jrdev, u32 *desc, u32 err,
 
 	edesc = (struct ahash_edesc *)((char *)desc -
 		 offsetof(struct ahash_edesc, hw_desc));
+
+	if (err == -EINPROGRESS)
+		goto out_bklogged;
+
 	if (err)
 		caam_jr_strstatus(jrdev, err);
 
@@ -666,6 +670,7 @@ static void ahash_done(struct device *jrdev, u32 *desc, u32 err,
 			       digestsize, 1);
 #endif
 
+out_bklogged:
 	req->base.complete(&req->base, err);
 }
 
@@ -685,6 +690,10 @@ static void ahash_done_bi(struct device *jrdev, u32 *desc, u32 err,
 
 	edesc = (struct ahash_edesc *)((char *)desc -
 		 offsetof(struct ahash_edesc, hw_desc));
+
+	if (err == -EINPROGRESS)
+		goto out_bklogged;
+
 	if (err)
 		caam_jr_strstatus(jrdev, err);
 
@@ -701,6 +710,7 @@ static void ahash_done_bi(struct device *jrdev, u32 *desc, u32 err,
 			       digestsize, 1);
 #endif
 
+out_bklogged:
 	req->base.complete(&req->base, err);
 }
 
@@ -720,6 +730,10 @@ static void ahash_done_ctx_src(struct device *jrdev, u32 *desc, u32 err,
 
 	edesc = (struct ahash_edesc *)((char *)desc -
 		 offsetof(struct ahash_edesc, hw_desc));
+
+	if (err == -EINPROGRESS)
+		goto out_bklogged;
+
 	if (err)
 		caam_jr_strstatus(jrdev, err);
 
@@ -736,6 +750,7 @@ static void ahash_done_ctx_src(struct device *jrdev, u32 *desc, u32 err,
 			       digestsize, 1);
 #endif
 
+out_bklogged:
 	req->base.complete(&req->base, err);
 }
 
@@ -755,6 +770,10 @@ static void ahash_done_ctx_dst(struct device *jrdev, u32 *desc, u32 err,
 
 	edesc = (struct ahash_edesc *)((char *)desc -
 		 offsetof(struct ahash_edesc, hw_desc));
+
+	if (err == -EINPROGRESS)
+		goto out_bklogged;
+
 	if (err)
 		caam_jr_strstatus(jrdev, err);
 
@@ -771,6 +790,7 @@ static void ahash_done_ctx_dst(struct device *jrdev, u32 *desc, u32 err,
 			       digestsize, 1);
 #endif
 
+out_bklogged:
 	req->base.complete(&req->base, err);
 }
 
@@ -876,7 +896,15 @@ static int ahash_update_ctx(struct ahash_request *req)
 			       desc_bytes(desc), 1);
 #endif
 
-		ret = caam_jr_enqueue(jrdev, desc, ahash_done_bi, req);
+		if (req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG) {
+			ret = caam_jr_enqueue_bklog(jrdev, desc, ahash_done_bi,
+						    req);
+			if (ret == -EBUSY)
+				return ret;
+		} else {
+			ret = caam_jr_enqueue(jrdev, desc, ahash_done_bi, req);
+		}
+
 		if (!ret) {
 			ret = -EINPROGRESS;
 		} else {
@@ -973,7 +1001,15 @@ static int ahash_final_ctx(struct ahash_request *req)
 		       DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
 #endif
 
-	ret = caam_jr_enqueue(jrdev, desc, ahash_done_ctx_src, req);
+	if (req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG) {
+		ret = caam_jr_enqueue_bklog(jrdev, desc, ahash_done_ctx_src,
+					    req);
+		if (ret == -EBUSY)
+			return ret;
+	} else {
+		ret = caam_jr_enqueue(jrdev, desc, ahash_done_ctx_src, req);
+	}
+
 	if (!ret) {
 		ret = -EINPROGRESS;
 	} else {
@@ -1065,7 +1101,15 @@ static int ahash_finup_ctx(struct ahash_request *req)
 		       DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
 #endif
 
-	ret = caam_jr_enqueue(jrdev, desc, ahash_done_ctx_src, req);
+	if (req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG) {
+		ret = caam_jr_enqueue_bklog(jrdev, desc, ahash_done_ctx_src,
+					    req);
+		if (ret == -EBUSY)
+			return ret;
+	} else {
+		ret = caam_jr_enqueue(jrdev, desc, ahash_done_ctx_src, req);
+	}
+
 	if (!ret) {
 		ret = -EINPROGRESS;
 	} else {
@@ -1145,7 +1189,14 @@ static int ahash_digest(struct ahash_request *req)
 		       DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
 #endif
 
-	ret = caam_jr_enqueue(jrdev, desc, ahash_done, req);
+	if (req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG) {
+		ret = caam_jr_enqueue_bklog(jrdev, desc, ahash_done, req);
+		if (ret == -EBUSY)
+			return ret;
+	} else {
+		ret = caam_jr_enqueue(jrdev, desc, ahash_done, req);
+	}
+
 	if (!ret) {
 		ret = -EINPROGRESS;
 	} else {
@@ -1207,7 +1258,14 @@ static int ahash_final_no_ctx(struct ahash_request *req)
 		       DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
 #endif
 
-	ret = caam_jr_enqueue(jrdev, desc, ahash_done, req);
+	if (req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG) {
+		ret = caam_jr_enqueue_bklog(jrdev, desc, ahash_done, req);
+		if (ret == -EBUSY)
+			return ret;
+	} else {
+		ret = caam_jr_enqueue(jrdev, desc, ahash_done, req);
+	}
+
 	if (!ret) {
 		ret = -EINPROGRESS;
 	} else {
@@ -1308,7 +1366,16 @@ static int ahash_update_no_ctx(struct ahash_request *req)
 			       desc_bytes(desc), 1);
 #endif
 
-		ret = caam_jr_enqueue(jrdev, desc, ahash_done_ctx_dst, req);
+		if (req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG) {
+			ret = caam_jr_enqueue_bklog(jrdev, desc,
+						    ahash_done_ctx_dst, req);
+			if (ret == -EBUSY)
+				return ret;
+		} else {
+			ret = caam_jr_enqueue(jrdev, desc, ahash_done_ctx_dst,
+					      req);
+		}
+
 		if (!ret) {
 			ret = -EINPROGRESS;
 			state->update = ahash_update_ctx;
@@ -1411,7 +1478,15 @@ static int ahash_finup_no_ctx(struct ahash_request *req)
 		       DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
 #endif
 
-	ret = caam_jr_enqueue(jrdev, desc, ahash_done, req);
+	if (req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG) {
+		ret = caam_jr_enqueue_bklog(jrdev, desc, ahash_done,
+					    req);
+		if (ret == -EBUSY)
+			return ret;
+	} else {
+		ret = caam_jr_enqueue(jrdev, desc, ahash_done, req);
+	}
+
 	if (!ret) {
 		ret = -EINPROGRESS;
 	} else {
@@ -1514,8 +1589,16 @@ static int ahash_update_first(struct ahash_request *req)
 			       desc_bytes(desc), 1);
 #endif
 
-		ret = caam_jr_enqueue(jrdev, desc, ahash_done_ctx_dst,
-				      req);
+		if (req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG) {
+			ret = caam_jr_enqueue_bklog(jrdev, desc,
+						    ahash_done_ctx_dst, req);
+			if (ret == -EBUSY)
+				return ret;
+		} else {
+			ret = caam_jr_enqueue(jrdev, desc, ahash_done_ctx_dst,
+					      req);
+		}
+
 		if (!ret) {
 			ret = -EINPROGRESS;
 			state->update = ahash_update_ctx;
diff --git a/drivers/crypto/caam/intern.h b/drivers/crypto/caam/intern.h
index e2bcacc..aa4e257 100644
--- a/drivers/crypto/caam/intern.h
+++ b/drivers/crypto/caam/intern.h
@@ -11,6 +11,12 @@
 
 /* Currently comes from Kconfig param as a ^2 (driver-required) */
 #define JOBR_DEPTH (1 << CONFIG_CRYPTO_DEV_FSL_CAAM_RINGSIZE)
+/*
+ * If the user tries to enqueue a job and the number of slots available
+ * is less than this value, then the job will be backlogged (if the user
+ * allows for it) or it will be dropped.
+ */
+#define JOBR_THRESH (JOBR_DEPTH / 2 - 1)
 
 /* Kconfig params for interrupt coalescing if selected (else zero) */
 #ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_INTC
@@ -33,6 +39,7 @@ struct caam_jrentry_info {
 	u32 *desc_addr_virt;	/* Stored virt addr for postprocessing */
 	dma_addr_t desc_addr_dma;	/* Stored bus addr for done matching */
 	u32 desc_size;	/* Stored size for postprocessing, header derived */
+	bool is_backlogged; /* True if the request has been backlogged */
 };
 
 /* Private sub-storage for a single JobR */
diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c
index 5ef4be2..49790e1 100644
--- a/drivers/crypto/caam/jr.c
+++ b/drivers/crypto/caam/jr.c
@@ -168,6 +168,7 @@ static void caam_jr_dequeue(unsigned long devarg)
 	void (*usercall)(struct device *dev, u32 *desc, u32 status, void *arg);
 	u32 *userdesc, userstatus;
 	void *userarg;
+	bool is_backlogged;
 
 	while (rd_reg32(&jrp->rregs->outring_used)) {
 
@@ -201,6 +202,9 @@ static void caam_jr_dequeue(unsigned long devarg)
 		userarg = jrp->entinfo[sw_idx].cbkarg;
 		userdesc = jrp->entinfo[sw_idx].desc_addr_virt;
 		userstatus = jrp->outring[hw_idx].jrstatus;
+		is_backlogged = jrp->entinfo[sw_idx].is_backlogged;
+		/* Reset backlogging status here */
+		jrp->entinfo[sw_idx].is_backlogged = false;
 
 		/*
 		 * Make sure all information from the job has been obtained
@@ -231,6 +235,20 @@ static void caam_jr_dequeue(unsigned long devarg)
 
 		spin_unlock(&jrp->outlock);
 
+		if (is_backlogged)
+			/*
+			 * For backlogged requests, the user callback needs to
+			 * be called twice: once when starting to process it
+			 * (with a status of -EINPROGRESS and once when it's
+			 * done. Since SEC cheats by enqueuing the request in
+			 * its HW ring but returning -EBUSY, the time when the
+			 * request's processing has started is not known.
+			 * Thus notify here the user. The second call is on the
+			 * normal path (i.e. the one that is called even for
+			 * non-backlogged requests).
+			 */
+			usercall(dev, userdesc, -EINPROGRESS, userarg);
+
 		/* Finally, execute user's callback */
 		usercall(dev, userdesc, userstatus, userarg);
 	}
@@ -261,6 +279,15 @@ struct device *caam_jr_alloc(void)
 
 	list_for_each_entry(jrpriv, &driver_data.jr_list, list_node) {
 		tfm_cnt = atomic_read(&jrpriv->tfm_count);
+
+		/*
+		 * Don't allow more than JOBR_THRES jobs on this JR. If more
+		 * are allowed, then backlogging API contract won't work (each
+		 * "backloggable" tfm must allow for at least 1 enqueue.
+		 */
+		if (tfm_cnt == JOBR_THRESH)
+			continue;
+
 		if (tfm_cnt < min_tfm_cnt) {
 			min_tfm_cnt = tfm_cnt;
 			min_jrpriv = jrpriv;
@@ -292,6 +319,80 @@ void caam_jr_free(struct device *rdev)
 }
 EXPORT_SYMBOL(caam_jr_free);
 
+static inline int __caam_jr_enqueue(struct caam_drv_private_jr *jrp, u32 *desc,
+				    int desc_size, dma_addr_t desc_dma,
+				    void (*cbk)(struct device *dev, u32 *desc,
+						u32 status, void *areq),
+				    void *areq,
+				    bool can_be_backlogged)
+{
+	int head, tail;
+	struct caam_jrentry_info *head_entry;
+	int ret = 0, hw_slots, sw_slots;
+
+	spin_lock_bh(&jrp->inplock);
+
+	head = jrp->head;
+	tail = ACCESS_ONCE(jrp->tail);
+
+	head_entry = &jrp->entinfo[head];
+
+	hw_slots = rd_reg32(&jrp->rregs->inpring_avail);
+	sw_slots = CIRC_SPACE(head, tail, JOBR_DEPTH);
+
+	if (hw_slots <= JOBR_THRESH || sw_slots <= JOBR_THRESH) {
+		/*
+		 * The state below can be reached in three cases:
+		 * 1) A badly behaved backlogging user doesn't back off when
+		 *    told so by the -EBUSY return code
+		 * 2) More than JOBR_THRESH backlogging users requests
+		 * 3) Due to the high system load, the entries reserved for the
+		 *    backlogging users are being filled (slowly) in between
+		 *    the successive calls to the user callback (the first one
+		 *    with -EINPROGRESS and the 2nd one with the real result.
+		 * The code below is a last-resort measure which will DROP
+		 * any request if there is physically no more space. This will
+		 * lead to data-loss for disk-related users.
+		 */
+		if (!hw_slots || !sw_slots) {
+			ret = -EIO;
+			goto out_unlock;
+		}
+
+		ret = -EBUSY;
+		if (!can_be_backlogged)
+			goto out_unlock;
+
+		head_entry->is_backlogged = true;
+	}
+
+	head_entry->desc_addr_virt = desc;
+	head_entry->desc_size = desc_size;
+	head_entry->callbk = (void *)cbk;
+	head_entry->cbkarg = areq;
+	head_entry->desc_addr_dma = desc_dma;
+
+	jrp->inpring[jrp->inp_ring_write_index] = desc_dma;
+
+	/*
+	 * Guarantee that the descriptor's DMA address has been written to
+	 * the next slot in the ring before the write index is updated, since
+	 * other cores may update this index independently.
+	 */
+	smp_wmb();
+
+	jrp->inp_ring_write_index = (jrp->inp_ring_write_index + 1) &
+				    (JOBR_DEPTH - 1);
+	jrp->head = (head + 1) & (JOBR_DEPTH - 1);
+
+	wr_reg32(&jrp->rregs->inpring_jobadd, 1);
+
+out_unlock:
+	spin_unlock_bh(&jrp->inplock);
+
+	return ret;
+}
+
 /**
  * caam_jr_enqueue() - Enqueue a job descriptor head. Returns 0 if OK,
  * -EBUSY if the queue is full, -EIO if it cannot map the caller's
@@ -326,8 +427,7 @@ int caam_jr_enqueue(struct device *dev, u32 *desc,
 		    void *areq)
 {
 	struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
-	struct caam_jrentry_info *head_entry;
-	int head, tail, desc_size;
+	int desc_size, ret;
 	dma_addr_t desc_dma;
 
 	desc_size = (*desc & HDR_JD_LENGTH_MASK) * sizeof(u32);
@@ -337,51 +437,71 @@ int caam_jr_enqueue(struct device *dev, u32 *desc,
 		return -EIO;
 	}
 
-	spin_lock_bh(&jrp->inplock);
-
-	head = jrp->head;
-	tail = ACCESS_ONCE(jrp->tail);
-
-	if (!rd_reg32(&jrp->rregs->inpring_avail) ||
-	    CIRC_SPACE(head, tail, JOBR_DEPTH) <= 0) {
-		spin_unlock_bh(&jrp->inplock);
+	ret = __caam_jr_enqueue(jrp, desc, desc_size, desc_dma, cbk, areq,
+				false);
+	if (unlikely(ret))
 		dma_unmap_single(dev, desc_dma, desc_size, DMA_TO_DEVICE);
-		return -EBUSY;
-	}
 
-	head_entry = &jrp->entinfo[head];
-	head_entry->desc_addr_virt = desc;
-	head_entry->desc_size = desc_size;
-	head_entry->callbk = (void *)cbk;
-	head_entry->cbkarg = areq;
-	head_entry->desc_addr_dma = desc_dma;
-
-	jrp->inpring[jrp->inp_ring_write_index] = desc_dma;
+	return 0;
+}
+EXPORT_SYMBOL(caam_jr_enqueue);
 
-	/*
-	 * Guarantee that the descriptor's DMA address has been written to
-	 * the next slot in the ring before the write index is updated, since
-	 * other cores may update this index independently.
-	 */
-	smp_wmb();
+/**
+ * caam_jr_enqueue_bklog() - Enqueue a job descriptor head, returns 0 if OK, or
+ * -EBUSY if the number of available entries in the Job Ring is less
+ * than the threshold configured through JOBR_THRESH, and -EIO if it cannot map
+ * the caller's descriptor or if there is really no more space in the hardware
+ * job ring.
+ * @dev:  device of the job ring to be used. This device should have
+ *        been assigned prior by caam_jr_register().
+ * @desc: points to a job descriptor that execute our request. All
+ *        descriptors (and all referenced data) must be in a DMAable
+ *        region, and all data references must be physical addresses
+ *        accessible to CAAM (i.e. within a PAMU window granted
+ *        to it).
+ * @cbk:  pointer to a callback function to be invoked upon completion
+ *        of this request. This has the form:
+ *        callback(struct device *dev, u32 *desc, u32 stat, void *arg)
+ *        where:
+ *        @dev:    contains the job ring device that processed this
+ *                 response.
+ *        @desc:   descriptor that initiated the request, same as
+ *                 "desc" being argued to caam_jr_enqueue().
+ *        @status: untranslated status received from CAAM. See the
+ *                 reference manual for a detailed description of
+ *                 error meaning, or see the JRSTA definitions in the
+ *                 register header file
+ *        @areq:   optional pointer to an argument passed with the
+ *                 original request
+ * @areq: optional pointer to a user argument for use at callback
+ *        time.
+ **/
+int caam_jr_enqueue_bklog(struct device *dev, u32 *desc,
+			  void (*cbk)(struct device *dev, u32 *desc,
+				      u32 status, void *areq),
+			  void *areq)
+{
+	struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
+	int desc_size, ret;
+	dma_addr_t desc_dma;
 
-	jrp->inp_ring_write_index = (jrp->inp_ring_write_index + 1) &
-				    (JOBR_DEPTH - 1);
-	jrp->head = (head + 1) & (JOBR_DEPTH - 1);
 
-	/*
-	 * Ensure that all job information has been written before
-	 * notifying CAAM that a new job was added to the input ring.
-	 */
-	wmb();
+	desc_size = (*desc & HDR_JD_LENGTH_MASK) * sizeof(u32);
+	desc_dma = dma_map_single(dev, desc, desc_size, DMA_TO_DEVICE);
+	if (dma_mapping_error(dev, desc_dma)) {
+		dev_err(dev, "caam_jr_enqueue(): can't map jobdesc\n");
+		return -EIO;
+	}
 
-	wr_reg32(&jrp->rregs->inpring_jobadd, 1);
+	ret = __caam_jr_enqueue(jrp, desc, desc_size, desc_dma, cbk, areq,
+				true);
+	if (unlikely(ret && (ret != -EBUSY)))
+		dma_unmap_single(dev, desc_dma, desc_size, DMA_TO_DEVICE);
 
-	spin_unlock_bh(&jrp->inplock);
+	return ret;
 
-	return 0;
 }
-EXPORT_SYMBOL(caam_jr_enqueue);
+EXPORT_SYMBOL(caam_jr_enqueue_bklog);
 
 /*
  * Init JobR independent of platform property detection
diff --git a/drivers/crypto/caam/jr.h b/drivers/crypto/caam/jr.h
index 97113a6..21558df 100644
--- a/drivers/crypto/caam/jr.h
+++ b/drivers/crypto/caam/jr.h
@@ -15,4 +15,9 @@ int caam_jr_enqueue(struct device *dev, u32 *desc,
 				void *areq),
 		    void *areq);
 
+int caam_jr_enqueue_bklog(struct device *dev, u32 *desc,
+			  void (*cbk)(struct device *dev, u32 *desc, u32 status,
+				      void *areq),
+			  void *areq);
+
 #endif /* JR_H */
-- 
1.8.3.1

^ permalink raw reply related

* Re: [PATCH RESEND v5 1/6] crypto: AF_ALG -- add sign/verify API
From: Stephan Mueller @ 2016-05-06 10:36 UTC (permalink / raw)
  To: Tadeusz Struk
  Cc: dhowells, herbert, linux-api, marcel, linux-kernel, keyrings,
	linux-crypto, dwmw2, davem
In-Reply-To: <20160505195054.1843.11748.stgit@tstruk-mobl1>

Am Donnerstag, 5. Mai 2016, 12:50:54 schrieb Tadeusz Struk:

Hi Tadeusz, David,

> From: Stephan Mueller <smueller@chronox.de>
> 
> Add the flags for handling signature generation and signature
> verification.
> 
> Also, the patch adds the interface for setting a public key.
> 
> Signed-off-by: Stephan Mueller <smueller@chronox.de>
> Signed-off-by: Tadeusz Struk <tadeusz.struk@intel.com>

All four patches from me:

Acked-by: Stephan Mueller <smueller@chronox.de>

> ---
>  include/uapi/linux/if_alg.h |    3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/include/uapi/linux/if_alg.h b/include/uapi/linux/if_alg.h
> index f2acd2f..02e6162 100644
> --- a/include/uapi/linux/if_alg.h
> +++ b/include/uapi/linux/if_alg.h
> @@ -34,9 +34,12 @@ struct af_alg_iv {
>  #define ALG_SET_OP			3
>  #define ALG_SET_AEAD_ASSOCLEN		4
>  #define ALG_SET_AEAD_AUTHSIZE		5
> +#define ALG_SET_PUBKEY			6
> 
>  /* Operations */
>  #define ALG_OP_DECRYPT			0
>  #define ALG_OP_ENCRYPT			1
> +#define ALG_OP_SIGN			2
> +#define ALG_OP_VERIFY			3
> 
>  #endif	/* _LINUX_IF_ALG_H */


Ciao
Stephan

^ permalink raw reply

* [RESEND PATCH v2 1/8] asm-generic/io.h: allow barriers in io{read,write}{16,32}be
From: Horia Geantă @ 2016-05-06  8:28 UTC (permalink / raw)
  To: Herbert Xu; +Cc: linux-crypto, David S. Miller
In-Reply-To: <1462462435-27403-1-git-send-email-horia.geanta@nxp.com>

While reviewing the addition of io{read,write}64be accessors, Arnd

-finds a potential problem:
"If an architecture overrides readq/writeq to have barriers but does
not override ioread64be/iowrite64be, this will lack the barriers and
behave differently from the little-endian version. I think the only
affected architecture is ARC, since ARM and ARM64 both override the
big-endian accessors to have the correct barriers, and all others
don't use barriers at all."

-suggests a fix for the same problem in existing code (16/32-bit
accessors); the fix leads "to a double-swap on architectures that
don't override the io{read,write}{16,32}be accessors, but it will
work correctly on all architectures without them having to override
these accessors."

Suggested-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
---

Herbert, I forgot to add you and/or linux-crypto in the loop,
so I am resending this patch. Apologies for the noise.

Current patch got the Ack from Arnd:
https://lkml.org/lkml/2016/5/5/376

As the cover letter mentions, I am looking to go with patches 1-4
through cryptodev tree.

 include/asm-generic/io.h | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
index eed3bbe88c8a..b79fb2c248a1 100644
--- a/include/asm-generic/io.h
+++ b/include/asm-generic/io.h
@@ -613,7 +613,7 @@ static inline void iowrite32(u32 value, volatile void __iomem *addr)
 #define ioread16be ioread16be
 static inline u16 ioread16be(const volatile void __iomem *addr)
 {
-	return __be16_to_cpu(__raw_readw(addr));
+	return swab16(readw(addr));
 }
 #endif
 
@@ -621,7 +621,7 @@ static inline u16 ioread16be(const volatile void __iomem *addr)
 #define ioread32be ioread32be
 static inline u32 ioread32be(const volatile void __iomem *addr)
 {
-	return __be32_to_cpu(__raw_readl(addr));
+	return swab32(readl(addr));
 }
 #endif
 
@@ -629,7 +629,7 @@ static inline u32 ioread32be(const volatile void __iomem *addr)
 #define iowrite16be iowrite16be
 static inline void iowrite16be(u16 value, void volatile __iomem *addr)
 {
-	__raw_writew(__cpu_to_be16(value), addr);
+	writew(swab16(value), addr);
 }
 #endif
 
@@ -637,7 +637,7 @@ static inline void iowrite16be(u16 value, void volatile __iomem *addr)
 #define iowrite32be iowrite32be
 static inline void iowrite32be(u32 value, volatile void __iomem *addr)
 {
-	__raw_writel(__cpu_to_be32(value), addr);
+	writel(swab32(value), addr);
 }
 #endif
 
-- 
2.4.4

^ permalink raw reply related

* Re: UB in general ... and linux/bitops.h in particular
From: Jeffrey Walton @ 2016-05-06  2:25 UTC (permalink / raw)
  To: John Denker
  Cc: H. Peter Anvin, Theodore Ts'o, linux-kernel, Stephan Mueller,
	Herbert Xu, Andi Kleen, Sandy Harris, cryptography, linux-crypto
In-Reply-To: <572B71A7.1020100@av8n.com>

>    -- Perhaps the compiler guys could be persuaded to support
>     the needed features explicitly, perhaps via a command-line
>     option: -std=vanilla
>     This should be a no-cost option as things stand today, but
>     it helps to prevent nasty surprises in the future.

It looks LLVM has the -rainbow option; see
http://blog.llvm.org/2016/04/undefined-behavior-is-magic.html :)

Jeff

^ permalink raw reply

* Re: better patch for linux/bitops.h
From: H. Peter Anvin @ 2016-05-06  0:13 UTC (permalink / raw)
  To: tytso, Sandy Harris, Jeffrey Walton, John Denker, LKML,
	Stephan Mueller, Herbert Xu, Andi Kleen, Jason Cooper,
	linux-crypto
In-Reply-To: <20160505221809.GC17625@thunk.org>

On 05/05/2016 03:18 PM, tytso@mit.edu wrote:
> 
> So this is why I tend to take a much more pragmatic viewpoint on
> things.  Sure, it makes sense to pay attention to what the C standard
> writers are trying to do to us; but if we need to suppress certain
> optimizations to write sane kernel code --- I'm ok with that.  And
> this is why using a trust-but-verify on a specific set of compilers
> and ranges of compiler versions is a really good idea....
> 

For the record, the "portable" construct has apparently only been
supported since gcc 4.6.3.

	-hpa

^ permalink raw reply

* Re: better patch for linux/bitops.h
From: H. Peter Anvin @ 2016-05-05 22:38 UTC (permalink / raw)
  To: tytso, Sandy Harris
  Cc: Jeffrey Walton, John Denker, LKML, Stephan Mueller, Herbert Xu,
	Andi Kleen, Jason Cooper, linux-crypto
In-Reply-To: <20160505221809.GC17625@thunk.org>

On May 5, 2016 3:18:09 PM PDT, tytso@mit.edu wrote:
>On Thu, May 05, 2016 at 05:34:50PM -0400, Sandy Harris wrote:
>> 
>> I completely fail to see why tests or compiler versions should be
>> part of the discussion. The C standard says the behaviour in
>> certain cases is undefined, so a standard-compliant compiler
>> can generate more-or-less any code there.
>> 
>
>> As long as any of portability, reliability or security are among our
>> goals, any code that can give undefined behaviour should be
>> considered problematic.
>
>Because compilers have been known not necessarily to obey the specs,
>and/or interpret the specs in way that not everyone agrees with.  It's
>also the case that we are *already* disabling certain C optimizations
>which are technically allowed by the spec, but which kernel
>programmers consider insane (e.g., strict aliasing).
>
>And of course, memzero_explicit() which crypto people understand is
>necessary, is something that technically compilers are allowed to
>optimize according to the spec.  So trying to write secure kernel code
>which will work on arbitrary compilers may well be impossible.
>
>And which is also why people have said (mostly in jest), "A
>sufficiently advanced compiler is indistinguishable from an
>adversary."  (I assume people will agree that optimizing away a memset
>needed to clear secrets from memory would be considered adversarial,
>at the very least!)
>
>So this is why I tend to take a much more pragmatic viewpoint on
>things.  Sure, it makes sense to pay attention to what the C standard
>writers are trying to do to us; but if we need to suppress certain
>optimizations to write sane kernel code --- I'm ok with that.  And
>this is why using a trust-but-verify on a specific set of compilers
>and ranges of compiler versions is a really good idea....
>
>    	      	       		     - Ted

I have filed a gcc bug to have the preexisting rotate idiom officially documented as a GNU C extension.

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70967
-- 
Sent from my Android device with K-9 Mail. Please excuse brevity and formatting.

^ permalink raw reply

* Re: better patch for linux/bitops.h
From: H. Peter Anvin @ 2016-05-05 22:22 UTC (permalink / raw)
  To: tytso, Sandy Harris, Jeffrey Walton, John Denker, LKML,
	Stephan Mueller, Herbert Xu, Andi Kleen, Jason Cooper,
	linux-crypto
In-Reply-To: <20160505221809.GC17625@thunk.org>

On 05/05/2016 03:18 PM, tytso@mit.edu wrote:
> On Thu, May 05, 2016 at 05:34:50PM -0400, Sandy Harris wrote:
>>
>> I completely fail to see why tests or compiler versions should be
>> part of the discussion. The C standard says the behaviour in
>> certain cases is undefined, so a standard-compliant compiler
>> can generate more-or-less any code there.
>>
> 
>> As long as any of portability, reliability or security are among our
>> goals, any code that can give undefined behaviour should be
>> considered problematic.
> 
> Because compilers have been known not necessarily to obey the specs,
> and/or interpret the specs in way that not everyone agrees with.  It's
> also the case that we are *already* disabling certain C optimizations
> which are technically allowed by the spec, but which kernel
> programmers consider insane (e.g., strict aliasing).
> 
> And of course, memzero_explicit() which crypto people understand is
> necessary, is something that technically compilers are allowed to
> optimize according to the spec.  So trying to write secure kernel code
> which will work on arbitrary compilers may well be impossible.
> 
> And which is also why people have said (mostly in jest), "A
> sufficiently advanced compiler is indistinguishable from an
> adversary."  (I assume people will agree that optimizing away a memset
> needed to clear secrets from memory would be considered adversarial,
> at the very least!)
> 
> So this is why I tend to take a much more pragmatic viewpoint on
> things.  Sure, it makes sense to pay attention to what the C standard
> writers are trying to do to us; but if we need to suppress certain
> optimizations to write sane kernel code --- I'm ok with that.  And
> this is why using a trust-but-verify on a specific set of compilers
> and ranges of compiler versions is a really good idea....
> 

In theory, theory and practice should agree, but in practice, practice
is what counts.  I fully agree we should get rid of UD behavior where
doing so is practical, but not at the cost of breaking real-life
compilers, expecially not gcc, and to a lesser but still very real
extent icc and clang.

I would also agree that we should push the gcc developers to add to the
manual C-standard-UD behavior which are well-defined under the
gnu89/gnu99/gnu11 C dialects.

	-hpa

^ permalink raw reply

* Re: better patch for linux/bitops.h
From: tytso @ 2016-05-05 22:18 UTC (permalink / raw)
  To: Sandy Harris
  Cc: Jeffrey Walton, H. Peter Anvin, John Denker, LKML,
	Stephan Mueller, Herbert Xu, Andi Kleen, Jason Cooper,
	linux-crypto
In-Reply-To: <CACXcFmmk=DZMVqgZAOm1Lf3LP76By50af8NnPquRA8sF2Vgk0w@mail.gmail.com>

On Thu, May 05, 2016 at 05:34:50PM -0400, Sandy Harris wrote:
> 
> I completely fail to see why tests or compiler versions should be
> part of the discussion. The C standard says the behaviour in
> certain cases is undefined, so a standard-compliant compiler
> can generate more-or-less any code there.
> 

> As long as any of portability, reliability or security are among our
> goals, any code that can give undefined behaviour should be
> considered problematic.

Because compilers have been known not necessarily to obey the specs,
and/or interpret the specs in way that not everyone agrees with.  It's
also the case that we are *already* disabling certain C optimizations
which are technically allowed by the spec, but which kernel
programmers consider insane (e.g., strict aliasing).

And of course, memzero_explicit() which crypto people understand is
necessary, is something that technically compilers are allowed to
optimize according to the spec.  So trying to write secure kernel code
which will work on arbitrary compilers may well be impossible.

And which is also why people have said (mostly in jest), "A
sufficiently advanced compiler is indistinguishable from an
adversary."  (I assume people will agree that optimizing away a memset
needed to clear secrets from memory would be considered adversarial,
at the very least!)

So this is why I tend to take a much more pragmatic viewpoint on
things.  Sure, it makes sense to pay attention to what the C standard
writers are trying to do to us; but if we need to suppress certain
optimizations to write sane kernel code --- I'm ok with that.  And
this is why using a trust-but-verify on a specific set of compilers
and ranges of compiler versions is a really good idea....

    	      	       		     - Ted

^ permalink raw reply

* Re: better patch for linux/bitops.h
From: Sandy Harris @ 2016-05-05 21:34 UTC (permalink / raw)
  To: Theodore Ts'o, Jeffrey Walton, H. Peter Anvin, John Denker,
	LKML, Stephan Mueller, Herbert Xu, Andi Kleen, Sandy Harris,
	Jason Cooper, linux-crypto
In-Reply-To: <20160505035028.GD10776@thunk.org>

On Wed, May 4, 2016 at 11:50 PM, Theodore Ts'o <tytso@mit.edu> wrote:

> Instead of arguing over who's "sane" or "insane", can we come up with
> a agreed upon set of tests, and a set of compiler and compiler
> versions ...

I completely fail to see why tests or compiler versions should be
part of the discussion. The C standard says the behaviour in
certain cases is undefined, so a standard-compliant compiler
can generate more-or-less any code there.

As long as any of portability, reliability or security are among our
goals, any code that can give undefined behaviour should be
considered problematic.

> But instead of arguing over what works and doesn't, let's just create
> the the test set and just try it on a wide range of compilers and
> architectures, hmmm?

No. Let's just fix the code so that undefined behaviour cannot occur.

Creating test cases for a fix and trying them on a range of systems
would be useful, perhaps essential, work. Doing tests without a fix
would be a complete waste of time.

^ permalink raw reply

* [PATCH RESEND v5 6/6] crypto: AF_ALG - add support for key_id
From: Tadeusz Struk @ 2016-05-05 19:51 UTC (permalink / raw)
  To: dhowells-H+wXaHxf7aLQT0dZR+AlfA
  Cc: herbert-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q,
	tadeusz.struk-ral2JQCrhuEAvxtiuMwx3w,
	smueller-T9tCv8IpfcWELgA04lAiVw, linux-api-u79uwXL29TY76Z2rM5mHXA,
	marcel-kz+m5ild9QBg9hUCZPvPmw,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	keyrings-u79uwXL29TY76Z2rM5mHXA,
	linux-crypto-u79uwXL29TY76Z2rM5mHXA, dwmw2-wEGCiKHe2LqWVfeAwA7xHQ,
	davem-fT/PcQaiUtIeIZ0/mPfg9Q
In-Reply-To: <20160505195048.1843.7817.stgit@tstruk-mobl1>

This patch adds support for asymmetric key type to AF_ALG.
It will work as follows: A new PF_ALG socket options are
added on top of existing ALG_SET_KEY and ALG_SET_PUBKEY, namely
ALG_SET_KEY_ID and ALG_SET_PUBKEY_ID for setting public and
private keys respectively. When these new options will be used
the user, instead of providing the key material, will provide a
key id and the key itself will be obtained from kernel keyring
subsystem. The user will use the standard tools (keyctl tool
		or the keyctl syscall) for key instantiation and to obtain the
key id. The key id can also be obtained by reading the
/proc/keys file.

When a key corresponding to the given keyid is found, it is stored
in the socket context and subsequent crypto operation invoked by the
user will use the new asymmetric accessor functions instead of akcipher
api. The asymmetric subtype can internally use akcipher api or
invoke operations defined by a given subtype, depending on the
key type.

Signed-off-by: Tadeusz Struk <tadeusz.struk-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
---
 crypto/af_alg.c             |   10 ++
 crypto/algif_akcipher.c     |  207 ++++++++++++++++++++++++++++++++++++++++++-
 include/crypto/if_alg.h     |    1 
 include/uapi/linux/if_alg.h |    2 
 4 files changed, 215 insertions(+), 5 deletions(-)

diff --git a/crypto/af_alg.c b/crypto/af_alg.c
index 24dc082..59c8244 100644
--- a/crypto/af_alg.c
+++ b/crypto/af_alg.c
@@ -260,6 +260,16 @@ static int alg_setsockopt(struct socket *sock, int level, int optname,
 
 		err = alg_setkey(sk, optval, optlen, type->setpubkey);
 		break;
+
+	case ALG_SET_KEY_ID:
+	case ALG_SET_PUBKEY_ID:
+		/* ALG_SET_KEY_ID is only for akcipher */
+		if (!strcmp(type->name, "akcipher") ||
+		    sock->state == SS_CONNECTED)
+			goto unlock;
+
+		err = alg_setkey(sk, optval, optlen, type->setkeyid);
+		break;
 	case ALG_SET_AEAD_AUTHSIZE:
 		if (sock->state == SS_CONNECTED)
 			goto unlock;
diff --git a/crypto/algif_akcipher.c b/crypto/algif_akcipher.c
index e00793d..f486b6d 100644
--- a/crypto/algif_akcipher.c
+++ b/crypto/algif_akcipher.c
@@ -14,6 +14,8 @@
 #include <crypto/akcipher.h>
 #include <crypto/scatterwalk.h>
 #include <crypto/if_alg.h>
+#include <crypto/public_key.h>
+#include <keys/asymmetric-type.h>
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/kernel.h>
@@ -29,6 +31,7 @@ struct akcipher_sg_list {
 
 struct akcipher_tfm {
 	struct crypto_akcipher *akcipher;
+	char keyid[12];
 	bool has_key;
 };
 
@@ -37,6 +40,7 @@ struct akcipher_ctx {
 	struct af_alg_sgl rsgl[ALG_MAX_PAGES];
 
 	struct af_alg_completion completion;
+	struct key *key;
 
 	unsigned long used;
 
@@ -322,6 +326,153 @@ unlock:
 	return err ? err : size;
 }
 
+static int asym_key_encrypt(const struct key *key, struct akcipher_request *req)
+{
+	struct kernel_pkey_params params = {0};
+	char *src = NULL, *dst = NULL, *in, *out;
+	int ret;
+
+	if (!sg_is_last(req->src)) {
+		src = kmalloc(req->src_len, GFP_KERNEL);
+		if (!src)
+			return -ENOMEM;
+		scatterwalk_map_and_copy(src, req->src, 0, req->src_len, 0);
+		in = src;
+	} else {
+		in = sg_virt(req->src);
+	}
+	if (!sg_is_last(req->dst)) {
+		dst = kmalloc(req->dst_len, GFP_KERNEL);
+		if (!dst) {
+			kfree(src);
+			return -ENOMEM;
+		}
+		out = dst;
+	} else {
+		out = sg_virt(req->dst);
+	}
+	params.key = (struct key *)key;
+	params.data_len = req->src_len;
+	params.enc_len = req->dst_len;
+	ret = encrypt_blob(&params, in, out);
+	if (ret)
+		goto free;
+
+	if (dst)
+		scatterwalk_map_and_copy(dst, req->dst, 0, req->dst_len, 1);
+free:
+	kfree(src);
+	kfree(dst);
+	return ret;
+}
+
+static int asym_key_decrypt(const struct key *key, struct akcipher_request *req)
+{
+	struct kernel_pkey_params params = {0};
+	char *src = NULL, *dst = NULL, *in, *out;
+	int ret;
+
+	if (!sg_is_last(req->src)) {
+		src = kmalloc(req->src_len, GFP_KERNEL);
+		if (!src)
+			return -ENOMEM;
+		scatterwalk_map_and_copy(src, req->src, 0, req->src_len, 0);
+		in = src;
+	} else {
+		in = sg_virt(req->src);
+	}
+	if (!sg_is_last(req->dst)) {
+		dst = kmalloc(req->dst_len, GFP_KERNEL);
+		if (!dst) {
+			kfree(src);
+			return -ENOMEM;
+		}
+		out = dst;
+	} else {
+		out = sg_virt(req->dst);
+	}
+	params.key = (struct key *)key;
+	params.data_len = req->src_len;
+	params.enc_len = req->dst_len;
+	ret = decrypt_blob(&params, in, out);
+	if (ret)
+		goto free;
+
+	if (dst)
+		scatterwalk_map_and_copy(dst, req->dst, 0, req->dst_len, 1);
+free:
+	kfree(src);
+	kfree(dst);
+	return ret;
+}
+
+static int asym_key_sign(const struct key *key, struct akcipher_request *req)
+{
+	struct kernel_pkey_params params = {0};
+	char *src = NULL, *dst = NULL, *in, *out;
+	int ret;
+
+	if (!sg_is_last(req->src)) {
+		src = kmalloc(req->src_len, GFP_KERNEL);
+		if (!src)
+			return -ENOMEM;
+		scatterwalk_map_and_copy(src, req->src, 0, req->src_len, 0);
+		in = src;
+	} else {
+		in = sg_virt(req->src);
+	}
+	if (!sg_is_last(req->dst)) {
+		dst = kmalloc(req->dst_len, GFP_KERNEL);
+		if (!dst) {
+			kfree(src);
+			return -ENOMEM;
+		}
+		out = dst;
+	} else {
+		out = sg_virt(req->dst);
+	}
+	params.key = (struct key *)key;
+	params.data_len = req->src_len;
+	params.enc_len = req->dst_len;
+	ret = create_signature(&params, in, out);
+	if (ret)
+		goto free;
+
+	if (dst)
+		scatterwalk_map_and_copy(dst, req->dst, 0, req->dst_len, 1);
+free:
+	kfree(src);
+	kfree(dst);
+	return ret;
+}
+
+static int asym_key_verify(const struct key *key, struct akcipher_request *req)
+{
+	struct public_key_signature sig;
+	char *src = NULL, *in;
+	int ret;
+
+	if (!sg_is_last(req->src)) {
+		src = kmalloc(req->src_len, GFP_KERNEL);
+		if (!src)
+			return -ENOMEM;
+		scatterwalk_map_and_copy(src, req->src, 0, req->src_len, 0);
+		in = src;
+	} else {
+		in = sg_virt(req->src);
+	}
+	sig.pkey_algo = "rsa";
+	sig.encoding = "pkcs1";
+	/* Need to find a way to pass the hash param */
+	sig.hash_algo = "sha1";
+	sig.digest_size = 20;
+	sig.s_size = req->src_len;
+	sig.s = src;
+	ret = verify_signature(key, NULL, &sig);
+	kfree(src);
+	return ret;
+}
+
 static int akcipher_recvmsg(struct socket *sock, struct msghdr *msg,
 			    size_t ignored, int flags)
 {
@@ -377,16 +528,28 @@ static int akcipher_recvmsg(struct socket *sock, struct msghdr *msg,
 				   usedpages);
 	switch (ctx->op) {
 	case ALG_OP_VERIFY:
-		err = crypto_akcipher_verify(&ctx->req);
+		if (ctx->key)
+			err = asym_key_verify(ctx->key, &ctx->req);
+		else
+			err = crypto_akcipher_verify(&ctx->req);
 		break;
 	case ALG_OP_SIGN:
-		err = crypto_akcipher_sign(&ctx->req);
+		if (ctx->key)
+			err = asym_key_sign(ctx->key, &ctx->req);
+		else
+			err = crypto_akcipher_sign(&ctx->req);
 		break;
 	case ALG_OP_ENCRYPT:
-		err = crypto_akcipher_encrypt(&ctx->req);
+		if (ctx->key)
+			err = asym_key_encrypt(ctx->key, &ctx->req);
+		else
+			err = crypto_akcipher_encrypt(&ctx->req);
 		break;
 	case ALG_OP_DECRYPT:
-		err = crypto_akcipher_decrypt(&ctx->req);
+		if (ctx->key)
+			err = asym_key_decrypt(ctx->key, &ctx->req);
+		else
+			err = crypto_akcipher_decrypt(&ctx->req);
 		break;
 	default:
 		err = -EFAULT;
@@ -579,6 +742,27 @@ static void akcipher_release(void *private)
 	kfree(tfm);
 }
 
+static int akcipher_setkeyid(void *private, const u8 *key, unsigned int keylen)
+{
+	struct akcipher_tfm *tfm = private;
+	struct key *akey;
+	u32 keyid = *((u32 *)key);
+	int err = -ENOKEY;
+
+	/* Store the key id and verify that a key with the given id is present.
+	 * The actual key will be acquired in the accept_parent function
+	 */
+	sprintf(tfm->keyid, "id:%08x", keyid);
+	akey = request_key(&key_type_asymmetric, tfm->keyid, NULL);
+	if (IS_ERR(key))
+		goto out;
+
+	tfm->has_key = true;
+	key_put(akey);
+out:
+	return err;
+}
+
 static int akcipher_setprivkey(void *private, const u8 *key,
 			       unsigned int keylen)
 {
@@ -610,6 +794,8 @@ static void akcipher_sock_destruct(struct sock *sk)
 	akcipher_put_sgl(sk);
 	sock_kfree_s(sk, ctx, ctx->len);
 	af_alg_release_parent(sk);
+	if (ctx->key)
+		key_put(ctx->key);
 }
 
 static int akcipher_accept_parent_nokey(void *private, struct sock *sk)
@@ -618,6 +804,7 @@ static int akcipher_accept_parent_nokey(void *private, struct sock *sk)
 	struct alg_sock *ask = alg_sk(sk);
 	struct akcipher_tfm *tfm = private;
 	struct crypto_akcipher *akcipher = tfm->akcipher;
+	struct key *key;
 	unsigned int len = sizeof(*ctx) + crypto_akcipher_reqsize(akcipher);
 
 	ctx = sock_kmalloc(sk, len, GFP_KERNEL);
@@ -634,11 +821,20 @@ static int akcipher_accept_parent_nokey(void *private, struct sock *sk)
 	af_alg_init_completion(&ctx->completion);
 	sg_init_table(ctx->tsgl.sg, ALG_MAX_PAGES);
 
-	ask->private = ctx;
+	if (strlen(tfm->keyid)) {
+		key = request_key(&key_type_asymmetric, tfm->keyid, NULL);
+		if (IS_ERR(key)) {
+			sock_kfree_s(sk, ctx, len);
+			return -ENOKEY;
+		}
 
+		ctx->key = key;
+		memset(tfm->keyid, '\0', sizeof(tfm->keyid));
+	}
 	akcipher_request_set_tfm(&ctx->req, akcipher);
 	akcipher_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG,
 				      af_alg_complete, &ctx->completion);
+	ask->private = ctx;
 
 	sk->sk_destruct = akcipher_sock_destruct;
 
@@ -660,6 +856,7 @@ static const struct af_alg_type algif_type_akcipher = {
 	.release	=	akcipher_release,
 	.setkey		=	akcipher_setprivkey,
 	.setpubkey	=	akcipher_setpubkey,
+	.setkeyid	=	akcipher_setkeyid,
 	.accept		=	akcipher_accept_parent,
 	.accept_nokey	=	akcipher_accept_parent_nokey,
 	.ops		=	&algif_akcipher_ops,
diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h
index 6c3e6e7..09c99ab 100644
--- a/include/crypto/if_alg.h
+++ b/include/crypto/if_alg.h
@@ -53,6 +53,7 @@ struct af_alg_type {
 	void (*release)(void *private);
 	int (*setkey)(void *private, const u8 *key, unsigned int keylen);
 	int (*setpubkey)(void *private, const u8 *key, unsigned int keylen);
+	int (*setkeyid)(void *private, const u8 *key, unsigned int keylen);
 	int (*accept)(void *private, struct sock *sk);
 	int (*accept_nokey)(void *private, struct sock *sk);
 	int (*setauthsize)(void *private, unsigned int authsize);
diff --git a/include/uapi/linux/if_alg.h b/include/uapi/linux/if_alg.h
index 02e6162..0379766 100644
--- a/include/uapi/linux/if_alg.h
+++ b/include/uapi/linux/if_alg.h
@@ -35,6 +35,8 @@ struct af_alg_iv {
 #define ALG_SET_AEAD_ASSOCLEN		4
 #define ALG_SET_AEAD_AUTHSIZE		5
 #define ALG_SET_PUBKEY			6
+#define ALG_SET_PUBKEY_ID		7
+#define ALG_SET_KEY_ID			8
 
 /* Operations */
 #define ALG_OP_DECRYPT			0

^ permalink raw reply related

* [PATCH RESEND v5 5/6] crypto: algif_akcipher - add ops_nokey
From: Tadeusz Struk @ 2016-05-05 19:51 UTC (permalink / raw)
  To: dhowells
  Cc: herbert, tadeusz.struk, smueller, linux-api, marcel, linux-kernel,
	keyrings, linux-crypto, dwmw2, davem
In-Reply-To: <20160505195048.1843.7817.stgit@tstruk-mobl1>

Similar to algif_skcipher and algif_hash, algif_akcipher needs
to prevent user space from using the interface in an improper way.
This patch adds nokey ops handlers, which do just that.

Signed-off-by: Tadeusz Struk <tadeusz.struk@intel.com>
---
 crypto/algif_akcipher.c |  159 +++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 152 insertions(+), 7 deletions(-)

diff --git a/crypto/algif_akcipher.c b/crypto/algif_akcipher.c
index 6342b6e..e00793d 100644
--- a/crypto/algif_akcipher.c
+++ b/crypto/algif_akcipher.c
@@ -27,6 +27,11 @@ struct akcipher_sg_list {
 	struct scatterlist sg[ALG_MAX_PAGES];
 };
 
+struct akcipher_tfm {
+	struct crypto_akcipher *akcipher;
+	bool has_key;
+};
+
 struct akcipher_ctx {
 	struct akcipher_sg_list tsgl;
 	struct af_alg_sgl rsgl[ALG_MAX_PAGES];
@@ -450,25 +455,151 @@ static struct proto_ops algif_akcipher_ops = {
 	.poll		=	akcipher_poll,
 };
 
+static int akcipher_check_key(struct socket *sock)
+{
+	int err = 0;
+	struct sock *psk;
+	struct alg_sock *pask;
+	struct akcipher_tfm *tfm;
+	struct sock *sk = sock->sk;
+	struct alg_sock *ask = alg_sk(sk);
+
+	lock_sock(sk);
+	if (ask->refcnt)
+		goto unlock_child;
+
+	psk = ask->parent;
+	pask = alg_sk(ask->parent);
+	tfm = pask->private;
+
+	err = -ENOKEY;
+	lock_sock_nested(psk, SINGLE_DEPTH_NESTING);
+	if (!tfm->has_key)
+		goto unlock;
+
+	if (!pask->refcnt++)
+		sock_hold(psk);
+
+	ask->refcnt = 1;
+	sock_put(psk);
+
+	err = 0;
+
+unlock:
+	release_sock(psk);
+unlock_child:
+	release_sock(sk);
+
+	return err;
+}
+
+static int akcipher_sendmsg_nokey(struct socket *sock, struct msghdr *msg,
+				  size_t size)
+{
+	int err;
+
+	err = akcipher_check_key(sock);
+	if (err)
+		return err;
+
+	return akcipher_sendmsg(sock, msg, size);
+}
+
+static ssize_t akcipher_sendpage_nokey(struct socket *sock, struct page *page,
+				       int offset, size_t size, int flags)
+{
+	int err;
+
+	err = akcipher_check_key(sock);
+	if (err)
+		return err;
+
+	return akcipher_sendpage(sock, page, offset, size, flags);
+}
+
+static int akcipher_recvmsg_nokey(struct socket *sock, struct msghdr *msg,
+				  size_t ignored, int flags)
+{
+	int err;
+
+	err = akcipher_check_key(sock);
+	if (err)
+		return err;
+
+	return akcipher_recvmsg(sock, msg, ignored, flags);
+}
+
+static struct proto_ops algif_akcipher_ops_nokey = {
+	.family		=	PF_ALG,
+
+	.connect	=	sock_no_connect,
+	.socketpair	=	sock_no_socketpair,
+	.getname	=	sock_no_getname,
+	.ioctl		=	sock_no_ioctl,
+	.listen		=	sock_no_listen,
+	.shutdown	=	sock_no_shutdown,
+	.getsockopt	=	sock_no_getsockopt,
+	.mmap		=	sock_no_mmap,
+	.bind		=	sock_no_bind,
+	.accept		=	sock_no_accept,
+	.setsockopt	=	sock_no_setsockopt,
+
+	.release	=	af_alg_release,
+	.sendmsg	=	akcipher_sendmsg_nokey,
+	.sendpage	=	akcipher_sendpage_nokey,
+	.recvmsg	=	akcipher_recvmsg_nokey,
+	.poll		=	akcipher_poll,
+};
+
 static void *akcipher_bind(const char *name, u32 type, u32 mask)
 {
-	return crypto_alloc_akcipher(name, type, mask);
+	struct akcipher_tfm *tfm;
+	struct crypto_akcipher *akcipher;
+
+	tfm = kzalloc(sizeof(*tfm), GFP_KERNEL);
+	if (!tfm)
+		return ERR_PTR(-ENOMEM);
+
+	akcipher = crypto_alloc_akcipher(name, type, mask);
+	if (IS_ERR(akcipher)) {
+		kfree(tfm);
+		return ERR_CAST(akcipher);
+	}
+
+	tfm->akcipher = akcipher;
+	return tfm;
 }
 
 static void akcipher_release(void *private)
 {
-	crypto_free_akcipher(private);
+	struct akcipher_tfm *tfm = private;
+	struct crypto_akcipher *akcipher = tfm->akcipher;
+
+	crypto_free_akcipher(akcipher);
+	kfree(tfm);
 }
 
 static int akcipher_setprivkey(void *private, const u8 *key,
 			       unsigned int keylen)
 {
-	return crypto_akcipher_set_priv_key(private, key, keylen);
+	struct akcipher_tfm *tfm = private;
+	struct crypto_akcipher *akcipher = tfm->akcipher;
+	int err;
+
+	err = crypto_akcipher_set_priv_key(akcipher, key, keylen);
+	tfm->has_key = !err;
+	return err;
 }
 
 static int akcipher_setpubkey(void *private, const u8 *key, unsigned int keylen)
 {
-	return crypto_akcipher_set_pub_key(private, key, keylen);
+	struct akcipher_tfm *tfm = private;
+	struct crypto_akcipher *akcipher = tfm->akcipher;
+	int err;
+
+	err = crypto_akcipher_set_pub_key(akcipher, key, keylen);
+	tfm->has_key = !err;
+	return err;
 }
 
 static void akcipher_sock_destruct(struct sock *sk)
@@ -481,11 +612,13 @@ static void akcipher_sock_destruct(struct sock *sk)
 	af_alg_release_parent(sk);
 }
 
-static int akcipher_accept_parent(void *private, struct sock *sk)
+static int akcipher_accept_parent_nokey(void *private, struct sock *sk)
 {
 	struct akcipher_ctx *ctx;
 	struct alg_sock *ask = alg_sk(sk);
-	unsigned int len = sizeof(*ctx) + crypto_akcipher_reqsize(private);
+	struct akcipher_tfm *tfm = private;
+	struct crypto_akcipher *akcipher = tfm->akcipher;
+	unsigned int len = sizeof(*ctx) + crypto_akcipher_reqsize(akcipher);
 
 	ctx = sock_kmalloc(sk, len, GFP_KERNEL);
 	if (!ctx)
@@ -503,7 +636,7 @@ static int akcipher_accept_parent(void *private, struct sock *sk)
 
 	ask->private = ctx;
 
-	akcipher_request_set_tfm(&ctx->req, private);
+	akcipher_request_set_tfm(&ctx->req, akcipher);
 	akcipher_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG,
 				      af_alg_complete, &ctx->completion);
 
@@ -512,13 +645,25 @@ static int akcipher_accept_parent(void *private, struct sock *sk)
 	return 0;
 }
 
+static int akcipher_accept_parent(void *private, struct sock *sk)
+{
+	struct akcipher_tfm *tfm = private;
+
+	if (!tfm->has_key)
+		return -ENOKEY;
+
+	return akcipher_accept_parent_nokey(private, sk);
+}
+
 static const struct af_alg_type algif_type_akcipher = {
 	.bind		=	akcipher_bind,
 	.release	=	akcipher_release,
 	.setkey		=	akcipher_setprivkey,
 	.setpubkey	=	akcipher_setpubkey,
 	.accept		=	akcipher_accept_parent,
+	.accept_nokey	=	akcipher_accept_parent_nokey,
 	.ops		=	&algif_akcipher_ops,
+	.ops_nokey	=	&algif_akcipher_ops_nokey,
 	.name		=	"akcipher",
 	.owner		=	THIS_MODULE
 };

^ permalink raw reply related

* [PATCH RESEND v5 4/6] crypto: algif_akcipher - enable compilation
From: Tadeusz Struk @ 2016-05-05 19:51 UTC (permalink / raw)
  To: dhowells
  Cc: herbert, tadeusz.struk, smueller, linux-api, marcel, linux-kernel,
	keyrings, linux-crypto, dwmw2, davem
In-Reply-To: <20160505195048.1843.7817.stgit@tstruk-mobl1>

From: Stephan Mueller <smueller@chronox.de>

Add the Makefile and Kconfig updates to allow algif_akcipher to be
compiled.

Signed-off-by: Stephan Mueller <smueller@chronox.de>
Signed-off-by: Tadeusz Struk <tadeusz.struk@intel.com>
---
 crypto/Kconfig  |    9 +++++++++
 crypto/Makefile |    1 +
 2 files changed, 10 insertions(+)

diff --git a/crypto/Kconfig b/crypto/Kconfig
index 93a1fdc..b932319 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -1626,6 +1626,15 @@ config CRYPTO_USER_API_AEAD
 	  This option enables the user-spaces interface for AEAD
 	  cipher algorithms.
 
+config CRYPTO_USER_API_AKCIPHER
+	tristate "User-space interface for asymmetric key cipher algorithms"
+	depends on NET
+	select CRYPTO_AKCIPHER2
+	select CRYPTO_USER_API
+	help
+	  This option enables the user-spaces interface for asymmetric
+	  key cipher algorithms.
+
 config CRYPTO_HASH_INFO
 	bool
 
diff --git a/crypto/Makefile b/crypto/Makefile
index 4f4ef7e..c51ac16 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -121,6 +121,7 @@ obj-$(CONFIG_CRYPTO_USER_API_HASH) += algif_hash.o
 obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o
 obj-$(CONFIG_CRYPTO_USER_API_RNG) += algif_rng.o
 obj-$(CONFIG_CRYPTO_USER_API_AEAD) += algif_aead.o
+obj-$(CONFIG_CRYPTO_USER_API_AKCIPHER) += algif_akcipher.o
 
 #
 # generic algorithms and the async_tx api

^ permalink raw reply related

* [PATCH RESEND v5 3/6] crypto: AF_ALG -- add asymmetric cipher interface
From: Tadeusz Struk @ 2016-05-05 19:51 UTC (permalink / raw)
  To: dhowells
  Cc: herbert, tadeusz.struk, smueller, linux-api, marcel, linux-kernel,
	keyrings, linux-crypto, dwmw2, davem
In-Reply-To: <20160505195048.1843.7817.stgit@tstruk-mobl1>

From: Stephan Mueller <smueller@chronox.de>

This patch adds the user space interface for asymmetric ciphers. The
interface allows the use of sendmsg as well as vmsplice to provide data.

This version has been rebased on top of 4.6 and a few chackpatch issues
have been fixed.

Signed-off-by: Stephan Mueller <smueller@chronox.de>
Signed-off-by: Tadeusz Struk <tadeusz.struk@intel.com>
---
 crypto/algif_akcipher.c |  542 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 542 insertions(+)
 create mode 100644 crypto/algif_akcipher.c

diff --git a/crypto/algif_akcipher.c b/crypto/algif_akcipher.c
new file mode 100644
index 0000000..6342b6e
--- /dev/null
+++ b/crypto/algif_akcipher.c
@@ -0,0 +1,542 @@
+/*
+ * algif_akcipher: User-space interface for asymmetric cipher algorithms
+ *
+ * Copyright (C) 2015, Stephan Mueller <smueller@chronox.de>
+ *
+ * This file provides the user-space API for asymmetric ciphers.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <crypto/akcipher.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/if_alg.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/net.h>
+#include <net/sock.h>
+
+struct akcipher_sg_list {
+	unsigned int cur;
+	struct scatterlist sg[ALG_MAX_PAGES];
+};
+
+struct akcipher_ctx {
+	struct akcipher_sg_list tsgl;
+	struct af_alg_sgl rsgl[ALG_MAX_PAGES];
+
+	struct af_alg_completion completion;
+
+	unsigned long used;
+
+	unsigned int len;
+	bool more;
+	bool merge;
+	int op;
+
+	struct akcipher_request req;
+};
+
+static inline int akcipher_sndbuf(struct sock *sk)
+{
+	struct alg_sock *ask = alg_sk(sk);
+	struct akcipher_ctx *ctx = ask->private;
+
+	return max_t(int, max_t(int, sk->sk_sndbuf & PAGE_MASK, PAGE_SIZE) -
+			  ctx->used, 0);
+}
+
+static inline bool akcipher_writable(struct sock *sk)
+{
+	return akcipher_sndbuf(sk) >= PAGE_SIZE;
+}
+
+static inline int akcipher_calcsize(struct akcipher_ctx *ctx)
+{
+	return crypto_akcipher_maxsize(crypto_akcipher_reqtfm(&ctx->req));
+}
+
+static void akcipher_put_sgl(struct sock *sk)
+{
+	struct alg_sock *ask = alg_sk(sk);
+	struct akcipher_ctx *ctx = ask->private;
+	struct akcipher_sg_list *sgl = &ctx->tsgl;
+	struct scatterlist *sg = sgl->sg;
+	unsigned int i;
+
+	for (i = 0; i < sgl->cur; i++) {
+		if (!sg_page(sg + i))
+			continue;
+
+		put_page(sg_page(sg + i));
+		sg_assign_page(sg + i, NULL);
+	}
+	sg_init_table(sg, ALG_MAX_PAGES);
+	sgl->cur = 0;
+	ctx->used = 0;
+	ctx->more = 0;
+	ctx->merge = 0;
+}
+
+static void akcipher_wmem_wakeup(struct sock *sk)
+{
+	struct socket_wq *wq;
+
+	if (!akcipher_writable(sk))
+		return;
+
+	rcu_read_lock();
+	wq = rcu_dereference(sk->sk_wq);
+	if (wq_has_sleeper(&wq->wait))
+		wake_up_interruptible_sync_poll(&wq->wait, POLLIN |
+							   POLLRDNORM |
+							   POLLRDBAND);
+	sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN);
+	rcu_read_unlock();
+}
+
+static int akcipher_wait_for_data(struct sock *sk, unsigned int flags)
+{
+	struct alg_sock *ask = alg_sk(sk);
+	struct akcipher_ctx *ctx = ask->private;
+	long timeout;
+	DEFINE_WAIT(wait);
+	int err = -ERESTARTSYS;
+
+	if (flags & MSG_DONTWAIT)
+		return -EAGAIN;
+
+	set_bit(SOCKWQ_ASYNC_WAITDATA, &sk->sk_socket->flags);
+
+	for (;;) {
+		if (signal_pending(current))
+			break;
+		prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
+		timeout = MAX_SCHEDULE_TIMEOUT;
+		if (sk_wait_event(sk, &timeout, !ctx->more)) {
+			err = 0;
+			break;
+		}
+	}
+	finish_wait(sk_sleep(sk), &wait);
+
+	clear_bit(SOCKWQ_ASYNC_WAITDATA, &sk->sk_socket->flags);
+
+	return err;
+}
+
+static void akcipher_data_wakeup(struct sock *sk)
+{
+	struct alg_sock *ask = alg_sk(sk);
+	struct akcipher_ctx *ctx = ask->private;
+	struct socket_wq *wq;
+
+	if (ctx->more)
+		return;
+	if (!ctx->used)
+		return;
+
+	rcu_read_lock();
+	wq = rcu_dereference(sk->sk_wq);
+	if (wq_has_sleeper(&wq->wait))
+		wake_up_interruptible_sync_poll(&wq->wait, POLLOUT |
+							   POLLRDNORM |
+							   POLLRDBAND);
+	sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT);
+	rcu_read_unlock();
+}
+
+static int akcipher_sendmsg(struct socket *sock, struct msghdr *msg,
+			    size_t size)
+{
+	struct sock *sk = sock->sk;
+	struct alg_sock *ask = alg_sk(sk);
+	struct akcipher_ctx *ctx = ask->private;
+	struct akcipher_sg_list *sgl = &ctx->tsgl;
+	struct af_alg_control con = {};
+	long copied = 0;
+	int op = 0;
+	bool init = 0;
+	int err;
+
+	if (msg->msg_controllen) {
+		err = af_alg_cmsg_send(msg, &con);
+		if (err)
+			return err;
+
+		init = 1;
+		switch (con.op) {
+		case ALG_OP_VERIFY:
+		case ALG_OP_SIGN:
+		case ALG_OP_ENCRYPT:
+		case ALG_OP_DECRYPT:
+			op = con.op;
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	lock_sock(sk);
+	if (!ctx->more && ctx->used)
+		goto unlock;
+
+	if (init)
+		ctx->op = op;
+
+	while (size) {
+		unsigned long len = size;
+		struct scatterlist *sg = NULL;
+
+		/* use the existing memory in an allocated page */
+		if (ctx->merge) {
+			sg = sgl->sg + sgl->cur - 1;
+			len = min_t(unsigned long, len,
+				    PAGE_SIZE - sg->offset - sg->length);
+			err = memcpy_from_msg(page_address(sg_page(sg)) +
+					      sg->offset + sg->length,
+					      msg, len);
+			if (err)
+				goto unlock;
+
+			sg->length += len;
+			ctx->merge = (sg->offset + sg->length) &
+				     (PAGE_SIZE - 1);
+
+			ctx->used += len;
+			copied += len;
+			size -= len;
+			continue;
+		}
+
+		if (!akcipher_writable(sk)) {
+			/* user space sent too much data */
+			akcipher_put_sgl(sk);
+			err = -EMSGSIZE;
+			goto unlock;
+		}
+
+		/* allocate a new page */
+		len = min_t(unsigned long, size, akcipher_sndbuf(sk));
+		while (len) {
+			int plen = 0;
+
+			if (sgl->cur >= ALG_MAX_PAGES) {
+				akcipher_put_sgl(sk);
+				err = -E2BIG;
+				goto unlock;
+			}
+
+			sg = sgl->sg + sgl->cur;
+			plen = min_t(int, len, PAGE_SIZE);
+
+			sg_assign_page(sg, alloc_page(GFP_KERNEL));
+			if (!sg_page(sg)) {
+				err = -ENOMEM;
+				goto unlock;
+			}
+
+			err = memcpy_from_msg(page_address(sg_page(sg)),
+					      msg, plen);
+			if (err) {
+				__free_page(sg_page(sg));
+				sg_assign_page(sg, NULL);
+				goto unlock;
+			}
+
+			sg->offset = 0;
+			sg->length = plen;
+			len -= plen;
+			ctx->used += plen;
+			copied += plen;
+			sgl->cur++;
+			size -= plen;
+			ctx->merge = plen & (PAGE_SIZE - 1);
+		}
+	}
+
+	err = 0;
+
+	ctx->more = msg->msg_flags & MSG_MORE;
+
+unlock:
+	akcipher_data_wakeup(sk);
+	release_sock(sk);
+
+	return err ?: copied;
+}
+
+static ssize_t akcipher_sendpage(struct socket *sock, struct page *page,
+				 int offset, size_t size, int flags)
+{
+	struct sock *sk = sock->sk;
+	struct alg_sock *ask = alg_sk(sk);
+	struct akcipher_ctx *ctx = ask->private;
+	struct akcipher_sg_list *sgl = &ctx->tsgl;
+	int err = 0;
+
+	if (flags & MSG_SENDPAGE_NOTLAST)
+		flags |= MSG_MORE;
+
+	if (sgl->cur >= ALG_MAX_PAGES)
+		return -E2BIG;
+
+	lock_sock(sk);
+	if (!ctx->more && ctx->used)
+		goto unlock;
+
+	if (!size)
+		goto done;
+
+	if (!akcipher_writable(sk)) {
+		/* user space sent too much data */
+		akcipher_put_sgl(sk);
+		err = -EMSGSIZE;
+		goto unlock;
+	}
+
+	ctx->merge = 0;
+
+	get_page(page);
+	sg_set_page(sgl->sg + sgl->cur, page, size, offset);
+	sgl->cur++;
+	ctx->used += size;
+
+done:
+	ctx->more = flags & MSG_MORE;
+unlock:
+	akcipher_data_wakeup(sk);
+	release_sock(sk);
+
+	return err ? err : size;
+}
+
+static int akcipher_recvmsg(struct socket *sock, struct msghdr *msg,
+			    size_t ignored, int flags)
+{
+	struct sock *sk = sock->sk;
+	struct alg_sock *ask = alg_sk(sk);
+	struct akcipher_ctx *ctx = ask->private;
+	struct akcipher_sg_list *sgl = &ctx->tsgl;
+	unsigned int i = 0;
+	int err;
+	unsigned long used = 0;
+	size_t usedpages = 0;
+	unsigned int cnt = 0;
+
+	/* Limit number of IOV blocks to be accessed below */
+	if (msg->msg_iter.nr_segs > ALG_MAX_PAGES)
+		return -ENOMSG;
+
+	lock_sock(sk);
+
+	if (ctx->more) {
+		err = akcipher_wait_for_data(sk, flags);
+		if (err)
+			goto unlock;
+	}
+
+	used = ctx->used;
+
+	/* convert iovecs of output buffers into scatterlists */
+	while (iov_iter_count(&msg->msg_iter)) {
+		/* make one iovec available as scatterlist */
+		err = af_alg_make_sg(&ctx->rsgl[cnt], &msg->msg_iter,
+				     iov_iter_count(&msg->msg_iter));
+		if (err < 0)
+			goto unlock;
+		usedpages += err;
+		/* chain the new scatterlist with previous one */
+		if (cnt)
+			af_alg_link_sg(&ctx->rsgl[cnt - 1], &ctx->rsgl[cnt]);
+
+		iov_iter_advance(&msg->msg_iter, err);
+		cnt++;
+	}
+
+	/* ensure output buffer is sufficiently large */
+	if (usedpages < akcipher_calcsize(ctx)) {
+		err = -EMSGSIZE;
+		goto unlock;
+	}
+
+	sg_mark_end(sgl->sg + sgl->cur - 1);
+
+	akcipher_request_set_crypt(&ctx->req, sgl->sg, ctx->rsgl[0].sg, used,
+				   usedpages);
+	switch (ctx->op) {
+	case ALG_OP_VERIFY:
+		err = crypto_akcipher_verify(&ctx->req);
+		break;
+	case ALG_OP_SIGN:
+		err = crypto_akcipher_sign(&ctx->req);
+		break;
+	case ALG_OP_ENCRYPT:
+		err = crypto_akcipher_encrypt(&ctx->req);
+		break;
+	case ALG_OP_DECRYPT:
+		err = crypto_akcipher_decrypt(&ctx->req);
+		break;
+	default:
+		err = -EFAULT;
+		goto unlock;
+	}
+
+	err = af_alg_wait_for_completion(err, &ctx->completion);
+
+	if (err) {
+		/* EBADMSG implies a valid cipher operation took place */
+		if (err == -EBADMSG)
+			akcipher_put_sgl(sk);
+		goto unlock;
+	}
+
+	akcipher_put_sgl(sk);
+
+unlock:
+	for (i = 0; i < cnt; i++)
+		af_alg_free_sg(&ctx->rsgl[i]);
+
+	akcipher_wmem_wakeup(sk);
+	release_sock(sk);
+
+	return err ? err : ctx->req.dst_len;
+}
+
+static unsigned int akcipher_poll(struct file *file, struct socket *sock,
+				  poll_table *wait)
+{
+	struct sock *sk = sock->sk;
+	struct alg_sock *ask = alg_sk(sk);
+	struct akcipher_ctx *ctx = ask->private;
+	unsigned int mask = 0;
+
+	sock_poll_wait(file, sk_sleep(sk), wait);
+
+	if (!ctx->more)
+		mask |= POLLIN | POLLRDNORM;
+
+	if (akcipher_writable(sk))
+		mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
+
+	return mask;
+}
+
+static struct proto_ops algif_akcipher_ops = {
+	.family		=	PF_ALG,
+
+	.connect	=	sock_no_connect,
+	.socketpair	=	sock_no_socketpair,
+	.getname	=	sock_no_getname,
+	.ioctl		=	sock_no_ioctl,
+	.listen		=	sock_no_listen,
+	.shutdown	=	sock_no_shutdown,
+	.getsockopt	=	sock_no_getsockopt,
+	.mmap		=	sock_no_mmap,
+	.bind		=	sock_no_bind,
+	.accept		=	sock_no_accept,
+	.setsockopt	=	sock_no_setsockopt,
+
+	.release	=	af_alg_release,
+	.sendmsg	=	akcipher_sendmsg,
+	.sendpage	=	akcipher_sendpage,
+	.recvmsg	=	akcipher_recvmsg,
+	.poll		=	akcipher_poll,
+};
+
+static void *akcipher_bind(const char *name, u32 type, u32 mask)
+{
+	return crypto_alloc_akcipher(name, type, mask);
+}
+
+static void akcipher_release(void *private)
+{
+	crypto_free_akcipher(private);
+}
+
+static int akcipher_setprivkey(void *private, const u8 *key,
+			       unsigned int keylen)
+{
+	return crypto_akcipher_set_priv_key(private, key, keylen);
+}
+
+static int akcipher_setpubkey(void *private, const u8 *key, unsigned int keylen)
+{
+	return crypto_akcipher_set_pub_key(private, key, keylen);
+}
+
+static void akcipher_sock_destruct(struct sock *sk)
+{
+	struct alg_sock *ask = alg_sk(sk);
+	struct akcipher_ctx *ctx = ask->private;
+
+	akcipher_put_sgl(sk);
+	sock_kfree_s(sk, ctx, ctx->len);
+	af_alg_release_parent(sk);
+}
+
+static int akcipher_accept_parent(void *private, struct sock *sk)
+{
+	struct akcipher_ctx *ctx;
+	struct alg_sock *ask = alg_sk(sk);
+	unsigned int len = sizeof(*ctx) + crypto_akcipher_reqsize(private);
+
+	ctx = sock_kmalloc(sk, len, GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+	memset(ctx, 0, len);
+
+	ctx->len = len;
+	ctx->used = 0;
+	ctx->more = 0;
+	ctx->merge = 0;
+	ctx->op = 0;
+	ctx->tsgl.cur = 0;
+	af_alg_init_completion(&ctx->completion);
+	sg_init_table(ctx->tsgl.sg, ALG_MAX_PAGES);
+
+	ask->private = ctx;
+
+	akcipher_request_set_tfm(&ctx->req, private);
+	akcipher_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+				      af_alg_complete, &ctx->completion);
+
+	sk->sk_destruct = akcipher_sock_destruct;
+
+	return 0;
+}
+
+static const struct af_alg_type algif_type_akcipher = {
+	.bind		=	akcipher_bind,
+	.release	=	akcipher_release,
+	.setkey		=	akcipher_setprivkey,
+	.setpubkey	=	akcipher_setpubkey,
+	.accept		=	akcipher_accept_parent,
+	.ops		=	&algif_akcipher_ops,
+	.name		=	"akcipher",
+	.owner		=	THIS_MODULE
+};
+
+static int __init algif_akcipher_init(void)
+{
+	return af_alg_register_type(&algif_type_akcipher);
+}
+
+static void __exit algif_akcipher_exit(void)
+{
+	int err = af_alg_unregister_type(&algif_type_akcipher);
+
+	WARN_ON(err);
+}
+
+module_init(algif_akcipher_init);
+module_exit(algif_akcipher_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Stephan Mueller <smueller@chronox.de>");
+MODULE_DESCRIPTION("Asymmetric kernel crypto API user space interface");

^ permalink raw reply related

* [PATCH RESEND v5 2/6] crypto: AF_ALG -- add setpubkey setsockopt call
From: Tadeusz Struk @ 2016-05-05 19:50 UTC (permalink / raw)
  To: dhowells
  Cc: herbert, tadeusz.struk, smueller, linux-api, marcel, linux-kernel,
	keyrings, linux-crypto, dwmw2, davem
In-Reply-To: <20160505195048.1843.7817.stgit@tstruk-mobl1>

From: Stephan Mueller <smueller@chronox.de>

For supporting asymmetric ciphers, user space must be able to set the
public key. The patch adds a new setsockopt call for setting the public
key.

Signed-off-by: Stephan Mueller <smueller@chronox.de>
---
 crypto/af_alg.c         |   18 +++++++++++++-----
 include/crypto/if_alg.h |    1 +
 2 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/crypto/af_alg.c b/crypto/af_alg.c
index f5e18c2..24dc082 100644
--- a/crypto/af_alg.c
+++ b/crypto/af_alg.c
@@ -202,13 +202,17 @@ unlock:
 }
 
 static int alg_setkey(struct sock *sk, char __user *ukey,
-		      unsigned int keylen)
+		      unsigned int keylen,
+		      int (*setkey)(void *private, const u8 *key,
+				    unsigned int keylen))
 {
 	struct alg_sock *ask = alg_sk(sk);
-	const struct af_alg_type *type = ask->type;
 	u8 *key;
 	int err;
 
+	if (!setkey)
+		return -ENOPROTOOPT;
+
 	key = sock_kmalloc(sk, keylen, GFP_KERNEL);
 	if (!key)
 		return -ENOMEM;
@@ -217,7 +221,7 @@ static int alg_setkey(struct sock *sk, char __user *ukey,
 	if (copy_from_user(key, ukey, keylen))
 		goto out;
 
-	err = type->setkey(ask->private, key, keylen);
+	err = setkey(ask->private, key, keylen);
 
 out:
 	sock_kzfree_s(sk, key, keylen);
@@ -247,10 +251,14 @@ static int alg_setsockopt(struct socket *sock, int level, int optname,
 	case ALG_SET_KEY:
 		if (sock->state == SS_CONNECTED)
 			goto unlock;
-		if (!type->setkey)
+
+		err = alg_setkey(sk, optval, optlen, type->setkey);
+		break;
+	case ALG_SET_PUBKEY:
+		if (sock->state == SS_CONNECTED)
 			goto unlock;
 
-		err = alg_setkey(sk, optval, optlen);
+		err = alg_setkey(sk, optval, optlen, type->setpubkey);
 		break;
 	case ALG_SET_AEAD_AUTHSIZE:
 		if (sock->state == SS_CONNECTED)
diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h
index a2bfd78..6c3e6e7 100644
--- a/include/crypto/if_alg.h
+++ b/include/crypto/if_alg.h
@@ -52,6 +52,7 @@ struct af_alg_type {
 	void *(*bind)(const char *name, u32 type, u32 mask);
 	void (*release)(void *private);
 	int (*setkey)(void *private, const u8 *key, unsigned int keylen);
+	int (*setpubkey)(void *private, const u8 *key, unsigned int keylen);
 	int (*accept)(void *private, struct sock *sk);
 	int (*accept_nokey)(void *private, struct sock *sk);
 	int (*setauthsize)(void *private, unsigned int authsize);

^ permalink raw reply related

* [PATCH RESEND v5 1/6] crypto: AF_ALG -- add sign/verify API
From: Tadeusz Struk @ 2016-05-05 19:50 UTC (permalink / raw)
  To: dhowells
  Cc: herbert, tadeusz.struk, smueller, linux-api, marcel, linux-kernel,
	keyrings, linux-crypto, dwmw2, davem
In-Reply-To: <20160505195048.1843.7817.stgit@tstruk-mobl1>

From: Stephan Mueller <smueller@chronox.de>

Add the flags for handling signature generation and signature
verification.

Also, the patch adds the interface for setting a public key.

Signed-off-by: Stephan Mueller <smueller@chronox.de>
Signed-off-by: Tadeusz Struk <tadeusz.struk@intel.com>
---
 include/uapi/linux/if_alg.h |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/include/uapi/linux/if_alg.h b/include/uapi/linux/if_alg.h
index f2acd2f..02e6162 100644
--- a/include/uapi/linux/if_alg.h
+++ b/include/uapi/linux/if_alg.h
@@ -34,9 +34,12 @@ struct af_alg_iv {
 #define ALG_SET_OP			3
 #define ALG_SET_AEAD_ASSOCLEN		4
 #define ALG_SET_AEAD_AUTHSIZE		5
+#define ALG_SET_PUBKEY			6
 
 /* Operations */
 #define ALG_OP_DECRYPT			0
 #define ALG_OP_ENCRYPT			1
+#define ALG_OP_SIGN			2
+#define ALG_OP_VERIFY			3
 
 #endif	/* _LINUX_IF_ALG_H */

^ permalink raw reply related

* [PATCH RESEND v5 0/6] crypto: algif - add akcipher
From: Tadeusz Struk @ 2016-05-05 19:50 UTC (permalink / raw)
  To: dhowells-H+wXaHxf7aLQT0dZR+AlfA
  Cc: herbert-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q,
	tadeusz.struk-ral2JQCrhuEAvxtiuMwx3w,
	smueller-T9tCv8IpfcWELgA04lAiVw, linux-api-u79uwXL29TY76Z2rM5mHXA,
	marcel-kz+m5ild9QBg9hUCZPvPmw,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	keyrings-u79uwXL29TY76Z2rM5mHXA,
	linux-crypto-u79uwXL29TY76Z2rM5mHXA, dwmw2-wEGCiKHe2LqWVfeAwA7xHQ,
	davem-fT/PcQaiUtIeIZ0/mPfg9Q

First four patches are a resend of the v3 algif_akcipher from
Stephan Mueller, with minor changes after rebase on top of 4.6-rc1.

The next three patches add support for keys stored in system
keyring subsystem.

First patch adds algif_akcipher nokey hadlers.

Second patch adds generic sign, verify, encrypt, decrypt accessors
functions to the asymmetric key type. These will be defined by
asymmetric subtypes, similarly to how public_key currently defines
the verify_signature function.

Third patch adds support for ALG_SET_KEY_ID and ALG_SET_PUBKEY_ID
commands to AF_ALG and setkeyid operation to the af_alg_type struct.
If the keyid is used then the afalg layer acquires the key for the
keyring subsystem and uses the new asymmetric accessor functions
instead of akcipher api. The asymmetric subtypes can use akcipher
api internally.

This is the same v5 version as before rebased on top of
http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=keys-asym-keyctl

v5 changes:
- drop public key changes and use new version provided by David

v4 changes:
- don't use internal public_key struct in af_alg.
- add generic accessor functions to asymmetric key type, which take
  the generic struct key type and resolve the specific subtype internally

v3 changes:
- include Stephan's patches (rebased on 4.6-rc1)
- add algif_akcipher nokey hadlers
- add public_key info struct to public_key and helper query functions
- add a check if a key is a software accessible key on af_alg, and
  return -ENOKEY if it isn't

v2 changes:
- pass the original skcipher request in ablkcipher.base.data instead of
  casting it back from the ablkcipher request.
- rename _req to base_req
- dropped 3/3

---

Stephan Mueller (4):
      crypto: AF_ALG -- add sign/verify API
      crypto: AF_ALG -- add setpubkey setsockopt call
      crypto: AF_ALG -- add asymmetric cipher interface
      crypto: algif_akcipher - enable compilation

Tadeusz Struk (2):
      crypto: algif_akcipher - add ops_nokey
      crypto: AF_ALG - add support for key_id

 crypto/Kconfig              |    9 
 crypto/Makefile             |    1 
 crypto/af_alg.c             |   28 +
 crypto/algif_akcipher.c     |  884 +++++++++++++++++++++++++++++++++++++++++++
 include/crypto/if_alg.h     |    2 
 include/uapi/linux/if_alg.h |    5 
 6 files changed, 924 insertions(+), 5 deletions(-)
 create mode 100644 crypto/algif_akcipher.c

--
TS

^ permalink raw reply

* Re: UB in general ... and linux/bitops.h in particular
From: Andi Kleen @ 2016-05-05 17:32 UTC (permalink / raw)
  To: John Denker
  Cc: H. Peter Anvin, noloader, Theodore Ts'o, linux-kernel,
	Stephan Mueller, Herbert Xu, Andi Kleen, Sandy Harris,
	cryptography, linux-crypto
In-Reply-To: <572B71A7.1020100@av8n.com>

> Suggestions:
> 
>  a) Going forward, I suggest that UB should not be invoked
>   unless there is a good solid reason.

Good luck rewriting most of the kernel source.

This discussion is insane!

-Andi

^ permalink raw reply

* Re: [PATCH v2 3/8] arm64: add io{read,write}64be accessors
From: Catalin Marinas @ 2016-05-05 17:25 UTC (permalink / raw)
  To: Horia Geantă
  Cc: Herbert Xu, Will Deacon, linux-arm-kernel, linux-kernel,
	Cristian Stoica, Scott Wood, linux-crypto, Tudor Ambarus,
	David S. Miller, Alexandru Porosanu
In-Reply-To: <1462462564-27731-1-git-send-email-horia.geanta@nxp.com>

On Thu, May 05, 2016 at 06:36:04PM +0300, Horia Geantă wrote:
> This will allow device drivers to consistently use io{read,write}XXbe
> also for 64-bit accesses.
> 
> Signed-off-by: Alex Porosanu <alexandru.porosanu@nxp.com>
> Signed-off-by: Horia Geantă <horia.geanta@nxp.com>

Acked-by: Catalin Marinas <catalin.marinas@arm.com>

^ permalink raw reply

* Re: [PATCH v2 2/8] asm-generic/io.h: add io{read,write}64 accessors
From: Arnd Bergmann @ 2016-05-05 16:29 UTC (permalink / raw)
  To: Horia Geantă
  Cc: Herbert Xu, linux-crypto, linux-arch, linux-kernel,
	David S. Miller, Scott Wood, Alexandru Porosanu, Tudor Ambarus,
	Cristian Stoica
In-Reply-To: <1462462556-27684-1-git-send-email-horia.geanta@nxp.com>

On Thursday 05 May 2016 18:35:56 Horia Geantă wrote:
> This will allow device drivers to consistently use io{read,write}XX
> also for 64-bit accesses.
> 
> Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
> 

Acked-by: Arnd Bergmann <arnd@arndb.de>

^ permalink raw reply

* Re: [crypto / sparc64] cryptomgr_test OOPS
From: Tadeusz Struk @ 2016-05-05 16:17 UTC (permalink / raw)
  To: Herbert Xu, Anatoly Pugachev
  Cc: David Miller, linux-crypto, sparclinux, Nicolai Stange
In-Reply-To: <20160505095020.GA5473@gondor.apana.org.au>

On 05/05/2016 02:50 AM, Herbert Xu wrote:
> On Thu, May 05, 2016 at 12:40:18PM +0300, Anatoly Pugachev wrote:
>>
>> sure, based on your cryptodev git, just tried 4.3 (6a13feb , good)
>> kernel in attempt to find (bisect) when RSA code break, already tested
>> 4.5 (44d1b6d , bad) , 4.4 (afd2ff9 , bad).
>> Going to try your patch soon (when I'm back home).
>> So far 4.3 passes RSA stage without OOPS, but for other reason does
>> not boot to login prompt. Boot log exempt (4.3), this is with
>> CONFIG_CRYPTO_RSA=y :
> 
> That jibes with this being a problem with the SG list since it
> was only added in 4.4.

Before 4.4 the rsa sw implementation kmalloced intermediate flat buffer
and copied the data internally.
Thanks,
-- 
TS

^ permalink raw reply

* Re: UB in general ... and linux/bitops.h in particular
From: John Denker @ 2016-05-05 16:15 UTC (permalink / raw)
  To: H. Peter Anvin, noloader, Theodore Ts'o, linux-kernel,
	Stephan Mueller, Herbert Xu, Andi Kleen, Sandy Harris,
	cryptography, linux-crypto
In-Reply-To: <572AE9A2.20609@zytor.com>

On 05/04/2016 11:35 PM, H. Peter Anvin wrote:

> The disagreement here is the priority between these points. 

Yes.

As usual, all the extremes are wrong.
Tradeoffs must be made.
Perspective and judgment are required.

> In my very strong opinion, "no undefined behavior" per the C standard
> is way less important than the others; what matters is what gcc and
> the other compilers we care about do.

But we don't control what the compilers do.  The gcc guys have
a track record of assuming that UB gives them a license to do
whatever they want.  At any moment they can change their mind
and do something new.

> The kernel relies on various versions of C-standard-undefined
> behavior *all over the place*;>

One should be careful with that argument.  Not all types of UB 
are created equal.  There is a world of difference between
  -- UB_type_1 used "all over the place" by necessity, and
  -- UB_type_2 used here-and-there for convenience.

UB_type_1 defines a de_facto dialect of the language.

Ideally there would be a formal specification of the dialect,
but that's not super-urgent, because the compiler guys are
probably not crazy enough to break something if it really is 
used "all over the place".

Formalized or not, UB_type_1 does not make it OK for programmers
to invoke *other* types of UB.  I'll say it again: the gcc guys
have a track record of assuming UB gives them a license to do 
whatever they want.  The results can be very counterintuitive.

UB is a nightmare from the point of view of reliability,
security, and maintainability.  The fact that your favorite
compiler does what you want as of today is *not* a guarantee
that it will do so in the future.

===========

As for the suggestion that the UB code is somehow more
efficient or in any way better, I'm not buying it.

Using gcc 5.2.1 I observe that [1] and [2] (given below)
generate the exact same code at any optimization level
from -O1 on up. My kernel is compiled with -O2.

(They generate different code with -O0 but that doesn't
seem like an important consideration.)

The relevant code is
   (word >> shift) | (word >> ((-shift) & 31));  /* [1] */
   (word >> shift) | (word << (32 - shift));     /* [2] */

> for one thing sizeof(void *) == sizeof(size_t) == sizeof(unsigned long)!!

I assume that comes up in the context of type punning.  I
am not a language lawyer, but it is my understanding that
type punning *is* permitted by the C language specification.
(C++ is another story entirely, but not relevant here.)

There is a world of difference between
 -- loosely specified options (LSO), and
 -- undefined behavior (UB)

The sizeof() example is LSO not UB.  One could easily check
the sizes at compile time, so that no looseness remains.
The result is perfectly reasonable, efficient, reliable code.

Similarly, the kernel assumes two's complement arithmetic
"all over the place" but this is LSO not UB.

This is relevant to linux/bitops.h because [2] is UB when
shift==0.  In contrast [1] is a very mild example of LSO
because it assumes two's complement.

I consider it a step in the right direction to get rid of UB
when it can be done at zero cost.  UB is dangerous.

==========================

Suggestions:

 a) Going forward, I suggest that UB should not be invoked
  unless there is a good solid reason.

 b) In cases where a this-or-that UB really is needed, it
  should be carefully documented.

   -- Perhaps there could be a file linux_kernel_dialect.c 
    that gives examples of all the constructs that the kernel
    needs but are not in the basic C specification.  One would
    hope this would be very, very short.

   -- Perhaps the compiler guys could be persuaded to support
    the needed features explicitly, perhaps via a command-line
    option: -std=vanilla
    This should be a no-cost option as things stand today, but
    it helps to prevent nasty surprises in the future.

^ permalink raw reply

* Re: [crypto / sparc64] cryptomgr_test OOPS
From: Tadeusz Struk @ 2016-05-05 16:09 UTC (permalink / raw)
  To: Anatoly Pugachev
  Cc: Herbert Xu, David Miller, linux-crypto, sparclinux,
	Nicolai Stange
In-Reply-To: <CADxRZqzyZgG=e-6aPcHrEopq51nqoU0NqdMnRcCUWkw39XB56A@mail.gmail.com>

On 05/05/2016 08:31 AM, Anatoly Pugachev wrote:
> On Thu, May 5, 2016 at 6:00 PM, Tadeusz Struk <tadeusz.struk@intel.com> wrote:
>> On 05/05/2016 02:40 AM, Anatoly Pugachev wrote:
>>> sure, based on your cryptodev git, just tried 4.3 (6a13feb , good)
>>> kernel in attempt to find (bisect) when RSA code break, already tested
>>> 4.5 (44d1b6d , bad) , 4.4 (afd2ff9 , bad).
>>> Going to try your patch soon (when I'm back home).
>>> So far 4.3 passes RSA stage without OOPS, but for other reason does
>>> not boot to login prompt. Boot log exempt (4.3), this is with
>>> CONFIG_CRYPTO_RSA=y :
>>
>> Anatoly, could you also give this a try please:
>> Thanks
>>
>> diff --git a/crypto/testmgr.c b/crypto/testmgr.c
>> index b86883a..770970ff 100644
>> --- a/crypto/testmgr.c
>> +++ b/crypto/testmgr.c
>> @@ -1805,8 +1805,8 @@ static int do_test_rsa(struct crypto_akcipher *tfm,
>>                 goto free_req;
>>
>>         sg_init_table(src_tab, 2);
>> -       sg_set_buf(&src_tab[0], vecs->m, 8);
>> -       sg_set_buf(&src_tab[1], vecs->m + 8, vecs->m_size - 8);
>> +       sg_set_buf(&src_tab[0], vecs->m, 4);
>> +       sg_set_buf(&src_tab[1], vecs->m + 4, vecs->m_size - 4);
>>         sg_init_one(&dst, outbuf_enc, out_len_max);
>>         akcipher_request_set_crypt(req, src_tab, &dst, vecs->m_size,
>>                                    out_len_max);
> 
> 
> Tadeusz,
> 
> do you still want to test it , after I have reported that Herbert patch works?
> 

Hi Anatoly,
Since Herbert's patch fixes it for you here is no need to test this one.
Thanks,
-- 
TS

^ permalink raw reply

* [PATCH v2 6/8] crypto: caam - handle core endianness != caam endianness
From: Horia Geantă @ 2016-05-05 15:36 UTC (permalink / raw)
  To: Herbert Xu
  Cc: linux-crypto, linux-kernel, David S. Miller, Scott Wood,
	Alexandru Porosanu, Tudor Ambarus, Cristian Stoica, Fabio Estevam,
	Steve Cornelius
In-Reply-To: <1462462435-27403-1-git-send-email-horia.geanta@nxp.com>

There are SoCs like LS1043A where CAAM endianness (BE) does not match
the default endianness of the core (LE).
Moreover, there are requirements for the driver to handle cases like
CPU_BIG_ENDIAN=y on ARM-based SoCs.
This requires for a complete rewrite of the I/O accessors.

PPC-specific accessors - {in,out}_{le,be}XX - are replaced with
generic ones - io{read,write}[be]XX.

Endianness is detected dynamically (at runtime) to allow for
multiplatform kernels, for e.g. running the same kernel image
on LS1043A (BE CAAM) and LS2080A (LE CAAM) armv8-based SoCs.

While here: debugfs entries need to take into consideration the
endianness of the core when displaying data. Add the necessary
glue code so the entries remain the same, but they are properly
read, regardless of the core and/or SEC endianness.

Note: pdb.h fixes only what is currently being used (IPsec).

Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
Signed-off-by: Alex Porosanu <alexandru.porosanu@nxp.com>
---
 drivers/crypto/caam/Kconfig       |   4 -
 drivers/crypto/caam/caamhash.c    |   5 +-
 drivers/crypto/caam/ctrl.c        | 125 +++++++++++++++++++------------
 drivers/crypto/caam/desc.h        |   7 +-
 drivers/crypto/caam/desc_constr.h |  44 +++++++----
 drivers/crypto/caam/jr.c          |  22 +++---
 drivers/crypto/caam/pdb.h         | 137 ++++++++++++++++++++++++++--------
 drivers/crypto/caam/regs.h        | 151 +++++++++++++++++++++++++-------------
 drivers/crypto/caam/sg_sw_sec4.h  |  11 +--
 9 files changed, 340 insertions(+), 166 deletions(-)

diff --git a/drivers/crypto/caam/Kconfig b/drivers/crypto/caam/Kconfig
index 5652a53415dc..d2c2909a4020 100644
--- a/drivers/crypto/caam/Kconfig
+++ b/drivers/crypto/caam/Kconfig
@@ -116,10 +116,6 @@ config CRYPTO_DEV_FSL_CAAM_IMX
 	def_bool SOC_IMX6 || SOC_IMX7D
 	depends on CRYPTO_DEV_FSL_CAAM
 
-config CRYPTO_DEV_FSL_CAAM_LE
-	def_bool CRYPTO_DEV_FSL_CAAM_IMX || SOC_LS1021A
-	depends on CRYPTO_DEV_FSL_CAAM
-
 config CRYPTO_DEV_FSL_CAAM_DEBUG
 	bool "Enable debug output in CAAM driver"
 	depends on CRYPTO_DEV_FSL_CAAM
diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c
index 5845d4a08797..f1ecc8df8d41 100644
--- a/drivers/crypto/caam/caamhash.c
+++ b/drivers/crypto/caam/caamhash.c
@@ -847,7 +847,7 @@ static int ahash_update_ctx(struct ahash_request *req)
 							 *next_buflen, 0);
 		} else {
 			(edesc->sec4_sg + sec4_sg_src_index - 1)->len |=
-							SEC4_SG_LEN_FIN;
+				cpu_to_caam32(SEC4_SG_LEN_FIN);
 		}
 
 		state->current_buf = !state->current_buf;
@@ -949,7 +949,8 @@ static int ahash_final_ctx(struct ahash_request *req)
 	state->buf_dma = try_buf_map_to_sec4_sg(jrdev, edesc->sec4_sg + 1,
 						buf, state->buf_dma, buflen,
 						last_buflen);
-	(edesc->sec4_sg + sec4_sg_src_index - 1)->len |= SEC4_SG_LEN_FIN;
+	(edesc->sec4_sg + sec4_sg_src_index - 1)->len |=
+		cpu_to_caam32(SEC4_SG_LEN_FIN);
 
 	edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg,
 					    sec4_sg_bytes, DMA_TO_DEVICE);
diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c
index 44d30b45f3cc..1c8e764872ae 100644
--- a/drivers/crypto/caam/ctrl.c
+++ b/drivers/crypto/caam/ctrl.c
@@ -15,6 +15,9 @@
 #include "desc_constr.h"
 #include "error.h"
 
+bool caam_little_end;
+EXPORT_SYMBOL(caam_little_end);
+
 /*
  * i.MX targets tend to have clock control subsystems that can
  * enable/disable clocking to our device.
@@ -106,7 +109,7 @@ static inline int run_descriptor_deco0(struct device *ctrldev, u32 *desc,
 
 
 	if (ctrlpriv->virt_en == 1) {
-		setbits32(&ctrl->deco_rsr, DECORSR_JR0);
+		clrsetbits_32(&ctrl->deco_rsr, 0, DECORSR_JR0);
 
 		while (!(rd_reg32(&ctrl->deco_rsr) & DECORSR_VALID) &&
 		       --timeout)
@@ -115,7 +118,7 @@ static inline int run_descriptor_deco0(struct device *ctrldev, u32 *desc,
 		timeout = 100000;
 	}
 
-	setbits32(&ctrl->deco_rq, DECORR_RQD0ENABLE);
+	clrsetbits_32(&ctrl->deco_rq, 0, DECORR_RQD0ENABLE);
 
 	while (!(rd_reg32(&ctrl->deco_rq) & DECORR_DEN0) &&
 								 --timeout)
@@ -123,12 +126,12 @@ static inline int run_descriptor_deco0(struct device *ctrldev, u32 *desc,
 
 	if (!timeout) {
 		dev_err(ctrldev, "failed to acquire DECO 0\n");
-		clrbits32(&ctrl->deco_rq, DECORR_RQD0ENABLE);
+		clrsetbits_32(&ctrl->deco_rq, DECORR_RQD0ENABLE, 0);
 		return -ENODEV;
 	}
 
 	for (i = 0; i < desc_len(desc); i++)
-		wr_reg32(&deco->descbuf[i], *(desc + i));
+		wr_reg32(&deco->descbuf[i], caam32_to_cpu(*(desc + i)));
 
 	flags = DECO_JQCR_WHL;
 	/*
@@ -139,7 +142,7 @@ static inline int run_descriptor_deco0(struct device *ctrldev, u32 *desc,
 		flags |= DECO_JQCR_FOUR;
 
 	/* Instruct the DECO to execute it */
-	setbits32(&deco->jr_ctl_hi, flags);
+	clrsetbits_32(&deco->jr_ctl_hi, 0, flags);
 
 	timeout = 10000000;
 	do {
@@ -158,10 +161,10 @@ static inline int run_descriptor_deco0(struct device *ctrldev, u32 *desc,
 		  DECO_OP_STATUS_HI_ERR_MASK;
 
 	if (ctrlpriv->virt_en == 1)
-		clrbits32(&ctrl->deco_rsr, DECORSR_JR0);
+		clrsetbits_32(&ctrl->deco_rsr, DECORSR_JR0, 0);
 
 	/* Mark the DECO as free */
-	clrbits32(&ctrl->deco_rq, DECORR_RQD0ENABLE);
+	clrsetbits_32(&ctrl->deco_rq, DECORR_RQD0ENABLE, 0);
 
 	if (!timeout)
 		return -EAGAIN;
@@ -349,7 +352,7 @@ static void kick_trng(struct platform_device *pdev, int ent_delay)
 	r4tst = &ctrl->r4tst[0];
 
 	/* put RNG4 into program mode */
-	setbits32(&r4tst->rtmctl, RTMCTL_PRGM);
+	clrsetbits_32(&r4tst->rtmctl, 0, RTMCTL_PRGM);
 
 	/*
 	 * Performance-wise, it does not make sense to
@@ -363,7 +366,7 @@ static void kick_trng(struct platform_device *pdev, int ent_delay)
 	      >> RTSDCTL_ENT_DLY_SHIFT;
 	if (ent_delay <= val) {
 		/* put RNG4 into run mode */
-		clrbits32(&r4tst->rtmctl, RTMCTL_PRGM);
+		clrsetbits_32(&r4tst->rtmctl, RTMCTL_PRGM, 0);
 		return;
 	}
 
@@ -381,9 +384,9 @@ static void kick_trng(struct platform_device *pdev, int ent_delay)
 	 * select raw sampling in both entropy shifter
 	 * and statistical checker
 	 */
-	setbits32(&val, RTMCTL_SAMP_MODE_RAW_ES_SC);
+	clrsetbits_32(&val, 0, RTMCTL_SAMP_MODE_RAW_ES_SC);
 	/* put RNG4 into run mode */
-	clrbits32(&val, RTMCTL_PRGM);
+	clrsetbits_32(&val, RTMCTL_PRGM, 0);
 	/* write back the control register */
 	wr_reg32(&r4tst->rtmctl, val);
 }
@@ -406,6 +409,23 @@ int caam_get_era(void)
 }
 EXPORT_SYMBOL(caam_get_era);
 
+#ifdef CONFIG_DEBUG_FS
+static int caam_debugfs_u64_get(void *data, u64 *val)
+{
+	*val = caam64_to_cpu(*(u64 *)data);
+	return 0;
+}
+
+static int caam_debugfs_u32_get(void *data, u64 *val)
+{
+	*val = caam32_to_cpu(*(u32 *)data);
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(caam_fops_u32_ro, caam_debugfs_u32_get, NULL, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(caam_fops_u64_ro, caam_debugfs_u64_get, NULL, "%llu\n");
+#endif
+
 /* Probe routine for CAAM top (controller) level */
 static int caam_probe(struct platform_device *pdev)
 {
@@ -504,6 +524,10 @@ static int caam_probe(struct platform_device *pdev)
 		ret = -ENOMEM;
 		goto disable_caam_emi_slow;
 	}
+
+	caam_little_end = !(bool)(rd_reg32(&ctrl->perfmon.status) &
+				  (CSTA_PLEND | CSTA_ALT_PLEND));
+
 	/* Finding the page size for using the CTPR_MS register */
 	comp_params = rd_reg32(&ctrl->perfmon.comp_parms_ms);
 	pg_size = (comp_params & CTPR_MS_PG_SZ_MASK) >> CTPR_MS_PG_SZ_SHIFT;
@@ -559,9 +583,9 @@ static int caam_probe(struct platform_device *pdev)
 	}
 
 	if (ctrlpriv->virt_en == 1)
-		setbits32(&ctrl->jrstart, JRSTART_JR0_START |
-			  JRSTART_JR1_START | JRSTART_JR2_START |
-			  JRSTART_JR3_START);
+		clrsetbits_32(&ctrl->jrstart, 0, JRSTART_JR0_START |
+			      JRSTART_JR1_START | JRSTART_JR2_START |
+			      JRSTART_JR3_START);
 
 	if (sizeof(dma_addr_t) == sizeof(u64))
 		if (of_device_is_compatible(nprop, "fsl,sec-v5.0"))
@@ -693,7 +717,7 @@ static int caam_probe(struct platform_device *pdev)
 		ctrlpriv->rng4_sh_init = ~ctrlpriv->rng4_sh_init & RDSTA_IFMASK;
 
 		/* Enable RDB bit so that RNG works faster */
-		setbits32(&ctrl->scfgr, SCFGR_RDBENABLE);
+		clrsetbits_32(&ctrl->scfgr, 0, SCFGR_RDBENABLE);
 	}
 
 	/* NOTE: RTIC detection ought to go here, around Si time */
@@ -719,48 +743,59 @@ static int caam_probe(struct platform_device *pdev)
 	ctrlpriv->ctl = debugfs_create_dir("ctl", ctrlpriv->dfs_root);
 
 	/* Controller-level - performance monitor counters */
+
 	ctrlpriv->ctl_rq_dequeued =
-		debugfs_create_u64("rq_dequeued",
-				   S_IRUSR | S_IRGRP | S_IROTH,
-				   ctrlpriv->ctl, &perfmon->req_dequeued);
+		debugfs_create_file("rq_dequeued",
+				    S_IRUSR | S_IRGRP | S_IROTH,
+				    ctrlpriv->ctl, &perfmon->req_dequeued,
+				    &caam_fops_u64_ro);
 	ctrlpriv->ctl_ob_enc_req =
-		debugfs_create_u64("ob_rq_encrypted",
-				   S_IRUSR | S_IRGRP | S_IROTH,
-				   ctrlpriv->ctl, &perfmon->ob_enc_req);
+		debugfs_create_file("ob_rq_encrypted",
+				    S_IRUSR | S_IRGRP | S_IROTH,
+				    ctrlpriv->ctl, &perfmon->ob_enc_req,
+				    &caam_fops_u64_ro);
 	ctrlpriv->ctl_ib_dec_req =
-		debugfs_create_u64("ib_rq_decrypted",
-				   S_IRUSR | S_IRGRP | S_IROTH,
-				   ctrlpriv->ctl, &perfmon->ib_dec_req);
+		debugfs_create_file("ib_rq_decrypted",
+				    S_IRUSR | S_IRGRP | S_IROTH,
+				    ctrlpriv->ctl, &perfmon->ib_dec_req,
+				    &caam_fops_u64_ro);
 	ctrlpriv->ctl_ob_enc_bytes =
-		debugfs_create_u64("ob_bytes_encrypted",
-				   S_IRUSR | S_IRGRP | S_IROTH,
-				   ctrlpriv->ctl, &perfmon->ob_enc_bytes);
+		debugfs_create_file("ob_bytes_encrypted",
+				    S_IRUSR | S_IRGRP | S_IROTH,
+				    ctrlpriv->ctl, &perfmon->ob_enc_bytes,
+				    &caam_fops_u64_ro);
 	ctrlpriv->ctl_ob_prot_bytes =
-		debugfs_create_u64("ob_bytes_protected",
-				   S_IRUSR | S_IRGRP | S_IROTH,
-				   ctrlpriv->ctl, &perfmon->ob_prot_bytes);
+		debugfs_create_file("ob_bytes_protected",
+				    S_IRUSR | S_IRGRP | S_IROTH,
+				    ctrlpriv->ctl, &perfmon->ob_prot_bytes,
+				    &caam_fops_u64_ro);
 	ctrlpriv->ctl_ib_dec_bytes =
-		debugfs_create_u64("ib_bytes_decrypted",
-				   S_IRUSR | S_IRGRP | S_IROTH,
-				   ctrlpriv->ctl, &perfmon->ib_dec_bytes);
+		debugfs_create_file("ib_bytes_decrypted",
+				    S_IRUSR | S_IRGRP | S_IROTH,
+				    ctrlpriv->ctl, &perfmon->ib_dec_bytes,
+				    &caam_fops_u64_ro);
 	ctrlpriv->ctl_ib_valid_bytes =
-		debugfs_create_u64("ib_bytes_validated",
-				   S_IRUSR | S_IRGRP | S_IROTH,
-				   ctrlpriv->ctl, &perfmon->ib_valid_bytes);
+		debugfs_create_file("ib_bytes_validated",
+				    S_IRUSR | S_IRGRP | S_IROTH,
+				    ctrlpriv->ctl, &perfmon->ib_valid_bytes,
+				    &caam_fops_u64_ro);
 
 	/* Controller level - global status values */
 	ctrlpriv->ctl_faultaddr =
-		debugfs_create_u64("fault_addr",
-				   S_IRUSR | S_IRGRP | S_IROTH,
-				   ctrlpriv->ctl, &perfmon->faultaddr);
+		debugfs_create_file("fault_addr",
+				    S_IRUSR | S_IRGRP | S_IROTH,
+				    ctrlpriv->ctl, &perfmon->faultaddr,
+				    &caam_fops_u32_ro);
 	ctrlpriv->ctl_faultdetail =
-		debugfs_create_u32("fault_detail",
-				   S_IRUSR | S_IRGRP | S_IROTH,
-				   ctrlpriv->ctl, &perfmon->faultdetail);
+		debugfs_create_file("fault_detail",
+				    S_IRUSR | S_IRGRP | S_IROTH,
+				    ctrlpriv->ctl, &perfmon->faultdetail,
+				    &caam_fops_u32_ro);
 	ctrlpriv->ctl_faultstatus =
-		debugfs_create_u32("fault_status",
-				   S_IRUSR | S_IRGRP | S_IROTH,
-				   ctrlpriv->ctl, &perfmon->status);
+		debugfs_create_file("fault_status",
+				    S_IRUSR | S_IRGRP | S_IROTH,
+				    ctrlpriv->ctl, &perfmon->status,
+				    &caam_fops_u32_ro);
 
 	/* Internal covering keys (useful in non-secure mode only) */
 	ctrlpriv->ctl_kek_wrap.data = &ctrlpriv->ctrl->kek[0];
diff --git a/drivers/crypto/caam/desc.h b/drivers/crypto/caam/desc.h
index fe30ff69088c..d8d5584b600b 100644
--- a/drivers/crypto/caam/desc.h
+++ b/drivers/crypto/caam/desc.h
@@ -23,16 +23,15 @@
 #define SEC4_SG_OFFSET_MASK	0x00001fff
 
 struct sec4_sg_entry {
-#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_IMX
+#if !defined(CONFIG_ARCH_DMA_ADDR_T_64BIT) && \
+	defined(CONFIG_CRYPTO_DEV_FSL_CAAM_IMX)
 	u32 rsvd1;
 	dma_addr_t ptr;
 #else
 	u64 ptr;
 #endif /* CONFIG_CRYPTO_DEV_FSL_CAAM_IMX */
 	u32 len;
-	u8 rsvd2;
-	u8 buf_pool_id;
-	u16 offset;
+	u32 bpid_offset;
 };
 
 /* Max size of any CAAM descriptor in 32-bit words, inclusive of header */
diff --git a/drivers/crypto/caam/desc_constr.h b/drivers/crypto/caam/desc_constr.h
index 98d07de24fc4..ae3aef6e9fee 100644
--- a/drivers/crypto/caam/desc_constr.h
+++ b/drivers/crypto/caam/desc_constr.h
@@ -5,6 +5,7 @@
  */
 
 #include "desc.h"
+#include "regs.h"
 
 #define IMMEDIATE (1 << 23)
 #define CAAM_CMD_SZ sizeof(u32)
@@ -30,9 +31,11 @@
 			       LDST_SRCDST_WORD_DECOCTRL | \
 			       (LDOFF_ENABLE_AUTO_NFIFO << LDST_OFFSET_SHIFT))
 
+extern bool caam_little_end;
+
 static inline int desc_len(u32 *desc)
 {
-	return *desc & HDR_DESCLEN_MASK;
+	return caam32_to_cpu(*desc) & HDR_DESCLEN_MASK;
 }
 
 static inline int desc_bytes(void *desc)
@@ -52,7 +55,7 @@ static inline void *sh_desc_pdb(u32 *desc)
 
 static inline void init_desc(u32 *desc, u32 options)
 {
-	*desc = (options | HDR_ONE) + 1;
+	*desc = cpu_to_caam32((options | HDR_ONE) + 1);
 }
 
 static inline void init_sh_desc(u32 *desc, u32 options)
@@ -78,9 +81,10 @@ static inline void append_ptr(u32 *desc, dma_addr_t ptr)
 {
 	dma_addr_t *offset = (dma_addr_t *)desc_end(desc);
 
-	*offset = ptr;
+	*offset = cpu_to_caam_dma(ptr);
 
-	(*desc) += CAAM_PTR_SZ / CAAM_CMD_SZ;
+	(*desc) = cpu_to_caam32(caam32_to_cpu(*desc) +
+				CAAM_PTR_SZ / CAAM_CMD_SZ);
 }
 
 static inline void init_job_desc_shared(u32 *desc, dma_addr_t ptr, int len,
@@ -99,16 +103,17 @@ static inline void append_data(u32 *desc, void *data, int len)
 	if (len) /* avoid sparse warning: memcpy with byte count of 0 */
 		memcpy(offset, data, len);
 
-	(*desc) += (len + CAAM_CMD_SZ - 1) / CAAM_CMD_SZ;
+	(*desc) = cpu_to_caam32(caam32_to_cpu(*desc) +
+				(len + CAAM_CMD_SZ - 1) / CAAM_CMD_SZ);
 }
 
 static inline void append_cmd(u32 *desc, u32 command)
 {
 	u32 *cmd = desc_end(desc);
 
-	*cmd = command;
+	*cmd = cpu_to_caam32(command);
 
-	(*desc)++;
+	(*desc) = cpu_to_caam32(caam32_to_cpu(*desc) + 1);
 }
 
 #define append_u32 append_cmd
@@ -117,16 +122,22 @@ static inline void append_u64(u32 *desc, u64 data)
 {
 	u32 *offset = desc_end(desc);
 
-	*offset = upper_32_bits(data);
-	*(++offset) = lower_32_bits(data);
+	/* Only 32-bit alignment is guaranteed in descriptor buffer */
+	if (caam_little_end) {
+		*offset = cpu_to_caam32(lower_32_bits(data));
+		*(++offset) = cpu_to_caam32(upper_32_bits(data));
+	} else {
+		*offset = cpu_to_caam32(upper_32_bits(data));
+		*(++offset) = cpu_to_caam32(lower_32_bits(data));
+	}
 
-	(*desc) += 2;
+	(*desc) = cpu_to_caam32(caam32_to_cpu(*desc) + 2);
 }
 
 /* Write command without affecting header, and return pointer to next word */
 static inline u32 *write_cmd(u32 *desc, u32 command)
 {
-	*desc = command;
+	*desc = cpu_to_caam32(command);
 
 	return desc + 1;
 }
@@ -168,14 +179,17 @@ APPEND_CMD_RET(move, MOVE)
 
 static inline void set_jump_tgt_here(u32 *desc, u32 *jump_cmd)
 {
-	*jump_cmd = *jump_cmd | (desc_len(desc) - (jump_cmd - desc));
+	*jump_cmd = cpu_to_caam32(caam32_to_cpu(*jump_cmd) |
+				  (desc_len(desc) - (jump_cmd - desc)));
 }
 
 static inline void set_move_tgt_here(u32 *desc, u32 *move_cmd)
 {
-	*move_cmd &= ~MOVE_OFFSET_MASK;
-	*move_cmd = *move_cmd | ((desc_len(desc) << (MOVE_OFFSET_SHIFT + 2)) &
-				 MOVE_OFFSET_MASK);
+	u32 val = caam32_to_cpu(*move_cmd);
+
+	val &= ~MOVE_OFFSET_MASK;
+	val |= (desc_len(desc) << (MOVE_OFFSET_SHIFT + 2)) & MOVE_OFFSET_MASK;
+	*move_cmd = cpu_to_caam32(val);
 }
 
 #define APPEND_CMD(cmd, op) \
diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c
index 6fd63a600614..90aaa72ce0d0 100644
--- a/drivers/crypto/caam/jr.c
+++ b/drivers/crypto/caam/jr.c
@@ -31,7 +31,7 @@ static int caam_reset_hw_jr(struct device *dev)
 	 * mask interrupts since we are going to poll
 	 * for reset completion status
 	 */
-	setbits32(&jrp->rregs->rconfig_lo, JRCFG_IMSK);
+	clrsetbits_32(&jrp->rregs->rconfig_lo, 0, JRCFG_IMSK);
 
 	/* initiate flush (required prior to reset) */
 	wr_reg32(&jrp->rregs->jrcommand, JRCR_RESET);
@@ -57,7 +57,7 @@ static int caam_reset_hw_jr(struct device *dev)
 	}
 
 	/* unmask interrupts */
-	clrbits32(&jrp->rregs->rconfig_lo, JRCFG_IMSK);
+	clrsetbits_32(&jrp->rregs->rconfig_lo, JRCFG_IMSK, 0);
 
 	return 0;
 }
@@ -147,7 +147,7 @@ static irqreturn_t caam_jr_interrupt(int irq, void *st_dev)
 	}
 
 	/* mask valid interrupts */
-	setbits32(&jrp->rregs->rconfig_lo, JRCFG_IMSK);
+	clrsetbits_32(&jrp->rregs->rconfig_lo, 0, JRCFG_IMSK);
 
 	/* Have valid interrupt at this point, just ACK and trigger */
 	wr_reg32(&jrp->rregs->jrintstatus, irqstate);
@@ -182,7 +182,7 @@ static void caam_jr_dequeue(unsigned long devarg)
 			sw_idx = (tail + i) & (JOBR_DEPTH - 1);
 
 			if (jrp->outring[hw_idx].desc ==
-			    jrp->entinfo[sw_idx].desc_addr_dma)
+			    caam_dma_to_cpu(jrp->entinfo[sw_idx].desc_addr_dma))
 				break; /* found */
 		}
 		/* we should never fail to find a matching descriptor */
@@ -200,7 +200,7 @@ static void caam_jr_dequeue(unsigned long devarg)
 		usercall = jrp->entinfo[sw_idx].callbk;
 		userarg = jrp->entinfo[sw_idx].cbkarg;
 		userdesc = jrp->entinfo[sw_idx].desc_addr_virt;
-		userstatus = jrp->outring[hw_idx].jrstatus;
+		userstatus = caam32_to_cpu(jrp->outring[hw_idx].jrstatus);
 
 		/*
 		 * Make sure all information from the job has been obtained
@@ -236,7 +236,7 @@ static void caam_jr_dequeue(unsigned long devarg)
 	}
 
 	/* reenable / unmask IRQs */
-	clrbits32(&jrp->rregs->rconfig_lo, JRCFG_IMSK);
+	clrsetbits_32(&jrp->rregs->rconfig_lo, JRCFG_IMSK, 0);
 }
 
 /**
@@ -330,7 +330,7 @@ int caam_jr_enqueue(struct device *dev, u32 *desc,
 	int head, tail, desc_size;
 	dma_addr_t desc_dma;
 
-	desc_size = (*desc & HDR_JD_LENGTH_MASK) * sizeof(u32);
+	desc_size = (caam32_to_cpu(*desc) & HDR_JD_LENGTH_MASK) * sizeof(u32);
 	desc_dma = dma_map_single(dev, desc, desc_size, DMA_TO_DEVICE);
 	if (dma_mapping_error(dev, desc_dma)) {
 		dev_err(dev, "caam_jr_enqueue(): can't map jobdesc\n");
@@ -356,7 +356,7 @@ int caam_jr_enqueue(struct device *dev, u32 *desc,
 	head_entry->cbkarg = areq;
 	head_entry->desc_addr_dma = desc_dma;
 
-	jrp->inpring[jrp->inp_ring_write_index] = desc_dma;
+	jrp->inpring[jrp->inp_ring_write_index] = cpu_to_caam_dma(desc_dma);
 
 	/*
 	 * Guarantee that the descriptor's DMA address has been written to
@@ -444,9 +444,9 @@ static int caam_jr_init(struct device *dev)
 	spin_lock_init(&jrp->outlock);
 
 	/* Select interrupt coalescing parameters */
-	setbits32(&jrp->rregs->rconfig_lo, JOBR_INTC |
-		  (JOBR_INTC_COUNT_THLD << JRCFG_ICDCT_SHIFT) |
-		  (JOBR_INTC_TIME_THLD << JRCFG_ICTT_SHIFT));
+	clrsetbits_32(&jrp->rregs->rconfig_lo, 0, JOBR_INTC |
+		      (JOBR_INTC_COUNT_THLD << JRCFG_ICDCT_SHIFT) |
+		      (JOBR_INTC_TIME_THLD << JRCFG_ICTT_SHIFT));
 
 	return 0;
 
diff --git a/drivers/crypto/caam/pdb.h b/drivers/crypto/caam/pdb.h
index 3a87c0cf879a..fa60c4573131 100644
--- a/drivers/crypto/caam/pdb.h
+++ b/drivers/crypto/caam/pdb.h
@@ -11,8 +11,8 @@
 /*
  * PDB- IPSec ESP Header Modification Options
  */
-#define PDBHMO_ESP_DECAP_SHIFT	12
-#define PDBHMO_ESP_ENCAP_SHIFT	4
+#define PDBHMO_ESP_DECAP_SHIFT	28
+#define PDBHMO_ESP_ENCAP_SHIFT	28
 /*
  * Encap and Decap - Decrement TTL (Hop Limit) - Based on the value of the
  * Options Byte IP version (IPvsn) field:
@@ -32,12 +32,23 @@
  */
 #define PDBHMO_ESP_DFBIT		(0x04 << PDBHMO_ESP_ENCAP_SHIFT)
 
+#define PDBNH_ESP_ENCAP_SHIFT		16
+#define PDBNH_ESP_ENCAP_MASK		(0xff << PDBNH_ESP_ENCAP_SHIFT)
+
+#define PDBHDRLEN_ESP_DECAP_SHIFT	16
+#define PDBHDRLEN_MASK			(0x0fff << PDBHDRLEN_ESP_DECAP_SHIFT)
+
+#define PDB_NH_OFFSET_SHIFT		8
+#define PDB_NH_OFFSET_MASK		(0xff << PDB_NH_OFFSET_SHIFT)
+
 /*
  * PDB - IPSec ESP Encap/Decap Options
  */
 #define PDBOPTS_ESP_ARSNONE	0x00 /* no antireplay window */
 #define PDBOPTS_ESP_ARS32	0x40 /* 32-entry antireplay window */
+#define PDBOPTS_ESP_ARS128	0x80 /* 128-entry antireplay window */
 #define PDBOPTS_ESP_ARS64	0xc0 /* 64-entry antireplay window */
+#define PDBOPTS_ESP_ARS_MASK	0xc0 /* antireplay window mask */
 #define PDBOPTS_ESP_IVSRC	0x20 /* IV comes from internal random gen */
 #define PDBOPTS_ESP_ESN		0x10 /* extended sequence included */
 #define PDBOPTS_ESP_OUTFMT	0x08 /* output only decapsulation (decap) */
@@ -54,35 +65,73 @@
 /*
  * General IPSec encap/decap PDB definitions
  */
+
+/**
+ * ipsec_encap_cbc - PDB part for IPsec CBC encapsulation
+ * @iv: 16-byte array initialization vector
+ */
 struct ipsec_encap_cbc {
-	u32 iv[4];
+	u8 iv[16];
 };
 
+/**
+ * ipsec_encap_ctr - PDB part for IPsec CTR encapsulation
+ * @ctr_nonce: 4-byte array nonce
+ * @ctr_initial: initial count constant
+ * @iv: initialization vector
+ */
 struct ipsec_encap_ctr {
-	u32 ctr_nonce;
+	u8 ctr_nonce[4];
 	u32 ctr_initial;
-	u32 iv[2];
+	u64 iv;
 };
 
+/**
+ * ipsec_encap_ccm - PDB part for IPsec CCM encapsulation
+ * @salt: 3-byte array salt (lower 24 bits)
+ * @ccm_opt: CCM algorithm options - MSB-LSB description:
+ *  b0_flags (8b) - CCM B0; use 0x5B for 8-byte ICV, 0x6B for 12-byte ICV,
+ *    0x7B for 16-byte ICV (cf. RFC4309, RFC3610)
+ *  ctr_flags (8b) - counter flags; constant equal to 0x3
+ *  ctr_initial (16b) - initial count constant
+ * @iv: initialization vector
+ */
 struct ipsec_encap_ccm {
-	u32 salt; /* lower 24 bits */
-	u8 b0_flags;
-	u8 ctr_flags;
-	u16 ctr_initial;
-	u32 iv[2];
+	u8 salt[4];
+	u32 ccm_opt;
+	u64 iv;
 };
 
+/**
+ * ipsec_encap_gcm - PDB part for IPsec GCM encapsulation
+ * @salt: 3-byte array salt (lower 24 bits)
+ * @rsvd: reserved, do not use
+ * @iv: initialization vector
+ */
 struct ipsec_encap_gcm {
-	u32 salt; /* lower 24 bits */
+	u8 salt[4];
 	u32 rsvd1;
-	u32 iv[2];
+	u64 iv;
 };
 
+/**
+ * ipsec_encap_pdb - PDB for IPsec encapsulation
+ * @options: MSB-LSB description
+ *  hmo (header manipulation options) - 4b
+ *  reserved - 4b
+ *  next header - 8b
+ *  next header offset - 8b
+ *  option flags (depend on selected algorithm) - 8b
+ * @seq_num_ext_hi: (optional) IPsec Extended Sequence Number (ESN)
+ * @seq_num: IPsec sequence number
+ * @spi: IPsec SPI (Security Parameters Index)
+ * @ip_hdr_len: optional IP Header length (in bytes)
+ *  reserved - 16b
+ *  Opt. IP Hdr Len - 16b
+ * @ip_hdr: optional IP Header content
+ */
 struct ipsec_encap_pdb {
-	u8 hmo_rsvd;
-	u8 ip_nh;
-	u8 ip_nh_offset;
-	u8 options;
+	u32 options;
 	u32 seq_num_ext_hi;
 	u32 seq_num;
 	union {
@@ -92,36 +141,65 @@ struct ipsec_encap_pdb {
 		struct ipsec_encap_gcm gcm;
 	};
 	u32 spi;
-	u16 rsvd1;
-	u16 ip_hdr_len;
-	u32 ip_hdr[0]; /* optional IP Header content */
+	u32 ip_hdr_len;
+	u32 ip_hdr[0];
 };
 
+/**
+ * ipsec_decap_cbc - PDB part for IPsec CBC decapsulation
+ * @rsvd: reserved, do not use
+ */
 struct ipsec_decap_cbc {
 	u32 rsvd[2];
 };
 
+/**
+ * ipsec_decap_ctr - PDB part for IPsec CTR decapsulation
+ * @ctr_nonce: 4-byte array nonce
+ * @ctr_initial: initial count constant
+ */
 struct ipsec_decap_ctr {
-	u32 salt;
+	u8 ctr_nonce[4];
 	u32 ctr_initial;
 };
 
+/**
+ * ipsec_decap_ccm - PDB part for IPsec CCM decapsulation
+ * @salt: 3-byte salt (lower 24 bits)
+ * @ccm_opt: CCM algorithm options - MSB-LSB description:
+ *  b0_flags (8b) - CCM B0; use 0x5B for 8-byte ICV, 0x6B for 12-byte ICV,
+ *    0x7B for 16-byte ICV (cf. RFC4309, RFC3610)
+ *  ctr_flags (8b) - counter flags; constant equal to 0x3
+ *  ctr_initial (16b) - initial count constant
+ */
 struct ipsec_decap_ccm {
-	u32 salt;
-	u8 iv_flags;
-	u8 ctr_flags;
-	u16 ctr_initial;
+	u8 salt[4];
+	u32 ccm_opt;
 };
 
+/**
+ * ipsec_decap_gcm - PDB part for IPsec GCN decapsulation
+ * @salt: 4-byte salt
+ * @rsvd: reserved, do not use
+ */
 struct ipsec_decap_gcm {
-	u32 salt;
+	u8 salt[4];
 	u32 resvd;
 };
 
+/**
+ * ipsec_decap_pdb - PDB for IPsec decapsulation
+ * @options: MSB-LSB description
+ *  hmo (header manipulation options) - 4b
+ *  IP header length - 12b
+ *  next header offset - 8b
+ *  option flags (depend on selected algorithm) - 8b
+ * @seq_num_ext_hi: (optional) IPsec Extended Sequence Number (ESN)
+ * @seq_num: IPsec sequence number
+ * @anti_replay: Anti-replay window; size depends on ARS (option flags)
+ */
 struct ipsec_decap_pdb {
-	u16 hmo_ip_hdr_len;
-	u8 ip_nh_offset;
-	u8 options;
+	u32 options;
 	union {
 		struct ipsec_decap_cbc cbc;
 		struct ipsec_decap_ctr ctr;
@@ -130,8 +208,7 @@ struct ipsec_decap_pdb {
 	};
 	u32 seq_num_ext_hi;
 	u32 seq_num;
-	u32 anti_replay[2];
-	u32 end_index[0];
+	be32 anti_replay[4];
 };
 
 /*
diff --git a/drivers/crypto/caam/regs.h b/drivers/crypto/caam/regs.h
index 0ba9c40597dc..8c766cf9202c 100644
--- a/drivers/crypto/caam/regs.h
+++ b/drivers/crypto/caam/regs.h
@@ -8,6 +8,7 @@
 #define REGS_H
 
 #include <linux/types.h>
+#include <linux/bitops.h>
 #include <linux/io.h>
 
 /*
@@ -65,46 +66,56 @@
  *
  */
 
-#ifdef CONFIG_ARM
-/* These are common macros for Power, put here for ARM */
-#define setbits32(_addr, _v) writel((readl(_addr) | (_v)), (_addr))
-#define clrbits32(_addr, _v) writel((readl(_addr) & ~(_v)), (_addr))
+extern bool caam_little_end;
 
-#define out_arch(type, endian, a, v)	__raw_write##type(cpu_to_##endian(v), a)
-#define in_arch(type, endian, a)	endian##_to_cpu(__raw_read##type(a))
+#define caam_to_cpu(len)				\
+static inline u##len caam##len ## _to_cpu(u##len val)	\
+{							\
+	if (caam_little_end)				\
+		return le##len ## _to_cpu(val);		\
+	else						\
+		return be##len ## _to_cpu(val);		\
+}
 
-#define out_le32(a, v)	out_arch(l, le32, a, v)
-#define in_le32(a)	in_arch(l, le32, a)
+#define cpu_to_caam(len)				\
+static inline u##len cpu_to_caam##len(u##len val)	\
+{							\
+	if (caam_little_end)				\
+		return cpu_to_le##len(val);		\
+	else						\
+		return cpu_to_be##len(val);		\
+}
 
-#define out_be32(a, v)	out_arch(l, be32, a, v)
-#define in_be32(a)	in_arch(l, be32, a)
+caam_to_cpu(16)
+caam_to_cpu(32)
+caam_to_cpu(64)
+cpu_to_caam(16)
+cpu_to_caam(32)
+cpu_to_caam(64)
 
-#define clrsetbits(type, addr, clear, set) \
-	out_##type((addr), (in_##type(addr) & ~(clear)) | (set))
+static inline void wr_reg32(void __iomem *reg, u32 data)
+{
+	if (caam_little_end)
+		iowrite32(data, reg);
+	else
+		iowrite32be(data, reg);
+}
 
-#define clrsetbits_be32(addr, clear, set) clrsetbits(be32, addr, clear, set)
-#define clrsetbits_le32(addr, clear, set) clrsetbits(le32, addr, clear, set)
-#endif
+static inline u32 rd_reg32(void __iomem *reg)
+{
+	if (caam_little_end)
+		return ioread32(reg);
 
-#ifdef __BIG_ENDIAN
-#define wr_reg32(reg, data) out_be32(reg, data)
-#define rd_reg32(reg) in_be32(reg)
-#define clrsetbits_32(addr, clear, set) clrsetbits_be32(addr, clear, set)
-#ifdef CONFIG_64BIT
-#define wr_reg64(reg, data) out_be64(reg, data)
-#define rd_reg64(reg) in_be64(reg)
-#endif
-#else
-#ifdef __LITTLE_ENDIAN
-#define wr_reg32(reg, data) __raw_writel(data, reg)
-#define rd_reg32(reg) __raw_readl(reg)
-#define clrsetbits_32(addr, clear, set) clrsetbits_le32(addr, clear, set)
-#ifdef CONFIG_64BIT
-#define wr_reg64(reg, data) __raw_writeq(data, reg)
-#define rd_reg64(reg) __raw_readq(reg)
-#endif
-#endif
-#endif
+	return ioread32be(reg);
+}
+
+static inline void clrsetbits_32(void __iomem *reg, u32 clear, u32 set)
+{
+	if (caam_little_end)
+		iowrite32((ioread32(reg) & ~clear) | set, reg);
+	else
+		iowrite32be((ioread32be(reg) & ~clear) | set, reg);
+}
 
 /*
  * The only users of these wr/rd_reg64 functions is the Job Ring (JR).
@@ -123,29 +134,67 @@
  *    base + 0x0000 : least-significant 32 bits
  *    base + 0x0004 : most-significant 32 bits
  */
+#ifdef CONFIG_64BIT
+static inline void wr_reg64(void __iomem *reg, u64 data)
+{
+	if (caam_little_end)
+		iowrite64(data, reg);
+	else
+		iowrite64be(data, reg);
+}
 
-#ifndef CONFIG_64BIT
-#if !defined(CONFIG_CRYPTO_DEV_FSL_CAAM_LE) || \
-	defined(CONFIG_CRYPTO_DEV_FSL_CAAM_IMX)
-#define REG64_MS32(reg) ((u32 __iomem *)(reg))
-#define REG64_LS32(reg) ((u32 __iomem *)(reg) + 1)
-#else
-#define REG64_MS32(reg) ((u32 __iomem *)(reg) + 1)
-#define REG64_LS32(reg) ((u32 __iomem *)(reg))
-#endif
-
-static inline void wr_reg64(u64 __iomem *reg, u64 data)
+static inline u64 rd_reg64(void __iomem *reg)
 {
-	wr_reg32(REG64_MS32(reg), data >> 32);
-	wr_reg32(REG64_LS32(reg), data);
+	if (caam_little_end)
+		return ioread64(reg);
+	else
+		return ioread64be(reg);
 }
 
-static inline u64 rd_reg64(u64 __iomem *reg)
+#else /* CONFIG_64BIT */
+static inline void wr_reg64(void __iomem *reg, u64 data)
 {
-	return ((u64)rd_reg32(REG64_MS32(reg)) << 32 |
-		(u64)rd_reg32(REG64_LS32(reg)));
+#ifndef CONFIG_CRYPTO_DEV_FSL_CAAM_IMX
+	if (caam_little_end) {
+		wr_reg32((u32 __iomem *)(reg) + 1, data >> 32);
+		wr_reg32((u32 __iomem *)(reg), data);
+	} else
+#endif
+	{
+		wr_reg32((u32 __iomem *)(reg), data >> 32);
+		wr_reg32((u32 __iomem *)(reg) + 1, data);
+	}
 }
+
+static inline u64 rd_reg64(void __iomem *reg)
+{
+#ifndef CONFIG_CRYPTO_DEV_FSL_CAAM_IMX
+	if (caam_little_end)
+		return ((u64)rd_reg32((u32 __iomem *)(reg) + 1) << 32 |
+			(u64)rd_reg32((u32 __iomem *)(reg)));
+	else
 #endif
+		return ((u64)rd_reg32((u32 __iomem *)(reg)) << 32 |
+			(u64)rd_reg32((u32 __iomem *)(reg) + 1));
+}
+#endif /* CONFIG_64BIT  */
+
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+#ifdef CONFIG_SOC_IMX7D
+#define cpu_to_caam_dma(value) \
+		(((u64)cpu_to_caam32(lower_32_bits(value)) << 32) | \
+		 (u64)cpu_to_caam32(higher_32_bits(value)))
+#define caam_dma_to_cpu(value) \
+		(((u64)caam32_to_cpu(lower_32_bits(value)) << 32) | \
+		 (u64)caam32_to_cpu(higher_32_bits(value)))
+#else
+#define cpu_to_caam_dma(value) cpu_to_caam64(value)
+#define caam_dma_to_cpu(value) caam64_to_cpu(value)
+#endif /* CONFIG_SOC_IMX7D */
+#else
+#define cpu_to_caam_dma(value) cpu_to_caam32(value)
+#define caam_dma_to_cpu(value) caam32_to_cpu(value)
+#endif /* CONFIG_ARCH_DMA_ADDR_T_64BIT  */
 
 /*
  * jr_outentry
@@ -249,6 +298,8 @@ struct caam_perfmon {
 	u32 faultliodn;	/* FALR - Fault Address LIODN	*/
 	u32 faultdetail;	/* FADR - Fault Addr Detail	*/
 	u32 rsvd2;
+#define CSTA_PLEND		BIT(10)
+#define CSTA_ALT_PLEND		BIT(18)
 	u32 status;		/* CSTA - CAAM Status */
 	u64 rsvd3;
 
diff --git a/drivers/crypto/caam/sg_sw_sec4.h b/drivers/crypto/caam/sg_sw_sec4.h
index 2311341b7356..19dc64fede0d 100644
--- a/drivers/crypto/caam/sg_sw_sec4.h
+++ b/drivers/crypto/caam/sg_sw_sec4.h
@@ -5,6 +5,8 @@
  *
  */
 
+#include "regs.h"
+
 struct sec4_sg_entry;
 
 /*
@@ -13,10 +15,9 @@ struct sec4_sg_entry;
 static inline void dma_to_sec4_sg_one(struct sec4_sg_entry *sec4_sg_ptr,
 				      dma_addr_t dma, u32 len, u16 offset)
 {
-	sec4_sg_ptr->ptr = dma;
-	sec4_sg_ptr->len = len;
-	sec4_sg_ptr->buf_pool_id = 0;
-	sec4_sg_ptr->offset = offset & SEC4_SG_OFFSET_MASK;
+	sec4_sg_ptr->ptr = cpu_to_caam_dma(dma);
+	sec4_sg_ptr->len = cpu_to_caam32(len);
+	sec4_sg_ptr->bpid_offset = cpu_to_caam32(offset & SEC4_SG_OFFSET_MASK);
 #ifdef DEBUG
 	print_hex_dump(KERN_ERR, "sec4_sg_ptr@: ",
 		       DUMP_PREFIX_ADDRESS, 16, 4, sec4_sg_ptr,
@@ -51,7 +52,7 @@ static inline void sg_to_sec4_sg_last(struct scatterlist *sg, int sg_count,
 				      u16 offset)
 {
 	sec4_sg_ptr = sg_to_sec4_sg(sg, sg_count, sec4_sg_ptr, offset);
-	sec4_sg_ptr->len |= SEC4_SG_LEN_FIN;
+	sec4_sg_ptr->len |= cpu_to_caam32(SEC4_SG_LEN_FIN);
 }
 
 static inline struct sec4_sg_entry *sg_to_sec4_sg_len(
-- 
2.4.4

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox