Control: tags -1 -moreinfo
Control: retitle -1 unblock: ecryptfs-utils/103-5

On Sun, Mar 22, 2015 at 10:55 AM, Niels Thykier <ni...@thykier.net> wrote:
> Thanks for reporting this.  Unfortunately, I do have a concern with one
> of the changes.
>
>  * The function "static int read_v1_wrapped_passphrase_file":
>    - The documentation says it will return negatively on failure, but
>      AFAICT it will unconditionally return 0.
>    - I guess the last line should have been "return rc" rather than
>      "return 0".
 You are right. This is fixed upstream and backported.
Debdiff between the versions of testing and unstable attached.

Cheers,
Laszlo/GCS
diff -Nru ecryptfs-utils-103/debian/changelog ecryptfs-utils-103/debian/changelog
--- ecryptfs-utils-103/debian/changelog	2013-09-18 08:49:47.000000000 +0000
+++ ecryptfs-utils-103/debian/changelog	2015-03-28 06:22:00.000000000 +0000
@@ -1,3 +1,15 @@
+ecryptfs-utils (103-5) unstable; urgency=medium
+
+  * Backport fix for upstream mistake in CVE-2014-9687.
+
+ -- Laszlo Boszormenyi (GCS) <g...@debian.org>  Sat, 28 Mar 2015 06:16:10 +0000
+
+ecryptfs-utils (103-4) unstable; urgency=high
+
+  * Backport upstream fix for CVE-2014-9687 (closes: #780385).
+
+ -- Laszlo Boszormenyi (GCS) <g...@debian.org>  Fri, 20 Mar 2015 21:08:39 +0000
+
 ecryptfs-utils (103-3) unstable; urgency=low
 
   * New maintainer (closes: #723595).
diff -Nru ecryptfs-utils-103/debian/patches/CVE-2014-9687.patch ecryptfs-utils-103/debian/patches/CVE-2014-9687.patch
--- ecryptfs-utils-103/debian/patches/CVE-2014-9687.patch	1970-01-01 00:00:00.000000000 +0000
+++ ecryptfs-utils-103/debian/patches/CVE-2014-9687.patch	2015-03-28 00:46:46.000000000 +0000
@@ -0,0 +1,1074 @@
+Subject: Salt the wrapping passphrase
+ Modify ecryptfs_wrap_passphrase() to randomly generate an 8 byte salt to be
+ used with the wrapping passphrase.
+ .
+ The salt is stored in the wrapped-passphrase file. To accomodate the randomly
+ generated salt, a new wrapped-passphrase file format is introduced. It is
+ referred to as "version 2".
+ .
+ The ability to read the version 1 wrapped-passphrase file format is retained.
+ However, ecryptfs_wrap_passphrase() is modified to only create version 2
+ wrapped-passphrase files.
+ .
+ The pam_ecryptfs module is modified to transparently migrate from version 1 to
+ version 2 files when the user successfully logs in with their login password.
+Author: Tyler Hicks <tyhi...@canonical.com>
+Forwarded: https://code.launchpad.net/~tyhicks/ecryptfs/v2-wrapped-passphrase-files/+merge/249908
+
+---
+ src/include/ecryptfs.h                             |    4 
+ src/libecryptfs/key_management.c                   |  516 +++++++++++++++++++--
+ src/pam_ecryptfs/pam_ecryptfs.c                    |   32 +
+ tests/userspace/Makefile.am                        |   15 
+ tests/userspace/tests.rc                           |    2 
+ tests/userspace/v1-to-v2-wrapped-passphrase.sh     |   63 ++
+ tests/userspace/v1-to-v2-wrapped-passphrase/test.c |  189 +++++++
+ tests/userspace/v1-to-v2-wrapped-passphrase/wp01   |    1 
+ tests/userspace/v1-to-v2-wrapped-passphrase/wp02   |    1 
+ tests/userspace/v1-to-v2-wrapped-passphrase/wp03   |    1 
+ tests/userspace/v1-to-v2-wrapped-passphrase/wp04   |    1 
+ tests/userspace/v1-to-v2-wrapped-passphrase/wp05   |    1 
+ tests/userspace/wrap-unwrap.sh                     |    7 
+ 13 files changed, 776 insertions(+), 57 deletions(-)
+
+Index: ecryptfs-utils-104/src/include/ecryptfs.h
+===================================================================
+--- ecryptfs-utils-104.orig/src/include/ecryptfs.h	2015-02-19 14:22:42.278097623 -0600
++++ ecryptfs-utils-104/src/include/ecryptfs.h	2015-02-19 14:22:42.266097681 -0600
+@@ -515,10 +515,12 @@ int ecryptfs_read_salt_hex_from_rc(char
+ int ecryptfs_check_sig(char *auth_tok_sig, char *sig_cache_filename,
+ 		       int *flags);
+ int ecryptfs_append_sig(char *auth_tok_sig, char *sig_cache_filename);
++int __ecryptfs_detect_wrapped_passphrase_file_version(const char *filename,
++						      uint8_t *version);
+ int ecryptfs_wrap_passphrase_file(char *dest, char *wrapping_passphrase,
+  			     char *wrapping_salt, char *src);
+ int ecryptfs_wrap_passphrase(char *filename, char *wrapping_passphrase,
+-			     char *wrapping_salt, char *decrypted_passphrase);
++			     char *unused, char *decrypted_passphrase);
+ int ecryptfs_unwrap_passphrase(char *decrypted_passphrase, char *filename,
+ 			       char *wrapping_passphrase, char *wrapping_salt);
+ int ecryptfs_insert_wrapped_passphrase_into_keyring(
+Index: ecryptfs-utils-104/src/libecryptfs/key_management.c
+===================================================================
+--- ecryptfs-utils-104.orig/src/libecryptfs/key_management.c	2015-02-19 14:22:42.278097623 -0600
++++ ecryptfs-utils-104/src/libecryptfs/key_management.c	2015-02-19 14:22:44.470087236 -0600
+@@ -38,6 +38,7 @@
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <pwd.h>
++#include <inttypes.h>
+ #include "../include/ecryptfs.h"
+ 
+ #ifndef ENOKEY
+@@ -242,6 +243,163 @@ out:
+ 	return rc;
+ }
+ 
++/**
++ * A wrapper around write(2) that handles short and interrupted writes.
++ *
++ * Returns the number of bytes written or -1 with errno set on failure.
++ */
++static ssize_t do_write(int fd, const void *buf, size_t count)
++{
++	ssize_t rc = 0;
++
++	do {
++		ssize_t bytes = write(fd, buf + rc, count - rc);
++
++		if (bytes == -1) {
++			if (errno == EINTR)
++				continue;
++			return -1;
++		}
++
++		rc += bytes;
++	} while (rc < count);
++
++	return rc;
++}
++
++/**
++ * A wrapper around read(2) that handles short and interrupted reads.
++ *
++ * Returns the number of bytes read or -1 with errno set on failure.
++ */
++static ssize_t do_read(int fd, void *buf, size_t count)
++{
++	ssize_t rc = 0;
++
++	do {
++		ssize_t bytes = read(fd, buf + rc, count - rc);
++
++		if (bytes == 0) {
++			break;
++		} else if (bytes == -1) {
++			if (errno == EINTR)
++				continue;
++
++			return -1;
++		}
++
++		rc += bytes;
++	} while (rc < count);
++
++	return rc;
++}
++
++/**
++ * read_wrapped_passphrase_file_version
++ * @fd: A file descriptor, opened for reading, of a wrapped passphrase file
++ * @version: On success, *version is set to the detected file version
++ *
++ * Sets the fd offset to 0 and attempts to determine the version number of the
++ * opened wrapped-passphrase file. If a versioned wrapped-passphrase file is
++ * not found and the first 16 bytes of the file are hex encoded values, then
++ * the version is assumed to be '1'.
++ *
++ * Returns 0 on success, sets *version to the determined wrapped-passphrase
++ * file version, and ensures that the fd offset is appropriately set for
++ * reading the next field in the wrapped passphrase file. Returns negative on
++ * error (*version and the fd offset is undefined upon error).
++ */
++static int read_wrapped_passphrase_file_version(int fd, uint8_t *version)
++{
++	char buf[ECRYPTFS_SIG_SIZE_HEX];
++	int bytes_read, i;
++
++	memset(buf, 0, sizeof(buf));
++
++	if (lseek(fd, 0, SEEK_SET) != 0)
++		return -errno;
++
++	bytes_read = do_read(fd, buf, sizeof(buf));
++	if (bytes_read < 0)
++		return -errno;
++	else if (bytes_read != sizeof(buf))
++		return -EINVAL;
++
++	if (buf[0] == ':') {
++		/* A leading ':' character means that this is a properly
++		 * versioned wrapped passphrase file. The second octet contains
++		 * the version number.
++		 */
++		uint8_t v = buf[1];
++
++		/* Only version 2 files are currently supported */
++		if (v != 2)
++			return -ENOTSUP;
++
++		/* Set the offset to the beginning of the wrapping salt field */
++		if (lseek(fd, 2, SEEK_SET) != 2)
++			return -errno;
++
++		*version = v;
++	} else {
++		/* This wrapped passphrase file isn't versioned. We can assume
++		 * that it is a "version 1" file if the first 16 bytes are hex
++		 * encoded values.
++		 */
++		for (i = 0; i < bytes_read; i++) {
++			if (!isxdigit(buf[i]))
++				return -EINVAL;
++		}
++
++		/* Reset the offset to 0 since there is no actual version field
++		 * in version 1 files
++		 */
++		if (lseek(fd, 0, SEEK_SET) != 0)
++			return -errno;
++
++		*version = 1;
++	}
++
++	return 0;
++}
++
++/**
++ * __ecryptfs_detect_wrapped_passphrase_file_version
++ * @filename: The path of a wrapped passphrase file
++ * @version: On success, *version is set to the detected file version
++ *
++ * THIS FUNCTION IS NOT PART OF THE LIBECRYPTFS PUBLIC API. Code external to
++ * ecryptfs-utils should not use it.
++ *
++ * Detects the wrapped passphrase file version of @filename.
++ *
++ * Returns 0 on success, sets *version to the determined wrapped-passphrase
++ * file version. Returns negative on error (*version is undefined upon error).
++ */
++int __ecryptfs_detect_wrapped_passphrase_file_version(const char *filename,
++						      uint8_t *version)
++{
++	int fd = -1;
++	int rc;
++
++	fd = open(filename, O_RDONLY);
++	if (fd == -1) {
++		rc = -errno;
++		goto out;
++	}
++
++	rc = read_wrapped_passphrase_file_version(fd, version);
++	if (rc != 0)
++		goto out;
++
++	rc = 0;
++out:
++	if (fd != -1)
++		close(fd);
++
++	return rc;
++}
++
+ int ecryptfs_wrap_passphrase_file(char *dest, char *wrapping_passphrase,
+ 				  char *salt, char *src)
+ {
+@@ -260,8 +418,8 @@ int ecryptfs_wrap_passphrase_file(char *
+ 		close(fd);
+ 		goto out;
+ 	}
+-	if ((size = read(fd, decrypted_passphrase,
+-			 ECRYPTFS_MAX_PASSPHRASE_BYTES)) <= 0) {
++	if ((size = do_read(fd, decrypted_passphrase,
++			    ECRYPTFS_MAX_PASSPHRASE_BYTES)) <= 0) {
+ 		syslog(LOG_ERR, "Error attempting to read encrypted "
+ 		       "passphrase from file [%s]; size = [%zd]\n",
+ 		       src, size);
+@@ -285,9 +443,127 @@ out:
+ 	return rc;
+ }
+ 
++static int read_urandom(void *buf, size_t count)
++{
++	ssize_t bytes;
++	int fd = -1;
++
++	fd = open("/dev/urandom", O_RDONLY);
++	if (fd == -1)
++		return -1;
++
++	bytes = do_read(fd, buf, count);
++	close(fd);
++
++	return bytes;
++}
++
++/**
++ * write_v2_wrapped_passphrase_file
++ * @filename: Path to the wrapped passphrase file
++ * @wrapping_salt: The salt to be used with the wrapping passphrase
++ * @wrapping_key_sig: The signature of the wrapping key
++ * @encrypted_passphrase: The encrypted passphrase
++ * @encrypted_passphrase_bytes: The size of the encrypted passphrase
++ *
++ * Writes a version 2 wrapped passphrase file containing the following format
++ * described in the read_v2_wrapped_passphrase_file() function.
++ *
++ * Returns 0 upon success. Negative upon error.
++ */
++static int write_v2_wrapped_passphrase_file(const char *filename,
++			const char wrapping_salt[ECRYPTFS_SALT_SIZE],
++			const char wrapping_key_sig[ECRYPTFS_SIG_SIZE_HEX],
++			const char *encrypted_passphrase,
++			int encrypted_passphrase_bytes)
++{
++	ssize_t size;
++	uint8_t version = 2;
++	mode_t old_umask;
++	char *temp = NULL;
++	int fd = -1;
++	int rc;
++
++	if (asprintf(&temp, "%s-XXXXXX", filename) < 0) {
++		rc = -errno;
++		temp = NULL;
++		goto out;
++	}
++
++	old_umask = umask(S_IRWXG | S_IRWXO);
++	fd = mkstemp(temp);
++	umask(old_umask);
++	if (fd == -1) {
++		rc = -errno;
++		goto out;
++	}
++
++	size = do_write(fd, ":", 1);
++	if (size != 1) {
++		rc = size == -1 ? -errno : -EIO;
++		goto out;
++	}
++
++	size = do_write(fd, &version, 1);
++	if (size != 1) {
++		rc = size == -1 ? -errno : -EIO;
++		goto out;
++	}
++
++	size = do_write(fd, wrapping_salt, ECRYPTFS_SALT_SIZE);
++	if (size != ECRYPTFS_SALT_SIZE) {
++		rc = size == -1 ? -errno : -EIO;
++		goto out;
++	}
++
++	size = do_write(fd, wrapping_key_sig, ECRYPTFS_SIG_SIZE_HEX);
++	if (size != ECRYPTFS_SIG_SIZE_HEX) {
++		rc = size == -1 ? -errno : -EIO;
++		goto out;
++	}
++
++	size = do_write(fd, encrypted_passphrase, encrypted_passphrase_bytes);
++	if (size != encrypted_passphrase_bytes) {
++		rc = size == -1 ? -errno : -EIO;
++		goto out;
++	}
++
++	if (fsync(fd) == -1) {
++		rc = -errno;
++		goto out;
++	}
++
++	close(fd);
++	fd = -1;
++
++	if (rename(temp, filename) == -1) {
++		rc = -errno;
++		goto out;
++	}
++
++	rc = 0;
++out:
++	if (fd != -1)
++		close(fd);
++	free(temp);
++
++	return rc;
++}
++
++/**
++ * ecryptfs_wrap_passphrase
++ * @filename: Path to the wrapped passphrase file
++ * @wrapping_passphrase: The passphrase used for wrapping the @decrypted_passphrase
++ * @unused: Previously used for specifying a wrapping salt. It is now randomly
++ *  generated so @unused is no longer used.
++ * @decrypted_passphrase: The passphrase to be wrapped
++ *
++ * Returns 0 upon success. Negative upon error.
++ */
+ int ecryptfs_wrap_passphrase(char *filename, char *wrapping_passphrase,
+-			     char *wrapping_salt, char *decrypted_passphrase)
++			     char *unused, char *decrypted_passphrase)
+ {
++	char wrapping_salt[ECRYPTFS_SALT_SIZE];
+ 	char wrapping_auth_tok_sig[ECRYPTFS_SIG_SIZE_HEX + 1];
+ 	char wrapping_key[ECRYPTFS_MAX_KEY_BYTES];
+ 	char padded_decrypted_passphrase[ECRYPTFS_MAX_PASSPHRASE_BYTES +
+@@ -318,6 +594,13 @@ int ecryptfs_wrap_passphrase(char *filen
+ 		rc = -EIO;
+ 		goto out;
+ 	}
++	rc = read_urandom(wrapping_salt, ECRYPTFS_SALT_SIZE);
++	if (rc != ECRYPTFS_SALT_SIZE) {
++		rc = rc == -1 ? -errno : -EIO;
++		syslog(LOG_ERR, "Error generating random salt: %s\n",
++		       strerror(-rc));
++		goto out;
++	}
+ 	rc = generate_passphrase_sig(wrapping_auth_tok_sig, wrapping_key,
+ 				     wrapping_salt, wrapping_passphrase);
+ 	if (rc) {
+@@ -395,35 +678,163 @@ nss_finish:
+ 		rc = - EIO;
+ 		goto out;
+ 	}
+-	unlink(filename);
+-	if ((fd = open(filename, (O_WRONLY | O_CREAT | O_EXCL),
+-		       (S_IRUSR | S_IWUSR))) == -1) {
+-		syslog(LOG_ERR, "Error attempting to open [%s] for writing\n",
++	rc = write_v2_wrapped_passphrase_file(filename, wrapping_salt,
++					      wrapping_auth_tok_sig,
++					      encrypted_passphrase,
++					      encrypted_passphrase_bytes);
++	if (rc)
++		goto out;
++	rc = 0;
++out:
++	return rc;
++}
++
++/**
++ * read_v1_wrapped_passphrase_file - Reads a v1 wrapped passphrase file
++ * @filename: Path to the wrapped passphrase file
++ * @wrapping_key_sig: Will contain the parsed wrapping key sig upon success.
++ *  MUST be zeroed prior to calling this function.
++ * @encrypted_passphrase: Will contain the parsed encrypted passphrase upon
++ *  success. MUST be zeroed prior to calling this function.
++ * @encrypted_passphrase_bytes: Will contain the size of the parsed encrypted
++ *  passphrase upon success
++ *
++ * Reads a version 1 wrapped passphrase file containing the following format:
++ *
++ *   Octets 0-15:   Signature of wrapping key
++ *   Octets 16-79:  Variable length field containing the encrypted
++ *                  passphrase.
++ *
++ * Returns 0 upon success with the size of the encrypted passphrase returned in
++ * *encrypted_passphrase_bytes. Returns negative upon failure.
++ */
++static int read_v1_wrapped_passphrase_file(const char *filename,
++				char wrapping_key_sig[ECRYPTFS_SIG_SIZE_HEX],
++				char encrypted_passphrase[ECRYPTFS_MAX_PASSPHRASE_BYTES],
++				int *encrypted_passphrase_bytes)
++{
++	ssize_t size;
++	int fd;
++	int rc;
++
++	*encrypted_passphrase_bytes = 0;
++
++	if ((fd = open(filename, O_RDONLY)) == -1) {
++		syslog(LOG_ERR, "Error attempting to open [%s] for reading\n",
+ 		       filename);
+ 		rc = -EIO;
+ 		goto out;
+ 	}
+-	if ((size = write(fd, wrapping_auth_tok_sig,
+-			  ECRYPTFS_SIG_SIZE_HEX)) <= 0) {
+-		syslog(LOG_ERR, "Error attempting to write encrypted "
+-		       "passphrase ([%d] bytes) to file [%s]; size = [%zu]\n",
+-		       encrypted_passphrase_bytes, filename, size);
++
++	if ((size = do_read(fd, wrapping_key_sig,
++			    ECRYPTFS_SIG_SIZE_HEX)) < ECRYPTFS_SIG_SIZE_HEX) {
++		syslog(LOG_ERR,
++		       "Error attempting to read encrypted passphrase from file [%s]; size = [%zu]\n",
++		       filename, size);
+ 		rc = -EIO;
+-		close(fd);
+ 		goto out;
+ 	}
+-	if ((size = write(fd, encrypted_passphrase,
+-			  encrypted_passphrase_bytes)) <= 0) {
+-		syslog(LOG_ERR, "Error attempting to write encrypted "
+-		       "passphrase ([%d] bytes) to file [%s]; size = [%zu]\n",
+-		       encrypted_passphrase_bytes, filename, size);
++
++	if ((size = do_read(fd, encrypted_passphrase,
++			    ECRYPTFS_MAX_PASSPHRASE_BYTES)) <= 0) {
++		syslog(LOG_ERR,
++		       "Error attempting to read encrypted passphrase from file [%s]; size = [%zu]\n",
++		       filename, size);
+ 		rc = -EIO;
++		goto out;
++	}
++
++	*encrypted_passphrase_bytes = size;
++	rc = 0;
++out:
++	if (fd != -1)
+ 		close(fd);
++
++	return rc;
++}
++
++/**
++ * read_v2_wrapped_passphrase_file - Reads a v2 wrapped passphrase file
++ * @filename: Path to the wrapped passphrase file
++ * @wrapping_salt: Will contain the parsed wrapping salt upon success. MUST be
++ *  zeroed prior to calling this function.
++ * @wrapping_key_sig: Will contain the parsed wrapping key sig upon success.
++ *  MUST be zeroed prior to calling this function.
++ * @encrypted_passphrase: Will contain the parsed encrypted passphrase upon
++ *  success. MUST be zeroed prior to calling this function.
++ * @encrypted_passphrase_bytes: Will contain the size of the parsed encrypted
++ *  passphrase upon success
++ *
++ * Reads a version 2 wrapped passphrase file containing the following format:
++ *
++ *   Octet  0:      A ':' character
++ *   Octet  1:      uint8_t value indicating file version (MUST be 0x02)
++ *   Octets 2-9:    Wrapping salt
++ *   Octets 10-25:  Signature of wrapping key (16 octets)
++ *   Octets 26-N1:  Variable length field containing the encrypted
++ *                  passphrase. (Up to 64 octets. Must be non-empty.)
++ *
++ * Returns 0 upon success with the size of the encrypted passphrase returned in
++ * *encrypted_passphrase_bytes. Returns negative upon failure.
++ */
++static int read_v2_wrapped_passphrase_file(const char *filename,
++				char wrapping_salt[ECRYPTFS_SALT_SIZE],
++				char wrapping_key_sig[ECRYPTFS_SIG_SIZE_HEX],
++				char encrypted_passphrase[ECRYPTFS_MAX_PASSPHRASE_BYTES],
++				int *encrypted_passphrase_bytes)
++{
++	uint8_t version = 0;
++	uint8_t salt_len = 0;
++	ssize_t size;
++	int fd = -1;
++	int rc;
++
++	*encrypted_passphrase_bytes = 0;
++
++	if ((fd = open(filename, O_RDONLY)) == -1) {
++		rc = -errno;
+ 		goto out;
+ 	}
+-	close(fd);
++
++	/* Parse file version (must be 2) */
++	rc = read_wrapped_passphrase_file_version(fd, &version);
++	if (rc != 0) {
++		goto out;
++	} else if (version != 2) {
++		rc = -EINVAL;
++		goto out;
++	}
++
++	/* Parse the wrapping salt */
++	size = do_read(fd, wrapping_salt, ECRYPTFS_SALT_SIZE);
++	if (size != ECRYPTFS_SALT_SIZE) {
++		rc = size == -1 ? errno : -EINVAL;
++		goto out;
++	}
++
++	/* Parse the wrapping key signature */
++	size = do_read(fd, wrapping_key_sig, ECRYPTFS_SIG_SIZE_HEX);
++	if (size != ECRYPTFS_SIG_SIZE_HEX) {
++		rc = size == -1 ? errno : -EINVAL;
++		goto out;
++	}
++
++	/* Parse the encrypted passphrase */
++	size = do_read(fd, encrypted_passphrase, ECRYPTFS_MAX_PASSPHRASE_BYTES);
++	if (size < 0) {
++		rc = size;
++		goto out;
++	} else if(size == 0) {
++		rc = -EINVAL;
++		goto out;
++	}
++
++	*encrypted_passphrase_bytes = size;
+ 	rc = 0;
+ out:
++	if (fd != -1)
++		close(fd);
++
+ 	return rc;
+ }
+ 
+@@ -434,6 +845,7 @@ out:
+ int ecryptfs_unwrap_passphrase(char *decrypted_passphrase, char *filename,
+ 			       char *wrapping_passphrase, char *wrapping_salt)
+ {
++	char v2_wrapping_salt[ECRYPTFS_SALT_SIZE];
+ 	char wrapping_auth_tok_sig[ECRYPTFS_SIG_SIZE_HEX + 1];
+ 	char wrapping_auth_tok_sig_from_file[ECRYPTFS_SIG_SIZE_HEX + 1];
+ 	char wrapping_key[ECRYPTFS_MAX_KEY_BYTES];
+@@ -448,14 +860,53 @@ int ecryptfs_unwrap_passphrase(char *dec
+ 	PK11SlotInfo *slot = NULL;
+ 	PK11Context *enc_ctx = NULL;
+ 	SECItem *sec_param = NULL;
++	uint8_t version = 0;
+ 	int encrypted_passphrase_bytes;
+-	int fd;
+-	ssize_t size;
+ 	int rc;
+ 
+ 	memset(wrapping_auth_tok_sig_from_file, 0,
+ 	       sizeof(wrapping_auth_tok_sig_from_file));
+ 	memset(encrypted_passphrase, 0, sizeof(encrypted_passphrase));
++
++	rc = __ecryptfs_detect_wrapped_passphrase_file_version(filename,
++							       &version);
++	if (rc) {
++		syslog(LOG_ERR,
++		       "Failed to detect wrapped passphrase version: %s\n",
++		       strerror(-rc));
++		goto out;
++	}
++
++	if (version == 1) {
++		rc = read_v1_wrapped_passphrase_file(filename,
++						wrapping_auth_tok_sig_from_file,
++						encrypted_passphrase,
++						&encrypted_passphrase_bytes);
++		if (rc)
++			goto out;
++	} else if (version == 2) {
++		rc = read_v2_wrapped_passphrase_file(filename,
++						v2_wrapping_salt,
++						wrapping_auth_tok_sig_from_file,
++						encrypted_passphrase,
++						&encrypted_passphrase_bytes);
++		if (rc)
++			goto out;
++
++		/**
++		 * Version 2 wrapped passphrase self-contains the wrapping salt.
++		 * The passed in @wrapping_salt buffer is ignored and the
++		 * parsed wrapping salt is used instead.
++		 */
++		wrapping_salt = v2_wrapping_salt;
++	} else {
++		syslog(LOG_ERR,
++		       "Unsupported wrapped passphrase file version: %u\n",
++		       version);
++		rc = -ENOTSUP;
++		goto out;
++	}
++
+ 	rc = generate_passphrase_sig(wrapping_auth_tok_sig, wrapping_key,
+ 				     wrapping_salt, wrapping_passphrase);
+ 	if (rc) {
+@@ -464,31 +915,7 @@ int ecryptfs_unwrap_passphrase(char *dec
+ 		rc = (rc < 0) ? rc : rc * -1;
+ 		goto out;
+ 	}
+-	if ((fd = open(filename, O_RDONLY)) == -1) {
+-		syslog(LOG_ERR, "Error attempting to open [%s] for reading\n",
+-		       filename);
+-		rc = -EIO;
+-		goto out;
+-	}
+-	if ((size = read(fd, wrapping_auth_tok_sig_from_file,
+-			 ECRYPTFS_SIG_SIZE_HEX)) <= 0) {
+-		syslog(LOG_ERR, "Error attempting to read encrypted "
+-		       "passphrase from file [%s]; size = [%zu]\n",
+-		       filename, size);
+-		rc = -EIO;
+-		close(fd);
+-		goto out;
+-	}
+-	if ((size = read(fd, encrypted_passphrase,
+-			 ECRYPTFS_MAX_PASSPHRASE_BYTES)) <= 0) {
+-		syslog(LOG_ERR, "Error attempting to read encrypted "
+-		       "passphrase from file [%s]; size = [%zu]\n",
+-		       filename, size);
+-		rc = -EIO;
+-		close(fd);
+-		goto out;
+-	}
+-	close(fd);
++
+ 	if (memcmp(wrapping_auth_tok_sig_from_file, wrapping_auth_tok_sig,
+ 		   ECRYPTFS_SIG_SIZE_HEX) != 0) {
+ 		syslog(LOG_ERR, "Incorrect wrapping key for file [%s]\n",
+@@ -496,7 +923,6 @@ int ecryptfs_unwrap_passphrase(char *dec
+ 		rc = -EIO;
+ 		goto out;
+ 	}
+-	encrypted_passphrase_bytes = size;
+ 	NSS_NoDB_Init(NULL);
+ 	slot = PK11_GetBestSlot(CKM_AES_ECB, NULL);
+ 	key_item.data = (unsigned char *)wrapping_key;
+Index: ecryptfs-utils-104/src/pam_ecryptfs/pam_ecryptfs.c
+===================================================================
+--- ecryptfs-utils-104.orig/src/pam_ecryptfs/pam_ecryptfs.c	2015-02-19 14:22:42.278097623 -0600
++++ ecryptfs-utils-104/src/pam_ecryptfs/pam_ecryptfs.c	2015-02-19 14:22:42.270097662 -0600
+@@ -120,6 +120,34 @@ static int wrap_passphrase_if_necessary(
+ 	return 0;
+ }
+ 
++static int rewrap_passphrase_if_necessary(char *wrapped_pw_filename,
++					  char *wrapping_passphrase, char *salt)
++{
++	char passphrase[ECRYPTFS_MAX_PASSPHRASE_BYTES + 1];
++	uint8_t version;
++	int rc;
++
++	memset(passphrase, 0, sizeof(passphrase));
++
++	rc = __ecryptfs_detect_wrapped_passphrase_file_version(
++							wrapped_pw_filename,
++							&version);
++	if (rc)
++		return rc;
++
++	/* Only rewrap version 1 files */
++	if (version > 1)
++		return 0;
++
++	rc = ecryptfs_unwrap_passphrase(passphrase, wrapped_pw_filename,
++					wrapping_passphrase, salt);
++	if (rc)
++		return rc;
++
++	return ecryptfs_wrap_passphrase(wrapped_pw_filename,
++					wrapping_passphrase, NULL, passphrase);
++}
++
+ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
+ 				   const char **argv)
+ {
+@@ -228,6 +256,10 @@ PAM_EXTERN int pam_sm_authenticate(pam_h
+ 			} else {
+ 				goto out_child;
+ 			}
++			if (rewrap_passphrase_if_necessary(wrapped_pw_filename, passphrase, salt)) {
++				/* Non fatal condition. Log a warning. */
++				syslog(LOG_WARNING, "pam_ecryptfs: Unable to rewrap passphrase file\n");
++			}
+ 			rc = ecryptfs_insert_wrapped_passphrase_into_keyring(
+ 				auth_tok_sig, wrapped_pw_filename, passphrase,
+ 				salt);
+Index: ecryptfs-utils-104/tests/userspace/Makefile.am
+===================================================================
+--- ecryptfs-utils-104.orig/tests/userspace/Makefile.am	2015-02-19 14:22:42.278097623 -0600
++++ ecryptfs-utils-104/tests/userspace/Makefile.am	2015-02-19 14:22:42.270097662 -0600
+@@ -1,17 +1,15 @@
+ AUTOMAKE_OPTIONS = subdir-objects
+ 
+ # Only place tests worth of 'make check' here. All other tests are noinst.
+-dist_check_SCRIPTS = verify-passphrase-sig.sh
+-check_PROGRAMS = verify-passphrase-sig/test
++dist_check_SCRIPTS = verify-passphrase-sig.sh wrap-unwrap.sh v1-to-v2-wrapped-passphrase.sh
++check_PROGRAMS = verify-passphrase-sig/test wrap-unwrap/test v1-to-v2-wrapped-passphrase/test
+ 
+ dist_noinst_DATA = tests.rc
+ 
+-dist_noinst_SCRIPTS = $(dist_check_SCRIPTS) \
+-		      wrap-unwrap.sh
++dist_noinst_SCRIPTS = $(dist_check_SCRIPTS)
+ 
+ if ENABLE_TESTS
+-noinst_PROGRAMS = $(check_PROGRAMS) \
+-		  wrap-unwrap/test
++noinst_PROGRAMS = $(check_PROGRAMS)
+ endif
+ 
+ verify_passphrase_sig_test_SOURCES = verify-passphrase-sig/test.c
+@@ -20,5 +18,8 @@ verify_passphrase_sig_test_LDADD = $(top
+ wrap_unwrap_test_SOURCES = wrap-unwrap/test.c
+ wrap_unwrap_test_LDADD = $(top_builddir)/src/libecryptfs/libecryptfs.la
+ 
+-TESTS = verify-passphrase-sig.sh
++v1_to_v2_wrapped_passphrase_test_SOURCES = v1-to-v2-wrapped-passphrase/test.c
++v1_to_v2_wrapped_passphrase_test_LDADD = $(top_builddir)/src/libecryptfs/libecryptfs.la
++
++TESTS = verify-passphrase-sig.sh wrap-unwrap.sh v1-to-v2-wrapped-passphrase.sh
+ 
+Index: ecryptfs-utils-104/tests/userspace/tests.rc
+===================================================================
+--- ecryptfs-utils-104.orig/tests/userspace/tests.rc	2015-02-19 14:22:42.278097623 -0600
++++ ecryptfs-utils-104/tests/userspace/tests.rc	2015-02-19 14:22:42.270097662 -0600
+@@ -1 +1 @@
+-safe="verify-passphrase-sig.sh wrap-unwrap.sh"
++safe="verify-passphrase-sig.sh wrap-unwrap.sh v1-to-v2-wrapped-passphrase.sh"
+Index: ecryptfs-utils-104/tests/userspace/v1-to-v2-wrapped-passphrase.sh
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ ecryptfs-utils-104/tests/userspace/v1-to-v2-wrapped-passphrase.sh	2015-02-19 14:22:42.270097662 -0600
+@@ -0,0 +1,63 @@
++#!/bin/bash
++#
++# v1-to-v2-wrapped-passphrase.sh: Verify that v1 wrapped passphrase files can
++#				   be unwrapped and then rewrapped as v2 files.
++# Author: Tyler Hicks <tyhi...@canonical.com>
++#
++# Copyright (C) 2015 Canonical Ltd.
++#
++# This program is free software; you can redistribute it and/or
++# modify it under the terms of the GNU General Public License
++# as published by the Free Software Foundation version 2
++# of the License.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
++
++test_script_dir=$(dirname $0)
++rc=1
++
++. ${test_script_dir}/../lib/etl_funcs.sh
++
++test_cleanup()
++{
++	etl_remove_test_dir $test_dir
++	exit $rc
++}
++trap test_cleanup 0 1 2 3 15
++
++do_test()
++{
++	${test_script_dir}/v1-to-v2-wrapped-passphrase/test "$@"
++	rc=$?
++	if [ "$rc" -ne 0 ]; then
++		exit
++	fi
++}
++
++test_dir_parent="$TMPDIR"
++if [ -z "$test_dir_parent"]; then
++	test_dir_parent="/tmp"
++fi
++
++test_dir=$(etl_create_test_dir "$test_dir_parent") || exit
++cp "${test_script_dir}/v1-to-v2-wrapped-passphrase/wp"* "$test_dir"
++
++do_test "${test_dir}/wp01" "This is test #1" "Wrapping pass" "0011223344556677"
++
++do_test "${test_dir}/wp02" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" "0011223344556677"
++
++do_test "${test_dir}/wp03" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" "5a175a175a175a17"
++
++do_test "${test_dir}/wp04" "!" "*" "0011223344556677"
++
++do_test "${test_dir}/wp05" "!" "*" "0123456789abcdef"
++
++rc=0
++exit
+Index: ecryptfs-utils-104/tests/userspace/v1-to-v2-wrapped-passphrase/test.c
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ ecryptfs-utils-104/tests/userspace/v1-to-v2-wrapped-passphrase/test.c	2015-02-19 14:22:42.270097662 -0600
+@@ -0,0 +1,189 @@
++/**
++ * test.c: Verify the migration from version 1 to version 2 wrapped-passphrase
++ * 	   files
++ * Author: Tyler Hicks <tyhi...@canonical.com>
++ *
++ * Copyright (C) 2015 Canonical, Ltd.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
++ * 02110-1301, USA
++ */
++
++#include <errno.h>
++#include <stdio.h>
++#include <string.h>
++#include "../../src/include/ecryptfs.h"
++
++#define ECRYPTFS_MAX_KEY_HEX_BYTES (ECRYPTFS_MAX_KEY_BYTES * 2)
++
++#define NEW_WRAPPING_PASSPHRASE "The *new* eCryptfs wrapping passphrase."
++
++static void usage(const char *name)
++{
++	fprintf(stderr,
++		"%s FILENAME EXPECTED_PASS WRAPPING_PASS WRAPPING_SALT_HEX\n",
++		name);
++}
++
++/**
++ * Returns 0 if the unwrap operation resulted in the expected decrypted
++ * passphrase
++ */
++static int verify_unwrap(char *expected_decrypted_passphrase, char *filename,
++			 char *wrapping_passphrase, char *wrapping_salt)
++{
++	char decrypted_passphrase[ECRYPTFS_MAX_PASSPHRASE_BYTES + 1];
++	int rc;
++
++	memset(decrypted_passphrase, 0, sizeof(decrypted_passphrase));
++
++	rc = ecryptfs_unwrap_passphrase(decrypted_passphrase, filename,
++					wrapping_passphrase, wrapping_salt);
++	if (rc)
++		return 1;
++
++	if (strcmp(decrypted_passphrase, expected_decrypted_passphrase))
++		return 1;
++
++	return 0;
++}
++
++/**
++ * Returns 0 if the *invalid* unwrap operations always fail
++ */
++static int verify_bad_unwrap(char *expected_decrypted_passphrase, char *filename,
++			     char *wrapping_passphrase, char *wrapping_salt)
++{
++	char *last;
++	int rc;
++
++	/* Increment first char in the wrapping_passphrase and verify that the
++	 * unwrapping operation fails */
++	wrapping_passphrase[0]++;
++	rc = verify_unwrap(expected_decrypted_passphrase, filename,
++			   wrapping_passphrase, wrapping_salt);
++	wrapping_passphrase[0]--;
++	if (!rc)
++		return 1;
++
++	/* Increment last char in the wrapping_passphrase and verify that the
++	 * unwrapping operation fails */
++	last = wrapping_passphrase + (strlen(wrapping_passphrase) - 1);
++	(*last)++;
++	rc = verify_unwrap(expected_decrypted_passphrase, filename,
++			   wrapping_passphrase, wrapping_salt);
++	(*last)--;
++	if (!rc)
++		return 1;
++
++	/* Perform a one's complement on the first char in the salt and verify
++	 * that the unwrapping operation fails */
++	wrapping_salt[0] = ~wrapping_salt[0];
++	rc = verify_unwrap(expected_decrypted_passphrase, filename,
++			   wrapping_passphrase, wrapping_salt);
++	wrapping_salt[0] = ~wrapping_salt[0];
++	if (!rc)
++		return 1;
++
++	/* Perform a one's complement on the last char in the salt and verify
++	 * that the unwrapping operation fails */
++	last = wrapping_salt + (ECRYPTFS_SALT_SIZE - 1);
++	*last = ~(*last);
++	rc = verify_unwrap(expected_decrypted_passphrase, filename,
++			  wrapping_passphrase, wrapping_salt);
++	*last = ~(*last);
++	if (!rc)
++		return 1;
++
++	return 0;
++}
++
++static int do_rewrap(char *filename, char *old_wrapping_passphrase,
++		     char *old_wrapping_salt, char *new_wrapping_passphrase)
++{
++	char decrypted_passphrase[ECRYPTFS_MAX_PASSPHRASE_BYTES + 1];
++	uint8_t version = 0;
++	int rc;
++
++	memset(decrypted_passphrase, 0, sizeof(decrypted_passphrase));
++
++	rc = ecryptfs_unwrap_passphrase(decrypted_passphrase, filename,
++					old_wrapping_passphrase,
++					old_wrapping_salt);
++	if (rc)
++		return 1;
++
++	rc = ecryptfs_wrap_passphrase(filename, new_wrapping_passphrase, NULL,
++				      decrypted_passphrase);
++	if (rc)
++		return 1;
++
++	rc = __ecryptfs_detect_wrapped_passphrase_file_version(filename,
++							       &version);
++	if (version != 2)
++		return 1;
++
++	return 0;
++}
++
++int main(int argc, char *argv[])
++{
++	char wrapping_salt[ECRYPTFS_SALT_SIZE];
++	char *expected_decrypted_passphrase, *filename, *wrapping_passphrase,
++	     *wrapping_salt_hex;
++	int rc;
++
++	if (argc != 5) {
++		usage(argv[0]);
++		return EINVAL;
++	}
++
++	filename = argv[1];
++	expected_decrypted_passphrase = argv[2];
++	wrapping_passphrase = argv[3];
++	wrapping_salt_hex = argv[4];
++
++	if (strlen(expected_decrypted_passphrase) > ECRYPTFS_MAX_PASSPHRASE_BYTES ||
++	    strlen(wrapping_passphrase) > ECRYPTFS_MAX_PASSPHRASE_BYTES ||
++	    strlen(wrapping_salt_hex) != ECRYPTFS_SALT_SIZE_HEX) {
++		usage(argv[0]);
++		return EINVAL;
++	}
++
++	from_hex(wrapping_salt, wrapping_salt_hex, ECRYPTFS_SALT_SIZE);
++
++	rc = verify_unwrap(expected_decrypted_passphrase, filename,
++			   wrapping_passphrase, wrapping_salt);
++	if (rc)
++		return 1;
++
++	rc = verify_bad_unwrap(expected_decrypted_passphrase, filename,
++			       wrapping_passphrase, wrapping_salt);
++	if (rc)
++		return 2;
++
++	rc = do_rewrap(filename, wrapping_passphrase, wrapping_salt,
++		       NEW_WRAPPING_PASSPHRASE);
++	if (rc)
++		return 3;
++
++	rc = verify_unwrap(expected_decrypted_passphrase, filename,
++			   NEW_WRAPPING_PASSPHRASE, NULL);
++	if (rc)
++		return 4;
++
++	return 0;
++}
++
+Index: ecryptfs-utils-104/tests/userspace/v1-to-v2-wrapped-passphrase/wp01
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ ecryptfs-utils-104/tests/userspace/v1-to-v2-wrapped-passphrase/wp01	2015-02-19 14:22:42.270097662 -0600
+@@ -0,0 +1 @@
++6ee51761d91019e7±:³gf¤ã|ºHF]”
+\ No newline at end of file
+Index: ecryptfs-utils-104/tests/userspace/v1-to-v2-wrapped-passphrase/wp02
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ ecryptfs-utils-104/tests/userspace/v1-to-v2-wrapped-passphrase/wp02	2015-02-19 14:22:42.274097642 -0600
+@@ -0,0 +1 @@
++ebe6ff9d87ea09d6ߺùèËµ©îÁ:…ÁÄߺùèËµ©îÁ:…ÁÄߺùèËµ©îÁ:…ÁÄߺùèËµ©îÁ:…ÁÄ
+\ No newline at end of file
+Index: ecryptfs-utils-104/tests/userspace/v1-to-v2-wrapped-passphrase/wp03
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ ecryptfs-utils-104/tests/userspace/v1-to-v2-wrapped-passphrase/wp03	2015-02-19 14:22:42.274097642 -0600
+@@ -0,0 +1 @@
++4cc3757c3f538695R”u'Pƒý2N¤ˆ"_<R”u'Pƒý2N¤ˆ"_<R”u'Pƒý2N¤ˆ"_<R”u'Pƒý2N¤ˆ"_<
+\ No newline at end of file
+Index: ecryptfs-utils-104/tests/userspace/v1-to-v2-wrapped-passphrase/wp04
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ ecryptfs-utils-104/tests/userspace/v1-to-v2-wrapped-passphrase/wp04	2015-02-19 14:22:42.274097642 -0600
+@@ -0,0 +1 @@
++308b7ec65c69de6b$y­ØÓA|æ6£Ç¿À*É
+\ No newline at end of file
+Index: ecryptfs-utils-104/tests/userspace/v1-to-v2-wrapped-passphrase/wp05
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ ecryptfs-utils-104/tests/userspace/v1-to-v2-wrapped-passphrase/wp05	2015-02-19 14:22:42.274097642 -0600
+@@ -0,0 +1 @@
++bef9457e4740a855ϳ›'964¹÷¬‰¾p
+\ No newline at end of file
+Index: ecryptfs-utils-104/tests/userspace/wrap-unwrap.sh
+===================================================================
+--- ecryptfs-utils-104.orig/tests/userspace/wrap-unwrap.sh	2015-02-19 14:22:42.278097623 -0600
++++ ecryptfs-utils-104/tests/userspace/wrap-unwrap.sh	2015-02-19 14:22:42.274097642 -0600
+@@ -32,7 +32,12 @@ test_cleanup()
+ }
+ trap test_cleanup 0 1 2 3 15
+ 
+-test_dir=$(etl_create_test_dir) || exit
++test_dir_parent="$TMPDIR"
++if [ -z "$test_dir_parent"]; then
++	test_dir_parent="/tmp"
++fi
++
++test_dir=$(etl_create_test_dir "$test_dir_parent") || exit
+ path="${test_dir}/foo"
+ 
+ ${test_script_dir}/wrap-unwrap/test ${path}
diff -Nru ecryptfs-utils-103/debian/patches/series ecryptfs-utils-103/debian/patches/series
--- ecryptfs-utils-103/debian/patches/series	1970-01-01 00:00:00.000000000 +0000
+++ ecryptfs-utils-103/debian/patches/series	2015-03-20 21:21:42.000000000 +0000
@@ -0,0 +1 @@
+CVE-2014-9687.patch

Reply via email to