Skip to content

Commit

Permalink
Tarsnap 1.0.10
Browse files Browse the repository at this point in the history
Changes since 1.0.9:
* Restricted keyfiles can be generated using a new
  "tarsnap-keymgmt" utility containing the keys needed to write
  backups but not read or delete them, to read backups but not
  write or delete them, etc.
* Several minor bugfixes.
  • Loading branch information
cperciva authored and gperciva committed Aug 7, 2008
1 parent 07168b0 commit ca84cf9
Show file tree
Hide file tree
Showing 10 changed files with 411 additions and 7 deletions.
39 changes: 38 additions & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ distclean-local:
-rm -f *~

noinst_LIBRARIES= libarchive.a
bin_PROGRAMS= tarsnap tarsnap-keygen
bin_PROGRAMS= tarsnap tarsnap-keygen tarsnap-keymgmt
dist_man_MANS=$(tarsnap_dist_man_MANS) $(tarsnap_keygen_dist_man_MANS)

#
Expand Down Expand Up @@ -233,5 +233,42 @@ tarsnap_keygen_LDADD= -lcrypto

tarsnap_keygen_dist_man_MANS= keygen/tarsnap-keygen.1

#
#
# tarsnap-keymgmt source, docs, etc.
#
#

tarsnap_keymgmt_SOURCES= \
keymgmt/keymgmt.c \
datastruct/rwhashtab.c \
crypto/sha256.c \
crypto/crypto_entropy.c \
crypto/crypto_hash.c \
crypto/crypto_keys.c \
crypto/crypto_keys_subr.c \
crypto/crypto_session.c \
crypto/crypto_file.c \
crypto/crypto_rsa.c \
crypto/crypto_passwd_to_dh.c \
crypto/crypto_dh.c \
crypto/crypto_verify_bytes.c \
crypto/crypto_keys_server.c \
crypto/crypto_dh_group14.c \
util/entropy.c

tarsnap_keymgmt_CFLAGS= \
-Werror \
-I$(top_builddir)/tar \
-I${top_builddir}/libarchive \
-I$(top_builddir)/datastruct \
-I${top_builddir}/crypto \
-I$(top_builddir)/util \
-DUSERAGENT=\"tarsnap-keygen-${VERSION}\"

tarsnap_keymgmt_LDADD= -lcrypto

tarsnap_keymgmt_dist_man_MANS= keymgmt/tarsnap-keymgmt.1

# Tarsnap sample configuration file
sysconf_DATA = tar/tarsnap.conf.sample
16 changes: 16 additions & 0 deletions crypto/crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@
#define CRYPTO_KEYMASK_HMAC_CHUNK (1 << CRYPTO_KEY_HMAC_CHUNK)
#define CRYPTO_KEYMASK_HMAC_NAME (1 << CRYPTO_KEY_HMAC_NAME)
#define CRYPTO_KEYMASK_HMAC_CPARAMS (1 << CRYPTO_KEY_HMAC_CPARAMS)
#define CRYPTO_KEYMASK_READ \
(CRYPTO_KEYMASK_ENCR_PRIV | CRYPTO_KEYMASK_SIGN_PUB | \
CRYPTO_KEYMASK_HMAC_FILE | CRYPTO_KEYMASK_HMAC_CHUNK | \
CRYPTO_KEYMASK_HMAC_NAME | CRYPTO_KEYMASK_AUTH_GET )
#define CRYPTO_KEYMASK_WRITE \
(CRYPTO_KEYMASK_SIGN_PRIV | CRYPTO_KEYMASK_ENCR_PUB | \
CRYPTO_KEYMASK_HMAC_FILE | CRYPTO_KEYMASK_HMAC_CHUNK | \
CRYPTO_KEYMASK_HMAC_NAME | CRYPTO_KEYMASK_HMAC_CPARAMS | \
CRYPTO_KEYMASK_AUTH_PUT )

#define CRYPTO_KEYMASK_ROOT_PUB (1 << CRYPTO_KEY_ROOT_PUB)
#define CRYPTO_KEYMASK_AUTH_PUT (1 << CRYPTO_KEY_AUTH_PUT)
Expand Down Expand Up @@ -90,6 +99,13 @@ int crypto_keys_init(void);
*/
int crypto_keys_import(uint8_t * buf, size_t buflen);

/**
* crypto_keys_missing(keys):
* Look for the specified keys. If they are all present, return NULL; if
* not, return a pointer to the name of one of the keys.
*/
const char * crypto_keys_missing(int);

/**
* crypto_keys_export(keys, buf, buflen):
* Export the keys specified to a buffer allocated using malloc.
Expand Down
73 changes: 73 additions & 0 deletions crypto/crypto_keys.c
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,79 @@ crypto_keys_import(uint8_t * buf, size_t buflen)
return (-1);
}

/**
* crypto_keys_missing(keys):
* Look for the specified keys. If they are all present, return NULL; if
* not, return a pointer to the name of one of the keys.
*/
const char *
crypto_keys_missing(int keys)
{
const char * keyname = NULL;
int key;

/*
* Go through all the keys we know about and determine if (a) the key
* is in the provided mask; and (b) if we do not have it.
*/
for (key = 0; key < (int)(sizeof(int) * 8); key++)
if ((keys >> key) & 1) {
switch (key) {
case CRYPTO_KEY_SIGN_PRIV:
if (keycache.sign_priv == NULL)
keyname = "archive signing";
break;
case CRYPTO_KEY_SIGN_PUB:
if (keycache.sign_pub == NULL)
keyname = "archive signature verification";
break;
case CRYPTO_KEY_ENCR_PRIV:
if (keycache.encr_priv == NULL)
keyname = "archive decryption";
break;
case CRYPTO_KEY_ENCR_PUB:
if (keycache.encr_pub == NULL)
keyname = "archive encryption";
break;
case CRYPTO_KEY_HMAC_FILE:
if (keycache.hmac_file == NULL)
keyname = "file HMAC";
break;
case CRYPTO_KEY_HMAC_CHUNK:
if (keycache.hmac_chunk == NULL)
keyname = "chunk HMAC";
break;
case CRYPTO_KEY_HMAC_NAME:
if (keycache.hmac_name == NULL)
keyname = "archive name HMAC";
break;
case CRYPTO_KEY_HMAC_CPARAMS:
if (keycache.hmac_cparams == NULL)
keyname = "chunk randomization";
break;
case CRYPTO_KEY_ROOT_PUB:
if (keycache.root_pub == NULL)
keyname = "server root";
break;
case CRYPTO_KEY_AUTH_PUT:
if (keycache.auth_put == NULL)
keyname = "write authorization";
break;
case CRYPTO_KEY_AUTH_GET:
if (keycache.auth_get == NULL)
keyname = "read authorization";
break;
case CRYPTO_KEY_AUTH_DELETE:
if (keycache.auth_delete == NULL)
keyname = "delete authorization";
break;
}
}

/* Return the key name or NULL if we have everything. */
return (keyname);
}

/**
* crypto_keys_export(keys, buf, buflen):
* Export the keys specified to a buffer allocated using malloc.
Expand Down
2 changes: 1 addition & 1 deletion keygen/keygen.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ main(int argc, char **argv)
C.passwd = passbuf;

/* Parse arguments. */
while (--argc) {
while (--argc > 0) {
argv++;

if (strcmp(argv[0], "--user") == 0) {
Expand Down
211 changes: 211 additions & 0 deletions keymgmt/keymgmt.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
#include "bsdtar_platform.h"

#include <sys/stat.h>

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "crypto.h"
#include "sysendian.h"
#include "warnp.h"

static void usage(void);

static void
usage(void)
{

fprintf(stderr, "usage: tarsnap-keymgmt %s %s %s %s key-file ...\n",
"--outkeyfile new-key-file", "[-r]", "[-w]", "[-d]");
exit(1);

/* NOTREACHED */
}

int
main(int argc, char **argv)
{
const char * newkeyfile = NULL;
int keyswanted = 0;
char * tok, * brkb = NULL, * eptr;
long keynum;
struct stat sb;
uint8_t * keybuf;
size_t keybuflen;
FILE * f;
uint64_t machinenum = (uint64_t)(-1);
uint8_t machinenumvec[8];
const char * missingkey;

/* Initialize entropy subsystem. */
if (crypto_entropy_init()) {
warnp("Entropy subsystem initialization failed");
exit(1);
}

/* Initialize key cache. */
if (crypto_keys_init()) {
warnp("Key cache initialization failed");
exit(1);
}

/* Look for command-line options. */
while (--argc > 0) {
argv++;

if (strcmp(argv[0], "--outkeyfile") == 0) {
if ((newkeyfile != NULL) || (argc < 2))
usage();
newkeyfile = argv[1];
argv++; argc--;
} else if (strcmp(argv[0], "-r") == 0) {
keyswanted |= CRYPTO_KEYMASK_READ;
} else if (strcmp(argv[0], "-w") == 0) {
keyswanted |= CRYPTO_KEYMASK_WRITE;
} else if (strcmp(argv[0], "-d") == 0) {
/*
* Deleting data requires both delete authorization
* and being able to read archives -- we need to be
* able to figure out which bits are part of the
* archive.
*/
keyswanted |= CRYPTO_KEYMASK_READ;
keyswanted |= CRYPTO_KEYMASK_AUTH_DELETE;
} else if (strcmp(argv[0], "--keylist") == 0) {
/*
* This is a deliberately undocumented option used
* mostly for testing purposes; it allows a list of
* keys to be specified according to their numbers in
* crypto/crypto.h instead of using the predefined
* sets of "read", "write" and "delete" keys.
*/
if (argc < 2)
usage();
for (tok = strtok_r(argv[1], ",", &brkb);
tok;
tok = strtok_r(NULL, ",", &brkb)) {
keynum = strtol(tok, &eptr, 0);
if ((eptr == tok) ||
(keynum < 0) || (keynum > 32)) {
warn0("Not a valid key number: %s",
tok);
exit(1);
}
keyswanted |= 1 << keynum;
}
argv++; argc--;
} else {
/* Key files follow. */
break;
}
}

/* We should have an output key file. */
if (newkeyfile == NULL)
usage();

/* Read the specified key files. */
while (argc-- > 0) {
/* Stat the key file. */
if (stat(argv[0], &sb)) {
warnp("stat(%s)", argv[0]);
exit(1);
}

/* Allocate memory to hold the keyfile contents. */
if ((sb.st_size < 8) || (sb.st_size > 1000000)) {
warn0("Key file has unreasonable size: %s", argv[0]);
exit(1);
}
if ((keybuf = malloc(sb.st_size)) == NULL) {
warn0("Out of memory");
exit(1);
}

/* Read the file. */
if ((f = fopen(argv[0], "r")) == NULL) {
warnp("fopen(%s)", argv[0]);
exit(1);
}
if (fread(keybuf, sb.st_size, 1, f) != 1) {
warnp("fread(%s)", argv[0]);
exit(1);
}
if (fclose(f)) {
warnp("fclose(%s)", argv[0]);
exit(1);
}

/*
* Parse the machine number from the key file or check that
* the machine number from the key file matches the number
* we already have.
*/
if (machinenum == (uint64_t)(-1)) {
machinenum = be64dec(keybuf);
} else if (machinenum != be64dec(keybuf)) {
warn0("Keys from %s do not belong to the "
"same machine as earlier keys", argv[0]);
exit(1);
}

/* Parse keys. */
if (crypto_keys_import(&keybuf[8], sb.st_size - 8)) {
warn0("Error parsing keys in %s", argv[0]);
exit(1);
}

/* Free memory. */
free(keybuf);

/* Move on to the next file. */
argv++;
}

/* Make sure that we have the necessary keys. */
if ((missingkey = crypto_keys_missing(keyswanted)) != NULL) {
warn0("The %s key is required but not in any input key files",
missingkey);
exit(1);
}

/* Create key file. */
if ((f = fopen(newkeyfile, "w")) == NULL) {
warnp("Cannot create %s", newkeyfile);
exit(1);
}

/* Set the permissions on the key file to 0600. */
if (fchmod(fileno(f), S_IRUSR | S_IWUSR)) {
warnp("Cannot set permissions on key file: %s", newkeyfile);
exit(1);
}

/* Export keys. */
if (crypto_keys_export(keyswanted, &keybuf, &keybuflen)) {
warnp("Error exporting keys");
exit(1);
}

/* Write keys. */
be64enc(machinenumvec, machinenum);
if (fwrite(machinenumvec, 8, 1, f) != 1) {
warnp("Error writing keys");
exit(1);
}
if (fwrite(keybuf, keybuflen, 1, f) != 1) {
warnp("Error writing keys");
exit(1);
}

/* Close the key file. */
if (fclose(f)) {
warnp("Error closing key file");
exit(1);
}

/* Success! */
return (0);
}

0 comments on commit ca84cf9

Please sign in to comment.