socsvn commit: r239624 - soc2012/gpf/pefs_kmod/sbin/pefs

gpf at FreeBSD.org gpf at FreeBSD.org
Fri Jul 20 17:25:15 UTC 2012


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 <fs/pefs/pefs.h>
 
+#include <openssl/dsa.h>
+#include <openssl/engine.h>
 #include <openssl/evp.h>
+#include <openssl/pem.h>
+#include <openssl/rand.h>
 
 #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,


More information about the svn-soc-all mailing list