Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 20 Jul 2012 18:36:03 +0000
From:      gpf@FreeBSD.org
To:        svn-soc-all@FreeBSD.org
Subject:   socsvn commit: r239626 - soc2012/gpf/pefs_kmod/sbin/pefs
Message-ID:  <20120720183603.C65A1106564A@hub.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: gpf
Date: Fri Jul 20 18:36:03 2012
New Revision: 239626
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=239626

Log:
  verify .pefs.checksum's signature with public key found in .pefs.pkey.
  once again, dsa and sha1 are used by default.
  
  next commit will update comments and clean up new code as needed.
  

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 17:51:20 2012	(r239625)
+++ soc2012/gpf/pefs_kmod/sbin/pefs/pefs_checksum.c	Fri Jul 20 18:36:03 2012	(r239626)
@@ -1459,28 +1459,23 @@
 	}
 	rval = EVP_PKEY_assign_DSA(pkey, dsa);
 	if (rval != 1) {
-		pefs_warn("error generating dsa key");
+		pefs_warn("error assigning 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 (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)
 {
@@ -1507,7 +1502,7 @@
 
 	error = lseek(fd, 0, SEEK_SET);
 	if (error != 0) {
-		warn("lseek: ");
+		warn("lseek:");
 		EVP_PKEY_free(pkey);
 		return (PEFS_ERR_SYS);
 	}
@@ -1546,7 +1541,7 @@
 		pefs_warn("error writing signature");
 		free(sign);
 		EVP_PKEY_free(pkey);
-		return (PEFS_ERR_IO);	
+		return (PEFS_ERR_IO);
 	}
 
 	free(sign);
@@ -1555,15 +1550,126 @@
 	return (0);
 }
 
+static EVP_PKEY *
+pefs_read_dsa(FILE *pk_fp)
+{
+	DSA	*dsa;
+	EVP_PKEY *pkey;
+	int rval;
+
+	dsa = PEM_read_DSA_PUBKEY(pk_fp, NULL, NULL, NULL);
+	if (dsa == NULL) {
+		pefs_warn("error reading dsa pubkey");
+		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 assigning dsa key");
+		EVP_PKEY_free(pkey);
+		DSA_free(dsa);
+		return (NULL);
+	}
+
+	return (pkey);
+}
+
+static int
+pefs_verify_signature(int fd, FILE *pk_fp, FILE *sign_fp)
+{
+	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_read_dsa(pk_fp);
+	if (pkey == NULL)
+		return (PEFS_ERR_SYS);
+
+	sign = malloc(EVP_PKEY_size(pkey));
+	if (sign == NULL) {
+		pefs_warn("memory allocation error");
+		EVP_PKEY_free(pkey);
+		return (PEFS_ERR_SYS);
+	}
+
+	sign_len = fread(sign, sizeof(char), EVP_PKEY_size(pkey), sign_fp);
+	if (ferror(sign_fp)) {
+		pefs_warn("error reading from signature file");
+		free(sign);
+		return (PEFS_ERR_IO);
+	}
+
+	md = EVP_dss1();
+	if (md == NULL) {
+		pefs_warn("error acquiring digest type");
+		free(sign);
+		EVP_PKEY_free(pkey);
+		return (PEFS_ERR_GENERIC);
+	}
+	EVP_VerifyInit(&ctx, md);
+
+	error = lseek(fd, 0, SEEK_SET);
+	if (error != 0) {
+		warn("lseek:");
+		free(sign);
+		EVP_PKEY_free(pkey);
+		return (PEFS_ERR_SYS);
+	}
+
+	while ((bytes = read(fd, buf, sizeof(buf))) > 0) {
+		rval = EVP_VerifyUpdate(&ctx, buf, bytes);
+		if (rval != 1) {
+			pefs_warn("error updating sign data");
+			free(sign);
+			EVP_PKEY_free(pkey);
+			return (PEFS_ERR_SYS);
+		}
+	}
+
+	if (bytes == -1) {
+		warn("read error");
+		free(sign);
+		EVP_PKEY_free(pkey);
+		return (PEFS_ERR_IO);
+	}
+
+	rval = EVP_VerifyFinal(&ctx, sign, sign_len, pkey);
+	if (rval == 0) {
+		pefs_warn("file signature is not verified by public key");
+		free(sign);
+		EVP_PKEY_free(pkey);
+		return (PEFS_ERR_GENERIC);
+	}
+	else if (rval == -1) {
+		pefs_warn("error verifying signature");
+		free(sign);
+		EVP_PKEY_free(pkey);
+		return (PEFS_ERR_GENERIC);
+	}
+
+	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 
+ * 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_files(int *fdp, char *fsroot, char *csm_path, FILE **pkfpp, 
+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;
@@ -1599,22 +1705,22 @@
 			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);
@@ -2130,7 +2236,8 @@
  * D) check that every file in .pefs.checksum was actually found in filesystem.
  */
 int
-pefs_verify_checksum(int fdin, char *fsroot, int flags)
+pefs_verify_checksum(int fdin, FILE *pk_fp, FILE *sign_fp,
+	char *fsroot, int flags)
 {
 	struct statfs fs;
 	struct checksum_file_header cfh;
@@ -2186,7 +2293,7 @@
 		goto out;
 
 	/* pefs_rb_print(&hlc_head); */
-	pefs_rb_warn(&hlc_head);printf("3\n");
+	pefs_rb_warn(&hlc_head);
 	if ((flags & PEFS_UNMOUNTED) == 0 && (flags & PEFS_NOKEY) == 0)
 		pefs_symlink_warn(&cht, &fh_head);
 
@@ -2195,6 +2302,8 @@
 	if (error == 0 && checksum_error != 0)
 		error = checksum_error;
 
+	error = pefs_verify_signature(fdin, pk_fp, sign_fp);
+
 out:
 	pefs_free_hash_table(&cht);
 	pefs_rb_free(&hlc_head);

Modified: soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.c
==============================================================================
--- soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.c	Fri Jul 20 17:51:20 2012	(r239625)
+++ soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.c	Fri Jul 20 18:36:03 2012	(r239626)
@@ -1119,7 +1119,7 @@
 /*
  * XXXgpf: Instead of a man page entry:
  *
- * pefs verify [-u/-n] checksumpath filesystem
+ * pefs verify [-u/-n] [-k pkey_file] [-s sign_file] checksumpath filesystem
  *
  * $command verifies the contents of a .pefs.checksum file. It scans the
  * entire filesystem and checks that every entry in .pefs.checksum is
@@ -1144,12 +1144,24 @@
 pefs_verify(int argc, char *argv[])
 {
 	struct stat sb;
-	char fsroot[MAXPATHLEN + 1];
+	char fsroot[MAXPATHLEN + 1], pk_path[MAXPATHLEN + 1];
+	char sign_path[MAXPATHLEN + 1];
+	char *dirnamep;
+	FILE *pk_fp, *sign_fp;
 	int error, fdin, flags, i;
 
 	flags = PEFS_VERIFY;
-	while ((i = getopt(argc, argv, "nu")) != -1)
+	pk_fp = NULL;
+	sign_fp = NULL;
+	while ((i = getopt(argc, argv, "k:ns:u")) != -1)
 		switch(i) {
+		case 'k':
+			pk_fp = fopen(optarg, "r");
+			if (pk_fp == NULL) {
+				warn("error opening pkey file %s", optarg);
+				return (PEFS_ERR_SYS);
+			}
+			break;
 		case 'n':
 			flags|= PEFS_NOKEY;
 			if ((flags & PEFS_UNMOUNTED) != 0) {
@@ -1157,6 +1169,13 @@
 				return (PEFS_ERR_INVALID);
 			}
 			break;
+		case 's':
+			sign_fp = fopen(optarg, "r");
+			if (sign_fp == NULL) {
+				warn("error opening signature file %s", optarg);
+				return (PEFS_ERR_SYS);
+			}
+			break;
 		case 'u':
 			flags|= PEFS_UNMOUNTED;
 			if ((flags & PEFS_NOKEY) != 0) {
@@ -1178,11 +1197,31 @@
 		pefs_usage();
 	}
 
+	/* XXXgpf: [TODO] close files if error */
 	fdin = open(argv[0], O_RDONLY);
 	if (fdin == -1) {
 		warn("cannot open %s file: %s", PEFS_FILE_CHECKSUM, argv[0]);
 		return (PEFS_ERR_INVALID);
 	}
+	dirnamep = dirname(argv[0]);
+	if (pk_fp == NULL) {
+		snprintf(pk_path, sizeof(pk_path), "%s/%s", dirnamep, PEFS_FILE_PKEY);
+		pk_fp = fopen(pk_path, "r");
+		if (pk_fp == NULL) {
+			warn("error opening pkey file %s", pk_path);
+			return (PEFS_ERR_SYS);
+		}
+	}
+	if (sign_fp == NULL) {
+		snprintf(sign_path, sizeof(sign_path), "%s/%s", dirnamep,
+			PEFS_FILE_SIGNATURE);
+		sign_fp = fopen(sign_path, "r");
+		if (sign_fp == NULL) {
+			warn("error opening signature file %s", sign_path);
+			return (PEFS_ERR_SYS);
+		}
+	}
+
 	argc -=1;
 	argv +=1;
 
@@ -1207,13 +1246,15 @@
 		}
 	}
 
-	error = pefs_verify_checksum(fdin, fsroot, flags);
+	error = pefs_verify_checksum(fdin, pk_fp, sign_fp, fsroot, flags);
 	if (error == 0)
 		printf("integrity verification ok!\n");
 	else
 		pefs_warn("integrity verification encountered error(s)");
 
 	close(fdin);
+	fclose(pk_fp);
+	fclose(sign_fp);
 	return (error);
 }
 

Modified: soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.h
==============================================================================
--- soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.h	Fri Jul 20 17:51:20 2012	(r239625)
+++ soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.h	Fri Jul 20 18:36:03 2012	(r239626)
@@ -104,7 +104,8 @@
 uintmax_t	pefs_keyid_as_int(char *keyid);
 int pefs_create_checksum_file(FILE *fpin, char *fsroot, char *csm_path,
 		char *pk_path, char *sign_path, const char *algo, int flags);
-int pefs_verify_checksum(int fdin, char *fsroot, int flags);
+int pefs_verify_checksum(int fdin, FILE *pk_fp, FILE *sign_fp,
+		char *fsroot, int flags);
 
 int	pefs_name_pton(char const *src, size_t srclen, u_char *target,
 		size_t targsize);



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