Index: sbin/decryptcore/decryptcore.c =================================================================== --- sbin/decryptcore/decryptcore.c +++ sbin/decryptcore/decryptcore.c @@ -119,7 +119,8 @@ 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 @@ 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 @@ 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)); Index: sbin/dumpon/dumpon.8 =================================================================== --- sbin/dumpon/dumpon.8 +++ sbin/dumpon/dumpon.8 @@ -28,7 +28,7 @@ .\" From: @(#)swapon.8 8.1 (Berkeley) 6/5/93 .\" $FreeBSD$ .\" -.Dd May 1, 2019 +.Dd May 3, 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 .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. @@ -381,10 +391,6 @@ .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 Index: sbin/dumpon/dumpon.c =================================================================== --- sbin/dumpon/dumpon.c +++ sbin/dumpon/dumpon.c @@ -276,7 +276,16 @@ 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 @@ 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, remove; uint8_t ins_idx; @@ -387,9 +396,21 @@ 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 @@ 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 @@ } #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) Index: sys/kern/kern_shutdown.c =================================================================== --- sys/kern/kern_shutdown.c +++ sys/kern/kern_shutdown.c @@ -80,6 +80,7 @@ #include #include +#include #include #include @@ -180,8 +181,16 @@ 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 @@ 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 @@ 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 @@ } 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; } @@ -1368,6 +1384,9 @@ return (EIO); } break; + case KERNELDUMP_ENC_CHACHA20: + chacha_encrypt_bytes(&kdc->kdc_chacha, buf, buf, size); + break; default: return (EINVAL); } Index: sys/sys/kerneldump.h =================================================================== --- sys/sys/kerneldump.h +++ sys/sys/kerneldump.h @@ -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