static int send_pubkey_ok(const char *algo, const char *pubkey_data, uint32_t pubkey_len) { struct ssh2_packet *pkt; char *buf, *ptr; uint32_t buflen, bufsz; int res; /* Make sure to allocate a buffer large enough to hold the publickey * data we're sending back. */ bufsz = buflen = pubkey_len + 1024; pkt = sftp_ssh2_packet_create(sftp_pool); buflen = bufsz; ptr = buf = palloc(pkt->pool, bufsz); sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_MSG_USER_AUTH_PK_OK); sftp_msg_write_string(&buf, &buflen, algo); sftp_msg_write_data(&buf, &buflen, pubkey_data, pubkey_len, TRUE); pkt->payload = ptr; pkt->payload_len = (bufsz - buflen); (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "sending publickey OK"); res = sftp_ssh2_packet_write(sftp_conn->wfd, pkt); if (res < 0) { destroy_pool(pkt->pool); return -1; } destroy_pool(pkt->pool); return 0; }
int sftp_cipher_write_data(struct ssh2_packet *pkt, unsigned char *buf, size_t *buflen) { struct sftp_cipher *cipher; EVP_CIPHER_CTX *cipher_ctx; cipher = &(write_ciphers[write_cipher_idx]); cipher_ctx = write_ctxs[write_cipher_idx]; if (cipher->key) { int res; unsigned char *data, *ptr; uint32_t datalen, datasz = sizeof(uint32_t) + pkt->packet_len; datalen = datasz; ptr = data = palloc(pkt->pool, datasz); sftp_msg_write_int(&data, &datalen, pkt->packet_len); sftp_msg_write_byte(&data, &datalen, pkt->padding_len); sftp_msg_write_data(&data, &datalen, pkt->payload, pkt->payload_len, FALSE); sftp_msg_write_data(&data, &datalen, pkt->padding, pkt->padding_len, FALSE); res = EVP_Cipher(cipher_ctx, buf, ptr, (datasz - datalen)); if (res != 1) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error encrypting %s data for client: %s", cipher->algo, sftp_crypto_get_errors()); errno = EIO; return -1; } *buflen = (datasz - datalen); #ifdef SFTP_DEBUG_PACKET { unsigned int i; (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "encrypted packet data (len %lu):", (unsigned long) *buflen); for (i = 0; i < *buflen;) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, " %02x%02x %02x%02x %02x%02x %02x%02x", ((unsigned char *) buf)[i], ((unsigned char *) buf)[i+1], ((unsigned char *) buf)[i+2], ((unsigned char *) buf)[i+3], ((unsigned char *) buf)[i+4], ((unsigned char *) buf)[i+5], ((unsigned char *) buf)[i+6], ((unsigned char *) buf)[i+7]); i += 8; } } #endif return 0; } *buflen = 0; return 0; }
static int write_service_accept(struct ssh2_packet *pkt, const char *service) { unsigned char *buf, *ptr; uint32_t buflen, bufsz = 1024; buflen = bufsz; ptr = buf = palloc(pkt->pool, bufsz); sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_MSG_SERVICE_ACCEPT); sftp_msg_write_string(&buf, &buflen, service); pkt->payload = ptr; pkt->payload_len = (bufsz - buflen); return 0; }
int sftp_auth_hostbased(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) { struct passwd *pw; char *hostkey_algo, *host_fqdn, *host_user, *host_user_utf8; const char *fp = NULL; unsigned char *hostkey_data, *signature_data; unsigned char *buf2, *ptr2; const unsigned char *id; uint32_t buflen2, bufsz2, hostkey_datalen, id_len, signature_len; enum sftp_key_type_e pubkey_type; 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); *send_userauth_fail = TRUE; errno = EPERM; return 0; } hostkey_algo = sftp_msg_read_string(pkt->pool, buf, buflen); if (hostkey_algo == NULL) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "missing required host key algorithm, rejecting request"); *send_userauth_fail = TRUE; errno = EINVAL; return 0; } hostkey_datalen = sftp_msg_read_int(pkt->pool, buf, buflen); hostkey_data = sftp_msg_read_data(pkt->pool, buf, buflen, hostkey_datalen); host_fqdn = sftp_msg_read_string(pkt->pool, buf, buflen); host_user_utf8 = sftp_msg_read_string(pkt->pool, buf, buflen); host_user = sftp_utf8_decode_str(pkt->pool, host_user_utf8); signature_len = sftp_msg_read_int(pkt->pool, buf, buflen); signature_data = sftp_msg_read_data(pkt->pool, buf, buflen, signature_len); pr_trace_msg(trace_channel, 9, "client sent '%s' host key, FQDN %s, and remote user '%s'", hostkey_algo, host_fqdn, host_user); if (strncmp(hostkey_algo, "ssh-rsa", 8) == 0) { pubkey_type = SFTP_KEY_RSA; } else if (strncmp(hostkey_algo, "ssh-dss", 8) == 0) { pubkey_type = SFTP_KEY_DSA; #ifdef PR_USE_OPENSSL_ECC } else if (strncmp(hostkey_algo, "ecdsa-sha2-nistp256", 20) == 0) { pubkey_type = SFTP_KEY_ECDSA_256; } else if (strncmp(hostkey_algo, "ecdsa-sha2-nistp256", 20) == 0) { pubkey_type = SFTP_KEY_ECDSA_384; } else if (strncmp(hostkey_algo, "ecdsa-sha2-nistp256", 20) == 0) { pubkey_type = SFTP_KEY_ECDSA_521; #endif /* PR_USE_OPENSSL_ECC */ /* XXX Need to support X509v3 certs here */ } else { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "unsupported host key algorithm '%s' requested, rejecting request", hostkey_algo); *send_userauth_fail = TRUE; errno = EINVAL; return 0; } if (sftp_keys_verify_pubkey_type(pkt->pool, hostkey_data, hostkey_datalen, pubkey_type) != TRUE) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "unable to verify that given host key matches given '%s' algorithm", hostkey_algo); *send_userauth_fail = TRUE; errno = EINVAL; return 0; } #ifdef OPENSSL_FIPS if (FIPS_mode()) { fp = sftp_keys_get_fingerprint(pkt->pool, hostkey_data, hostkey_datalen, SFTP_KEYS_FP_DIGEST_SHA1); if (fp != NULL) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "public key SHA1 fingerprint: %s", fp); } else { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error obtaining public key SHA1 fingerprint: %s", strerror(errno)); } } else { #endif /* OPENSSL_FIPS */ fp = sftp_keys_get_fingerprint(pkt->pool, hostkey_data, hostkey_datalen, SFTP_KEYS_FP_DIGEST_MD5); if (fp != NULL) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "public key MD5 fingerprint: %s", fp); } else { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error obtaining public key MD5 fingerprint: %s", strerror(errno)); } #ifdef OPENSSL_FIPS } #endif /* OPENSSL_FIPS */ 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); *send_userauth_fail = TRUE; errno = ENOENT; return 0; } /* XXX Should we check the given FQDN here against the client's actual * DNS name and/or IP address? Or leave that up to the keystore's * verify_host_key() function? */ if (sftp_blacklist_reject_key(pkt->pool, hostkey_data, hostkey_datalen)) { *send_userauth_fail = TRUE; errno = EACCES; return 0; } /* The client signed the request as well; we need to authenticate the * host with the given key now. If that succeeds, we use the signature to * verify the request. And if that succeeds, then we're done authenticating. */ if (sftp_keystore_verify_host_key(pkt->pool, user, host_fqdn, host_user, hostkey_data, hostkey_datalen) < 0) { *send_userauth_fail = TRUE; errno = EACCES; return 0; } /* Make sure the signature matches as well. */ id_len = sftp_session_get_id(&id); /* XXX Is this buffer large enough? Too large? */ bufsz2 = buflen2 = 2048; ptr2 = buf2 = sftp_msg_getbuf(pkt->pool, bufsz2); sftp_msg_write_data(&buf2, &buflen2, id, id_len, TRUE); sftp_msg_write_byte(&buf2, &buflen2, SFTP_SSH2_MSG_USER_AUTH_REQUEST); sftp_msg_write_string(&buf2, &buflen2, orig_user); if (sftp_interop_supports_feature(SFTP_SSH2_FEAT_SERVICE_IN_HOST_SIG)) { sftp_msg_write_string(&buf2, &buflen2, service); } else { sftp_msg_write_string(&buf2, &buflen2, "ssh-userauth"); } sftp_msg_write_string(&buf2, &buflen2, "hostbased"); sftp_msg_write_string(&buf2, &buflen2, hostkey_algo); sftp_msg_write_data(&buf2, &buflen2, hostkey_data, hostkey_datalen, TRUE); sftp_msg_write_string(&buf2, &buflen2, host_fqdn); sftp_msg_write_string(&buf2, &buflen2, host_user_utf8); if (sftp_keys_verify_signed_data(pkt->pool, hostkey_algo, hostkey_data, hostkey_datalen, signature_data, signature_len, (unsigned char *) ptr2, (bufsz2 - buflen2)) < 0) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "failed to verify '%s' signature on hostbased auth request for " "user '%s', host %s", hostkey_algo, orig_user, host_fqdn); *send_userauth_fail = TRUE; return 0; } /* Make sure the user is authorized to login. Normally this is checked * as part of the password verification process, but in the case of * hostbased authentication, there is no password to verify. */ if (pr_auth_authorize(pkt->pool, user) != PR_AUTH_OK) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "authentication for user '%s' failed: User not authorized", user); pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): User not authorized " "for login", user); *send_userauth_fail = TRUE; errno = EACCES; return 0; } return 1; }
int sftp_kbdint_send_challenge(const char *user, const char *instruction, unsigned int count, sftp_kbdint_challenge_t *challenges) { register unsigned int i; unsigned char *buf, *ptr; uint32_t buflen, bufsz; struct ssh2_packet *pkt; int res; if (count == 0 || challenges == NULL) { errno = EINVAL; return -1; } pkt = sftp_ssh2_packet_create(kbdint_pool); /* XXX Is this large enough? Too large? */ buflen = bufsz = 3072; buf = ptr = palloc(pkt->pool, bufsz); /* See RFC4256, Section 3.2. */ sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_MSG_USER_AUTH_INFO_REQ); if (user) { sftp_msg_write_string(&buf, &buflen, sftp_utf8_encode_str(pkt->pool, user)); } else { /* Empty user strings are allowed. */ sftp_msg_write_string(&buf, &buflen, ""); } if (instruction) { sftp_msg_write_string(&buf, &buflen, sftp_utf8_encode_str(pkt->pool, instruction)); } else { /* Empty instruction strings are allowed. */ sftp_msg_write_string(&buf, &buflen, ""); } /* Empty language string. */ sftp_msg_write_string(&buf, &buflen, ""); sftp_msg_write_int(&buf, &buflen, count); for (i = 0; i < count; i++) { sftp_msg_write_string(&buf, &buflen, challenges[i].challenge); sftp_msg_write_bool(&buf, &buflen, challenges[i].display_response); } pkt->payload = ptr; pkt->payload_len = (bufsz - buflen); pr_trace_msg(trace_channel, 9, "sending USER_AUTH_INFO_REQ message to client"); res = sftp_ssh2_packet_write(sftp_conn->wfd, pkt); destroy_pool(pkt->pool); return res; }
int sftp_auth_publickey(struct ssh2_packet *pkt, cmd_rec *pass_cmd, const char *orig_user, const char *user, const char *service, char **buf, uint32_t *buflen, int *send_userauth_fail) { int have_signature, pubkey_type; char *pubkey_algo = NULL, *pubkey_data; const char *fp = NULL; uint32_t pubkey_len; struct passwd *pw; 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, pass_cmd->argv[0]); pr_cmd_dispatch_phase(pass_cmd, POST_CMD_ERR, 0); pr_cmd_dispatch_phase(pass_cmd, LOG_CMD_ERR, 0); *send_userauth_fail = TRUE; errno = EPERM; return 0; } have_signature = sftp_msg_read_bool(pkt->pool, buf, buflen); if (sftp_interop_supports_feature(SFTP_SSH2_FEAT_HAVE_PUBKEY_ALGO)) { pubkey_algo = sftp_msg_read_string(pkt->pool, buf, buflen); } pubkey_len = sftp_msg_read_int(pkt->pool, buf, buflen); pubkey_data = sftp_msg_read_data(pkt->pool, buf, buflen, pubkey_len); if (pubkey_algo == NULL) { /* The client did not send the string identifying the public key algorithm. * Thus we need to extract the algorithm string from the public key data. */ pubkey_algo = sftp_msg_read_string(pkt->pool, &pubkey_data, &pubkey_len); } pr_trace_msg(trace_channel, 9, "client sent '%s' public key %s", pubkey_algo, have_signature ? "with signature" : "without signature"); if (strncmp(pubkey_algo, "ssh-rsa", 8) == 0) { pubkey_type = EVP_PKEY_RSA; } else if (strncmp(pubkey_algo, "ssh-dss", 8) == 0) { pubkey_type = EVP_PKEY_DSA; /* XXX This is where we would add support for X509 public keys, e.g.: * * x509v3-ssh-dss * x509v3-ssh-rsa * x509v3-sign (older) * */ } else { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "unsupported public key algorithm '%s' requested, rejecting request", pubkey_algo); *send_userauth_fail = TRUE; errno = EINVAL; return 0; } if (sftp_keys_verify_pubkey_type(pkt->pool, pubkey_data, pubkey_len, pubkey_type) != TRUE) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "unable to verify that given public key matches given '%s' algorithm", pubkey_algo); *send_userauth_fail = TRUE; errno = EINVAL; return 0; } #ifdef OPENSSL_FIPS if (FIPS_mode()) { fp = sftp_keys_get_fingerprint(pkt->pool, pubkey_data, pubkey_len, SFTP_KEYS_FP_DIGEST_SHA1); if (fp != NULL) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "public key SHA1 fingerprint: %s", fp); } else { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error obtaining public key SHA1 fingerprint: %s", strerror(errno)); } } else { #endif /* OPENSSL_FIPS */ fp = sftp_keys_get_fingerprint(pkt->pool, pubkey_data, pubkey_len, SFTP_KEYS_FP_DIGEST_MD5); if (fp != NULL) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "public key MD5 fingerprint: %s", fp); } else { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error obtaining public key MD5 fingerprint: %s", strerror(errno)); } #ifdef OPENSSL_FIPS } #endif /* OPENSSL_FIPS */ 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); *send_userauth_fail = TRUE; errno = ENOENT; return 0; } if (!have_signature) { /* We don't perform the actual authentication just yet; we need to * let the client know that the pubkey algorithms are acceptable. */ if (send_pubkey_ok(pubkey_algo, pubkey_data, pubkey_len) < 0) { return -1; } return 0; } else { const unsigned char *id; char *buf2, *ptr2, *signature_data; uint32_t buflen2, bufsz2, id_len, signature_len; /* XXX This should become a more generic "is this key data * usable/acceptable?" check (and take the pubkey_type parameter), so that * that is where we would check the validity/usability of an X509v3 cert * (if a cert), or if the key is on the blacklist (if a key). */ if (sftp_blacklist_reject_key(pkt->pool, pubkey_data, pubkey_len)) { *send_userauth_fail = TRUE; errno = EPERM; return 0; } signature_len = sftp_msg_read_int(pkt->pool, buf, buflen); signature_data = sftp_msg_read_data(pkt->pool, buf, buflen, signature_len); /* The client signed the request as well; we need to authenticate the * user with the given pubkey now. If that succeeds, we use the * signature to verify the request. And if that succeeds, then we're * done authenticating. */ /* XXX Need to pass the pubkey_type here as well, so that the * verification routines can handle different databases of keys/certs. * * For X509v3 certs, we will want a way to enforce/restrict which * user names can be used with the provided cert. Perhaps a database * mapping cert fingerprints to user names/UIDs? Configurable callback * check (HOOK?), for modules to enforce. */ if (sftp_keystore_verify_user_key(pkt->pool, user, pubkey_data, pubkey_len) < 0) { *send_userauth_fail = TRUE; return 0; } /* Make sure the signature matches as well. */ id_len = sftp_session_get_id(&id); /* Make sure to allocate a buffer large enough to hold the publickey * signature and data we want to send back. */ bufsz2 = buflen2 = pubkey_len + 1024; ptr2 = buf2 = sftp_msg_getbuf(pkt->pool, bufsz2); sftp_msg_write_data(&buf2, &buflen2, (char *) id, id_len, TRUE); sftp_msg_write_byte(&buf2, &buflen2, SFTP_SSH2_MSG_USER_AUTH_REQUEST); sftp_msg_write_string(&buf2, &buflen2, orig_user); if (sftp_interop_supports_feature(SFTP_SSH2_FEAT_SERVICE_IN_PUBKEY_SIG)) { sftp_msg_write_string(&buf2, &buflen2, service); } else { sftp_msg_write_string(&buf2, &buflen2, "ssh-userauth"); } if (sftp_interop_supports_feature(SFTP_SSH2_FEAT_HAVE_PUBKEY_ALGO)) { sftp_msg_write_string(&buf2, &buflen2, "publickey"); sftp_msg_write_bool(&buf2, &buflen2, TRUE); sftp_msg_write_string(&buf2, &buflen2, pubkey_algo); } else { sftp_msg_write_bool(&buf2, &buflen2, TRUE); } sftp_msg_write_data(&buf2, &buflen2, pubkey_data, pubkey_len, TRUE); if (sftp_keys_verify_signed_data(pkt->pool, pubkey_algo, pubkey_data, pubkey_len, signature_data, signature_len, (unsigned char *) ptr2, (bufsz2 - buflen2)) < 0) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "failed to verify '%s' signature on public key auth request for " "user '%s'", pubkey_algo, orig_user); *send_userauth_fail = TRUE; return 0; } } /* Make sure the user is authorized to login. Normally this is checked * as part of the password verification process, but in the case of * publickey authentication, there is no password to verify. */ if (pr_auth_authorize(pkt->pool, user) != PR_AUTH_OK) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "authentication for user '%s' failed: User not authorized", user); pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): User not authorized " "for login", user); *send_userauth_fail = TRUE; errno = EACCES; return 0; } return 1; }
void sftp_disconnect_send(uint32_t reason, const char *explain, const char *file, int lineno, const char *func) { struct ssh2_packet *pkt; const pr_netaddr_t *remote_addr; const char *lang = "en-US"; unsigned char *buf, *ptr; uint32_t buflen, bufsz; int sockfd; /* Send the client a DISCONNECT mesg. */ pkt = sftp_ssh2_packet_create(sftp_pool); remote_addr = pr_netaddr_get_sess_remote_addr(); buflen = bufsz = 1024; ptr = buf = palloc(pkt->pool, bufsz); if (explain == NULL) { register unsigned int i; for (i = 0; explanations[i].explain; i++) { if (explanations[i].code == reason) { explain = explanations[i].explain; lang = explanations[i].lang; if (lang == NULL) { lang = "en-US"; } break; } } if (explain == NULL) { explain = "Unknown reason"; } } else { lang = "en-US"; } if (strlen(func) > 0) { pr_trace_msg(trace_channel, 9, "disconnecting (%s) [at %s:%d:%s()]", explain, file, lineno, func); } else { pr_trace_msg(trace_channel, 9, "disconnecting (%s) [at %s:%d]", explain, file, lineno); } sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_MSG_DISCONNECT); sftp_msg_write_int(&buf, &buflen, reason); sftp_msg_write_string(&buf, &buflen, explain); sftp_msg_write_string(&buf, &buflen, lang); pkt->payload = ptr; pkt->payload_len = (bufsz - buflen); (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "disconnecting %s (%s)", pr_netaddr_get_ipstr(remote_addr), explain); /* If we are called very early in the connection lifetime, then the * sftp_conn variable may not have been set yet, thus the conditional here. */ if (sftp_conn != NULL) { sockfd = sftp_conn->wfd; } else { sockfd = session.c->wfd; } /* Explicitly set a short poll timeout of 5 secs. */ sftp_ssh2_packet_set_poll_timeout(5); if (sftp_ssh2_packet_write(sockfd, pkt) < 0) { int xerrno = errno; pr_trace_msg(trace_channel, 12, "error writing DISCONNECT message: %s", strerror(xerrno)); } destroy_pool(pkt->pool); }
int sftp_tap_send_packet(void) { int chance; if (!sftp_interop_supports_feature(SFTP_SSH2_FEAT_IGNORE_MSG)) { pr_trace_msg(trace_channel, 3, "unable to send TAP packet: IGNORE not supported by client"); return 0; } if (curr_policy.chance_max == 0) { /* The "none" policy is in effect; nothing to do. */ return 0; } /* Calculate our odds of sending a tap packet, based on the configured * policy. */ if (curr_policy.chance_max != 1) { chance = (int) (rand() / (RAND_MAX / curr_policy.chance_max + 1)); } else { chance = 1; } if (chance == curr_policy.chance) { unsigned char *rand_data; char *buf, *ptr; uint32_t bufsz, buflen, rand_datalen; struct ssh2_packet *pkt; unsigned int max_datalen = 8192; if (curr_policy.max_datalen) { max_datalen = curr_policy.max_datalen; } rand_datalen = (uint32_t) (curr_policy.min_datalen + rand() / (RAND_MAX / (max_datalen - curr_policy.min_datalen) + 1)); pr_trace_msg(trace_channel, 20, "sending random SSH2_MSG_IGNORE message " "(%lu bytes) based on '%s' TAP policy", (unsigned long) rand_datalen, curr_policy.policy); pkt = sftp_ssh2_packet_create(tap_pool); bufsz = buflen = rand_datalen + 32; ptr = buf = palloc(pkt->pool, bufsz); rand_data = palloc(pkt->pool, rand_datalen); /* We don't need cryptographically secure random bytes here, just * pseudo-random data. */ RAND_pseudo_bytes(rand_data, rand_datalen); sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_MSG_IGNORE); sftp_msg_write_data(&buf, &buflen, (char *) rand_data, rand_datalen, TRUE); pkt->payload = ptr; pkt->payload_len = (bufsz - buflen); if (sftp_ssh2_packet_send(sftp_conn->wfd, pkt) < 0) { int xerrno = errno; pr_trace_msg(trace_channel, 12, "error writing TAP packet: %s", strerror(xerrno)); } destroy_pool(pkt->pool); } return 0; }
int sftp_mac_write_data(struct ssh2_packet *pkt) { struct sftp_mac *mac; HMAC_CTX *mac_ctx; mac = &(write_macs[write_mac_idx]); mac_ctx = &(write_ctxs[write_mac_idx]); if (mac->key) { unsigned char *mac_data; char *buf, *ptr; uint32_t buflen, bufsz = (sizeof(uint32_t) * 2) + pkt->packet_len, mac_len = 0; mac_data = pcalloc(pkt->pool, EVP_MAX_MD_SIZE); buflen = bufsz; ptr = buf = sftp_msg_getbuf(pkt->pool, bufsz); sftp_msg_write_int(&buf, &buflen, pkt->seqno); sftp_msg_write_int(&buf, &buflen, pkt->packet_len); sftp_msg_write_byte(&buf, &buflen, pkt->padding_len); sftp_msg_write_data(&buf, &buflen, pkt->payload, pkt->payload_len, FALSE); sftp_msg_write_data(&buf, &buflen, pkt->padding, pkt->padding_len, FALSE); #if OPENSSL_VERSION_NUMBER > 0x000907000L # if OPENSSL_VERSION_NUMBER >= 0x10000001L if (HMAC_Init_ex(mac_ctx, NULL, 0, NULL, NULL) != 1) { pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error resetting HMAC context: %s", sftp_crypto_get_errors()); errno = EPERM; return -1; } # else HMAC_Init_ex(mac_ctx, NULL, 0, NULL, NULL); # endif /* OpenSSL-1.0.0 and later */ #else HMAC_Init(mac_ctx, NULL, 0, NULL); #endif /* OpenSSL-0.9.7 and later */ #if OPENSSL_VERSION_NUMBER >= 0x10000001L if (HMAC_Update(mac_ctx, (unsigned char *) ptr, (bufsz - buflen)) != 1) { pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error adding %lu bytes of data to HMAC context: %s", (unsigned long) (bufsz - buflen), sftp_crypto_get_errors()); errno = EPERM; return -1; } if (HMAC_Final(mac_ctx, mac_data, &mac_len) != 1) { pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error finalizing HMAC context: %s", sftp_crypto_get_errors()); errno = EPERM; return -1; } #else HMAC_Update(mac_ctx, (unsigned char *) ptr, (bufsz - buflen)); HMAC_Final(mac_ctx, mac_data, &mac_len); #endif /* OpenSSL-1.0.0 and later */ if (mac_len == 0) { pkt->mac = NULL; pkt->mac_len = 0; (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error computing MAC using %s: %s", mac->algo, sftp_crypto_get_errors()); return -1; } if (mac->mac_len != 0) { mac_len = mac->mac_len; } pkt->mac_len = mac_len; pkt->mac = pcalloc(pkt->pool, pkt->mac_len); memcpy(pkt->mac, mac_data, mac_len); #ifdef SFTP_DEBUG_PACKET { unsigned int i; (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "server MAC (len %lu, seqno %lu):", (unsigned long) pkt->mac_len, (unsigned long) pkt->seqno); for (i = 0; i < mac_len;) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, " %02x%02x %02x%02x %02x%02x %02x%02x", ((unsigned char *) pkt->mac)[i], ((unsigned char *) pkt->mac)[i+1], ((unsigned char *) pkt->mac)[i+2], ((unsigned char *) pkt->mac)[i+3], ((unsigned char *) pkt->mac)[i+4], ((unsigned char *) pkt->mac)[i+5], ((unsigned char *) pkt->mac)[i+6], ((unsigned char *) pkt->mac)[i+7]); i += 8; } } #endif return 0; } pkt->mac = NULL; pkt->mac_len = 0; return 0; }
const unsigned char *sftp_agent_sign_data(pool *p, const char *agent_path, const unsigned char *key_data, uint32_t key_datalen, const unsigned char *data, uint32_t datalen, uint32_t *sig_datalen) { int fd; unsigned char *buf, *req, *resp, *sig_data; uint32_t buflen, flags, reqlen, reqsz, resplen; char resp_status; fd = agent_connect(agent_path); if (fd < 0) { return NULL; } /* XXX When to set flags to OLD_SIGNATURE? */ flags = 0; /* Write out the request for signing the given data. */ reqsz = buflen = 1 + key_datalen + 4 + datalen + 4 + 4; req = buf = palloc(p, reqsz); sftp_msg_write_byte(&buf, &buflen, SFTP_SSH_AGENT_REQ_SIGN_DATA); sftp_msg_write_data(&buf, &buflen, key_data, key_datalen, TRUE); sftp_msg_write_data(&buf, &buflen, data, datalen, TRUE); sftp_msg_write_int(&buf, &buflen, flags); reqlen = reqsz - buflen; resp = agent_request(p, fd, agent_path, req, reqlen, &resplen); if (resp == NULL) { int xerrno = errno; (void) close(fd); errno = xerrno; return NULL; } (void) close(fd); /* Read the response from the agent. */ resp_status = sftp_msg_read_byte(p, &resp, &resplen); if (agent_failure(resp_status) == TRUE) { pr_trace_msg(trace_channel, 5, "SSH agent at '%s' indicated failure (%d) for data signing request", agent_path, resp_status); errno = EPERM; return NULL; } if (resp_status != SFTP_SSH_AGENT_RESP_SIGN_DATA) { pr_trace_msg(trace_channel, 5, "unknown response type %d from SSH agent at '%s'", resp_status, agent_path); errno = EACCES; return NULL; } *sig_datalen = sftp_msg_read_int(p, &resp, &resplen); sig_data = sftp_msg_read_data(p, &resp, &resplen, *sig_datalen); return sig_data; }
int sftp_agent_get_keys(pool *p, const char *agent_path, array_header *key_list) { register unsigned int i; int fd; unsigned char *buf, *req, *resp; uint32_t buflen, key_count, reqlen, reqsz, resplen; char resp_status; fd = agent_connect(agent_path); if (fd < 0) { return -1; } /* Write out the request for the identities (i.e. the public keys). */ reqsz = buflen = 64; req = buf = palloc(p, reqsz); sftp_msg_write_byte(&buf, &buflen, SFTP_SSH_AGENT_REQ_IDS); reqlen = reqsz - buflen; resp = agent_request(p, fd, agent_path, req, reqlen, &resplen); if (resp == NULL) { int xerrno = errno; (void) close(fd); errno = xerrno; return -1; } (void) close(fd); /* Read the response from the agent. */ resp_status = sftp_msg_read_byte(p, &resp, &resplen); if (agent_failure(resp_status) == TRUE) { pr_trace_msg(trace_channel, 5, "SSH agent at '%s' indicated failure (%d) for identities request", agent_path, resp_status); errno = EPERM; return -1; } if (resp_status != SFTP_SSH_AGENT_RESP_IDS) { pr_trace_msg(trace_channel, 5, "unknown response type %d from SSH agent at '%s'", resp_status, agent_path); errno = EACCES; return -1; } key_count = sftp_msg_read_int(p, &resp, &resplen); if (key_count > AGENT_MAX_KEYS) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "SSH agent at '%s' returned too many keys (%lu, max %lu)", agent_path, (unsigned long) key_count, (unsigned long) AGENT_MAX_KEYS); errno = EPERM; return -1; } for (i = 0; i < key_count; i++) { unsigned char *key_data; uint32_t key_datalen; char *key_comment; struct agent_key *key; key_datalen = sftp_msg_read_int(p, &resp, &resplen); key_data = sftp_msg_read_data(p, &resp, &resplen, key_datalen); key_comment = sftp_msg_read_string(p, &resp, &resplen); if (key_comment != NULL) { pr_trace_msg(trace_channel, 9, "SSH agent at '%s' provided comment '%s' for key #%u", agent_path, key_comment, (i + 1)); } key = pcalloc(p, sizeof(struct agent_key)); key->key_data = key_data; key->key_datalen = key_datalen; key->agent_path = pstrdup(p, agent_path); *((struct agent_key **) push_array(key_list)) = key; } pr_trace_msg(trace_channel, 9, "SSH agent at '%s' provided %lu %s", agent_path, (unsigned long) key_count, key_count != 1 ? "keys" : "key"); return 0; }