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