socsvn commit: r294625 - in soc2013/def/crashdump-head: sbin/decryptcore sys/conf sys/kern
def at FreeBSD.org
def at FreeBSD.org
Mon Nov 30 22:06:14 UTC 2015
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,
More information about the svn-soc-all
mailing list