Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 22 May 2012 18:20:39 +0000
From:      gpf@FreeBSD.org
To:        svn-soc-all@FreeBSD.org
Subject:   socsvn commit: r236147 - soc2012/gpf/pefs_kmod/sbin/pefs
Message-ID:  <20120522182039.3200E106564A@hub.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: gpf
Date: Tue May 22 18:20:38 2012
New Revision: 236147
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=236147

Log:
  Create in memory database filled with file headers & checksums.
  Next step is to write database to .pefs.checksum.
  
  Note: Temporarily, inode numbers are used as file identifiers and
  size of hash table equals to number of elements.
  

Added:
  soc2012/gpf/pefs_kmod/sbin/pefs/pefs_checksum.c
Modified:
  soc2012/gpf/pefs_kmod/sbin/pefs/Makefile
  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/Makefile
==============================================================================
--- soc2012/gpf/pefs_kmod/sbin/pefs/Makefile	Tue May 22 17:11:18 2012	(r236146)
+++ soc2012/gpf/pefs_kmod/sbin/pefs/Makefile	Tue May 22 18:20:38 2012	(r236147)
@@ -5,7 +5,7 @@
 .PATH:	${SYS}/crypto/hmac ${SYS}/crypto/rijndael ${SYS}/crypto/sha2
 
 PROG=	pefs
-SRCS=	pefs_ctl.c pefs_key.c pefs_keychain.c pefs_subr.c
+SRCS=	pefs_ctl.c pefs_key.c pefs_keychain.c pefs_subr.c pefs_checksum.c
 SRCS+=	hmac_sha512.c sha2.c
 SRCS+=	rijndael-api.c rijndael-api-fst.c rijndael-alg-fst.c
 SRCS+=	pkcs5v2.c
@@ -17,7 +17,7 @@
 DEBUG_FLAGS+= -g
 
 DPADD=  ${LIBUTIL}
-LDADD=  -lutil
+LDADD=  -lutil -lcrypto
 
 BINDIR?= /sbin
 

Added: soc2012/gpf/pefs_kmod/sbin/pefs/pefs_checksum.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ soc2012/gpf/pefs_kmod/sbin/pefs/pefs_checksum.c	Tue May 22 18:20:38 2012	(r236147)
@@ -0,0 +1,443 @@
+/*-
+ * Copyright (c) 2012 Efstratios Karatzas
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/mount.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <err.h>
+
+#include <fs/pefs/pefs.h>
+
+#include <openssl/evp.h>
+
+#include "pefs_ctl.h"
+
+#define PEFS_INTEGRITY_DEBUG
+#if defined (PEFS_INTEGRITY_DEBUG)
+#define dprintf(a)		printf a
+#else
+#define dprintf(a)      (void)0
+#endif
+
+LIST_HEAD(file_header_head, file_header);
+TAILQ_HEAD(checksum_head, checksum);
+
+struct checksum {
+	unsigned char *hash;
+	TAILQ_ENTRY(checksum) checksum_entries;
+};
+
+struct file_header {
+	uint32_t nhashes;
+	uint64_t file_id;
+	char path[MAXPATHLEN];
+	LIST_ENTRY(file_header) bucket_entries;
+	struct checksum_head checksums;
+};
+
+struct bucket {
+	struct file_header_head file_headers;
+	uint32_t nelements;
+};
+
+struct hash_table {
+	struct bucket *buckets;
+	uint32_t size;
+};
+
+/*
+ * XXXgpf: dbg info:
+ * man page example(sha256) 318b20b83a6730b928c46163a2a1cefee4466132731c95c39613acb547ccb715
+ * "Test Message\n" + "Hello World\n"
+ */
+static int
+pefs_compute_file_checksums(struct file_header *fhp, const EVP_MD *md,
+	uint8_t hash_len)
+{
+	char buf[PEFS_SECTOR_SIZE];
+	EVP_MD_CTX mdctx;
+	int md_len, i, fd, bytes_read;
+	struct checksum *csp;
+
+	TAILQ_INIT(&(fhp->checksums));
+
+	fd = open(fhp->path, O_RDONLY);
+	if (fd < 0) {
+		warn("failed to open file: %s", fhp->path);
+		return (PEFS_ERR_IO);
+	}
+
+	fhp->nhashes = 0;
+	while ((bytes_read = read(fd, buf, sizeof(buf))) > 0) {
+		EVP_MD_CTX_init(&mdctx);
+		EVP_DigestInit_ex(&mdctx, md, NULL);
+		EVP_DigestUpdate(&mdctx, buf, bytes_read);
+
+		dprintf(("read %d bytes\n", bytes_read));
+		for (i=0; i<bytes_read; i++) dprintf(("%c", buf[i]));
+
+		csp = malloc(sizeof(struct checksum));
+		if (csp == NULL) {
+			pefs_warn("memory allocation error");
+			close(fd);
+			return (PEFS_ERR_SYS);
+		}
+		csp->hash = malloc(hash_len);
+		if (csp->hash == NULL) {
+			pefs_warn("memory allocation error");
+			close(fd);
+			return (PEFS_ERR_SYS);
+		}
+
+		EVP_DigestFinal_ex(&mdctx, csp->hash, &md_len);
+
+		dprintf(("Digest is: "));
+		for (i = 0; i < md_len; i++) dprintf(("%02x", csp->hash[i]));
+		dprintf(("\n"));
+
+		EVP_MD_CTX_cleanup(&mdctx);
+
+		TAILQ_INSERT_TAIL(&(fhp->checksums), csp, checksum_entries);
+		fhp->nhashes++;
+	}
+
+	close(fd);
+	return (0);
+}
+
+static int
+pefs_count_file_entries(FILE *fpin, uint32_t *nelementsp)
+{
+	char buf[MAXPATHLEN + 1];
+	uint32_t nfiles;
+
+	nfiles = 0;
+
+	while (fgets(buf, sizeof(buf), fpin) != NULL) {
+		nfiles++;
+	}
+
+	if (feof(fpin) == 0) {
+		warn("error reading input");
+		return (PEFS_ERR_IO);
+	}
+
+	fseek(fpin, 0, SEEK_SET);
+	*nelementsp = nfiles;
+
+	return (0);
+}
+
+static int
+pefs_allocate_hash_table(struct hash_table *checksum_hash_tablep, uint32_t nelements)
+{
+	uint32_t i;
+
+	/*
+	 * XXXgpf: needs optimization
+	 */
+	checksum_hash_tablep->size = nelements;
+	checksum_hash_tablep->buckets = malloc (nelements * sizeof(struct bucket));
+
+	if (checksum_hash_tablep->buckets == NULL) {
+		pefs_warn("memory allocation error");
+		return (PEFS_ERR_SYS);
+	}
+
+	for (i = 0; i < checksum_hash_tablep->size; i++) {
+		checksum_hash_tablep->buckets[i].nelements = 0;
+		LIST_INIT(&(checksum_hash_tablep->buckets[i].file_headers));
+	}
+
+	return (0);
+}
+
+static int
+pefs_add_to_bucket(struct bucket *bucketp, struct file_header *fhp)
+{
+	struct file_header *elementp;
+	uint32_t i;
+
+	i = 1;
+
+	if (bucketp->nelements == 0)
+		LIST_INSERT_HEAD(&(bucketp->file_headers), fhp, bucket_entries);
+	else
+		LIST_FOREACH(elementp, &(bucketp->file_headers), bucket_entries) {
+			if (elementp->file_id == fhp->file_id) {
+				warn("file identifier collision detected between files: %s & %s",
+						fhp->path, elementp->path);
+				return (PEFS_ERR_EXIST);
+			}
+
+			if (fhp->file_id < elementp->file_id) {
+				LIST_INSERT_BEFORE(elementp, fhp, bucket_entries);
+				break;
+			}
+			else if (i++ == bucketp->nelements) {
+				LIST_INSERT_AFTER(elementp, fhp, bucket_entries);
+				break;
+			}
+		}
+
+	bucketp->nelements++;
+	return (0);
+}
+
+static struct bucket *
+pefs_find_bucket(struct hash_table *checksum_hash_tablep, struct file_header *fhp)
+{
+	uint32_t nbucket;
+
+	nbucket = fhp->file_id % checksum_hash_tablep->size;
+	dprintf(("goto bucket %d\n", nbucket));
+	return (&(checksum_hash_tablep->buckets[nbucket]));
+}
+
+static int
+pefs_add_to_hash_table(struct hash_table *checksum_hash_tablep,
+	struct file_header *fhp)
+{
+	return (pefs_add_to_bucket(pefs_find_bucket(checksum_hash_tablep, fhp), fhp));
+}
+
+/* for debugging purposes */
+static void
+pefs_print_hash_table(struct hash_table *checksum_hash_tablep, uint8_t hash_len)
+{
+	struct file_header *fhp;
+	struct checksum *csp;
+	uint32_t i,j;
+
+	dprintf(("\n+++Printing Hash Table+++\n\n"));
+	for (i = 0; i < checksum_hash_tablep->size; i++) {
+		dprintf(("\nbucket %d with elements: %u\n", i, checksum_hash_tablep->buckets[i].nelements));
+		LIST_FOREACH(fhp, &(checksum_hash_tablep->buckets[i].file_headers), bucket_entries) {
+			dprintf(("\tpath=%s!\t id = %d!\tnhashes = %d\n", fhp->path, (int)fhp->file_id, fhp->nhashes));
+			TAILQ_FOREACH(csp, &(fhp->checksums), checksum_entries) {
+				dprintf(("\t\tdigest="));
+				for (j = 0; j < hash_len; j++)
+					dprintf(("%02x", csp->hash[j]));
+				dprintf(("\n"));
+			}
+		}
+	}
+}
+
+static int
+pefs_get_file_id(struct file_header *fhp)
+{
+	struct stat sb;
+
+	if (stat(fhp->path, &sb) != 0) {
+		warn("cannot stat file %s", fhp->path);
+		return (PEFS_ERR_SYS);
+	}
+	/*
+	 * XXXgpf: This is only temporary since retrieving the file's inode number
+	 * is way simpler than retrieving the checksum value from encrypted filename.
+	 * I'm thinking of an ioctl(), we'll see.
+	 */
+	fhp->file_id = sb.st_ino;
+	return (0);
+}
+
+static int
+pefs_file_semantic_checks(struct file_header *fhp, struct statfs *fsp)
+{
+	struct stat sb;
+	struct statfs this_fs;
+
+	if (stat(fhp->path, &sb) != 0) {
+		warn("cannot stat file %s", fhp->path);
+		return (PEFS_ERR_SYS);
+	}
+
+	if (statfs(fhp->path, &this_fs) == -1) {
+		pefs_warn("statfs failed: %s: %s", fhp->path, strerror(errno));
+		return (PEFS_ERR_SYS);
+	}
+
+	if (S_ISREG(sb.st_mode) == 0) {
+		pefs_warn("filename: %s is not a regular file", fhp->path);
+		return (PEFS_ERR_INVALID);
+	}
+
+	if ((fsp->f_fsid.val[0] != this_fs.f_fsid.val[0]) ||
+		(fsp->f_fsid.val[1] != this_fs.f_fsid.val[1])) {
+		pefs_warn("filename: %s does not reside in filesystem %s",
+			fhp->path, fsp->f_mntonname);
+		return (PEFS_ERR_INVALID);
+	}
+	return (0);
+}
+
+static struct file_header *
+pefs_next_file(FILE *fpin, int *error)
+{
+	char buf[MAXPATHLEN + 1];
+	struct file_header *fhp;
+
+	if (fgets(buf, sizeof(buf), fpin) == NULL) {
+		if (feof(fpin))
+			*error = 0;
+		else {
+			*error = PEFS_ERR_IO;
+			warn("error reading input");
+		}
+		return (NULL);
+	}
+
+	if (buf[strnlen(buf, sizeof(buf)) - 1] == '\n')
+		buf[strnlen(buf, sizeof(buf)) - 1] = '\0';
+	dprintf(("\nnext buf=%s!\n", buf));
+
+	fhp = malloc(sizeof(struct file_header));
+	if (fhp == NULL) {
+		warn("memory allocation error");
+		*error = PEFS_ERR_SYS;
+		return (NULL);
+	}
+
+	strlcpy(fhp->path, buf, sizeof(fhp->path));
+
+	return (fhp);
+}
+
+/*
+ * This function creates the in memory database that will be later written to
+ * the checksum file.
+ * A) The total sum of entries is gathered so that a hash table is allocated.
+ * B) For each file entry:
+ * 		B1) semantic checks: residing in pefs filesystem & regular file type checks.
+ * 		B2) the file_id is retrieved.
+ * 		B3) list of checksums is computed for the file's 4k blocks.
+ * 		B4) file entry is added to hash table. (separate chaining is used)
+ */
+static int
+pefs_create_in_memory_db(FILE *fpin, char *fsroot, const EVP_MD *md, uint8_t hash_len,
+	struct hash_table *checksum_hash_tablep)
+{
+	struct statfs fs;
+	struct file_header *fhp;
+	int error;
+	uint32_t nfiles;
+
+	if (statfs(fsroot, &fs) == -1) {
+		pefs_warn("statfs failed: %s: %s", fsroot, strerror(errno));
+		return (PEFS_ERR_SYS);
+	}
+
+	error = pefs_count_file_entries(fpin, &nfiles);
+	if (error != 0)
+		return (error);
+
+	error = pefs_allocate_hash_table(checksum_hash_tablep, nfiles);
+	if (error != 0)
+		return (error);
+
+	while((fhp = pefs_next_file(fpin, &error)) != NULL) {
+		error = pefs_file_semantic_checks(fhp, &fs);
+		if (error != 0)
+			return error;
+
+		error = pefs_get_file_id(fhp);
+		if (error != 0)
+			return error;
+
+		error = pefs_compute_file_checksums(fhp, md, hash_len);
+		if (error != 0)
+			return error;
+
+		error = pefs_add_to_hash_table(checksum_hash_tablep, fhp);
+		if (error != 0)
+			return error;
+	}
+
+	/* error during pefs_next_file() */
+	if (error != 0)
+		return error;
+
+	pefs_print_hash_table(checksum_hash_tablep, hash_len);
+
+	return (0);
+}
+
+int
+pefs_create_checksum_file(FILE *fpin, char *fsroot, const char *algo)
+{
+	char checksum_path[MAXPATHLEN];
+	struct hash_table checksum_hash_table;
+	const EVP_MD *md;
+	int error, fdout;
+	uint8_t hash_len;
+
+	OpenSSL_add_all_digests();
+	md = EVP_get_digestbyname(algo);
+
+	if(md == NULL) {
+		pefs_warn("Unknown message digest %s\n", algo);
+		return (PEFS_ERR_INVALID);
+	}
+	hash_len = EVP_MD_size(md);
+
+	snprintf(checksum_path, sizeof(checksum_path), "%s/%s", fsroot, PEFS_FILE_CHECKSUM);
+	fdout = open(checksum_path, O_WRONLY | O_CREAT | O_EXCL,  S_IRUSR | S_IWUSR);
+	if (fdout == -1) {
+		warn("cannot open %s", checksum_path);
+		return (PEFS_ERR_IO);
+	}
+
+	error = pefs_create_in_memory_db(fpin, fsroot, md, hash_len,
+		&checksum_hash_table);
+	if (error != 0)
+		goto out;
+
+	/* XXXgpf: [TODO] write the in memory db to .pefs.checksum */
+	/* error = pefs_write_checksum_file(&checksum_hash_table, fdout, ...); */
+
+out:
+	close(fdout);
+	if (error != 0)
+		unlink(checksum_path);
+	/* XXXgpf: [TODO] free dynamic memory */
+
+	return (error);
+}

Modified: soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.c
==============================================================================
--- soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.c	Tue May 22 17:11:18 2012	(r236146)
+++ soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.c	Tue May 22 18:20:38 2012	(r236147)
@@ -32,6 +32,7 @@
 #include <sys/ioccom.h>
 #include <sys/module.h>
 #include <sys/mount.h>
+#include <sys/stat.h>
 
 #include <assert.h>
 #include <ctype.h>
@@ -74,6 +75,7 @@
 static int	pefs_getkey(int argc, char *argv[]);
 static int	pefs_showchains(int argc, char *argv[]);
 static int	pefs_showalgs(int argc, char *argv[]);
+static int	pefs_addchecksum(int argc, char *argv[]);
 
 typedef int (*command_func_t)(int argc, char **argv);
 typedef int (*keyop_func_t)(struct pefs_keychain_head *kch, int fd,
@@ -100,9 +102,12 @@
 	{ "delchain",	pefs_delchain },
 	{ "showchains",	pefs_showchains },
 	{ "showalgs",	pefs_showalgs },
+	{ "addchecksum", pefs_addchecksum},
 	{ NULL, NULL },
 };
 
+const char *supported_digests[] = {"sha256","sha512"};
+
 void
 pefs_warn(const char *fmt, ...)
 {
@@ -991,6 +996,59 @@
 	return (0);
 }
 
+static int
+pefs_addchecksum(int argc, char *argv[])
+{
+	char fsroot[MAXPATHLEN];
+	FILE *fpin;
+	int error, i, j;
+	const char *algo;
+
+	fpin = NULL;
+	/* by default use sha256 */
+	algo = supported_digests[0];
+
+	while ((i = getopt(argc, argv, "a:f:")) != -1)
+		switch(i) {
+		case 'a':
+			for (j=0; j < PEFS_SUPPORTED_DIGESTS; j++)
+				if (strcmp(supported_digests[j], optarg) == 0) {
+					algo = supported_digests[j];
+					break;
+				}
+
+			if (j == PEFS_SUPPORTED_DIGESTS) {
+				pefs_warn("invalid digestname: %s", optarg);
+				return (PEFS_ERR_INVALID);
+			}
+			break;
+		case 'f':
+			fpin = fopen(optarg, "r");
+			if (fpin == NULL) {
+				warn("cannot open inputfile: %s", optarg);
+				return (PEFS_ERR_INVALID);
+			}
+			break;
+		default:
+			pefs_usage();
+		}
+	argc -= optind;
+	argv += optind;
+
+	if (fpin == NULL) {
+		pefs_warn("please supply an input file [-f]");
+		return (PEFS_ERR_USAGE);
+	}
+
+	initfsroot(argc, argv, 0, fsroot, sizeof(fsroot));
+
+	error = pefs_create_checksum_file(fpin, fsroot, algo);
+
+	fclose(fpin);
+
+	return (error);
+}
+
 static void
 pefs_usage_alg(void)
 {
@@ -1016,6 +1074,7 @@
 "	pefs randomchain [-fv] [-n min] [-N max] filesystem\n"
 "	pefs showchains [-fp] [-i iterations] [-k keyfile] filesystem\n"
 "	pefs showalgs\n"
+"	pefs addchecksum [-a algo] [-f inputfile] filesystem\n"
 );
 	exit(PEFS_ERR_USAGE);
 }

Modified: soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.h
==============================================================================
--- soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.h	Tue May 22 17:11:18 2012	(r236146)
+++ soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.h	Tue May 22 18:20:38 2012	(r236147)
@@ -28,6 +28,8 @@
 
 #include <inttypes.h>
 
+struct EVP_MD;
+
 #define	PEFS_FSTYPE			"pefs"
 #define	PEFS_KLD			PEFS_FSTYPE
 
@@ -36,8 +38,11 @@
 
 #define	PEFS_KDF_ITERATIONS		50000
 
+#define PEFS_BLOCKSIZE			4096
+
 #define	PEFS_FILE_KEYCHAIN		".pefs.db"
 #define	PEFS_FILE_KEYCONF		".pefs.conf"
+#define PEFS_FILE_CHECKSUM		".pefs.checksum"
 
 #define	PEFS_KEYCONF_ALG_IND		0
 #define	PEFS_KEYCONF_ITERATIONS_IND	1
@@ -47,6 +52,8 @@
 
 #define	PEFS_KEYENC_MAC_SIZE		(PEFS_KEY_SIZE / 2)
 
+#define PEFS_SUPPORTED_DIGESTS	2
+
 #define	PEFS_ERR_GENERIC		1
 #define	PEFS_ERR_USAGE			2
 #define	PEFS_ERR_IO			3
@@ -85,6 +92,7 @@
 int	pefs_key_decrypt(struct pefs_xkeyenc *xe,
 	    const struct pefs_xkey *xk_parent);
 uintmax_t	pefs_keyid_as_int(char *keyid);
+int pefs_create_checksum_file(FILE *fpin, char *fsroot, const char *algo);
 
 const char *	pefs_alg_name(struct pefs_xkey *xk);
 void	pefs_alg_list(FILE *stream);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20120522182039.3200E106564A>