int sftp_mac_set_read_key(pool *p, const EVP_MD *hash, const BIGNUM *k, const char *h, uint32_t hlen) { const unsigned char *id = NULL; char *buf, *ptr; uint32_t buflen, bufsz, id_len; char letter; size_t blocksz; struct sftp_mac *mac; HMAC_CTX *mac_ctx; switch_read_mac(); mac = &(read_macs[read_mac_idx]); mac_ctx = &(read_ctxs[read_mac_idx]); bufsz = buflen = 1024; ptr = buf = sftp_msg_getbuf(p, bufsz); /* Need to use SSH2-style format of K for the key. */ sftp_msg_write_mpint(&buf, &buflen, k); id_len = sftp_session_get_id(&id); /* HASH(K || H || "E" || session_id) */ letter = 'E'; set_mac_key(mac, hash, ptr, (bufsz - buflen), h, hlen, &letter, id, id_len); #if OPENSSL_VERSION_NUMBER > 0x000907000L HMAC_CTX_init(mac_ctx); # if OPENSSL_VERSION_NUMBER >= 0x10000001L if (HMAC_Init_ex(mac_ctx, mac->key, mac->key_len, mac->digest, NULL) != 1) { pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error initializing HMAC: %s", sftp_crypto_get_errors()); errno = EPERM; return -1; } # else HMAC_Init_ex(mac_ctx, mac->key, mac->key_len, mac->digest, NULL); # endif /* OpenSSL-1.0.0 and later */ #else /* Reset the HMAC context. */ HMAC_Init(mac_ctx, NULL, 0, NULL); HMAC_Init(mac_ctx, mac->key, mac->key_len, mac->digest); #endif if (mac->mac_len == 0) { blocksz = EVP_MD_size(mac->digest); } else { blocksz = mac->mac_len; } pr_memscrub(ptr, bufsz); sftp_mac_set_block_size(blocksz); return 0; }
static void clear_cipher(struct sftp_cipher *cipher) { if (cipher->iv) { pr_memscrub(cipher->iv, cipher->iv_len); free(cipher->iv); cipher->iv = NULL; cipher->iv_len = 0; } if (cipher->key) { pr_memscrub(cipher->key, cipher->key_len); free(cipher->key); cipher->key = NULL; cipher->key_len = 0; } cipher->cipher = NULL; cipher->algo = NULL; }
static void clear_mac(struct sftp_mac *mac) { if (mac->key) { pr_memscrub(mac->key, mac->keysz); free(mac->key); mac->key = NULL; mac->keysz = 0; mac->key_len = 0; } mac->digest = NULL; mac->algo = NULL; }
static int cleanup_bf_ctr(EVP_CIPHER_CTX *ctx) { struct bf_ctr_ex *bce; bce = EVP_CIPHER_CTX_get_app_data(ctx); if (bce != NULL) { pr_memscrub(bce, sizeof(struct bf_ctr_ex)); free(bce); EVP_CIPHER_CTX_set_app_data(ctx, NULL); } return 1; }
END_TEST START_TEST (memscrub_test) { size_t len; char *expected, *text; mark_point(); pr_memscrub(NULL, 1); expected = "Hello, World!"; text = pstrdup(p, expected); mark_point(); pr_memscrub(text, 0); len = strlen(text); mark_point(); pr_memscrub(text, len); fail_unless(strncmp(text, expected, len + 1) != 0, "Expected other than '%s'", expected); }
/* If the chosen cipher requires that we discard some of the initial bytes of * the cipher stream, then do so. (This is mostly for any RC4 ciphers.) */ static int set_cipher_discarded(struct sftp_cipher *cipher, EVP_CIPHER_CTX *cipher_ctx) { unsigned char *garbage_in, *garbage_out; if (cipher->discard_len == 0) { return 0; } garbage_in = malloc(cipher->discard_len); if (garbage_in == NULL) { pr_log_pri(PR_LOG_ALERT, MOD_SFTP_VERSION ": Out of memory!"); _exit(1); } garbage_out = malloc(cipher->discard_len); if (garbage_out == NULL) { pr_log_pri(PR_LOG_ALERT, MOD_SFTP_VERSION ": Out of memory!"); free(garbage_in); _exit(1); } if (EVP_Cipher(cipher_ctx, garbage_out, garbage_in, cipher->discard_len) != 1) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error ciphering discard data: %s", sftp_crypto_get_errors()); free(garbage_in); pr_memscrub(garbage_out, cipher->discard_len); free(garbage_out); return -1; } free(garbage_in); pr_memscrub(garbage_out, cipher->discard_len); free(garbage_out); return 0; }
void proxy_conn_clear_password(struct proxy_conn *pconn) { size_t len; if (pconn == NULL) { return; } if (pconn->pconn_password == NULL) { return; } len = strlen(pconn->pconn_password); pr_memscrub(pconn->pconn_password, len); pconn->pconn_password = NULL; }
void proxy_conn_clear_username(struct proxy_conn *pconn) { size_t len; if (pconn == NULL) { return; } if (pconn->pconn_username == NULL) { return; } len = strlen(pconn->pconn_username); pr_memscrub(pconn->pconn_username, len); pconn->pconn_username = NULL; }
int sftp_mac_set_write_key(pool *p, const EVP_MD *hash, const BIGNUM *k, const char *h, uint32_t hlen) { const unsigned char *id = NULL; char *buf, *ptr; uint32_t buflen, bufsz, id_len; char letter; struct sftp_mac *mac; HMAC_CTX *mac_ctx; switch_write_mac(); mac = &(write_macs[write_mac_idx]); mac_ctx = &(write_ctxs[write_mac_idx]); bufsz = buflen = 1024; ptr = buf = sftp_msg_getbuf(p, bufsz); /* Need to use SSH2-style format of K for the key. */ sftp_msg_write_mpint(&buf, &buflen, k); id_len = sftp_session_get_id(&id); /* HASH(K || H || "F" || session_id) */ letter = 'F'; set_mac_key(mac, hash, ptr, (bufsz - buflen), h, hlen, &letter, id, id_len); #if OPENSSL_VERSION_NUMBER > 0x000907000L HMAC_CTX_init(mac_ctx); #else /* Reset the HMAC context. */ HMAC_Init(mac_ctx, NULL, 0, NULL); #endif HMAC_Init(mac_ctx, mac->key, mac->key_len, mac->digest); pr_memscrub(ptr, bufsz); return 0; }
int sftp_auth_password(struct ssh2_packet *pkt, cmd_rec *pass_cmd, const char *orig_user, const char *user, const char *service, unsigned char **buf, uint32_t *buflen, int *send_userauth_fail) { const char *cipher_algo, *mac_algo; char *passwd; int have_new_passwd, res; struct passwd *pw; cipher_algo = sftp_cipher_get_read_algo(); mac_algo = sftp_mac_get_read_algo(); if (strncmp(cipher_algo, "none", 5) == 0 || strncmp(mac_algo, "none", 5) == 0) { if (sftp_opts & SFTP_OPT_ALLOW_INSECURE_LOGIN) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "WARNING: cipher algorithm '%s' or MAC algorithm '%s' INSECURE for " "password authentication (SFTPOption AllowInsecureLogin in effect)", cipher_algo, mac_algo); } else { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "cipher algorithm '%s' or MAC algorithm '%s' unacceptable for " "password authentication, denying password authentication request", cipher_algo, mac_algo); *send_userauth_fail = TRUE; errno = EPERM; return 0; } } /* XXX We currently don't do anything with this. */ have_new_passwd = sftp_msg_read_bool(pkt->pool, buf, buflen); if (have_new_passwd) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "%s", "client says they have provided a new password; this functionality " "is not currently supported"); } passwd = sftp_msg_read_string(pkt->pool, buf, buflen); passwd = sftp_utf8_decode_str(pkt->pool, passwd); pass_cmd->arg = passwd; if (pr_cmd_dispatch_phase(pass_cmd, PRE_CMD, 0) < 0) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "authentication request for user '%s' blocked by '%s' handler", orig_user, (char *) pass_cmd->argv[0]); pr_cmd_dispatch_phase(pass_cmd, POST_CMD_ERR, 0); pr_cmd_dispatch_phase(pass_cmd, LOG_CMD_ERR, 0); pr_memscrub(passwd, strlen(passwd)); *send_userauth_fail = TRUE; errno = EPERM; return 0; } pw = pr_auth_getpwnam(pkt->pool, user); if (pw == NULL) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "no account for user '%s' found", user); pr_log_auth(PR_LOG_NOTICE, "USER %s: no such user found from %s [%s] to %s:%d", user, session.c->remote_name, pr_netaddr_get_ipstr(session.c->remote_addr), pr_netaddr_get_ipstr(session.c->local_addr), session.c->local_port); pr_memscrub(passwd, strlen(passwd)); *send_userauth_fail = TRUE; errno = ENOENT; return 0; } res = pr_auth_authenticate(pkt->pool, user, passwd); pr_memscrub(passwd, strlen(passwd)); switch (res) { case PR_AUTH_OK: break; case PR_AUTH_NOPWD: (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "password authentication for user '%s' failed: No such user", user); pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): No such user found", user); *send_userauth_fail = TRUE; errno = ENOENT; return 0; case PR_AUTH_BADPWD: (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "password authentication for user '%s' failed: Incorrect password", user); pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): Incorrect password", user); *send_userauth_fail = TRUE; errno = EINVAL; return 0; case PR_AUTH_AGEPWD: (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "password authentication for user '%s' failed: Password expired", user); pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): Password expired", user); *send_userauth_fail = TRUE; errno = EINVAL; return 0; case PR_AUTH_DISABLEDPWD: (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "password authentication for user '%s' failed: Account disabled", user); pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): Account disabled", user); *send_userauth_fail = TRUE; errno = EINVAL; return 0; default: (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "unknown authentication value (%d), returning error", res); *send_userauth_fail = TRUE; errno = EINVAL; return 0; } return 1; }
static int set_mac_key(struct sftp_mac *mac, const EVP_MD *hash, const char *k, uint32_t klen, const char *h, uint32_t hlen, char *letter, const unsigned char *id, uint32_t id_len) { EVP_MD_CTX ctx; unsigned char *key = NULL; size_t key_sz; uint32_t key_len = 0; key_sz = sftp_crypto_get_size(EVP_MD_block_size(mac->digest), EVP_MD_size(hash)); if (key_sz == 0) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "unable to determine key length for MAC '%s'", mac->algo); errno = EINVAL; return -1; } key = malloc(key_sz); if (key == NULL) { pr_log_pri(PR_LOG_CRIT, MOD_SFTP_VERSION ": Out of memory!"); _exit(1); } /* In OpenSSL 0.9.6, many of the EVP_Digest* functions returned void, not * int. Without these ugly OpenSSL version preprocessor checks, the * compiler will error out with "void value not ignored as it ought to be". */ #if OPENSSL_VERSION_NUMBER >= 0x000907000L if (EVP_DigestInit(&ctx, hash) != 1) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error initializing message digest: %s", sftp_crypto_get_errors()); free(key); return -1; } #else EVP_DigestInit(&ctx, hash); #endif #if OPENSSL_VERSION_NUMBER >= 0x000907000L if (EVP_DigestUpdate(&ctx, k, klen) != 1) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error updating message digest with K: %s", sftp_crypto_get_errors()); free(key); return -1; } #else EVP_DigestUpdate(&ctx, k, klen); #endif #if OPENSSL_VERSION_NUMBER >= 0x000907000L if (EVP_DigestUpdate(&ctx, h, hlen) != 1) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error updating message digest with H: %s", sftp_crypto_get_errors()); free(key); return -1; } #else EVP_DigestUpdate(&ctx, h, hlen); #endif #if OPENSSL_VERSION_NUMBER >= 0x000907000L if (EVP_DigestUpdate(&ctx, letter, sizeof(char)) != 1) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error updating message digest with '%c': %s", *letter, sftp_crypto_get_errors()); free(key); return -1; } #else EVP_DigestUpdate(&ctx, letter, sizeof(char)); #endif #if OPENSSL_VERSION_NUMBER >= 0x000907000L if (EVP_DigestUpdate(&ctx, (char *) id, id_len) != 1) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error updating message digest with ID: %s", sftp_crypto_get_errors()); free(key); return -1; } #else EVP_DigestUpdate(&ctx, (char *) id, id_len); #endif #if OPENSSL_VERSION_NUMBER >= 0x000907000L if (EVP_DigestFinal(&ctx, key, &key_len) != 1) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error finalizing message digest: %s", sftp_crypto_get_errors()); pr_memscrub(key, key_sz); free(key); return -1; } #else EVP_DigestFinal(&ctx, key, &key_len); #endif /* If we need more, keep hashing, as per RFC, until we have enough * material. */ while (key_sz > key_len) { uint32_t len = key_len; pr_signals_handle(); #if OPENSSL_VERSION_NUMBER >= 0x000907000L if (EVP_DigestInit(&ctx, hash) != 1) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error initializing message digest: %s", sftp_crypto_get_errors()); pr_memscrub(key, key_sz); free(key); return -1; } #else EVP_DigestInit(&ctx, hash); #endif #if OPENSSL_VERSION_NUMBER >= 0x000907000L if (EVP_DigestUpdate(&ctx, k, klen) != 1) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error updating message digest with K: %s", sftp_crypto_get_errors()); pr_memscrub(key, key_sz); free(key); return -1; } #else EVP_DigestUpdate(&ctx, k, klen); #endif #if OPENSSL_VERSION_NUMBER >= 0x000907000L if (EVP_DigestUpdate(&ctx, h, hlen) != 1) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error updating message digest with H: %s", sftp_crypto_get_errors()); pr_memscrub(key, key_sz); free(key); return -1; } #else EVP_DigestUpdate(&ctx, h, hlen); #endif #if OPENSSL_VERSION_NUMBER >= 0x000907000L if (EVP_DigestUpdate(&ctx, key, len) != 1) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error updating message digest with data: %s", sftp_crypto_get_errors()); pr_memscrub(key, key_sz); free(key); return -1; } #else EVP_DigestUpdate(&ctx, key, len); #endif #if OPENSSL_VERSION_NUMBER >= 0x000907000L if (EVP_DigestFinal(&ctx, key + len, &len) != 1) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error finalizing message digest: %s", sftp_crypto_get_errors()); pr_memscrub(key, key_sz); free(key); return -1; } #else EVP_DigestFinal(&ctx, key + len, &len); #endif key_len += len; } mac->key = key; mac->keysz = key_sz; mac->key_len = EVP_MD_size(mac->digest); if (!sftp_interop_supports_feature(SFTP_SSH2_FEAT_MAC_LEN)) { mac->key_len = 16; } return 0; }
int sftp_cipher_set_write_key(pool *p, const EVP_MD *hash, const BIGNUM *k, const char *h, uint32_t hlen) { const unsigned char *id = NULL; unsigned char *buf, *ptr; char letter; uint32_t buflen, bufsz, id_len; int key_len; struct sftp_cipher *cipher; EVP_CIPHER_CTX *cipher_ctx; switch_write_cipher(); cipher = &(write_ciphers[write_cipher_idx]); cipher_ctx = write_ctxs[write_cipher_idx]; /* XXX EVP_CIPHER_CTX_init() first appeared in OpenSSL 0.9.7. What to do * for older OpenSSL installations? */ EVP_CIPHER_CTX_init(cipher_ctx); bufsz = buflen = SFTP_CIPHER_BUFSZ; ptr = buf = sftp_msg_getbuf(p, bufsz); /* Need to use SSH2-style format of K for the IV and key. */ sftp_msg_write_mpint(&buf, &buflen, k); id_len = sftp_session_get_id(&id); /* IV: HASH(K || H || "B" || session_id) */ letter = 'B'; if (set_cipher_iv(cipher, hash, ptr, (bufsz - buflen), h, hlen, &letter, id, id_len) < 0) { pr_memscrub(ptr, bufsz); return -1; } key_len = (int) cipher->key_len; /* Key: HASH(K || H || "D" || session_id) */ letter = 'D'; if (set_cipher_key(cipher, hash, ptr, (bufsz - buflen), h, hlen, &letter, id, id_len) < 0) { pr_memscrub(ptr, bufsz); return -1; } if (EVP_CipherInit(cipher_ctx, cipher->cipher, cipher->key, cipher->iv, 1) != 1) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error initializing %s cipher for encryption: %s", cipher->algo, sftp_crypto_get_errors()); pr_memscrub(ptr, bufsz); return -1; } if (key_len > 0) { /* Next, set the key length. */ if (EVP_CIPHER_CTX_set_key_length(cipher_ctx, key_len) != 1) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error setting key length (%d bytes) for %s cipher for decryption: %s", key_len, cipher->algo, sftp_crypto_get_errors()); pr_memscrub(ptr, bufsz); return -1; } } if (set_cipher_discarded(cipher, cipher_ctx) < 0) { pr_memscrub(ptr, bufsz); return -1; } pr_memscrub(ptr, bufsz); return 0; }