Beispiel #1
0
void TestAuth::testSaltGeneration()
{
	char salt[32 + 1] = { 0 };
	size_t max_size = sizeof(salt);

	CPPUNIT_ASSERT(1 < strlen(EMPTY_SALT)); // condition for the next test
	CPPUNIT_ASSERT(generate_salt(salt, 1) == -1); // shouldn't fill buffer if it's lesst than EMPTY_SALT

	CPPUNIT_ASSERT(max_size > strlen(EMPTY_SALT)); // condition for the next tests
	CPPUNIT_ASSERT(generate_salt(salt, strlen(EMPTY_SALT) + 1) == 0);
	CPPUNIT_ASSERT(strcmp(salt, EMPTY_SALT) == 0);

	// since generate_salt() is random, we're doing reasonable set of checks for valid salt
	for (int i = 0; i < 100; ++i)
	{
		memset(salt, 0, sizeof(salt));
		CPPUNIT_ASSERT(generate_salt(salt, max_size) == 0);
		CPPUNIT_ASSERT(strlen(salt) == max_size - 1);
		CPPUNIT_ASSERT(strstr(salt, EMPTY_SALT) == salt);
		for (size_t j = strlen(EMPTY_SALT); j < strlen(salt); ++j)
		{
			CPPUNIT_ASSERT(isalnum(salt[j]) != 0 || salt[j] == '.' || salt[j] == '/');
		}
	}
}
Beispiel #2
0
/** \brief Implementation of encrypt function.
 *
 * @param src Source chars.
 * @param srclen Length of source in chars.
 * @return Newly allocated encrypted string.
 */
static char* encrypt_2chan(const char *src, size_t srclen)
{
	char salt[3], enc[14],
			 *str = create_safe_cstr_buffer(srclen);

	generate_salt(salt, str, src, srclen);

	DES_fcrypt(str, salt, enc);
	free(str);
	return memdup(enc + 3, 11);
}
Beispiel #3
0
static int
build_reauthorize_challenge (const char *user,
                             const char *secret,
                             char **challenge)
{
  int ret;
  char *nonce = NULL;
  char *hex = NULL;
  ssize_t salt_len;
  int len;

  salt_len = parse_salt (secret);
  if (salt_len < 0)
    {
      message ("ignoring invalid reauthorize secret");
      ret = -EINVAL;
      goto out;
    }

  ret = generate_salt (&nonce);
  if (ret < 0)
    {
      errno = -ret;
      message ("unable to generate crypt salt: %m");
      goto out;
    }

  ret = hex_encode (user, -1, &hex);
  if (ret < 0)
    {
      errno = -ret;
      message ("couldn't encode user as hex: %m");
      goto out;
    }

  len = asprintf (challenge, "crypt1:%s:%s:%.*s", hex, nonce, (int)salt_len, secret);
  if (len < 0)
    {
      message ("failed to allocate challenge");
      ret = -ENOMEM;
      goto out;
    }

  /* Double check that we didn't include the whole secret */
  assert ((*challenge)[len - 1] == '$');
  assert (strstr (*challenge, secret) == NULL);
  ret = 0;

out:
  free (nonce);
  free (hex);
  return ret;
}
Beispiel #4
0
void TestAuth::setUp()
{
	init_rfsd_instance(&m_instance);

	// prepare in-memory passwd database
	const char *valid_user[2] = { "root", "root" };
	CPPUNIT_ASSERT(add_or_replace_auth(&m_instance.passwd.auths, valid_user[0], valid_user[1]) == 0);

	// prepare auth in server's instance
	m_instance.server.auth_user = strdup(valid_user[0]);
	CPPUNIT_ASSERT(generate_salt(m_instance.server.auth_salt, sizeof(m_instance.server.auth_salt)) == 0);
	m_instance.server.auth_passwd = passwd_hash(get_auth_password(m_instance.passwd.auths, valid_user[0]), m_instance.server.auth_salt);
	CPPUNIT_ASSERT(m_instance.server.auth_passwd != NULL);
}
Beispiel #5
0
/** \brief Implementation of the test function.
 *
 * @param src Source chars.
 * @param srclen Length of source in chars.
 * @param print File to print into.
 * @return Number of tests done.
 */
static int test_2chan(const char *src, size_t srclen, FILE *print)
{
	char salt[3],
			 enc[14],
			 cmp[11],
			 *str = create_safe_cstr_buffer(srclen);

	generate_salt(salt, str, src, srclen);

	DES_fcrypt(str, salt, enc);
	trip_transform(cmp, enc + 3, 10);
	trip_compare(src, enc + 3, cmp, 10, print);
	free(str);
	return 1;
}
Beispiel #6
0
	std::string sum(const std::string &data)
	{
		return compute_hash(data, generate_salt());
	}
Beispiel #7
0
boost::tuple<shared_data::action, client_info> shared_data::process_user(const std::string& uname,
        const std::string& phash,
        int session_id)
{
    boost::mutex::scoped_lock lock(guard_);
    // XXX Get password from database.
    // if(lookup_username_in_database_fails) {
    //     return boost::make_tuple(user_not_found, it->second);
    // }
    auto it = clients_.find(uname);
    if(session_id == -1) {
        // No session id, check if user name in list already.
        if(it == clients_.end()) {
            // User name not in list. Let's add it.
            auto ret = clients_.insert(std::pair<std::string, client_info>(uname, client_info(generate_session_id(), true, generate_salt())));
            it = ret.first;
        }
    } else {
        if(it == clients_.end()) {
            // user not in list, but we've got a session id. Expire session and generate a new id.
            auto ret = clients_.insert(std::pair<std::string, client_info>(uname, client_info(generate_session_id(), true, generate_salt())));
            it = ret.first;
        } else {
            // We have been sent a session_id, check if it's valid.
            if(it->second.session_id != session_id) {
                it->second.signed_in = false;
                return boost::make_tuple(bad_session_id, it->second);
            }
        }
    }
    if(phash.empty()) {
        return boost::make_tuple(send_salt, it->second);
    } else {
        if(check_password(it->second.salt, fixed_password, phash)) {
            it->second.signed_in = true;
            return boost::make_tuple(login_success, it->second);
        } else {
            it->second.signed_in = false;
            return boost::make_tuple(password_failed, it->second);
        }
    }
}
Beispiel #8
0
int main(int argc, char *argv[])
{
    int ch, i;
    int password_fd = -1;
    unsigned int salt_minlen = 0;
    unsigned int salt_maxlen = 0;
    unsigned int rounds_support = 0;
    const char *salt_prefix = NULL;
    const char *salt_arg = NULL;
    unsigned int rounds = 0;
    char *salt = NULL;
    char rounds_str[30];
    char *password = NULL;

#ifdef ENABLE_NLS
    setlocale(LC_ALL, "");
    bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
    textdomain(NLS_CAT_NAME);
#endif

    /* prepend options from environment */
    argv = merge_args(getenv("MKPASSWD_OPTIONS"), argv, &argc);

    while ((ch = GETOPT_LONGISH(argc, argv, "hH:m:5P:R:sS:V", longopts, 0))
	    > 0) {
	switch (ch) {
	case '5':
	    optarg = (char *) "md5";
	    /* fall through */
	case 'm':
	case 'H':
	    if (!optarg || strcaseeq("help", optarg)) {
		display_methods();
		exit(0);
	    }
	    for (i = 0; methods[i].method != NULL; i++)
		if (strcaseeq(methods[i].method, optarg)) {
		    salt_prefix = methods[i].prefix;
		    salt_minlen = methods[i].minlen;
		    salt_maxlen = methods[i].maxlen;
		    rounds_support = methods[i].rounds;
		    break;
		}
	    if (!salt_prefix) {
		fprintf(stderr, _("Invalid method '%s'.\n"), optarg);
		exit(1);
	    }
	    break;
	case 'P':
	    {
		char *p;
		password_fd = strtol(optarg, &p, 10);
		if (p == NULL || *p != '\0' || password_fd < 0) {
		    fprintf(stderr, _("Invalid number '%s'.\n"), optarg);
		    exit(1);
		}
	    }
	    break;
	case 'R':
	    {
		char *p;
		long r;

		r = strtol(optarg, &p, 10);
		if (p == NULL || *p != '\0' || r < 0) {
		    fprintf(stderr, _("Invalid number '%s'.\n"), optarg);
		    exit(1);
		}
		rounds = r;
	    }
	    break;
	case 's':
	    password_fd = 0;
	    break;
	case 'S':
	    salt_arg = optarg;
	    break;
	case 'V':
	    display_version();
	    exit(0);
	case 'h':
	    display_help(EXIT_SUCCESS);
	default:
	    fprintf(stderr, _("Try '%s --help' for more information.\n"),
		    argv[0]);
	    exit(1);
	}
    }
    argc -= optind;
    argv += optind;

    if (argc == 2 && !salt_arg) {
	password = argv[0];
	salt_arg = argv[1];
    } else if (argc == 1) {
	password = argv[0];
    } else if (argc == 0) {
    } else {
	display_help(EXIT_FAILURE);
    }

    /* default: DES password */
    if (!salt_prefix) {
	salt_minlen = methods[0].minlen;
	salt_maxlen = methods[0].maxlen;
	salt_prefix = methods[0].prefix;
    }

    if (streq(salt_prefix, "$2a$") || streq(salt_prefix, "$2y$")) {
	/* OpenBSD Blowfish and derivatives */
	if (rounds <= 5)
	    rounds = 5;
	/* actually for 2a/2y it is the logarithm of the number of rounds */
	snprintf(rounds_str, sizeof(rounds_str), "%02u$", rounds);
    } else if (rounds_support && rounds)
	snprintf(rounds_str, sizeof(rounds_str), "rounds=%u$", rounds);
    else
	rounds_str[0] = '\0';

    if (salt_arg) {
	unsigned int c = strlen(salt_arg);
	if (c < salt_minlen || c > salt_maxlen) {
	    if (salt_minlen == salt_maxlen)
		fprintf(stderr, ngettext(
			"Wrong salt length: %d byte when %d expected.\n",
			"Wrong salt length: %d bytes when %d expected.\n", c),
			c, salt_maxlen);
	    else
		fprintf(stderr, ngettext(
			"Wrong salt length: %d byte when %d <= n <= %d"
			" expected.\n",
			"Wrong salt length: %d bytes when %d <= n <= %d"
			" expected.\n", c),
			c, salt_minlen, salt_maxlen);
	    exit(1);
	}
	while (c-- > 0) {
	    if (strchr(valid_salts, salt_arg[c]) == NULL) {
		fprintf(stderr, _("Illegal salt character '%c'.\n"),
			salt_arg[c]);
		exit(1);
	    }
	}

	salt = NOFAIL(malloc(strlen(salt_prefix) + strlen(rounds_str)
		+ strlen(salt_arg) + 1));
	*salt = '\0';
	strcat(salt, salt_prefix);
	strcat(salt, rounds_str);
	strcat(salt, salt_arg);
    } else {
#ifdef HAVE_SOLARIS_CRYPT_GENSALT
	salt = crypt_gensalt(salt_prefix, NULL);
	if (!salt)
		perror("crypt_gensalt");
#elif defined HAVE_LINUX_CRYPT_GENSALT
	void *entropy = get_random_bytes(64);

	salt = crypt_gensalt(salt_prefix, rounds, entropy, 64);
	if (!salt) {
		fprintf(stderr, "crypt_gensalt failed.\n");
		exit(2);
	}
	free(entropy);
#else
	unsigned int salt_len = salt_maxlen;

	if (salt_minlen != salt_maxlen) { /* salt length can vary */
	    srand(time(NULL) + getpid());
	    salt_len = rand() % (salt_maxlen - salt_minlen + 1) + salt_minlen;
	}

	salt = NOFAIL(malloc(strlen(salt_prefix) + strlen(rounds_str)
		+ salt_len + 1));
	*salt = '\0';
	strcat(salt, salt_prefix);
	strcat(salt, rounds_str);
	generate_salt(salt + strlen(salt), salt_len);
#endif
    }

    if (password) {
    } else if (password_fd != -1) {
	FILE *fp;
	char *p;

	if (isatty(password_fd))
	    fprintf(stderr, _("Password: "******"r");
	if (!fp) {
	    perror("fdopen");
	    exit(2);
	}
	if (!fgets(password, 128, fp)) {
	    perror("fgets");
	    exit(2);
	}

	p = strpbrk(password, "\n\r");
	if (p)
	    *p = '\0';
    } else {
	password = getpass(_("Password: "******"getpass");
	    exit(2);
	}
    }

    {
	const char *result;
	result = crypt(password, salt);
	/* xcrypt returns "*0" on errors */
	if (!result || result[0] == '*') {
	    fprintf(stderr, "crypt failed.\n");
	    exit(2);
	}
	/* yes, using strlen(salt_prefix) on salt. It's not
	 * documented whether crypt_gensalt may change the prefix */
	if (!strneq(result, salt, strlen(salt_prefix))) {
	    fprintf(stderr, _("Method not supported by crypt(3).\n"));
	    exit(2);
	}
	printf("%s\n", result);
    }

    exit(0);
}
Beispiel #9
0
int
reauthorize_prepare (const char *user,
                     const char *password,
                     long keyring,
                     long *out_key)
{
  struct crypt_data *cd = NULL;
  key_serial_t key;
  const char *secret;
  char *salt = NULL;
  ssize_t salt_len;
  char *name = NULL;
  key_perm_t perm;
  int ret;

  if (password == NULL)
    {
      debug ("no password available for user %s", user);
      return 0;
    }

  /* The salt already contains algorithm prefix and suffix */
  ret = generate_salt (&salt);
  if (ret < 0)
    {
      message ("couldn't generate crypt salt: %m");
      goto out;
    }

  cd = calloc (1, sizeof (struct crypt_data));
  if (!cd)
    {
      message ("couldn't allocate crypt data");
      ret = -ENOMEM;
      goto out;
    }

  secret = crypt_r (password, salt, cd);
  if (!secret)
    {
      ret = -errno;
      message ("couldn't crypt reauthorize secret: %m");
      goto out;
    }

  /*
   * Double check that our assumptions about crypt() work
   * as expected. We're later going to be sending away the
   * salt as a challenge, so guarantee that it works.
   */

  salt_len = parse_salt (secret);
  if (salt_len != strlen (salt) || memcmp (secret, salt, salt_len) != 0)
    {
      ret = -EINVAL;
      message ("got invalid result from crypt");
      goto out;
    }

  if (asprintf (&name, "reauthorize/secret/%s", user) < 0)
    {
      ret = -ENOMEM;
      message ("couldn't allocate keyring name");
      goto out;
    }

  /*
   * Don't put our secret into the session keyring until the permissions
   * are strong enough. Since we want that to be atomic, first store in
   * our thread keyring, and then link below.
   */
  if (keyring == 0)
    keyring = KEY_SPEC_SESSION_KEYRING;

  key = add_key ("user", name, "xxx", 3, keyring);
  if (key < 0)
    {
      ret = -errno;
      message ("couldn't create key in kernel session keyring: %s: %m", name);
      goto out;
    }

  /* Set permissions, and double check that what we expect happened */
  perm = KEY_USR_VIEW | KEY_USR_READ | KEY_USR_WRITE | KEY_USR_SEARCH | KEY_USR_LINK;
  if (keyctl_setperm (key, perm) < 0)
    {
      ret = -errno;
      message ("couldn't set permissions on kernel key: %s: %m", name);
      goto out;
    }

  if (keyctl_update (key, secret, strlen (secret)))
    {
      ret = -errno;
      message ("couldn't update secret reauthorize key in kernel keyring: %s: %m", name);
      goto out;
    }

  debug ("placed secret in kernel session keyring");
  *out_key = key;
  ret = 0;

out:
  secfree (cd, sizeof (struct crypt_data));
  free (name);
  free (salt);
  return ret;
}
Beispiel #10
0
Datei: pman.c Projekt: tykel/pman
int authenticate(char **p)
{
    FILE *f_key, *f_salt;
    unsigned char key[AES256_KEY_SIZE], key_stored[AES256_KEY_SIZE];
    unsigned char salt[SHA256_SALT_SIZE];
    char *password, key_fn[BUFFER_SIZE], salt_fn[BUFFER_SIZE];
    int match, i, e, kl, sl, first;

    first = 0;

    snprintf(key_fn, BUFFER_SIZE, "%s/key", fn_dir);
    snprintf(salt_fn, BUFFER_SIZE, "%s/salt", fn_dir);
    f_key = fopen(key_fn, "rb");
    f_salt = fopen(salt_fn, "rb");
    first += (f_key == NULL) + (f_salt == NULL);
    /* A password and salt are stored, so we authenticate */
    if(!first) {
        /* Read salt and stored key for verification */
        kl = fread(key_stored, 1, AES256_KEY_SIZE, f_key);
        sl = fread(salt, 1, SHA256_SALT_SIZE, f_salt);
        fclose(f_key);
        fclose(f_salt);

        /* Check password */
        password = getpassword("Password: "******"gcry error: %d\n", e);
        for(i = 0, match = 1; i < AES256_KEY_SIZE; ++i)
            match = match && (key[i] == key_stored[i]);
        if(match)
            printf("Authentication OK, welcome\n");
        else {
            printf("Authentication failure\n");
            return 1;
        }
    /* One or both are missing, so we set up new ones */
    } else {
        char *cp;
        int match = 0;

        if(f_key) fclose(f_key);
        if(f_salt) fclose(f_salt);
        /* Prompt for new password */
        printf("No password set, prompting new one.\n");
        do {
            password = getpassword("Password: "******"Confirm password: "******"Passwords do not match, try again.\n");
        } while(!match);
        memset(cp, 0, BUFFER_SIZE);
        free(cp);

        /* Generate a salt and key from it */
        generate_salt(salt);
        gcry_kdf_derive(password, strlen(password), GCRY_KDF_PBKDF2, GCRY_MD_SHA256,
                salt, SHA256_SALT_SIZE, SHA256_ITERATIONS, AES256_KEY_SIZE, key);
        
        f_key = fopen(key_fn, "wb");
        fwrite(key, 1, AES256_KEY_SIZE, f_key);
        fclose(f_key);

        f_salt = fopen(salt_fn, "wb");
        fwrite(salt, 1, SHA256_SALT_SIZE, f_salt);
        fclose(f_salt);

        printf("New key stored.\n");
    }

    /* Allow the password to be passed back to the caller */
    *p = password;

    return 0;
}
Beispiel #11
0
/*
 * Make a password record from the given information.  A zero return
 * indicates success; on failure, ctx->errstr points to the error message.
 */
int mkhash(struct passwd_ctx *ctx)
{
    char *pw;
    char pwin[MAX_STRING_LEN];
    char salt[16];
    apr_status_t rv;
    int ret = 0;
#if CRYPT_ALGO_SUPPORTED
    char *cbuf;
#endif

    if (ctx->cost != 0 && ctx->alg != ALG_BCRYPT) {
        apr_file_printf(errfile,
                        "Warning: Ignoring -C argument for this algorithm." NL);
    }

    if (ctx->passwd != NULL) {
        pw = ctx->passwd;
    }
    else {
        if ((ret = get_password(ctx)) != 0)
            return ret;
        pw = pwin;
    }

    switch (ctx->alg) {
    case ALG_APSHA:
        /* XXX out >= 28 + strlen(sha1) chars - fixed len SHA */
        apr_sha1_base64(pw, strlen(pw), ctx->out);
        break;

    case ALG_APMD5:
        ret = generate_salt(salt, 8, &ctx->errstr, ctx->pool);
        if (ret != 0)
            break;
        rv = apr_md5_encode(pw, salt, ctx->out, ctx->out_len);
        if (rv != APR_SUCCESS) {
            ctx->errstr = apr_psprintf(ctx->pool,
                                       "could not encode password: %pm", &rv);
            ret = ERR_GENERAL;
        }
        break;

    case ALG_PLAIN:
        /* XXX this len limitation is not in sync with any HTTPd len. */
        apr_cpystrn(ctx->out, pw, ctx->out_len);
        break;

#if CRYPT_ALGO_SUPPORTED
    case ALG_CRYPT:
        ret = generate_salt(salt, 8, &ctx->errstr, ctx->pool);
        if (ret != 0)
            break;
        cbuf = crypt(pw, salt);
        if (cbuf == NULL) {
            rv = APR_FROM_OS_ERROR(errno);
            ctx->errstr = apr_psprintf(ctx->pool, "crypt() failed: %pm", &rv);
            ret = ERR_PWMISMATCH;
            break;
        }

        apr_cpystrn(ctx->out, cbuf, ctx->out_len - 1);
        if (strlen(pw) > 8) {
            char *truncpw = strdup(pw);
            truncpw[8] = '\0';
            if (!strcmp(ctx->out, crypt(truncpw, salt))) {
                apr_file_printf(errfile, "Warning: Password truncated to 8 "
                                "characters by CRYPT algorithm." NL);
            }
            memset(truncpw, '\0', strlen(pw));
            free(truncpw);
        }
        break;
#endif /* CRYPT_ALGO_SUPPORTED */

#if BCRYPT_ALGO_SUPPORTED
    case ALG_BCRYPT:
        rv = apr_generate_random_bytes((unsigned char*)salt, 16);
        if (rv != APR_SUCCESS) {
            ctx->errstr = apr_psprintf(ctx->pool, "Unable to generate random "
                                       "bytes: %pm", &rv);
            ret = ERR_RANDOM;
            break;
        }

        if (ctx->cost == 0)
            ctx->cost = BCRYPT_DEFAULT_COST;
        rv = apr_bcrypt_encode(pw, ctx->cost, (unsigned char*)salt, 16,
                               ctx->out, ctx->out_len);
        if (rv != APR_SUCCESS) {
            ctx->errstr = apr_psprintf(ctx->pool, "Unable to encode with "
                                       "bcrypt: %pm", &rv);
            ret = ERR_PWMISMATCH;
            break;
        }
        break;
#endif /* BCRYPT_ALGO_SUPPORTED */

    default:
        apr_file_printf(errfile, "mkhash(): BUG: invalid algorithm %d",
                        ctx->alg);
        abort();
    }
    memset(pw, '\0', strlen(pw));
    return ret;
}
Beispiel #12
0
/*
 * Make a password record from the given information.  A zero return
 * indicates success; failure means that the output buffer contains an
 * error message instead.
 */
static int mkrecord(char *user, char *record, apr_size_t rlen, char *passwd,
                    int alg)
{
    char *pw;
    char cpw[120];
    char pwin[MAX_STRING_LEN];
    char pwv[MAX_STRING_LEN];
    char salt[9];
    apr_size_t bufsize;

    if (passwd != NULL) {
        pw = passwd;
    }
    else {
        bufsize = sizeof(pwin);
        if (apr_password_get("New password: "******"password too long (>%"
                         APR_SIZE_T_FMT ")", sizeof(pwin) - 1);
            return ERR_OVERFLOW;
        }
        bufsize = sizeof(pwv);
        apr_password_get("Re-type new password: "******"password verification error", (rlen - 1));
            return ERR_PWMISMATCH;
        }
        pw = pwin;
        memset(pwv, '\0', sizeof(pwin));
    }
    switch (alg) {

    case ALG_APSHA:
        /* XXX cpw >= 28 + strlen(sha1) chars - fixed len SHA */
        apr_sha1_base64(pw,strlen(pw),cpw);
        break;

    case ALG_APMD5:
        if (seed_rand()) {
            break;
        }
        generate_salt(&salt[0], 8);
        salt[8] = '\0';

        apr_md5_encode((const char *)pw, (const char *)salt,
                     cpw, sizeof(cpw));
        break;

    case ALG_PLAIN:
        /* XXX this len limitation is not in sync with any HTTPd len. */
        apr_cpystrn(cpw,pw,sizeof(cpw));
        break;

#if (!(defined(WIN32) || defined(NETWARE)))
    case ALG_CRYPT:
    default:
        if (seed_rand()) {
            break;
        }
        to64(&salt[0], rand(), 8);
        salt[8] = '\0';

        apr_cpystrn(cpw, crypt(pw, salt), sizeof(cpw) - 1);
        if (strlen(pw) > 8) {
            char *truncpw = strdup(pw);
            truncpw[8] = '\0';
            if (!strcmp(cpw, crypt(truncpw, salt))) {
                apr_file_printf(errfile, "Warning: Password truncated to 8 characters "
                                "by CRYPT algorithm." NL);
            }
            free(truncpw);
        }
        break;
#endif
    }
    memset(pw, '\0', strlen(pw));

    /*
     * Check to see if the buffer is large enough to hold the username,
     * hash, and delimiters.
     */
    if ((strlen(user) + 1 + strlen(cpw)) > (rlen - 1)) {
        apr_cpystrn(record, "resultant record too long", (rlen - 1));
        return ERR_OVERFLOW;
    }
    strcpy(record, user);
    strcat(record, ":");
    strcat(record, cpw);
    strcat(record, "\n");
    return 0;
}
static int rehash_verity(const int meta_version, const int dm_verity_version,
                         const char * data_device, const size_t block_size)
{
	#if 0
    int r = -1;
	char *table, *salt = NULL;

	salt = malloc(32); /* biggest length */
	if (NULL == salt) {
		fprintf(stderr, "Failed to malloc mem for salt\n");
		return -1;
	}
    #endif
    
    int ret = 0;
	  
	uint64_t part_size;
	if(ext4_part_size(TARGET_DEV, &part_size)) {
        printf("failed to get part size.\n");
        return -1;
    }

    const char * tmp_hash_file = TMP_HASH_FILE;
    const char * tmp_hash_table = TMP_HASH_TABLE;
    //unlink(tmp_hash_file);
    //unlink(tmp_hash_table);

    const char * hash_name = HASH_NAME;
    int i;
    char * table = NULL, *p;
    const long data_blocks = part_size / DMVERITY_BLOCK_SIZE;
#ifdef USE_SHA256
    const int digest_size = 32;//sha256
#elif USE_SHA1
    const int digest_size = 20;//sha1
#else
    const int digest_size = 16;//md5
#endif
    char salt[digest_size];
    char root_hash[digest_size];
    const loff_t hash_start = (part_size + DMVERITY_META_SIZE)/DMVERITY_BLOCK_SIZE;
    const loff_t hash_position = DMVERITY_META_SIZE/DMVERITY_BLOCK_SIZE;

    struct verity_meta_header meta_header;
    FILE * fp;

    //0.1 generate random salt
    /* generate_salt(salt); */
    if (generate_salt(salt, digest_size) != digest_size) {
        printf("Error generating random salt.\n");
        // how to handle it better? now it will use whatever compiler gives: all 0's
    }
    
    // 1. generate hash, table and write to a tmp hash file
    if(VERITY_create_hash(dm_verity_version,                  \
                      hash_name,                              \
                      TMP_HASH_FILE,                          \
                      data_device,                             \
                      block_size,                    \
                      block_size,                    \
                      data_blocks,                            \
                      hash_position,                          \
                      (unsigned char *)root_hash,             \
                      digest_size,                            \
                      (const unsigned char *)salt,            \
                      digest_size))
    {
        printf("failed to create hash tree\n");
        ret = -1;
        goto rehash_out;
    }  


    int table_size = nDigits(dm_verity_version) + 1 + strlen(TARGET_DEV) + 1
        + strlen(TARGET_DEV) + 1 + nDigits(DMVERITY_BLOCK_SIZE) + 1
        + nDigits(DMVERITY_BLOCK_SIZE) + 1 + nDigits(data_blocks) + 1
        + nDigits(hash_start) + 1 + strlen(hash_name) + 1 + digest_size * 2
        + 1 + digest_size * 2 + 1;
    table = malloc(table_size);
    if(NULL == table){
        printf("malloc failed\n");
        ret = -1;
        goto rehash_out;
    }
    table[table_size-1] = 0;
    i = sprintf(table, "%d %s %s %lld %lld %lld %lld %s ", dm_verity_version, TARGET_DEV,
                TARGET_DEV, (long long int) DMVERITY_BLOCK_SIZE,
                (long long int) DMVERITY_BLOCK_SIZE, (long long int) data_blocks,
                (long long int) hash_start, hash_name);
    if(i <= 0){
        printf("sprintf error");
        free(table);
        ret = -1;
        goto rehash_out;
    }
    //printf("Table: %s\n", table);
    p = table + i;
    bytes_to_hex(root_hash, p, digest_size);
    p += digest_size * 2;
    p += sprintf(p, " ");
    bytes_to_hex(salt, p, digest_size);
    printf("table: %s", table);
    
    // 2.1 generate meta_header
    meta_header.magic_number = VERITY_METADATA_MAGIC_NUMBER;
    meta_header.protocol_version = 0;
    meta_header.table_length = strlen(table);//not including trailing NULL
    memset(&meta_header.signature, 0, sizeof(meta_header.signature));
    //tmp_hash_file it should have been created by generate_dm_verity_hash already.
    
    // 2.2 write table and meta_header to tmp hash file
    fp = fopen(tmp_hash_file, "r+");
    if (NULL == fp) {
        printf("failed to open temp file\n");
        ret = -1;
        goto rehash_out;
    }
    if(1 != fwrite(&meta_header, sizeof(struct verity_meta_header), 1, fp)){
        printf("failed to write temp file\n");
        fclose(fp);
        ret = -1;
        goto rehash_out;
    }
    printf("write meta_header %d\n", sizeof(struct verity_meta_header));
    if(1 != fwrite(table, meta_header.table_length+1, 1, fp)){
        printf("failed to write temp file\n");
        fclose(fp);
        ret = -1;
        goto rehash_out;
    }
    printf("write table %d\n", meta_header.table_length+1);
    fflush(fp);
    fsync(fileno(fp));
    fclose(fp);

    // 2.3 write table  to tmp hash meta table file
    fp = fopen(tmp_hash_table, "w");
    if (NULL == fp) {
        printf("failed to open temp meta table file\n");
        ret = -1;
        goto rehash_out;
    }
    
    if(1 != fwrite(table, meta_header.table_length+1, 1, fp)){
        printf("failed to write temp meta table file\n");
        fclose(fp);
        ret = -1;
        goto rehash_out;
    }
    printf("write table %d\n", meta_header.table_length+1);
    fflush(fp);
    fsync(fileno(fp));
    fclose(fp);
    
    // 3. write tmp hash file to the /system (not signed)
    /*
    if(file_to_device(tmp_hash_file, TARGET_DEV, 1024*1024, part_size)){
        printf("failed to write hash 001\n");
        goto rehash_out;
    }
    */
rehash_out:
    //unlink(tmp_hash_file);
    if(table)
        free(table);
	return ret;
}
Beispiel #14
0
json_t *broker_handshake_handle_conn(Broker *broker,
                                     const char *dsId,
                                     const char *token,
                                     json_t *handshake) {
    if (dslink_map_contains(&broker->client_connecting, (void *) dsId)) {
        ref_t *ref = dslink_map_remove_get(&broker->client_connecting,
                                           (void *) dsId);
        RemoteDSLink *link = ref->data;
        dslink_map_remove(&broker->client_connecting,
                          (void *) link->name);
        broker_remote_dslink_free(link);
        dslink_free(link);
        dslink_decref(ref);
    }

    RemoteDSLink *link = dslink_calloc(1, sizeof(RemoteDSLink));
    json_t *resp = json_object();
    if (!(link && resp)) {
        goto fail;
    }

    if (broker_remote_dslink_init(link) != 0) {
        goto fail;
    }

    link->broker = broker;
    link->auth = dslink_calloc(1, sizeof(RemoteAuth));
    if (!link->auth) {
        goto fail;
    }

    if (dslink_handshake_generate_key_pair(&link->auth->tempKey) != 0) {
        log_err("Failed to create temporary key for DSLink\n");
        goto fail;
    }

    {
        json_t *jsonPubKey = json_object_get(handshake, "publicKey");
        if (!jsonPubKey) {
            goto fail;
        }

        const char *tmp = json_string_value(jsonPubKey);
        if (!tmp) {
            goto fail;
        }
        tmp = dslink_strdup(tmp);
        if (!tmp) {
            goto fail;
        }
        link->auth->pubKey = tmp;
    }

    char tempKey[90];
    size_t tempKeyLen = 0;
    if (dslink_handshake_encode_pub_key(&link->auth->tempKey, tempKey,
                                        sizeof(tempKey), &tempKeyLen) != 0) {
        goto fail;
    }

    if (generate_salt((unsigned char *) link->auth->salt,
                      sizeof(link->auth->salt)) != 0) {
        goto fail;
    }

    json_object_set_new_nocheck(resp, "wsUri", json_string_nocheck("/ws"));
    json_object_set_new_nocheck(resp, "tempKey", json_string_nocheck(tempKey));
    json_object_set_new_nocheck(resp, "salt", json_string_nocheck(link->auth->salt));
    if (json_boolean_value(json_object_get(handshake, "isResponder"))) {
        link->isResponder = 1;
    }

    if (json_boolean_value(json_object_get(handshake, "isRequester"))) {
        link->isRequester = 1;
    }

    json_t *linkData = json_object_get(handshake, "linkData");
    if (json_is_object(linkData)) {
        json_incref(linkData);
        link->linkData = linkData;
    }

    {
        char buf[512] = {0};
        snprintf(buf, sizeof(buf), "/downstream/");
        char *name = buf + sizeof("/downstream/")-1;

        size_t dsIdLen = strlen(dsId);
        if (dsIdLen < 44) {
            goto fail;
        }
        size_t nameLen = dsIdLen - 43;
        if (dsId[nameLen - 1] == '-') {
            nameLen--;
        }
        int nodeExists = 0;
        // find a valid name from broker->client_names
        memcpy(name, dsId, nameLen);
        while (1) {
            ref_t *ref = dslink_map_get(&broker->client_connecting, name);
            if (ref) {
                RemoteDSLink *l = ref->data;
                if (l && l->dsId && strcmp(l->dsId->data, dsId) == 0) {
                    dslink_map_remove(&broker->client_connecting, name);
                    broker_remote_dslink_free(l);
                    break;
                } else {
                    name[nameLen] = dsId[nameLen];
                    nameLen++;
                }
            }
            ref = dslink_map_get(broker->downstream->children,
                                 (void *) name);
            if (ref == NULL) {
                break;
            }
            if (!((DownstreamNode *) ref->data)->dsId || strcmp(dsId, ((DownstreamNode *) ref->data)->dsId->data) == 0) {
                nodeExists = 1;
                break;
            }

            name[nameLen] = dsId[nameLen];
            nameLen++;
        }
        if (!nodeExists && broker_enable_token) {
            if (!token) {
                log_err("Failed to connet, need token\n");
                goto fail;
            }
            BrokerNode* tokenNode = get_token_node(token, dsId);
            if (tokenNode) {
                DownstreamNode *node = broker_init_downstream_node(broker->downstream, name);

                if (json_is_true(json_object_get(node->meta, "$$managed"))) {
                    json_object_set_new_nocheck(node->meta, "$$token", json_string_nocheck(tokenNode->name));
                }

                node->dsId = dslink_str_ref(dsId);
                if (broker->downstream->list_stream) {
                    update_list_child(broker->downstream,
                                      broker->downstream->list_stream,
                                      link->name);
                }

                json_t *group = json_object_get(tokenNode->meta, "$$group");
                if (json_is_string(group)) {
                    json_object_set_nocheck(node->meta, "$$group", group);
                }

                token_used(tokenNode);

                broker_downstream_nodes_changed(broker);
            } else {
                log_err("Invalid token: %s\n", token);
                goto fail;
            }
        }
        json_object_set_new_nocheck(resp, "path", json_string_nocheck(buf));

        link->path = dslink_strdup(buf);
        if (!link->path) {
            goto fail;
        }
        link->name = link->path + sizeof("/downstream/") - 1;

        // add to connecting map with the name
        if (dslink_map_set(&broker->client_connecting,
                           dslink_ref((void *) link->name, NULL),
                           dslink_ref(link, NULL)) != 0) {
            dslink_free((void *) link->path);
            goto fail;
        }
    }

    {
        ref_t *tmp = dslink_ref(dslink_strdup(dsId), dslink_free);
        if (!tmp) {
            goto fail;
        }
        // add to connecting map with dsId
        if (dslink_map_set(&broker->client_connecting, tmp,
                           dslink_ref(link, NULL)) != 0) {
            dslink_free(tmp);
            goto fail;
        }
    }

    return resp;
fail:
    if (link) {
        broker_remote_dslink_free(link);
        dslink_free((void *) link->path);
        dslink_free(link);
    }
    DSLINK_CHECKED_EXEC(json_decref, resp);
    return NULL;
}