From owner-svn-soc-all@FreeBSD.ORG Fri Jul 20 17:25:15 2012 Return-Path: Delivered-To: svn-soc-all@FreeBSD.org Received: from socsvn.FreeBSD.org (unknown [IPv6:2001:4f8:fff6::2f]) by hub.freebsd.org (Postfix) with SMTP id 5A94E1065670 for ; Fri, 20 Jul 2012 17:25:13 +0000 (UTC) (envelope-from gpf@FreeBSD.org) Received: by socsvn.FreeBSD.org (sSMTP sendmail emulation); Fri, 20 Jul 2012 17:25:13 +0000 Date: Fri, 20 Jul 2012 17:25:13 +0000 From: gpf@FreeBSD.org To: svn-soc-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Message-Id: <20120720172513.5A94E1065670@hub.freebsd.org> Cc: Subject: socsvn commit: r239624 - soc2012/gpf/pefs_kmod/sbin/pefs X-BeenThere: svn-soc-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the entire Summer of Code repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 20 Jul 2012 17:25:15 -0000 Author: gpf Date: Fri Jul 20 17:25:12 2012 New Revision: 239624 URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=239624 Log: use openssl lib to sign .pefs.checksum for the moment, DSA and sha1 are used by default. future commit will probably allow all legal combinations of digest type and dsa/rsa .pefs.checksum's signature is stored in a different file during `addchecksum` action: .pefs.signature. The public key of DSA is stored in yet another file, .pefs.pkey. Since all trust falls upon .pefs.checksum, having .pefs.pkey in a readonly media seems like a must. next commit will contain verification code for `/sbin/pefs verify` action. Modified: soc2012/gpf/pefs_kmod/sbin/pefs/pefs_checksum.c soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.c soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.h Modified: soc2012/gpf/pefs_kmod/sbin/pefs/pefs_checksum.c ============================================================================== --- soc2012/gpf/pefs_kmod/sbin/pefs/pefs_checksum.c Fri Jul 20 16:56:34 2012 (r239623) +++ soc2012/gpf/pefs_kmod/sbin/pefs/pefs_checksum.c Fri Jul 20 17:25:12 2012 (r239624) @@ -53,7 +53,11 @@ #include +#include +#include #include +#include +#include #include "pefs_ctl.h" @@ -72,6 +76,11 @@ #define PEFS_HASH_BYTE_ALIGNMENT 512 #define PEFS_EXTRA_TABLE_SIZE 15 +#define PEFS_PLEN 1024 +#define PEFS_SEED_LEN 20 + +#define PEFS_BUFISZE 512 + /* tail that contains a single file's checksums */ TAILQ_HEAD(checksum_head, checksum); /* tail that contains all file headers that require integrity checking */ @@ -1419,20 +1428,154 @@ strlcpy(cfhp->hash_algo, algo, sizeof(cfhp->hash_algo)); } +static EVP_PKEY * +pefs_generate_dsa(FILE *pkfp) +{ + unsigned char seed[PEFS_SEED_LEN]; + DSA *dsa; + EVP_PKEY *pkey; + int rval; + + RAND_bytes(seed, sizeof(seed)); + dsa = DSA_generate_parameters(PEFS_PLEN, seed, sizeof(seed), NULL, + NULL, NULL, NULL); + if (dsa == NULL) { + pefs_warn("error generating dsa parameters"); + return (NULL); + } + + rval = DSA_generate_key(dsa); + if (rval != 1) { + pefs_warn("error generating dsa key"); + DSA_free(dsa); + return (NULL); + } + + pkey = EVP_PKEY_new(); + if (pkey == NULL) { + pefs_warn("error allocating a pkey"); + DSA_free(dsa); + return (NULL); + } + rval = EVP_PKEY_assign_DSA(pkey, dsa); + if (rval != 1) { + pefs_warn("error generating dsa key"); + EVP_PKEY_free(pkey); + DSA_free(dsa); + return (NULL); + } + + rval = PEM_write_DSA_PUBKEY(pkfp, dsa); + if (rval != 1) { + pefs_warn("error writing dsa pubkey"); + EVP_PKEY_free(pkey); + DSA_free(dsa); + return (NULL); + } + + return (pkey); +} + +//int PEM_write_PUBKEY(FILe *, pkey *) +//int PEM_read_DSA_PUBKEY + +//Certificates using any digest algorithm are compatible with RSA sign keys; +//however, only SHA and SHA1 certificates are compatible with DSA sign keys. +static int +pefs_sign_file(int fd, FILE *pkfp, FILE *signfp) +{ + unsigned char buf[PEFS_BUFISZE]; + EVP_MD_CTX ctx; + const EVP_MD *md; + EVP_PKEY *pkey; + unsigned char *sign; + unsigned int sign_len; + int bytes, error, rval; + + pkey = pefs_generate_dsa(pkfp); + if (pkey == NULL) + return (PEFS_ERR_SYS); + + md = EVP_dss1(); + if (md == NULL) { + pefs_warn("error acquiring digest type"); + EVP_PKEY_free(pkey); + return (PEFS_ERR_GENERIC); + } + + EVP_SignInit(&ctx, md); + + error = lseek(fd, 0, SEEK_SET); + if (error != 0) { + warn("lseek: "); + EVP_PKEY_free(pkey); + return (PEFS_ERR_SYS); + } + + while ((bytes = read(fd, buf, sizeof(buf))) > 0) { + rval = EVP_SignUpdate(&ctx, buf, bytes); + if (rval != 1) { + pefs_warn("error updating sign data"); + EVP_PKEY_free(pkey); + return (PEFS_ERR_SYS); + } + } + + if (bytes == -1) { + warn("read error"); + EVP_PKEY_free(pkey); + return (PEFS_ERR_IO); + } + + sign = malloc(EVP_PKEY_size(pkey)); + if (sign == NULL) { + pefs_warn("memory allocation error"); + EVP_PKEY_free(pkey); + return (PEFS_ERR_SYS); + } + + rval = EVP_SignFinal(&ctx, sign, &sign_len, pkey); + if (rval != 1) { + pefs_warn("error generating signature"); + free(sign); + EVP_PKEY_free(pkey); + return (PEFS_ERR_SYS); + } + + if (fwrite(sign, sizeof(char), sign_len, signfp) < sign_len) { + pefs_warn("error writing signature"); + free(sign); + EVP_PKEY_free(pkey); + return (PEFS_ERR_IO); + } + + free(sign); + EVP_PKEY_free(pkey); + + return (0); +} + /* * If .pefs.checksum is created inside pefs mounted fs, then it will obtain an * encrypted filename & encrypted data, which is unacceptable. User should * create checksum file outside of filesystem and then copy it by hand. + * Alongside with the checksum file, we will create two additional files as + * placeholders for the public key and the file's digital signature. */ static int -pefs_open_checksum_file(int *fdp, char *fsroot, char *csm_path) +pefs_open_checksum_files(int *fdp, char *fsroot, char *csm_path, FILE **pkfpp, + char *pk_path, FILE **signfpp, char *sign_path) { struct statfs pefs_fs, checksum_fs; + FILE *pkfp, *signfp; int fd; *fdp = -1; + *pkfpp = NULL; + *signfpp = NULL; - fd = open(csm_path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); + /* create checksum file */ + fd = open(csm_path, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); if (fd == -1) { warn("cannot open %s", csm_path); return (PEFS_ERR_IO); @@ -1456,6 +1599,23 @@ csm_path, pefs_fs.f_mntonname); return (PEFS_ERR_INVALID); } + + /* create files for the public key and .pefs.checksum's signature */ + pkfp = fopen(pk_path, "wx"); + if (pkfp == NULL) { + warn("cannot open %s", pk_path); + return (PEFS_ERR_SYS); + } + + *pkfpp = pkfp; + + signfp = fopen(sign_path, "wx"); + if (signfp == NULL) { + warn("cannot open %s", sign_path); + return (PEFS_ERR_SYS); + } + + *signfpp = signfp; return (0); } @@ -1468,11 +1628,12 @@ */ int pefs_create_checksum_file(FILE *fpin, char *fsroot, char *csm_path, - const char *algo, int flags) + char *pk_path, char *sign_path, const char *algo, int flags) { struct cuckoo_hash_table checksum_hash_table; struct checksum_file_header cfh; const EVP_MD *md; + FILE *pkfp, *signfp; int error, fdout; uint8_t hash_len; @@ -1487,7 +1648,8 @@ pefs_init_hash_table(&checksum_hash_table); - error = pefs_open_checksum_file(&fdout, fsroot, csm_path); + error = pefs_open_checksum_files(&fdout, fsroot, csm_path, &pkfp, pk_path, + &signfp, sign_path); if (error != 0) goto out; @@ -1499,6 +1661,10 @@ pefs_init_checksum_file_header(&cfh, algo, hash_len, &checksum_hash_table); error = pefs_write_checksum_file(fdout, &cfh, &checksum_hash_table); + if (error != 0) + goto out; + + error = pefs_sign_file(fdout, pkfp, signfp); out: if (fdout >= 0) { @@ -1506,6 +1672,16 @@ if (error != 0) unlink(csm_path); } + if (pkfp != NULL) { + fclose(pkfp); + if (error != 0) + unlink(pk_path); + } + if (signfp != NULL) { + fclose(signfp); + if (error != 0) + unlink(sign_path); + } pefs_free_hash_table(&checksum_hash_table); return (error); Modified: soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.c ============================================================================== --- soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.c Fri Jul 20 16:56:34 2012 (r239623) +++ soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.c Fri Jul 20 17:25:12 2012 (r239624) @@ -1033,8 +1033,9 @@ static int pefs_addchecksum(int argc, char *argv[]) { - char fsroot[MAXPATHLEN]; - char csm_path[MAXPATHLEN]; + char fsroot[MAXPATHLEN + 1]; + char csm_path[MAXPATHLEN + 1], pk_path[MAXPATHLEN + 1]; + char sign_path[MAXPATHLEN + 1]; struct stat sb; FILE *fpin; int error, flags, i, j; @@ -1046,6 +1047,8 @@ algo = supported_digests[0]; /* by default create checksum file under $PWD */ snprintf(csm_path, sizeof(csm_path), "./%s", PEFS_FILE_CHECKSUM); + snprintf(pk_path, sizeof(pk_path), "./%s", PEFS_FILE_PKEY); + snprintf(sign_path, sizeof(sign_path), "./%s", PEFS_FILE_SIGNATURE); while ((i = getopt(argc, argv, "fa:i:p:")) != -1) switch(i) { @@ -1088,7 +1091,10 @@ snprintf(csm_path, sizeof(csm_path), "%s/%s", optarg, PEFS_FILE_CHECKSUM); - + snprintf(pk_path, sizeof(pk_path), "%s/%s", optarg, + PEFS_FILE_PKEY); + snprintf(sign_path, sizeof(sign_path), "%s/%s", optarg, + PEFS_FILE_SIGNATURE); break; default: if (fpin != NULL) @@ -1100,7 +1106,8 @@ initfsroot(argc, argv, 0, fsroot, sizeof(fsroot)); - error = pefs_create_checksum_file(fpin, fsroot, csm_path, algo, flags); + error = pefs_create_checksum_file(fpin, fsroot, csm_path, pk_path, + sign_path,algo, flags); out: if (fpin != NULL) @@ -1137,7 +1144,7 @@ pefs_verify(int argc, char *argv[]) { struct stat sb; - char fsroot[MAXPATHLEN]; + char fsroot[MAXPATHLEN + 1]; int error, fdin, flags, i; flags = PEFS_VERIFY; Modified: soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.h ============================================================================== --- soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.h Fri Jul 20 16:56:34 2012 (r239623) +++ soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.h Fri Jul 20 17:25:12 2012 (r239624) @@ -43,6 +43,8 @@ #define PEFS_FILE_KEYCHAIN ".pefs.db" #define PEFS_FILE_KEYCONF ".pefs.conf" #define PEFS_FILE_CHECKSUM ".pefs.checksum" +#define PEFS_FILE_SIGNATURE ".pefs.signature" +#define PEFS_FILE_PKEY ".pefs.pkey" #define PEFS_NOKEY 0x0001 #define PEFS_UNMOUNTED 0x0002 @@ -101,7 +103,7 @@ const struct pefs_xkey *xk_parent); uintmax_t pefs_keyid_as_int(char *keyid); int pefs_create_checksum_file(FILE *fpin, char *fsroot, char *csm_path, - const char *algo, int flags); + char *pk_path, char *sign_path, const char *algo, int flags); int pefs_verify_checksum(int fdin, char *fsroot, int flags); int pefs_name_pton(char const *src, size_t srclen, u_char *target,