Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 30 Nov 2015 22:06:12 GMT
From:      def@FreeBSD.org
To:        svn-soc-all@FreeBSD.org
Subject:   socsvn commit: r294625 - in soc2013/def/crashdump-head: sbin/decryptcore sys/conf sys/kern
Message-ID:  <201511302206.tAUM6Cfh073251@socsvn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: def
Date: Mon Nov 30 22:06:11 2015
New Revision: 294625
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=294625

Log:
  Allow to use chosen encryption algorithm. Simplify code.

Modified:
  soc2013/def/crashdump-head/sbin/decryptcore/decryptcore.c
  soc2013/def/crashdump-head/sys/conf/files
  soc2013/def/crashdump-head/sys/kern/kern_shutdown.c

Modified: soc2013/def/crashdump-head/sbin/decryptcore/decryptcore.c
==============================================================================
--- soc2013/def/crashdump-head/sbin/decryptcore/decryptcore.c	Mon Nov 30 22:04:02 2015	(r294624)
+++ soc2013/def/crashdump-head/sbin/decryptcore/decryptcore.c	Mon Nov 30 22:06:11 2015	(r294625)
@@ -33,12 +33,12 @@
 
 	if (waitpid(pid, &status, WUNTRACED | WEXITED) == -1) {
 		pjdlog_errno(LOG_ERR, "Unable to wait for a child process");
-		goto failed;
+		return (1);
 	}
 
 	if (WIFEXITED(status))
 		return (WEXITSTATUS(status));
-failed:
+
 	return (1);
 }
 
@@ -47,6 +47,7 @@
 {
 	uint8_t *buf, *p;
 	struct kerneldumpkey *kdk;
+	uint32_t encryptedkeysize;
 	ssize_t size;
 	size_t kdksize, bytes;
 
@@ -62,7 +63,7 @@
 		goto failed;
 	}
 
-	bytes = sizeof(kdk->kdk_algorithm) + sizeof(kdk->kdk_iv) +
+	bytes = sizeof(kdk->kdk_encryption) + sizeof(kdk->kdk_iv) +
 	    sizeof(kdk->kdk_encryptedkeysize);
 	buf = calloc(1, bytes);
 	if (buf == NULL) {
@@ -73,12 +74,13 @@
 	size = read(kfd, buf, bytes);
 	if (size == (ssize_t)bytes) {
 		p = buf;
-		kdk->kdk_algorithm = *p;
-		p += sizeof(kdk->kdk_algorithm);
+		kdk->kdk_encryption = *p;
+		p += sizeof(kdk->kdk_encryption);
 		bcopy(p, kdk->kdk_iv, sizeof(kdk->kdk_iv));
 		p += sizeof(kdk->kdk_iv);
-		kdk->kdk_encryptedkeysize = le32dec(p);
-		p += sizeof(kdk->kdk_encryptedkeysize);
+		bcopy(p, &encryptedkeysize, sizeof(encryptedkeysize));
+		kdk->kdk_encryptedkeysize = dtoh32(encryptedkeysize);
+		p += sizeof(encryptedkeysize);
 
 		kdksize += (size_t)kdk->kdk_encryptedkeysize;
 		kdk = realloc(kdk, kdksize);
@@ -107,14 +109,14 @@
 decrypt(const char *privkeyfile, const char *keyfile, const char *input,
     const char *output)
 {
-	uint8_t buf[2 * KERNELDUMP_BLOCK_SIZE], key[KERNELDUMP_KEY_SIZE];
+	uint8_t buf[2 * KERNELDUMP_BLOCK_SIZE], key[KERNELDUMP_KEY_MAX_SIZE];
 	EVP_CIPHER_CTX ctx;
+	const EVP_CIPHER *cipher;
 	FILE *fp;
 	struct kerneldumpkey *kdk;
 	RSA *privkey;
 	int ifd, kfd, ofd, olen, privkeysize;
 	ssize_t bytes;
-	size_t bufused;
 	pid_t pid;
 
 	PJDLOG_ASSERT(privkeyfile != NULL);
@@ -122,13 +124,11 @@
 	PJDLOG_ASSERT(input != NULL);
 	PJDLOG_ASSERT(output != NULL);
 
-	fp = NULL;
-	ifd = -1;
-	kdk = NULL;
-	kfd = -1;
-	ofd = -1;
 	privkey = NULL;
 
+	/*
+	 * TODO: comment.
+	 */
 	pid = fork();
 	if (pid == -1) {
 		pjdlog_errno(LOG_ERR, "Unable to create child process");
@@ -174,13 +174,11 @@
 
 	kdk = read_key(kfd);
 	close(kfd);
-	kfd = -1;
 	if (kdk == NULL)
 		goto failed;
 
 	privkey = PEM_read_RSAPrivateKey(fp, &privkey, NULL, NULL);
 	fclose(fp);
-	fp = NULL;
 	if (privkey == NULL) {
 		pjdlog_error("Unable to read data from %s.", privkeyfile);
 		goto failed;
@@ -192,9 +190,19 @@
 		    8 * privkeysize, 8 * kdk->kdk_encryptedkeysize);
 		goto failed;
 	}
+
+	switch (kdk->kdk_encryption) {
+	case KERNELDUMP_ENC_AES_256_CBC:
+		cipher = EVP_aes_256_cbc();
+		break;
+	default:
+		pjdlog_error("Invalid encryption algorithm.");
+		goto failed;
+	}
+
 	if (RSA_private_decrypt(kdk->kdk_encryptedkeysize,
 	    kdk->kdk_encryptedkey, key, privkey,
-	    RSA_PKCS1_PADDING) != sizeof(key)) {
+	    RSA_PKCS1_PADDING) != EVP_CIPHER_key_length(cipher)) {
 		pjdlog_error("Unable to decrypt key: %s",
 		    ERR_error_string(ERR_get_error(), NULL));
 		goto failed;
@@ -202,56 +210,52 @@
 	RSA_free(privkey);
 	privkey = NULL;
 
-	EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, key, kdk->kdk_iv);
-	EVP_CIPHER_CTX_set_key_length(&ctx, sizeof(key));
+	EVP_DecryptInit_ex(&ctx, cipher, NULL, key, kdk->kdk_iv);
 	EVP_CIPHER_CTX_set_padding(&ctx, 0);
 
-	bufused = 0;
-	while ((bytes = read(ifd, buf + bufused, sizeof(buf) - bufused)) > 0) {
-		bufused += bytes;
-		if (bufused != sizeof(buf))
-			continue;
+	bzero(key, sizeof(key));
 
-		if (EVP_DecryptUpdate(&ctx, buf, &olen, buf,
-		    sizeof(buf)) == 0) {
-			pjdlog_error("Unable to decrypt core.");
+	do {
+		bytes = read(ifd, buf, sizeof(buf));
+		if (bytes < 0) {
+			pjdlog_errno(LOG_ERR, "Unable to read data from %s",
+			    input);
 			goto failed;
+		} else if (bytes == 0) {
+			break;
+		}
+
+		if (bytes > 0) {
+			if (EVP_DecryptUpdate(&ctx, buf, &olen, buf,
+			    bytes) == 0) {
+				pjdlog_error("Unable to decrypt core.");
+				goto failed;
+			}
+		} else {
+			if (EVP_DecryptFinal(&ctx, buf, &olen) == 0) {
+				pjdlog_error("Unable to decrypt core.");
+				goto failed;
+			}
 		}
-		PJDLOG_ASSERT(olen == (int)sizeof(buf));
 
-		if (write(ofd, buf, sizeof(buf)) != (ssize_t)sizeof(buf)) {
+		if (olen == 0)
+			continue;
+
+		if (write(ofd, buf, olen) != olen) {
 			pjdlog_errno(LOG_ERR, "Unable to write data to %s",
 			    output);
 			goto failed;
 		}
-		bufused = 0;
-	}
-	if (bytes < 0) {
-		pjdlog_errno(LOG_ERR, "Unable to read data from %s", input);
-		goto failed;
-	}
+	} while (bytes > 0);
 
-	close(ofd);
-	close(ifd);
-	bzero(key, sizeof(key));
 	bzero(buf, sizeof(buf));
 	EVP_CIPHER_CTX_cleanup(&ctx);
-	free(kdk);
 	exit(0);
 failed:
-	if (ofd >= 0)
-		close(ofd);
-	if (ifd >= 0)
-		close(kfd);
-	if (kfd >= 0)
-		close(kfd);
-	if (fp != NULL)
-		fclose(fp);
 	bzero(key, sizeof(key));
 	bzero(buf, sizeof(buf));
-	EVP_CIPHER_CTX_cleanup(&ctx);
-	free(kdk);
 	RSA_free(privkey);
+	EVP_CIPHER_CTX_cleanup(&ctx);
 	exit(1);
 }
 
@@ -315,5 +319,5 @@
 
 	pjdlog_fini();
 
-	return (0);
+	exit(0);
 }

Modified: soc2013/def/crashdump-head/sys/conf/files
==============================================================================
--- soc2013/def/crashdump-head/sys/conf/files	Mon Nov 30 22:04:02 2015	(r294624)
+++ soc2013/def/crashdump-head/sys/conf/files	Mon Nov 30 22:06:11 2015	(r294625)
@@ -524,8 +524,8 @@
 					 netgraph_mppc_encryption | sctp
 crypto/sha2/sha2.c		optional crypto | geom_bde | ipsec | random | \
 					 sctp | zfs
-crypto/sha2/sha256c.c		optional crypto | geom_bde | ipsec | random | \
-					 sctp | zfs
+crypto/sha2/sha256c.c		optional crypto | ekcd | geom_bde | ipsec | \
+					 random | sctp | zfs
 crypto/siphash/siphash.c	optional inet | inet6
 crypto/siphash/siphash_test.c	optional inet | inet6
 ddb/db_access.c			optional ddb

Modified: soc2013/def/crashdump-head/sys/kern/kern_shutdown.c
==============================================================================
--- soc2013/def/crashdump-head/sys/kern/kern_shutdown.c	Mon Nov 30 22:04:02 2015	(r294624)
+++ soc2013/def/crashdump-head/sys/kern/kern_shutdown.c	Mon Nov 30 22:06:11 2015	(r294625)
@@ -73,6 +73,7 @@
 #include <sys/watchdog.h>
 
 #include <crypto/rijndael/rijndael-api-fst.h>
+#include <crypto/sha2/sha2.h>
 
 #include <ddb/ddb.h>
 
@@ -148,8 +149,8 @@
 MALLOC_DEFINE(M_EKCD, "ekcd", "Encrypted kernel crash dumps data");
 
 struct kerneldumpcrypto {
-	uint8_t		kdc_algorithm;
-	uint8_t		kdc_iv[KERNELDUMP_IV_SIZE];
+	uint8_t		kdc_encryption;
+	uint8_t		kdc_iv[KERNELDUMP_IV_MAX_SIZE];
 	keyInstance	kdc_ki;
 	cipherInstance	kdc_ci;
 	off_t		kdc_nextoffset;
@@ -850,37 +851,40 @@
 
 #ifdef EKCD
 static struct kerneldumpcrypto *
-kerneldumpcrypto_create(uint8_t *key, uint32_t encryptedkeysize,
-    uint8_t *encryptedkey)
+kerneldumpcrypto_create(const uint8_t *key, uint8_t encryption,
+    uint32_t encryptedkeysize, const uint8_t *encryptedkey)
 {
 	struct kerneldumpcrypto *kdc;
-	int error;
 
 	kdc = malloc(sizeof(*kdc) + encryptedkeysize, M_EKCD,
 	    M_WAITOK | M_ZERO);
 
-	kdc->kdc_algorithm = CRYPTO_AES_CBC;
-	error = rijndael_makeKey(&kdc->kdc_ki, DIR_ENCRYPT,
-	    8 * KERNELDUMP_KEY_SIZE, key);
-	bzero(key, KERNELDUMP_KEY_SIZE);
-	if (error <= 0)
-		goto failed;
-
 	arc4rand(kdc->kdc_iv, sizeof(kdc->kdc_iv), 0);
-	error = rijndael_cipherInit(&kdc->kdc_ci, MODE_CBC, kdc->kdc_iv);
-	if (error <= 0)
+
+	kdc->kdc_encryption = encryption;
+	switch (kdc->kdc_encryption) {
+	case KERNELDUMP_ENC_AES_256_CBC:
+		if (rijndael_makeKey(&kdc->kdc_ki, DIR_ENCRYPT, 256, key) <= 0)
+			goto failed;
+		if (rijndael_cipherInit(&kdc->kdc_ci, MODE_CBC,
+		    kdc->kdc_iv) <= 0) {
+			goto failed;
+		}
+		break;
+	default:
 		goto failed;
+	}
 
 	kdc->kdc_encryptedkeysize = encryptedkeysize;
-	bcopy(encryptedkey, kdc->kdc_encryptedkey, kdc->kdc_encryptedkeysize);
 
-	kdc->kdc_dumpkeysize = (sizeof(kdc->kdc_algorithm) +
+	kdc->kdc_dumpkeysize = (sizeof(kdc->kdc_encryption) +
 	    sizeof(kdc->kdc_iv) + sizeof(kdc->kdc_encryptedkeysize) +
 	    kdc->kdc_encryptedkeysize + KERNELDUMP_BLOCK_SIZE - 1) /
 	    KERNELDUMP_BLOCK_SIZE * KERNELDUMP_BLOCK_SIZE;
 
 	return (kdc);
 failed:
+	bzero(kdc, sizeof(*kdc));
 	free(kdc, M_EKCD);
 	return (NULL);
 }
@@ -888,7 +892,17 @@
 static void
 kerneldumpcrypto_init(struct kerneldumpcrypto *kdc)
 {
+	uint8_t hash[SHA256_DIGEST_LENGTH];
+	SHA256_CTX ctx;
 
+	/*
+	 * When a user enters ddb it can write a crash dump multiple times.
+	 * Each time it should be encrypted using a different IV.
+	 */
+	SHA256_Init(&ctx);
+	SHA256_Update(&ctx, kdc->kdc_iv, sizeof(kdc->kdc_iv));
+	SHA256_Final(hash, &ctx);
+	bcopy(hash, kdc->kdc_iv, sizeof(kdc->kdc_iv));
 	kdc->kdc_nextoffset = 0;
 }
 #endif /* EKCD */
@@ -909,8 +923,8 @@
 /* Registration of dumpers */
 int
 set_dumper(struct dumperinfo *di, const char *devname, struct thread *td,
-    uint8_t encrypt, uint8_t *key, uint32_t encryptedkeysize,
-    uint8_t *encryptedkey)
+    uint8_t encryption, const uint8_t *key, uint32_t encryptedkeysize,
+    const uint8_t *encryptedkey)
 {
 	size_t wantcopy;
 	int error;
@@ -920,27 +934,28 @@
 		return (error);
 
 	if (di == NULL) {
-#ifdef EKCD
-		free(dumper.kdc, M_EKCD);
-#endif
-		bzero(&dumper, sizeof dumper);
-		dumpdevname[0] = '\0';
-		return (0);
+		error = 0;
+		goto cleanup;
 	}
 	if (dumper.dumper != NULL)
 		return (EBUSY);
 	dumper = *di;
 	dumper.kdc = NULL;
 
+	if (encryption != KERNELDUMP_ENC_NONE) {
 #ifdef EKCD
-	if (encrypt == 1) {
-		dumper.kdc = kerneldumpcrypto_create(key, encryptedkeysize,
-		    encryptedkey);
-		if (dumper.kdc == NULL)
-			return (EINVAL);
+		dumper.kdc = kerneldumpcrypto_create(key, encryption,
+		    encryptedkeysize, encryptedkey);
+		if (dumper.kdc == NULL) {
+			error = EINVAL;
+			goto cleanup;
+		}
 		kerneldumpcrypto_init(dumper.kdc);
-	}
+#else
+		error = EOPTNOTSUPP;
+		goto cleanup;
 #endif
+	}
 
 	wantcopy = strlcpy(dumpdevname, devname, sizeof(dumpdevname));
 	if (wantcopy >= sizeof(dumpdevname)) {
@@ -949,6 +964,17 @@
 	}
 
 	return (0);
+cleanup:
+#ifdef EKCD
+	if (dumper.kdc != NULL) {
+		bzero(dumper.kdc, sizeof(*dumper.kdc) +
+		    dumper.kdc->kdc_encryptedkeysize);
+		free(dumper.kdc, M_EKCD);
+	}
+#endif
+	bzero(&dumper, sizeof(dumper));
+	dumpdevname[0] = '\0';
+	return (error);
 }
 
 static int
@@ -968,6 +994,30 @@
 }
 
 #ifdef EKCD
+static int
+dump_encrypt(struct kerneldumpcrypto *kdc, const uint8_t *src, uint8_t *dst,
+    size_t size)
+{
+	int error;
+
+	switch (kdc->kdc_encryption) {
+	case KERNELDUMP_ENC_AES_256_CBC:
+		error = rijndael_blockEncrypt(&kdc->kdc_ci, &kdc->kdc_ki, src,
+		    8 * size, dst);
+		if (error <= 0)
+			return (EIO);
+		error = rijndael_cipherInit(&kdc->kdc_ci, MODE_CBC,
+		    dst + size - 16 /* IV size for AES-256-CBC */);
+		if (error <= 0)
+			return (EIO);
+		break;
+	default:
+		return (EINVAL);
+	}
+
+	return (0);
+}
+
 /* Encrypt data and call dumper. */
 static int
 dump_encrypted_write(struct dumperinfo *di, void *virtual, vm_offset_t physical,
@@ -997,7 +1047,10 @@
 	if ((length % KERNELDUMP_BLOCK_SIZE) != 0)
 		return (EINVAL);
 
-	/* Data have to be written continuously. */
+	/*
+	 * Data have to be written continuously becase we're encrypting using
+	 * CBC mode which has this assumption.
+	 */
 	if (kdc->kdc_nextoffset != 0 && kdc->kdc_nextoffset != offset)
 		return (EINVAL);
 
@@ -1008,14 +1061,9 @@
 			nbytes = sizeof(buf);
 		else
 			nbytes = length;
-		memcpy(buf, virtual, nbytes);
+		bcopy(virtual, buf, nbytes);
 
-		error = rijndael_blockEncrypt(&kdc->kdc_ci, &kdc->kdc_ki, buf,
-		    8 * nbytes, buf);
-		if (error <= 0)
-			return (EIO);
-		error = rijndael_cipherInit(&kdc->kdc_ci, MODE_CBC,
-		    buf + nbytes - KERNELDUMP_IV_SIZE);
+		error = dump_encrypt(kdc, buf, buf, nbytes);
 		if (error <= 0)
 			return (EIO);
 
@@ -1071,12 +1119,15 @@
 	return (dump_raw_write(di, kdh, physical, offset, sizeof(*kdh)));
 }
 
-#ifdef EKCD
 int
 dump_write_key(struct dumperinfo *di, vm_offset_t physical, off_t offset)
 {
+#ifndef EKCD
+	return (0);
+#else /* EKCD */
 	uint8_t *buf, *p;
 	struct kerneldumpcrypto *kdc;
+	uint32_t encryptedkeysize;
 	int ret;
 
 	kdc = di->kdc;
@@ -1086,28 +1137,22 @@
 	buf = malloc(kdc->kdc_dumpkeysize, M_EKCD, M_WAITOK | M_ZERO);
 
 	p = buf;
-	*p = kdc->kdc_algorithm;
-	p += sizeof(kdc->kdc_algorithm);
+	*p = kdc->kdc_encryption;
+	p += sizeof(kdc->kdc_encryption);
 	bcopy(kdc->kdc_iv, p, sizeof(kdc->kdc_iv));
 	p += sizeof(kdc->kdc_iv);
-	le32enc(p, kdc->kdc_encryptedkeysize);
-	p += sizeof(kdc->kdc_encryptedkeysize);
+	encryptedkeysize = htod32(kdc->kdc_encryptedkeysize);
+	bcopy(&encryptedkeysize, p, sizeof(encryptedkeysize));
+	p += sizeof(encryptedkeysize);
 	bcopy(kdc->kdc_encryptedkey, p, kdc->kdc_encryptedkeysize);
 	p += kdc->kdc_encryptedkeysize;
 
 	ret = dump_raw_write(di, buf, physical, offset, kdc->kdc_dumpkeysize);
+	bzero(buf, kdc->kdc_dumpkeysize);
 	free(buf, M_EKCD);
 	return (ret);
+#endif /* !EKCD */
 }
-#else /* !EKCD */
-int
-dump_write_key(struct dumperinfo *di __unused, vm_offset_t physical __unused,
-    off_t offset __unused)
-{
-
-	return (0);
-}
-#endif /* EKCD */
 
 void
 mkdumpheader(struct kerneldumpheader *kdh, char *magic, uint32_t archver,



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201511302206.tAUM6Cfh073251>