/* Confirmation hash calculation */ void jpake_confirm_hash(const BIGNUM *k, const u_char *endpoint_id, u_int endpoint_id_len, const u_char *sess_id, u_int sess_id_len, u_char **confirm_hash, u_int *confirm_hash_len) { struct sshbuf *b; int r; /* * Calculate confirmation proof: * client: H(k || client_id || session_id) * server: H(k || server_id || session_id) */ if ((b = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __func__); if ((r = sshbuf_put_bignum2(b, k)) != 0 || (r = sshbuf_put_string(b, endpoint_id, endpoint_id_len)) != 0 || (r = sshbuf_put_string(b, sess_id, sess_id_len)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (hash_buffer(sshbuf_ptr(b), sshbuf_len(b), EVP_sha256(), confirm_hash, confirm_hash_len) != 0) fatal("%s: hash_buffer", __func__); sshbuf_free(b); }
/* * Hash a string. Returns a bitmask of HASH_SOURCE_CODE_* results. */ int hash_source_code_string( struct conf *conf, struct mdfour *hash, const char *str, size_t len, const char *path) { int result = HASH_SOURCE_CODE_OK; /* * Check for __DATE__ and __TIME__ if the sloppiness configuration tells us * we should. */ if (!(conf->sloppiness & SLOPPY_TIME_MACROS)) { result |= check_for_temporal_macros(str, len); } /* * Hash the source string. */ hash_buffer(hash, str, len); if (result & HASH_SOURCE_CODE_FOUND_DATE) { /* * Make sure that the hash sum changes if the (potential) expansion of * __DATE__ changes. */ time_t t = time(NULL); struct tm *now = localtime(&t); cc_log("Found __DATE__ in %s", path); hash_delimiter(hash, "date"); hash_buffer(hash, &now->tm_year, sizeof(now->tm_year)); hash_buffer(hash, &now->tm_mon, sizeof(now->tm_mon)); hash_buffer(hash, &now->tm_mday, sizeof(now->tm_mday)); } if (result & HASH_SOURCE_CODE_FOUND_TIME) { /* * We don't know for sure that the program actually uses the __TIME__ * macro, but we have to assume it anyway and hash the time stamp. However, * that's not very useful since the chance that we get a cache hit later * the same second should be quite slim... So, just signal back to the * caller that __TIME__ has been found so that the direct mode can be * disabled. */ cc_log("Found __TIME__ in %s", path); } return result; }
/* buffer up characters before hashing them */ static void pushchar(unsigned char c) { static unsigned char buf[64]; static int len; if (c == 0) { if (len > 0) { hash_buffer((char *)buf, len); len = 0; } hash_buffer(NULL, 0); return; } buf[len++] = c; if (len == 64) { hash_buffer((char *)buf, len); len = 0; } }
/* * Derive fake salt as H(username || first_private_host_key) * This provides relatively stable fake salts for non-existent * users and avoids the jpake method becoming an account validity * oracle. */ static void derive_rawsalt(const char *username, u_char *rawsalt, u_int len) { u_char *digest; u_int digest_len; struct sshbuf *b; struct sshkey *k; int r; if ((b = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __func__); if ((r = sshbuf_put_cstring(b, username)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if ((k = get_hostkey_by_index(0)) == NULL || (k->flags & SSHKEY_FLAG_EXT)) fatal("%s: no hostkeys", __func__); switch (k->type) { case KEY_RSA1: case KEY_RSA: if (k->rsa->p == NULL || k->rsa->q == NULL) fatal("%s: RSA key missing p and/or q", __func__); if ((r = sshbuf_put_bignum2(b, k->rsa->p)) != 0 || (r = sshbuf_put_bignum2(b, k->rsa->q)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); break; case KEY_DSA: if (k->dsa->priv_key == NULL) fatal("%s: DSA key missing priv_key", __func__); if ((r = sshbuf_put_bignum2(b, k->dsa->priv_key)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); break; case KEY_ECDSA: if (EC_KEY_get0_private_key(k->ecdsa) == NULL) fatal("%s: ECDSA key missing priv_key", __func__); if ((r = sshbuf_put_bignum2(b, EC_KEY_get0_private_key(k->ecdsa))) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); break; default: fatal("%s: unknown key type %d", __func__, k->type); } if (hash_buffer(sshbuf_ptr(b), sshbuf_len(b), EVP_sha256(), &digest, &digest_len) != 0) fatal("%s: hash_buffer", __func__); sshbuf_free(b); if (len > digest_len) fatal("%s: not enough bytes for rawsalt (want %u have %u)", __func__, len, digest_len); memcpy(rawsalt, digest, len); bzero(digest, digest_len); xfree(digest); }
/* * Calculate hash component of Schnorr signature H(g || g^v || g^x || id) * using the hash function defined by "hash_alg". Returns signature as * bignum or NULL on error. */ static BIGNUM * schnorr_hash(const BIGNUM *p, const BIGNUM *q, const BIGNUM *g, int hash_alg, const BIGNUM *g_v, const BIGNUM *g_x, const u_char *id, u_int idlen) { u_char *digest; u_int digest_len; BIGNUM *h; Buffer b; int success = -1; if ((h = BN_new()) == NULL) { error("%s: BN_new", __func__); return NULL; } buffer_init(&b); /* h = H(g || p || q || g^v || g^x || id) */ buffer_put_bignum2(&b, g); buffer_put_bignum2(&b, p); buffer_put_bignum2(&b, q); buffer_put_bignum2(&b, g_v); buffer_put_bignum2(&b, g_x); buffer_put_string(&b, id, idlen); SCHNORR_DEBUG_BUF((buffer_ptr(&b), buffer_len(&b), "%s: hashblob", __func__)); if (hash_buffer(buffer_ptr(&b), buffer_len(&b), hash_alg, &digest, &digest_len) != 0) { error("%s: hash_buffer", __func__); goto out; } if (BN_bin2bn(digest, (int)digest_len, h) == NULL) { error("%s: BN_bin2bn", __func__); goto out; } success = 0; SCHNORR_DEBUG_BN((h, "%s: h = ", __func__)); out: buffer_free(&b); bzero(digest, digest_len); free(digest); digest_len = 0; if (success == 0) return h; BN_clear_free(h); return NULL; }
/* * Add contents of an open file to the hash. Returns true on success, otherwise * false. */ bool hash_fd(struct mdfour *md, int fd) { char buf[READ_BUF_SZ]; ssize_t n; while ((n = read(fd, buf, sizeof(buf))) != 0) { if (n == -1 && errno != EINTR) { break; } if (n > 0) { hash_buffer(md, buf, n); } } return n == 0; }
/* * Derive fake salt as H(username || first_private_host_key) * This provides relatively stable fake salts for non-existent * users and avoids the jpake method becoming an account validity * oracle. */ static void derive_rawsalt(const char *username, u_char *rawsalt, u_int len) { u_char *digest; u_int digest_len; Buffer b; Key *k; buffer_init(&b); buffer_put_cstring(&b, username); if ((k = get_hostkey_by_index(0)) == NULL || (k->flags & KEY_FLAG_EXT)) fatal("%s: no hostkeys", __func__); switch (k->type) { case KEY_RSA1: case KEY_RSA: if (k->rsa->p == NULL || k->rsa->q == NULL) fatal("%s: RSA key missing p and/or q", __func__); buffer_put_bignum2(&b, k->rsa->p); buffer_put_bignum2(&b, k->rsa->q); break; case KEY_DSA: if (k->dsa->priv_key == NULL) fatal("%s: DSA key missing priv_key", __func__); buffer_put_bignum2(&b, k->dsa->priv_key); break; case KEY_ECDSA: if (EC_KEY_get0_private_key(k->ecdsa) == NULL) fatal("%s: ECDSA key missing priv_key", __func__); buffer_put_bignum2(&b, EC_KEY_get0_private_key(k->ecdsa)); break; default: fatal("%s: unknown key type %d", __func__, k->type); } if (hash_buffer(buffer_ptr(&b), buffer_len(&b), EVP_sha256(), &digest, &digest_len) != 0) fatal("%s: hash_buffer", __func__); buffer_free(&b); if (len > digest_len) fatal("%s: not enough bytes for rawsalt (want %u have %u)", __func__, len, digest_len); memcpy(rawsalt, digest, len); bzero(digest, digest_len); free(digest); }
/* Confirmation hash calculation */ void jpake_confirm_hash(const BIGNUM *k, const u_char *endpoint_id, u_int endpoint_id_len, const u_char *sess_id, u_int sess_id_len, u_char **confirm_hash, u_int *confirm_hash_len) { Buffer b; /* * Calculate confirmation proof: * client: H(k || client_id || session_id) * server: H(k || server_id || session_id) */ buffer_init(&b); buffer_put_bignum2(&b, k); buffer_put_string(&b, endpoint_id, endpoint_id_len); buffer_put_string(&b, sess_id, sess_id_len); if (hash_buffer(buffer_ptr(&b), buffer_len(&b), EVP_sha256(), confirm_hash, confirm_hash_len) != 0) fatal("%s: hash_buffer", __func__); buffer_free(&b); }
void hash_string_buffer(struct hash *hash, const char *s, int length) { hash_buffer(hash, s, length); do_debug_text(hash, "\n", 1); }
void hash_int(struct mdfour *md, int x) { hash_buffer(md, (char *)&x, sizeof(x)); }
void hash_string_length(struct mdfour *md, const char *s, int length) { hash_buffer(md, s, length); }
/* * Hash some data that is unlikely to occur in the input. The idea is twofold: * * - Delimit things like arguments from each other (e.g., so that -I -O2 and * -I-O2 hash differently). * - Tag different types of hashed information so that it's possible to do * conditional hashing of information in a safe way (e.g., if we want to hash * information X if CCACHE_A is set and information Y if CCACHE_B is set, * there should never be a hash collision risk). */ void hash_delimiter(struct mdfour *md, const char *type) { hash_buffer(md, HASH_DELIMITER, sizeof(HASH_DELIMITER)); hash_buffer(md, type, strlen(type) + 1); /* Include NUL. */ }
/* return the hash result as 16 binary bytes */ void hash_result_as_bytes(struct mdfour *md, unsigned char *out) { hash_buffer(md, NULL, 0); mdfour_result(md, out); }