ossl: Add ChaCha20 cipher support.

Sponsored by:	Netflix
Differential Revision:	https://reviews.freebsd.org/D28756
This commit is contained in:
John Baldwin 2021-03-03 15:17:43 -08:00
parent a899ce4ba4
commit 92aecd1e6f
10 changed files with 262 additions and 19 deletions

View file

@ -74,6 +74,8 @@ driver includes support for the following algorithms:
.Pp
.Bl -bullet -compact
.It
ChaCha20
.It
Poly1305
.It
SHA1

View file

@ -739,6 +739,7 @@ crypto/chacha20/chacha-sw.c optional crypto | ipsec | ipsec_support
crypto/des/des_ecb.c optional netsmb
crypto/des/des_setkey.c optional netsmb
crypto/openssl/ossl.c optional ossl
crypto/openssl/ossl_chacha20.c optional ossl
crypto/openssl/ossl_poly1305.c optional ossl
crypto/openssl/ossl_sha1.c optional ossl
crypto/openssl/ossl_sha256.c optional ossl

View file

@ -137,6 +137,7 @@ cddl/dev/dtrace/amd64/dtrace_asm.S optional dtrace compile-with "${DTRACE_S}"
cddl/dev/dtrace/amd64/dtrace_subr.c optional dtrace compile-with "${DTRACE_C}"
crypto/aesni/aeskeys_amd64.S optional aesni
crypto/des/des_enc.c optional netsmb
crypto/openssl/amd64/chacha-x86_64.S optional ossl
crypto/openssl/amd64/poly1305-x86_64.S optional ossl
crypto/openssl/amd64/sha1-x86_64.S optional ossl
crypto/openssl/amd64/sha256-x86_64.S optional ossl

View file

@ -125,6 +125,8 @@ ghashv8-armx.o optional armv8crypto \
crypto/des/des_enc.c optional netsmb
crypto/openssl/ossl_aarch64.c optional ossl
crypto/openssl/aarch64/chacha-armv8.S optional ossl \
compile-with "${CC} -c ${CFLAGS:N-mgeneral-regs-only} ${WERROR} ${PROF} ${.IMPSRC}"
crypto/openssl/aarch64/poly1305-armv8.S optional ossl \
compile-with "${CC} -c ${CFLAGS:N-mgeneral-regs-only} ${WERROR} ${PROF} ${.IMPSRC}"
crypto/openssl/aarch64/sha1-armv8.S optional ossl \

View file

@ -77,6 +77,7 @@ compat/linux/linux_vdso.c optional compat_linux
compat/linux/linux.c optional compat_linux
crypto/aesni/aeskeys_i386.S optional aesni
crypto/des/arch/i386/des_enc.S optional netsmb
crypto/openssl/i386/chacha-x86.S optional ossl
crypto/openssl/i386/poly1305-x86.S optional ossl
crypto/openssl/i386/sha1-586.S optional ossl
crypto/openssl/i386/sha256-586.S optional ossl

View file

@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$");
#include <opencrypto/xform_auth.h>
#include <crypto/openssl/ossl.h>
#include <crypto/openssl/ossl_chacha.h>
#include "cryptodev_if.h"
@ -154,6 +155,16 @@ ossl_probesession(device_t dev, const struct crypto_session_params *csp)
if (ossl_lookup_hash(csp) == NULL)
return (EINVAL);
break;
case CSP_MODE_CIPHER:
switch (csp->csp_cipher_alg) {
case CRYPTO_CHACHA20:
if (csp->csp_cipher_klen != CHACHA_KEY_SIZE)
return (EINVAL);
break;
default:
return (EINVAL);
}
break;
default:
return (EINVAL);
}
@ -161,15 +172,12 @@ ossl_probesession(device_t dev, const struct crypto_session_params *csp)
return (CRYPTODEV_PROBE_ACCEL_SOFTWARE);
}
static int
ossl_newsession(device_t dev, crypto_session_t cses,
static void
ossl_newsession_hash(struct ossl_session *s,
const struct crypto_session_params *csp)
{
struct ossl_session *s;
struct auth_hash *axf;
s = crypto_get_driver_session(cses);
axf = ossl_lookup_hash(csp);
s->hash.axf = axf;
if (csp->csp_auth_mlen == 0)
@ -195,31 +203,35 @@ ossl_newsession(device_t dev, crypto_session_t cses,
fpu_kern_leave(curthread, NULL);
}
}
}
static int
ossl_newsession(device_t dev, crypto_session_t cses,
const struct crypto_session_params *csp)
{
struct ossl_session *s;
s = crypto_get_driver_session(cses);
switch (csp->csp_mode) {
case CSP_MODE_DIGEST:
ossl_newsession_hash(s, csp);
break;
}
return (0);
}
static int
ossl_process(device_t dev, struct cryptop *crp, int hint)
ossl_process_hash(struct ossl_session *s, struct cryptop *crp,
const struct crypto_session_params *csp)
{
struct ossl_hash_context ctx;
char digest[HASH_MAX_LEN];
const struct crypto_session_params *csp;
struct ossl_session *s;
struct auth_hash *axf;
int error;
bool fpu_entered;
s = crypto_get_driver_session(crp->crp_session);
csp = crypto_get_params(crp->crp_session);
axf = s->hash.axf;
if (is_fpu_kern_thread(0)) {
fpu_entered = false;
} else {
fpu_kern_enter(curthread, NULL, FPU_KERN_NOCTX);
fpu_entered = true;
}
if (crp->crp_auth_key == NULL) {
ctx = s->hash.ictx;
} else {
@ -273,13 +285,45 @@ ossl_process(device_t dev, struct cryptop *crp, int hint)
explicit_bzero(digest, sizeof(digest));
out:
explicit_bzero(&ctx, sizeof(ctx));
return (error);
}
static int
ossl_process(device_t dev, struct cryptop *crp, int hint)
{
const struct crypto_session_params *csp;
struct ossl_session *s;
int error;
bool fpu_entered;
s = crypto_get_driver_session(crp->crp_session);
csp = crypto_get_params(crp->crp_session);
if (is_fpu_kern_thread(0)) {
fpu_entered = false;
} else {
fpu_kern_enter(curthread, NULL, FPU_KERN_NOCTX);
fpu_entered = true;
}
switch (csp->csp_mode) {
case CSP_MODE_DIGEST:
error = ossl_process_hash(s, crp, csp);
break;
case CSP_MODE_CIPHER:
error = ossl_chacha20(crp, csp);
break;
default:
__assert_unreachable();
}
if (fpu_entered)
fpu_kern_leave(curthread, NULL);
crp->crp_etype = error;
crypto_done(crp);
explicit_bzero(&ctx, sizeof(ctx));
return (0);
}

View file

@ -34,6 +34,11 @@
/* Compatibility shims. */
#define OPENSSL_cleanse explicit_bzero
struct cryptop;
struct crypto_session_params;
int ossl_chacha20(struct cryptop *crp,
const struct crypto_session_params *csp);
void ossl_cpuid(void);
/* Needs to be big enough to hold any hash context. */

View file

@ -0,0 +1,42 @@
/*
* Copyright 2015-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
/* From include/crypto/chacha.h */
#ifndef OSSL_CRYPTO_CHACHA_H
#define OSSL_CRYPTO_CHACHA_H
/*
* ChaCha20_ctr32 encrypts |len| bytes from |inp| with the given key and
* nonce and writes the result to |out|, which may be equal to |inp|.
* The |key| is not 32 bytes of verbatim key material though, but the
* said material collected into 8 32-bit elements array in host byte
* order. Same approach applies to nonce: the |counter| argument is
* pointer to concatenated nonce and counter values collected into 4
* 32-bit elements. This, passing crypto material collected into 32-bit
* elements as opposite to passing verbatim byte vectors, is chosen for
* efficiency in multi-call scenarios.
*/
void ChaCha20_ctr32(unsigned char *out, const unsigned char *inp,
size_t len, const unsigned int key[8],
const unsigned int counter[4]);
/*
* You can notice that there is no key setup procedure. Because it's
* as trivial as collecting bytes into 32-bit elements, it's reckoned
* that below macro is sufficient.
*/
#define CHACHA_U8TOU32(p) ( \
((unsigned int)(p)[0]) | ((unsigned int)(p)[1]<<8) | \
((unsigned int)(p)[2]<<16) | ((unsigned int)(p)[3]<<24) )
#define CHACHA_KEY_SIZE 32
#define CHACHA_CTR_SIZE 16
#define CHACHA_BLK_SIZE 64
#endif

View file

@ -0,0 +1,141 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2020 Netflix, Inc
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* 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 NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
*/
#include <sys/types.h>
#include <sys/endian.h>
#include <sys/malloc.h>
#include <sys/time.h>
#include <opencrypto/cryptodev.h>
#include <crypto/openssl/ossl.h>
#include <crypto/openssl/ossl_chacha.h>
int
ossl_chacha20(struct cryptop *crp, const struct crypto_session_params *csp)
{
_Alignas(8) unsigned int key[CHACHA_KEY_SIZE / 4];
unsigned int counter[CHACHA_CTR_SIZE / 4];
unsigned char block[CHACHA_BLK_SIZE];
struct crypto_buffer_cursor cc_in, cc_out;
const unsigned char *in, *inseg, *cipher_key;
unsigned char *out, *outseg;
size_t resid, todo, inlen, outlen;
uint32_t next_counter;
u_int i;
if (crp->crp_cipher_key != NULL)
cipher_key = crp->crp_cipher_key;
else
cipher_key = csp->csp_cipher_key;
for (i = 0; i < nitems(key); i++)
key[i] = CHACHA_U8TOU32(cipher_key + i * 4);
crypto_read_iv(crp, counter);
for (i = 0; i < nitems(counter); i++)
counter[i] = le32toh(counter[i]);
resid = crp->crp_payload_length;
crypto_cursor_init(&cc_in, &crp->crp_buf);
crypto_cursor_advance(&cc_in, crp->crp_payload_start);
inseg = crypto_cursor_segbase(&cc_in);
inlen = crypto_cursor_seglen(&cc_in);
if (CRYPTO_HAS_OUTPUT_BUFFER(crp)) {
crypto_cursor_init(&cc_out, &crp->crp_obuf);
crypto_cursor_advance(&cc_out, crp->crp_payload_output_start);
} else
cc_out = cc_in;
outseg = crypto_cursor_segbase(&cc_out);
outlen = crypto_cursor_seglen(&cc_out);
while (resid >= CHACHA_BLK_SIZE) {
if (inlen < CHACHA_BLK_SIZE) {
crypto_cursor_copydata(&cc_in, CHACHA_BLK_SIZE, block);
in = block;
inlen = CHACHA_BLK_SIZE;
} else
in = inseg;
if (outlen < CHACHA_BLK_SIZE) {
out = block;
outlen = CHACHA_BLK_SIZE;
} else
out = outseg;
/* Figure out how many blocks we can encrypt/decrypt at once. */
todo = rounddown(MIN(inlen, outlen), CHACHA_BLK_SIZE);
#ifdef __LP64__
/* ChaCha20_ctr32() assumes length is <= 4GB. */
todo = (uint32_t)todo;
#endif
/* Truncate if the 32-bit counter would roll over. */
next_counter = counter[0] + todo / CHACHA_BLK_SIZE;
if (next_counter < counter[0]) {
todo -= next_counter * CHACHA_BLK_SIZE;
next_counter = 0;
}
ChaCha20_ctr32(out, in, todo, key, counter);
counter[0] = next_counter;
if (counter[0] == 0)
counter[1]++;
if (out == block) {
crypto_cursor_copyback(&cc_out, CHACHA_BLK_SIZE, block);
outseg = crypto_cursor_segbase(&cc_out);
outlen = crypto_cursor_seglen(&cc_out);
} else {
crypto_cursor_advance(&cc_out, todo);
outseg += todo;
outlen -= todo;
}
if (in == block) {
inseg = crypto_cursor_segbase(&cc_in);
inlen = crypto_cursor_seglen(&cc_in);
} else {
crypto_cursor_advance(&cc_in, todo);
inseg += todo;
inlen -= todo;
}
resid -= todo;
}
if (resid > 0) {
memset(block, 0, sizeof(block));
crypto_cursor_copydata(&cc_in, resid, block);
ChaCha20_ctr32(block, block, CHACHA_BLK_SIZE, key, counter);
crypto_cursor_copyback(&cc_out, resid, block);
}
explicit_bzero(block, sizeof(block));
explicit_bzero(counter, sizeof(counter));
explicit_bzero(key, sizeof(key));
return (0);
}

View file

@ -8,6 +8,7 @@ SRCS= bus_if.h \
cryptodev_if.h \
device_if.h \
ossl.c \
ossl_chacha20.c \
ossl_poly1305.c \
ossl_sha1.c \
ossl_sha256.c \
@ -15,6 +16,7 @@ SRCS= bus_if.h \
${SRCS.${MACHINE_CPUARCH}}
SRCS.aarch64= \
chacha-armv8.S \
poly1305-armv8.S \
sha1-armv8.S \
sha256-armv8.S \
@ -22,6 +24,7 @@ SRCS.aarch64= \
ossl_aarch64.c
SRCS.amd64= \
chacha-x86_64.S \
poly1305-x86_64.S \
sha1-x86_64.S \
sha256-x86_64.S \
@ -29,6 +32,7 @@ SRCS.amd64= \
ossl_x86.c
SRCS.i386= \
chacha-x86.S \
poly1305-x86.S \
sha1-586.S \
sha256-586.S \