sesame/tools Makefile.am,1.2,1.3 sesame-setup.c,1.1.1.1,1.2
David Zeuthen
david at freedesktop.org
Fri Dec 31 05:35:49 PST 2004
Update of /cvs/hal/sesame/tools
In directory gabe:/tmp/cvs-serv25990/tools
Modified Files:
Makefile.am sesame-setup.c
Log Message:
2004-12-31 David Zeuthen <davidz at redhat.com>
Patch from W. Michael Petullo <mike at flyn.org>. I wrote a patch for
the sesame code in CVS that adds a C implementation of
sesame-setup. I used OpenSSL's libraries for the crypto because
this is what I am familiar with. Cryptsetup is also required. It
seems to work.
* configure.in: Check for openssl lib and cryptsetup
* tools/Makefile.am: pass CRYPTSETUP to be the path of the cryptsetup
binary
* tools/sesame-setup.c: (print_usage), (sslerror), (hash_authtok),
(decrypt), (decode), (strip_cr), (read_key), (msg),
(run_cryptsetup), (main): New functions
Index: Makefile.am
===================================================================
RCS file: /cvs/hal/sesame/tools/Makefile.am,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- Makefile.am 17 Dec 2004 17:02:42 -0000 1.2
+++ Makefile.am 31 Dec 2004 13:35:47 -0000 1.3
@@ -1,9 +1,9 @@
INCLUDES = \
+ -DCRYPTSETUP=\""$(CRYPTSETUP)\"" \
-DPACKAGE_DATA_DIR=\""$(datadir)"\" \
-DPACKAGE_BIN_DIR=\""$(bindir)"\" \
- -DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
- @PACKAGE_CFLAGS@
+ -DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\"
sbin_PROGRAMS = sesame-setup
Index: sesame-setup.c
===================================================================
RCS file: /cvs/hal/sesame/tools/sesame-setup.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -d -r1.1.1.1 -r1.2
--- sesame-setup.c 17 Dec 2004 16:56:52 -0000 1.1.1.1
+++ sesame-setup.c 31 Dec 2004 13:35:47 -0000 1.2
@@ -1,46 +1,409 @@
+#define _GNU_SOURCE
+
#include <stdio.h>
#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
+#include <ctype.h>
+#include <assert.h>
+#include <limits.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <openssl/ssl.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+
+#ifndef EVP_MAX_BLOCK_LENGTH
+#define EVP_MAX_BLOCK_LENGTH 32 /* some older openssl versions need this */
+#endif
#include "../libsesame/libsesame.h"
-int
-main (int argc, char *argv[])
+#define MAGICTAIL "SESAME0"
+
+int verbose = 0;
+char *device = NULL;
+
+static void print_usage(const int exitcode, const char *error,
+ const char *more)
{
- char md_file[] = "/dev/sda1";
- int fd_metadata;
+ if (error)
+ assert(more);
+
+ fprintf(stderr, "sesame-setup [options] device\n\n"
+ "-h, --help\n"
+ " print a list of options\n\n"
+ "-v, --verbose\n" " verbose display of messages\n\n");
+ if (error)
+ fprintf(stderr, "%s: %s\n", error, more);
+
+ exit(exitcode);
+}
+
+static void sslerror(const char *msg)
+{
+ assert(msg);
+
+ unsigned long err = ERR_get_error();
+ if (err != 0)
+ fprintf(stderr, "%s: %s", msg,
+ ERR_error_string(err, NULL));
+}
+
+static int hash_authtok(const char *data, const EVP_CIPHER * const cipher,
+ const char *const authtok,
+ unsigned char *const hash, unsigned char *const iv)
+{
+ const EVP_MD *md;
+ unsigned char salt[PKCS5_SALT_LEN];
+
+ assert(data != NULL);
+ assert(cipher != NULL); /* FIXME: is cipher is valid OpenSSL cipher? */
+ assert(authtok != NULL);
+ assert(hash != NULL); /* FIXME: check hash is big enough? */
+ assert(iv != NULL); /* FIXME: check iv is big enough? */
+
+ if (memcmp(data, "Salted__", sizeof "Salted__" - 1) != 0) {
+ fprintf(stderr, "magic string Salted__ not in stream\n");
+ return 0;
+ }
+ memcpy(salt, data + sizeof "Salted__" - 1, PKCS5_SALT_LEN);
+ md = EVP_md5();
+ if (EVP_BytesToKey
+ (cipher, md, salt, authtok, strlen(authtok), 1,
+ hash, iv) <= 0) {
+ fprintf(stderr, "failed to hash passphrase");
+ return 0;
+ }
+
+ return 1;
+}
+
+static int
+decrypt(char *const out, size_t * const out_len,
+ const char *const in, const size_t in_len,
+ const char *const cipher_name, const char *const authtok)
+{
+ int ret = 1;
+ int segment_len;
+ size_t data_len;
+ const char *data;
+ unsigned char hashed_authtok[EVP_MAX_KEY_LENGTH];
+ unsigned char iv[EVP_MAX_IV_LENGTH];
+ const EVP_CIPHER *cipher;
+ EVP_CIPHER_CTX ctx;
+
+ assert(out != NULL);
+ assert(out_len != NULL);
+ assert(cipher_name != NULL);
+ assert(in != NULL);
+ assert(authtok != NULL);
+
+ memset(out, 0x00, BUFSIZ + EVP_MAX_BLOCK_LENGTH);
+ OpenSSL_add_all_ciphers();
+ EVP_CIPHER_CTX_init(&ctx);
+ SSL_load_error_strings();
+ if (!(cipher = EVP_get_cipherbyname(cipher_name))) {
+ fprintf(stderr, "error getting cipher \"%s\"\n", (const char *)cipher);
+ ret = 0;
+ goto _return;
+ }
+ if (hash_authtok(in, cipher, authtok, hashed_authtok, iv) == 0) {
+ ret = 0;
+ goto _return;
+ }
+ if (EVP_DecryptInit_ex(&ctx, cipher, NULL, hashed_authtok, iv) ==
+ 0) {
+ sslerror("failed to initialize decryption code");
+ ret = 0;
+ goto _return;
+ }
+ data = in + (sizeof "Salted__" - 1) + PKCS5_SALT_LEN;
+ data_len = in_len - (sizeof "Salted__" - 1) - PKCS5_SALT_LEN;
+ /* assumes plaintexts is always <= ciphertext + EVP_MAX_BLOCK_LEN in length
+ * OpenSSL's documentation seems to promise this */
+ if (EVP_DecryptUpdate
+ (&ctx, out, &segment_len, data, data_len) == 0) {
+ sslerror("failed to decrypt key");
+ ret = 0;
+ goto _return;
+ }
+ *out_len = segment_len;
+ if (EVP_DecryptFinal_ex(&ctx, &out[*out_len], &segment_len) == 0) {
+ sslerror
+ ("bad pad on end of encrypted file (wrong algorithm or key size?)");
+ ret = 0;
+ goto _return;
+ }
+ *out_len += segment_len;
+ _return:
+ if (EVP_CIPHER_CTX_cleanup(&ctx) == 0) {
+ sslerror("error cleaning up cipher context");
+ ret = 0;
+ }
+
+ ERR_free_strings();
+ /* out_len is unsigned */
+ assert(ret == 0 || *out_len <= BUFSIZ + EVP_MAX_BLOCK_LENGTH);
+
+ return ret;
+}
+
+static unsigned char *decode(char *data)
+{
+ size_t i;
+ unsigned char *decoded =
+ (char *) malloc((strlen(data) / 2) * sizeof(char));
+ if (decoded == NULL)
+ return NULL;
+ for (i = 0; i < strlen(data); i += 2) {
+ decoded[i / 2] =
+ isdigit(data[i]) ? (data[i] - 48) << 4 : (data[i] -
+ 87) << 4;
+ decoded[i / 2] +=
+ isdigit(data[i + 1]) ? data[i + 1] - 48 : data[i + 1] -
+ 87;
+ }
+ return decoded;
+}
+
+static char *strip_cr(char *s)
+{
+ int len;
+
+ assert(s);
+
+ len = strlen(s);
+ s[len - 1] = s[len - 1] == '\n' ? 0x00 : s[len - 1];
+
+ return s;
+}
+
+static int read_key(char *buf, int size)
+{
+ int fnval = 1;
+
+ assert(buf);
+ assert(size > 0);
+
+ if (fgets(buf, size, stdin) == NULL) {
+ fnval = 0;
+ goto _return;
+ }
+
+ strip_cr(buf);
+
+ _return:
+ return fnval;
+}
+
+static void msg(const char *format, ...)
+{
+ assert(format != NULL);
+
+ if (verbose) {
+ /* Used to log issues that cause pam_mount to fail. */
+ va_list args;
+
+ va_start(args, format);
+ vfprintf(stdout, format, args);
+ va_end(args);
+ }
+}
+
+static int run_cryptsetup(const char *block_key_cipher, const char *device,
+ const char *uuid, const char *key,
+ const int key_len)
+{
+ pid_t child;
+ int fnval = 1, pipefd[2], child_exit;
+ char dmname[PATH_MAX + 1], *key_len_str;
+
+ assert(block_key_cipher != NULL);
+ assert(device != NULL);
+ assert(uuid != NULL);
+ assert(key != NULL);
+ assert(key_len > 0);
+
+ if (asprintf(&key_len_str, "%d", key_len) == -1) {
+ fprintf(stderr, "Failed to allocate memory, err=%s\n",
+ strerror(errno));
+ fnval = 0;
+ goto _return_no_free;
+ }
+
+ strcpy(dmname, "sesame_crypto_");
+ strncat(dmname, uuid, sizeof dmname - strlen(dmname));
+
+ if (pipe(pipefd) == -1) {
+ fprintf(stderr, "Failed to create pipe, err=%s\n",
+ strerror(errno));
+ fnval = 0;
+ goto _return;
+ }
+
+ child = fork();
+
+ if (child < 0) {
+ fprintf(stderr, "Failed to fork, err=%s\n",
+ strerror(errno));
+ fnval = 0;
+ goto _return;
+ } else if (child == 0) {
+ close(0);
+ dup(pipefd[0]);
+ close(pipefd[0]);
+ close(pipefd[1]);
+ execl(CRYPTSETUP, "cryptsetup", "-s", key_len_str, "-c",
+ block_key_cipher, "create", dmname, device, NULL);
+ fprintf(stderr, "Failed to execute %s, err=%s\n",
+ CRYPTSETUP, strerror(errno));
+ exit(EXIT_FAILURE);
+ } else {
+ close(pipefd[0]);
+ write(pipefd[1], key, key_len);
+ close(pipefd[1]);
+ waitpid(child, &child_exit, 0);
+ fnval = !WEXITSTATUS(child_exit);
+ goto _return;
+ }
+
+ _return:
+ free(key_len_str);
+ _return_no_free:
+ return fnval;
+}
+
+int main(int argc, char *argv[])
+{
+ int c, opt_index = 0;
+ char passphrase[BUFSIZ + 1];
+ char dec_key[BUFSIZ + EVP_MAX_KEY_LENGTH];
+ int dec_key_len, real_dec_key_len;
char buf[1024];
+ int fd_metadata;
+ const char *uuid, *enc_key, *enc_key_cipher, *block_key_cipher,
+ *block_key_sha1;
+ struct option opts[] = {
+ {"help", 0, 0, 'h'},
+ {"verbose", 0, 0, 'v'},
+ {0, 0, 0, 0}
+ };
SesameMetaData *md;
- fd_metadata = open (md_file, O_RDONLY);
+ while ((c = getopt_long(argc, argv, "hv", opts, &opt_index)) >= 0) {
+ switch (c) {
+ case 'h':
+ print_usage(EXIT_SUCCESS, NULL, NULL);
+ case 'v':
+ verbose = 1;
+ break;
+ default:
+ print_usage(EXIT_FAILURE, NULL, NULL);
+ }
+ }
+
+ if (argv[optind] == NULL)
+ print_usage(EXIT_FAILURE, NULL, NULL);
+ device = argv[optind];
+
+ msg("opening %s\n", device);
+ fd_metadata = open(device, O_RDONLY);
if (fd_metadata == -1) {
- printf ("Cannot open %s, err=%s\n", md_file, strerror (errno));
+ fprintf(stderr, "Cannot open %s, err=%s\n", device,
+ strerror(errno));
goto error;
}
- if (read (fd_metadata, buf, sizeof (buf)) == -1) {
- printf ("Cannot read from %s, err=%s\n",
- md_file, strerror (errno));
+
+ msg("reading from %s\n", device);
+ if (read(fd_metadata, buf, sizeof(buf)) == -1) {
+ fprintf(stderr, "Cannot read from %s, err=%s\n",
+ device, strerror(errno));
goto error1;
}
- md = sesame_get_metadata_from_buf (buf);
+ msg("parsing metadata\n");
+ md = sesame_get_metadata_from_buf(buf);
if (md == NULL) {
- printf ("Cannot not parse metadata\n");
+ fprintf(stderr, "Cannot not parse metadata\n");
goto error1;
}
- printf ("uuid = %s\n", sesame_get (md, "uuid"));
- printf ("enc_key = %s\n", sesame_get (md, "enc_key"));
+ msg("getting uuid\n");
+ uuid = sesame_get(md, "uuid");
+ if (uuid == NULL) {
+ fprintf(stderr, "Cannot read uuid from %s\n", device);
+ goto error2;
+ }
- sesame_free (md);
+ msg("getting enc_key\n");
+ enc_key = sesame_get(md, "enc_key");
+ if (enc_key == NULL) {
+ fprintf(stderr, "Cannot read enc_key from %s\n", device);
+ goto error2;
+ }
+
+ msg("getting enc_key_cipher\n");
+ enc_key_cipher = sesame_get(md, "enc_key_cipher");
+ if (enc_key == NULL) {
+ fprintf(stderr, "Cannot read enc_key_cipher from %s\n",
+ device);
+ goto error2;
+ }
+
+ msg("getting block_key_cipher\n");
+ block_key_cipher = sesame_get(md, "block_key_cipher");
+ if (block_key_cipher == NULL) {
+ fprintf(stderr, "Cannot read block_key_cipher from %s\n",
+ device);
+ goto error2;
+ }
+
+ msg("getting block_key_sha1\n");
+ block_key_sha1 = sesame_get(md, "block_key_sha1");
+ if (block_key_sha1 == NULL) {
+ fprintf(stderr, "Cannot read block_key_sha1 from %s\n",
+ device);
+ goto error2;
+ }
+
+ if (read_key(passphrase, BUFSIZ) == 0) {
+ fprintf(stderr, "Could not read key\n");
+ goto error2;
+ }
+
+ msg("decrypting key using passphrase\n");
+ if (decrypt
+ (dec_key, &dec_key_len, decode(enc_key), strlen(enc_key) / 2,
+ enc_key_cipher, passphrase) == 0) {
+ fprintf(stderr, "Cannot decrypt key\n");
+ goto error2;
+ }
+
+ msg("checking for MAGICTAIL tail in key\n");
+ real_dec_key_len = dec_key_len - strlen(MAGICTAIL);
+ if (memcmp
+ (dec_key + real_dec_key_len, MAGICTAIL, strlen(MAGICTAIL))) {
+ fprintf(stderr, "Key does not end in %s\n", MAGICTAIL);
+ goto error2;
+ }
+
+ msg("executing cryptsetup\n");
+ if (run_cryptsetup(block_key_cipher, device, uuid, dec_key,
+ real_dec_key_len) == 0) {
+ goto error2;
+ }
+
+error2:
+ msg("freeing memory\n");
+ sesame_free(md);
error1:
- close (fd_metadata);
+ close(fd_metadata);
error:
return 0;
}
More information about the hal-commit
mailing list