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>