From owner-svn-src-all@freebsd.org Sat Jul 11 06:51:44 2020 Return-Path: Delivered-To: svn-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 40138357FF5; Sat, 11 Jul 2020 06:51:44 +0000 (UTC) (envelope-from tsoome@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4B3gYr0hLGz4S7H; Sat, 11 Jul 2020 06:51:44 +0000 (UTC) (envelope-from tsoome@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id EEEE6EFBC; Sat, 11 Jul 2020 06:51:43 +0000 (UTC) (envelope-from tsoome@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id 06B6phNW006412; Sat, 11 Jul 2020 06:51:43 GMT (envelope-from tsoome@FreeBSD.org) Received: (from tsoome@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id 06B6pgca006405; Sat, 11 Jul 2020 06:51:42 GMT (envelope-from tsoome@FreeBSD.org) Message-Id: <202007110651.06B6pgca006405@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: tsoome set sender to tsoome@FreeBSD.org using -f From: Toomas Soome Date: Sat, 11 Jul 2020 06:51:42 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r363090 - in head/stand: i386/gptboot libsa/geli X-SVN-Group: head X-SVN-Commit-Author: tsoome X-SVN-Commit-Paths: in head/stand: i386/gptboot libsa/geli X-SVN-Commit-Revision: 363090 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.33 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 11 Jul 2020 06:51:44 -0000 Author: tsoome Date: Sat Jul 11 06:51:42 2020 New Revision: 363090 URL: https://svnweb.freebsd.org/changeset/base/363090 Log: loader: implement GELI writes Bug: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=247482 This patch is based on initial work from allanjude. PR: 247482 Obtained from: https://reviews.freebsd.org/D10236 Differential Revision: https://reviews.freebsd.org/D25605 Modified: head/stand/i386/gptboot/gptboot.c head/stand/libsa/geli/geliboot.c head/stand/libsa/geli/geliboot.h head/stand/libsa/geli/geliboot_crypto.c head/stand/libsa/geli/geliboot_internal.h head/stand/libsa/geli/gelidev.c Modified: head/stand/i386/gptboot/gptboot.c ============================================================================== --- head/stand/i386/gptboot/gptboot.c Sat Jul 11 03:39:44 2020 (r363089) +++ head/stand/i386/gptboot/gptboot.c Sat Jul 11 06:51:42 2020 (r363090) @@ -610,7 +610,7 @@ dskread(void *buf, daddr_t lba, unsigned nblk) #ifdef LOADER_GELI_SUPPORT if (err == 0 && gdsk.gdev != NULL) { /* Decrypt */ - if (geli_read(gdsk.gdev, lba * DEV_BSIZE, buf, + if (geli_io(gdsk.gdev, GELI_DECRYPT, lba * DEV_BSIZE, buf, nblk * DEV_BSIZE)) return (err); } Modified: head/stand/libsa/geli/geliboot.c ============================================================================== --- head/stand/libsa/geli/geliboot.c Sat Jul 11 03:39:44 2020 (r363089) +++ head/stand/libsa/geli/geliboot.c Sat Jul 11 06:51:42 2020 (r363090) @@ -310,7 +310,8 @@ found_key: } int -geli_read(struct geli_dev *gdev, off_t offset, u_char *buf, size_t bytes) +geli_io(struct geli_dev *gdev, geli_op_t enc, off_t offset, u_char *buf, + size_t bytes) { u_char iv[G_ELI_IVKEYLEN]; u_char *pbuf; @@ -343,12 +344,13 @@ geli_read(struct geli_dev *gdev, off_t offset, u_char keyno = (dstoff >> G_ELI_KEY_SHIFT) / secsize; g_eli_key_fill(&gdev->sc, &gkey, keyno); - error = geliboot_crypt(gdev->sc.sc_ealgo, 0, pbuf, secsize, + error = geliboot_crypt(gdev->sc.sc_ealgo, enc, pbuf, secsize, gkey.gek_key, gdev->sc.sc_ekeylen, iv); if (error != 0) { explicit_bzero(&gkey, sizeof(gkey)); - printf("Failed to decrypt in geli_read()!"); + printf("%s: Failed to %s!", __func__, + enc ? "encrypt" : "decrypt"); return (error); } pbuf += secsize; Modified: head/stand/libsa/geli/geliboot.h ============================================================================== --- head/stand/libsa/geli/geliboot.h Sat Jul 11 03:39:44 2020 (r363089) +++ head/stand/libsa/geli/geliboot.h Sat Jul 11 06:51:42 2020 (r363090) @@ -50,6 +50,11 @@ #define GELI_KEYBUF_SIZE (sizeof(struct keybuf) + \ (GELI_MAX_KEYS * sizeof(struct keybuf_ent))) +typedef enum geli_op { + GELI_DECRYPT, + GELI_ENCRYPT +} geli_op_t; + extern void pwgets(char *buf, int n, int hide); typedef u_char geli_ukey[G_ELI_USERKEYLEN]; @@ -73,9 +78,10 @@ struct preloaded_file; typedef int (*geli_readfunc)(void *vdev, void *readpriv, off_t offbytes, void *buf, size_t sizebytes); -struct geli_dev * geli_taste(geli_readfunc readfunc, void *readpriv, +struct geli_dev *geli_taste(geli_readfunc readfunc, void *readpriv, daddr_t lastsector, const char *namefmt, ...); -int geli_read(struct geli_dev *gdev, off_t offset, u_char *buf, size_t bytes); +int geli_io(struct geli_dev *gdev, geli_op_t, off_t offset, u_char *buf, + size_t bytes); int geli_havekey(struct geli_dev *gdev); int geli_passphrase(struct geli_dev *gdev, char *pw); Modified: head/stand/libsa/geli/geliboot_crypto.c ============================================================================== --- head/stand/libsa/geli/geliboot_crypto.c Sat Jul 11 03:39:44 2020 (r363089) +++ head/stand/libsa/geli/geliboot_crypto.c Sat Jul 11 06:51:42 2020 (r363090) @@ -35,7 +35,7 @@ #include "geliboot.h" int -geliboot_crypt(u_int algo, int enc, u_char *data, size_t datasize, +geliboot_crypt(u_int algo, geli_op_t enc, u_char *data, size_t datasize, const u_char *key, size_t keysize, u_char *iv) { keyInstance aeskey; @@ -49,7 +49,7 @@ geliboot_crypt(u_int algo, int enc, u_char *data, size err = rijndael_makeKey(&aeskey, !enc, keysize, (const char *)key); if (err < 0) { - printf("Failed to setup decryption keys: %d\n", err); + printf("Failed to setup crypo keys: %d\n", err); return (err); } @@ -59,18 +59,20 @@ geliboot_crypt(u_int algo, int enc, u_char *data, size return (err); } - if (enc == 0) { - /* decrypt */ + switch (enc) { + case GELI_DECRYPT: blks = rijndael_blockDecrypt(&cipher, &aeskey, data, datasize * 8, data); - } else { - /* encrypt */ + break; + case GELI_ENCRYPT: blks = rijndael_blockEncrypt(&cipher, &aeskey, data, datasize * 8, data); + break; } if (datasize != (blks / 8)) { - printf("Failed to decrypt the entire input: " - "%u != %zu\n", blks, datasize); + printf("Failed to %s the entire input: %u != %zu\n", + enc ? "decrypt" : "encrypt", + blks, datasize); return (1); } break; @@ -82,16 +84,16 @@ geliboot_crypt(u_int algo, int enc, u_char *data, size enc_xform_aes_xts.reinit(ctxp, iv); switch (enc) { - case 0: /* decrypt */ + case GELI_DECRYPT: for (i = 0; i < datasize; i += AES_XTS_BLOCKSIZE) { enc_xform_aes_xts.decrypt(ctxp, data + i, data + i); } break; - case 1: /* encrypt */ + case GELI_ENCRYPT: for (i = 0; i < datasize; i += AES_XTS_BLOCKSIZE) { enc_xform_aes_xts.encrypt(ctxp, data + i, - data + 1); + data + i); } break; } @@ -105,7 +107,7 @@ geliboot_crypt(u_int algo, int enc, u_char *data, size } static int -g_eli_crypto_cipher(u_int algo, int enc, u_char *data, size_t datasize, +g_eli_crypto_cipher(u_int algo, geli_op_t enc, u_char *data, size_t datasize, const u_char *key, size_t keysize) { u_char iv[keysize]; @@ -123,7 +125,8 @@ g_eli_crypto_encrypt(u_int algo, u_char *data, size_t if (algo == CRYPTO_AES_XTS) algo = CRYPTO_AES_CBC; - return (g_eli_crypto_cipher(algo, 1, data, datasize, key, keysize)); + return (g_eli_crypto_cipher(algo, GELI_ENCRYPT, data, datasize, key, + keysize)); } int @@ -135,5 +138,6 @@ g_eli_crypto_decrypt(u_int algo, u_char *data, size_t if (algo == CRYPTO_AES_XTS) algo = CRYPTO_AES_CBC; - return (g_eli_crypto_cipher(algo, 0, data, datasize, key, keysize)); + return (g_eli_crypto_cipher(algo, GELI_DECRYPT, data, datasize, key, + keysize)); } Modified: head/stand/libsa/geli/geliboot_internal.h ============================================================================== --- head/stand/libsa/geli/geliboot_internal.h Sat Jul 11 03:39:44 2020 (r363089) +++ head/stand/libsa/geli/geliboot_internal.h Sat Jul 11 06:51:42 2020 (r363090) @@ -55,6 +55,8 @@ #define STAND_H /* We don't want stand.h in {gpt,zfs,gptzfs}boot */ #include +#include "geliboot.h" + #define GELIDEV_NAMELEN 32 struct geli_dev { @@ -65,7 +67,7 @@ struct geli_dev { char *name; /* for prompting; it ends in ':' */ }; -int geliboot_crypt(u_int algo, int enc, u_char *data, size_t datasize, +int geliboot_crypt(u_int algo, geli_op_t enc, u_char *data, size_t datasize, const u_char *key, size_t keysize, u_char *iv); #endif /* _GELIBOOT_INTERNAL_H_ */ Modified: head/stand/libsa/geli/gelidev.c ============================================================================== --- head/stand/libsa/geli/gelidev.c Sat Jul 11 03:39:44 2020 (r363089) +++ head/stand/libsa/geli/gelidev.c Sat Jul 11 06:51:42 2020 (r363090) @@ -115,10 +115,6 @@ geli_dev_strategy(void *devdata, int rw, daddr_t blk, char *iobuf; int rc; - /* We only handle reading; no write support. */ - if ((rw & F_MASK) != F_READ) - return (EOPNOTSUPP); - gdesc = (struct geli_devdesc *)devdata; /* @@ -139,34 +135,63 @@ geli_dev_strategy(void *devdata, int rw, daddr_t blk, alnsize = alnend - alnstart; /* - * If alignment requires us to read more than the size of the provided - * buffer, allocate a temporary buffer. + * If alignment requires us to read/write more than the size of the + * provided buffer, allocate a temporary buffer. + * The writes will always get temporary buffer because of encryption. */ - if (alnsize <= size) + if (alnsize <= size && (rw & F_MASK) == F_READ) iobuf = buf; else if ((iobuf = malloc(alnsize)) == NULL) return (ENOMEM); - /* - * Read the encrypted data using the host provider, then decrypt it. - */ - rc = gdesc->hdesc->dd.d_dev->dv_strategy(gdesc->hdesc, rw, - alnstart / DEV_BSIZE, alnsize, iobuf, NULL); - if (rc != 0) - goto out; - rc = geli_read(gdesc->gdev, alnstart, iobuf, alnsize); - if (rc != 0) - goto out; + switch (rw & F_MASK) { + case F_READ: + /* + * Read the encrypted data using the host provider, + * then decrypt it. + */ + rc = gdesc->hdesc->dd.d_dev->dv_strategy(gdesc->hdesc, rw, + alnstart / DEV_BSIZE, alnsize, iobuf, NULL); + if (rc != 0) + goto out; + rc = geli_io(gdesc->gdev, GELI_DECRYPT, alnstart, iobuf, + alnsize); + if (rc != 0) + goto out; - /* - * If we had to use a temporary buffer, copy the requested part of the - * data to the caller's buffer. - */ - if (iobuf != buf) - memcpy(buf, iobuf + (reqstart - alnstart), size); + /* + * If we had to use a temporary buffer, copy the requested + * part of the data to the caller's buffer. + */ + if (iobuf != buf) + memcpy(buf, iobuf + (reqstart - alnstart), size); - if (rsize != NULL) - *rsize = size; + if (rsize != NULL) + *rsize = size; + break; + case F_WRITE: + if (iobuf != buf) { + /* Read, decrypt, then modify. */ + rc = gdesc->hdesc->dd.d_dev->dv_strategy(gdesc->hdesc, + F_READ, alnstart / DEV_BSIZE, alnsize, iobuf, NULL); + if (rc != 0) + goto out; + rc = geli_io(gdesc->gdev, GELI_DECRYPT, alnstart, iobuf, + alnsize); + if (rc != 0) + goto out; + /* Copy data to iobuf */ + memcpy(iobuf + (reqstart - alnstart), buf, size); + } + + /* Encrypt and write it. */ + rc = geli_io(gdesc->gdev, GELI_ENCRYPT, alnstart, iobuf, + alnsize); + if (rc != 0) + goto out; + rc = gdesc->hdesc->dd.d_dev->dv_strategy(gdesc->hdesc, + rw, alnstart / DEV_BSIZE, alnsize, iobuf, NULL); + } out: if (iobuf != buf) free(iobuf);