svn commit: r348197 - in head: sbin/decryptcore sbin/dumpon sys/kern sys/sys

Conrad Meyer cem at FreeBSD.org
Thu May 23 20:12:26 UTC 2019


Author: cem
Date: Thu May 23 20:12:24 2019
New Revision: 348197
URL: https://svnweb.freebsd.org/changeset/base/348197

Log:
  EKCD: Add Chacha20 encryption mode
  
  Add Chacha20 mode to Encrypted Kernel Crash Dumps.
  
  Chacha20 does not require messages to be multiples of block size, so it is
  valid to use the cipher on non-block-sized messages without the explicit
  padding AES-CBC would require.  Therefore, allow use with simultaneous dump
  compression.  (Continue to disallow use of AES-CBC EKCD with compression.)
  
  dumpon(8) gains a -C cipher flag to select between chacha and aes-cbc.
  It defaults to chacha if no -C option is provided.  The man page documents this
  behavior.
  
  Relnotes:	sure
  Sponsored by:	Dell EMC Isilon

Modified:
  head/sbin/decryptcore/decryptcore.c
  head/sbin/dumpon/dumpon.8
  head/sbin/dumpon/dumpon.c
  head/sys/kern/kern_shutdown.c
  head/sys/sys/kerneldump.h

Modified: head/sbin/decryptcore/decryptcore.c
==============================================================================
--- head/sbin/decryptcore/decryptcore.c	Thu May 23 20:04:22 2019	(r348196)
+++ head/sbin/decryptcore/decryptcore.c	Thu May 23 20:12:24 2019	(r348197)
@@ -119,7 +119,8 @@ static bool
 decrypt(int ofd, const char *privkeyfile, const char *keyfile,
     const char *input)
 {
-	uint8_t buf[KERNELDUMP_BUFFER_SIZE], key[KERNELDUMP_KEY_MAX_SIZE];
+	uint8_t buf[KERNELDUMP_BUFFER_SIZE], key[KERNELDUMP_KEY_MAX_SIZE],
+	    chachaiv[4 * 4];
 	EVP_CIPHER_CTX *ctx;
 	const EVP_CIPHER *cipher;
 	FILE *fp;
@@ -207,6 +208,9 @@ decrypt(int ofd, const char *privkeyfile, const char *
 	case KERNELDUMP_ENC_AES_256_CBC:
 		cipher = EVP_aes_256_cbc();
 		break;
+	case KERNELDUMP_ENC_CHACHA20:
+		cipher = EVP_chacha20();
+		break;
 	default:
 		pjdlog_error("Invalid encryption algorithm.");
 		goto failed;
@@ -222,7 +226,23 @@ decrypt(int ofd, const char *privkeyfile, const char *
 	RSA_free(privkey);
 	privkey = NULL;
 
-	EVP_DecryptInit_ex(ctx, cipher, NULL, key, kdk->kdk_iv);
+	if (kdk->kdk_encryption == KERNELDUMP_ENC_CHACHA20) {
+		/*
+		 * OpenSSL treats the IV as 4 little-endian 32 bit integers.
+		 *
+		 * The first two represent a 64-bit counter, where the low half
+		 * is the first 32-bit word.
+		 *
+		 * Start at counter block zero...
+		 */
+		memset(chachaiv, 0, 4 * 2);
+		/*
+		 * And use the IV specified by the dump.
+		 */
+		memcpy(&chachaiv[4 * 2], kdk->kdk_iv, 4 * 2);
+		EVP_DecryptInit_ex(ctx, cipher, NULL, key, chachaiv);
+	} else
+		EVP_DecryptInit_ex(ctx, cipher, NULL, key, kdk->kdk_iv);
 	EVP_CIPHER_CTX_set_padding(ctx, 0);
 
 	explicit_bzero(key, sizeof(key));

Modified: head/sbin/dumpon/dumpon.8
==============================================================================
--- head/sbin/dumpon/dumpon.8	Thu May 23 20:04:22 2019	(r348196)
+++ head/sbin/dumpon/dumpon.8	Thu May 23 20:12:24 2019	(r348197)
@@ -28,7 +28,7 @@
 .\"     From: @(#)swapon.8	8.1 (Berkeley) 6/5/93
 .\" $FreeBSD$
 .\"
-.Dd May 21, 2019
+.Dd May 23, 2019
 .Dt DUMPON 8
 .Os
 .Sh NAME
@@ -39,6 +39,7 @@
 .Op Fl i Ar index
 .Op Fl r
 .Op Fl v
+.Op Fl C Ar cipher
 .Op Fl k Ar pubkey
 .Op Fl Z
 .Op Fl z
@@ -47,6 +48,7 @@
 .Op Fl i Ar index
 .Op Fl r
 .Op Fl v
+.Op Fl C Ar cipher
 .Op Fl k Ar pubkey
 .Op Fl Z
 .Op Fl z
@@ -129,6 +131,14 @@ The goal of the mechanism is to provide confidentialit
 The
 .Va pubkey
 file should be a PEM-formatted RSA key of at least 1024 bits.
+.It Fl C Ar cipher
+Select the symmetric algorithm used for encrypted kernel crash dump.
+The default is
+.Dq chacha20
+but
+.Dq aes256-cbc
+is also available.
+(AES256-CBC mode does not work in conjunction with compression.)
 .It Fl l
 List the currently configured dump device(s), or /dev/null if no devices are
 configured.
@@ -420,10 +430,6 @@ requires the
 .Dv GZIO
 option.
 .Sh BUGS
-It is currently not possible to configure both compression and encryption.
-The encrypted dump format assumes that the kernel dump size is a multiple
-of the cipher block size, which may not be true when the dump is compressed.
-.Pp
 Netdump only supports IPv4 at this time.
 .Sh SECURITY CONSIDERATIONS
 The current encrypted kernel core dump scheme does not provide integrity nor

Modified: head/sbin/dumpon/dumpon.c
==============================================================================
--- head/sbin/dumpon/dumpon.c	Thu May 23 20:04:22 2019	(r348196)
+++ head/sbin/dumpon/dumpon.c	Thu May 23 20:12:24 2019	(r348197)
@@ -276,7 +276,16 @@ genkey(const char *pubkeyfile, struct diocskerneldump_
 	if (kdap->kda_encryptedkey == NULL)
 		err(1, "Unable to allocate encrypted key");
 
-	kdap->kda_encryption = KERNELDUMP_ENC_AES_256_CBC;
+	/*
+	 * If no cipher was specified, choose a reasonable default.
+	 */
+	if (kdap->kda_encryption == KERNELDUMP_ENC_NONE)
+		kdap->kda_encryption = KERNELDUMP_ENC_CHACHA20;
+	else if (kdap->kda_encryption == KERNELDUMP_ENC_AES_256_CBC &&
+	    kdap->kda_compression != KERNELDUMP_COMP_NONE)
+		errx(EX_USAGE, "Unpadded AES256-CBC mode cannot be used "
+		    "with compression.");
+
 	arc4random_buf(kdap->kda_key, sizeof(kdap->kda_key));
 	if (RSA_public_encrypt(sizeof(kdap->kda_key), kdap->kda_key,
 	    kdap->kda_encryptedkey, pubkey,
@@ -378,7 +387,7 @@ main(int argc, char *argv[])
 	struct diocskerneldump_arg ndconf, *kdap;
 	struct addrinfo hints, *res;
 	const char *dev, *pubkeyfile, *server, *client, *gateway;
-	int ch, error, fd;
+	int ch, error, fd, cipher;
 	bool gzip, list, netdump, zstd, insert, rflag;
 	uint8_t ins_idx;
 
@@ -387,9 +396,21 @@ main(int argc, char *argv[])
 	pubkeyfile = NULL;
 	server = client = gateway = NULL;
 	ins_idx = KDA_APPEND;
+	cipher = KERNELDUMP_ENC_NONE;
 
-	while ((ch = getopt(argc, argv, "c:g:i:k:lrs:vZz")) != -1)
+	while ((ch = getopt(argc, argv, "C:c:g:i:k:lrs:vZz")) != -1)
 		switch ((char)ch) {
+		case 'C':
+			if (strcasecmp(optarg, "chacha") == 0 ||
+			    strcasecmp(optarg, "chacha20") == 0)
+				cipher = KERNELDUMP_ENC_CHACHA20;
+			else if (strcasecmp(optarg, "aes-cbc") == 0 ||
+			    strcasecmp(optarg, "aes256-cbc") == 0)
+				cipher = KERNELDUMP_ENC_AES_256_CBC;
+			else
+				errx(EX_USAGE, "Unrecognized cipher algorithm "
+				    "'%s'", optarg);
+			break;
 		case 'c':
 			client = optarg;
 			break;
@@ -451,7 +472,10 @@ main(int argc, char *argv[])
 	if (argc != 1)
 		usage();
 
-#ifndef HAVE_CRYPTO
+#ifdef HAVE_CRYPTO
+	if (cipher != KERNELDUMP_ENC_NONE && pubkeyfile == NULL)
+		errx(EX_USAGE, "-C option requires a public key file.");
+#else
 	if (pubkeyfile != NULL)
 		errx(EX_UNAVAILABLE,"Unable to use the public key."
 				    " Recompile dumpon with OpenSSL support.");
@@ -526,8 +550,10 @@ main(int argc, char *argv[])
 	}
 
 #ifdef HAVE_CRYPTO
-	if (pubkeyfile != NULL)
+	if (pubkeyfile != NULL) {
+		kdap->kda_encryption = cipher;
 		genkey(pubkeyfile, kdap);
+	}
 #endif
 	error = ioctl(fd, DIOCSKERNELDUMP, kdap);
 	if (error != 0)

Modified: head/sys/kern/kern_shutdown.c
==============================================================================
--- head/sys/kern/kern_shutdown.c	Thu May 23 20:04:22 2019	(r348196)
+++ head/sys/kern/kern_shutdown.c	Thu May 23 20:12:24 2019	(r348197)
@@ -80,6 +80,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/vnode.h>
 #include <sys/watchdog.h>
 
+#include <crypto/chacha20/chacha.h>
 #include <crypto/rijndael/rijndael-api-fst.h>
 #include <crypto/sha2/sha256.h>
 
@@ -180,8 +181,16 @@ MALLOC_DEFINE(M_EKCD, "ekcd", "Encrypted kernel crash 
 struct kerneldumpcrypto {
 	uint8_t			kdc_encryption;
 	uint8_t			kdc_iv[KERNELDUMP_IV_MAX_SIZE];
-	keyInstance		kdc_ki;
-	cipherInstance		kdc_ci;
+	union {
+		struct {
+			keyInstance	aes_ki;
+			cipherInstance	aes_ci;
+		} u_aes;
+		struct chacha_ctx	u_chacha;
+	} u;
+#define	kdc_ki	u.u_aes.aes_ki
+#define	kdc_ci	u.u_aes.aes_ci
+#define	kdc_chacha	u.u_chacha
 	uint32_t		kdc_dumpkeysize;
 	struct kerneldumpkey	kdc_dumpkey[];
 };
@@ -1024,6 +1033,9 @@ kerneldumpcrypto_create(size_t blocksize, uint8_t encr
 		if (rijndael_makeKey(&kdc->kdc_ki, DIR_ENCRYPT, 256, key) <= 0)
 			goto failed;
 		break;
+	case KERNELDUMP_ENC_CHACHA20:
+		chacha_keysetup(&kdc->kdc_chacha, key, 256);
+		break;
 	default:
 		goto failed;
 	}
@@ -1072,6 +1084,9 @@ kerneldumpcrypto_init(struct kerneldumpcrypto *kdc)
 			goto out;
 		}
 		break;
+	case KERNELDUMP_ENC_CHACHA20:
+		chacha_ivsetup(&kdc->kdc_chacha, kdc->kdc_iv, NULL);
+		break;
 	default:
 		error = EINVAL;
 		goto out;
@@ -1208,11 +1223,12 @@ dumper_insert(const struct dumperinfo *di_template, co
 	}
 	if (kda->kda_compression != KERNELDUMP_COMP_NONE) {
 		/*
-		 * We currently can't support simultaneous encryption and
-		 * compression because our only encryption mode is an unpadded
-		 * block cipher, go figure.  This is low hanging fruit to fix.
+		 * We can't support simultaneous unpadded block cipher
+		 * encryption and compression because there is no guarantee the
+		 * length of the compressed result is exactly a multiple of the
+		 * cipher block size.
 		 */
-		if (kda->kda_encryption != KERNELDUMP_ENC_NONE) {
+		if (kda->kda_encryption == KERNELDUMP_ENC_AES_256_CBC) {
 			error = EOPNOTSUPP;
 			goto cleanup;
 		}
@@ -1367,6 +1383,9 @@ dump_encrypt(struct kerneldumpcrypto *kdc, uint8_t *bu
 		    buf + size - 16 /* IV size for AES-256-CBC */) <= 0) {
 			return (EIO);
 		}
+		break;
+	case KERNELDUMP_ENC_CHACHA20:
+		chacha_encrypt_bytes(&kdc->kdc_chacha, buf, buf, size);
 		break;
 	default:
 		return (EINVAL);

Modified: head/sys/sys/kerneldump.h
==============================================================================
--- head/sys/sys/kerneldump.h	Thu May 23 20:04:22 2019	(r348196)
+++ head/sys/sys/kerneldump.h	Thu May 23 20:12:24 2019	(r348197)
@@ -63,6 +63,7 @@
 
 #define	KERNELDUMP_ENC_NONE		0
 #define	KERNELDUMP_ENC_AES_256_CBC	1
+#define	KERNELDUMP_ENC_CHACHA20		2
 
 #define	KERNELDUMP_BUFFER_SIZE		4096
 #define	KERNELDUMP_IV_MAX_SIZE		32


More information about the svn-src-all mailing list