socsvn commit: r236147 - soc2012/gpf/pefs_kmod/sbin/pefs
gpf at FreeBSD.org
gpf at FreeBSD.org
Tue May 22 18:20:41 UTC 2012
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);
More information about the svn-soc-all
mailing list