# server key destruction and auditing # based on: # https://bugzilla.mindrot.org/show_bug.cgi?id=1402 # https://bugzilla.mindrot.org/attachment.cgi?id=2015 # by jchadima@redhat.com diff --git a/openssh-6.5p1/audit-bsm.c b/openssh-6.5p1/audit-bsm.c --- a/openssh-6.5p1/audit-bsm.c +++ b/openssh-6.5p1/audit-bsm.c @@ -486,9 +486,27 @@ audit_kex_body(int ctos, char *enc, char /* not implemented */ } void audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) { /* not implemented */ } + +void +audit_destroy_sensitive_data(const char *fp) +{ + /* not implemented */ +} + +void +audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid) +{ + /* not implemented */ +} + +void +audit_generate_ephemeral_server_key(const char *fp) +{ + /* not implemented */ +} #endif /* BSM */ diff --git a/openssh-6.5p1/audit-linux.c b/openssh-6.5p1/audit-linux.c --- a/openssh-6.5p1/audit-linux.c +++ b/openssh-6.5p1/audit-linux.c @@ -351,9 +351,55 @@ audit_session_key_free_body(int ctos, pi audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, buf, NULL, get_remote_ipaddr(), NULL, 1); audit_close(audit_fd); /* do not abort if the error is EPERM and sshd is run as non root user */ if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0))) error("cannot write into audit"); } +void +audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid) +{ + char buf[AUDIT_LOG_SIZE]; + int audit_fd, audit_ok; + + snprintf(buf, sizeof(buf), "op=destroy kind=server fp=%s direction=? spid=%jd suid=%jd ", + fp, (intmax_t)pid, (intmax_t)uid); + audit_fd = audit_open(); + if (audit_fd < 0) { + if (errno != EINVAL && errno != EPROTONOSUPPORT && + errno != EAFNOSUPPORT) + error("cannot open audit"); + return; + } + audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, + buf, NULL, + listening_for_clients() ? NULL : get_remote_ipaddr(), + NULL, 1); + audit_close(audit_fd); + /* do not abort if the error is EPERM and sshd is run as non root user */ + if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0))) + error("cannot write into audit"); +} + +void +audit_generate_ephemeral_server_key(const char *fp) +{ + char buf[AUDIT_LOG_SIZE]; + int audit_fd, audit_ok; + + snprintf(buf, sizeof(buf), "op=create kind=server fp=%s direction=? ", fp); + audit_fd = audit_open(); + if (audit_fd < 0) { + if (errno != EINVAL && errno != EPROTONOSUPPORT && + errno != EAFNOSUPPORT) + error("cannot open audit"); + return; + } + audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, + buf, NULL, 0, NULL, 1); + audit_close(audit_fd); + /* do not abort if the error is EPERM and sshd is run as non root user */ + if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0))) + error("cannot write into audit"); +} #endif /* USE_LINUX_AUDIT */ diff --git a/openssh-6.5p1/audit.c b/openssh-6.5p1/audit.c --- a/openssh-6.5p1/audit.c +++ b/openssh-6.5p1/audit.c @@ -285,10 +285,29 @@ audit_kex_body(int ctos, char *enc, char * This will be called on succesfull session key discard */ void audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) { debug("audit session key discard euid %u direction %d from pid %ld uid %u", (unsigned)geteuid(), ctos, (long)pid, (unsigned)uid); } + +/* + * This will be called on destroy private part of the server key + */ +void +audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid) +{ + debug("audit destroy sensitive data euid %d fingerprint %s from pid %ld uid %u", + geteuid(), fp, (long)pid, (unsigned)uid); +} + +/* + * This will be called on generation of the ephemeral server key + */ +void +audit_generate_ephemeral_server_key(const char *) +{ + debug("audit create ephemeral server key euid %d fingerprint %s", geteuid(), fp); +} # endif /* !defined CUSTOM_SSH_AUDIT_EVENTS */ #endif /* SSH_AUDIT_EVENTS */ diff --git a/openssh-6.5p1/audit.h b/openssh-6.5p1/audit.h --- a/openssh-6.5p1/audit.h +++ b/openssh-6.5p1/audit.h @@ -43,26 +43,30 @@ enum ssh_audit_event_type { SSH_INVALID_USER, SSH_NOLOGIN, /* denied by /etc/nologin, not implemented */ SSH_CONNECTION_CLOSE, /* closed after attempting auth or session */ SSH_CONNECTION_ABANDON, /* closed without completing auth */ SSH_AUDIT_UNKNOWN }; typedef enum ssh_audit_event_type ssh_audit_event_t; +int listening_for_clients(void); + void audit_connection_from(const char *, int); void audit_event(ssh_audit_event_t); void audit_count_session_open(void); void audit_session_open(struct logininfo *); void audit_session_close(struct logininfo *); int audit_run_command(const char *); void audit_end_command(int, const char *); ssh_audit_event_t audit_classify_auth(const char *); int audit_keyusage(int, const char *, unsigned, char *, int); void audit_key(int, int *, const Key *); void audit_unsupported(int); void audit_kex(int, char *, char *, char *); void audit_unsupported_body(int); void audit_kex_body(int, char *, char *, char *, pid_t, uid_t); void audit_session_key_free(int ctos); void audit_session_key_free_body(int ctos, pid_t, uid_t); +void audit_destroy_sensitive_data(const char *, pid_t, uid_t); +void audit_generate_ephemeral_server_key(const char *); #endif /* _SSH_AUDIT_H */ diff --git a/openssh-6.5p1/key.c b/openssh-6.5p1/key.c --- a/openssh-6.5p1/key.c +++ b/openssh-6.5p1/key.c @@ -1959,16 +1959,41 @@ key_demote(const Key *k) fatal("key_demote: bad key type %d", k->type); break; } return (pk); } int +key_is_private(const Key *k) +{ + switch (k->type) { + case KEY_RSA_CERT_V00: + case KEY_RSA_CERT: + case KEY_RSA1: + case KEY_RSA: + return k->rsa->d != NULL; + case KEY_DSA_CERT_V00: + case KEY_DSA_CERT: + case KEY_DSA: + return k->dsa->priv_key != NULL; +#ifdef OPENSSL_HAS_ECC + case KEY_ECDSA_CERT: + case KEY_ECDSA: + return EC_KEY_get0_private_key(k->ecdsa) != NULL; +#endif + default: + /* fatal("key_is_private: bad key type %d", k->type); */ + debug2("key_is_private: bad key type %d", k->type); + return 1; + } +} + +int key_is_cert(const Key *k) { if (k == NULL) return 0; return key_type_is_cert(k->type); } /* Return the cert-less equivalent to a certified key type */ diff --git a/openssh-6.5p1/key.h b/openssh-6.5p1/key.h --- a/openssh-6.5p1/key.h +++ b/openssh-6.5p1/key.h @@ -113,16 +113,17 @@ int key_read(Key *, char **); u_int key_size(const Key *); enum fp_type key_fp_type_select(void); char *key_fp_type_str(enum fp_type); Key *key_generate(int, u_int); Key *key_from_private(const Key *); int key_type_from_name(char *); int key_is_cert(const Key *); +int key_is_private(const Key *k); int key_type_is_cert(int); int key_type_plain(int); int key_to_certified(Key *, int); int key_drop_cert(Key *); int key_certify(Key *, Key *); void key_cert_copy(const Key *, struct Key *); int key_cert_check_authority(const Key *, int, int, const char *, const char **); diff --git a/openssh-6.5p1/monitor.c b/openssh-6.5p1/monitor.c --- a/openssh-6.5p1/monitor.c +++ b/openssh-6.5p1/monitor.c @@ -110,16 +110,18 @@ extern u_int utmp_len; extern Newkeys *current_keys[]; extern z_stream incoming_stream; extern z_stream outgoing_stream; extern u_char session_id[]; extern Buffer auth_debug; extern int auth_debug_init; extern Buffer loginmsg; +extern void destroy_sensitive_data(int); + /* State exported from the child */ struct { z_stream incoming; z_stream outgoing; u_char *keyin; u_int keyinlen; u_char *keyout; @@ -186,16 +188,17 @@ int mm_answer_gss_checkmic(int, Buffer * #ifdef SSH_AUDIT_EVENTS int mm_answer_audit_event(int, Buffer *); int mm_answer_audit_command(int, Buffer *); int mm_answer_audit_end_command(int, Buffer *); int mm_answer_audit_unsupported_body(int, Buffer *); int mm_answer_audit_kex_body(int, Buffer *); int mm_answer_audit_session_key_free_body(int, Buffer *); +int mm_answer_audit_server_key_free(int, Buffer *); #endif static int monitor_read_log(struct monitor *); static Authctxt *authctxt; static BIGNUM *ssh1_challenge = NULL; /* used for ssh1 rsa auth */ /* local state for key verify */ @@ -240,16 +243,17 @@ struct mon_table mon_dispatch_proto20[] {MONITOR_REQ_PAM_RESPOND, MON_ISAUTH, mm_answer_pam_respond}, {MONITOR_REQ_PAM_FREE_CTX, MON_ONCE|MON_AUTHDECIDE, mm_answer_pam_free_ctx}, #endif #ifdef SSH_AUDIT_EVENTS {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body}, {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body}, {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body}, + {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free}, #endif #ifdef BSD_AUTH {MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery}, {MONITOR_REQ_BSDAUTHRESPOND, MON_AUTH, mm_answer_bsdauthrespond}, #endif #ifdef SKEY {MONITOR_REQ_SKEYQUERY, MON_ISAUTH, mm_answer_skeyquery}, {MONITOR_REQ_SKEYRESPOND, MON_AUTH, mm_answer_skeyrespond}, @@ -280,16 +284,17 @@ struct mon_table mon_dispatch_postauth20 {MONITOR_REQ_TERM, 0, mm_answer_term}, #ifdef SSH_AUDIT_EVENTS {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT, mm_answer_audit_command}, {MONITOR_REQ_AUDIT_END_COMMAND, MON_PERMIT, mm_answer_audit_end_command}, {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body}, {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body}, {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body}, + {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free}, #endif {0, 0, NULL} }; struct mon_table mon_dispatch_proto15[] = { {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, {MONITOR_REQ_SESSKEY, MON_ONCE, mm_answer_sesskey}, {MONITOR_REQ_SESSID, MON_ONCE, mm_answer_sessid}, @@ -314,31 +319,33 @@ struct mon_table mon_dispatch_proto15[] {MONITOR_REQ_PAM_RESPOND, MON_ISAUTH, mm_answer_pam_respond}, {MONITOR_REQ_PAM_FREE_CTX, MON_ONCE|MON_AUTHDECIDE, mm_answer_pam_free_ctx}, #endif #ifdef SSH_AUDIT_EVENTS {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body}, {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body}, {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body}, + {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free}, #endif {0, 0, NULL} }; struct mon_table mon_dispatch_postauth15[] = { {MONITOR_REQ_PTY, MON_ONCE, mm_answer_pty}, {MONITOR_REQ_PTYCLEANUP, MON_ONCE, mm_answer_pty_cleanup}, {MONITOR_REQ_TERM, 0, mm_answer_term}, #ifdef SSH_AUDIT_EVENTS {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT|MON_ONCE, mm_answer_audit_command}, {MONITOR_REQ_AUDIT_END_COMMAND, MON_PERMIT, mm_answer_audit_end_command}, {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body}, {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body}, {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body}, + {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free}, #endif {0, 0, NULL} }; struct mon_table *mon_dispatch; /* Specifies if a certain message is allowed at the moment */ @@ -1761,16 +1768,18 @@ mm_answer_term(int sock, Buffer *req) /* The child is terminating */ session_destroy_all(&mm_session_close); #ifdef USE_PAM if (options.use_pam) sshpam_cleanup(); #endif + destroy_sensitive_data(0); + while (waitpid(pmonitor->m_pid, &status, 0) == -1) if (errno != EINTR) exit(1); res = WIFEXITED(status) ? WEXITSTATUS(status) : 1; /* Terminate process */ exit(res); @@ -2505,9 +2514,30 @@ mm_answer_audit_session_key_free_body(in audit_session_key_free_body(ctos, pid, uid); buffer_clear(m); mm_request_send(sock, MONITOR_ANS_AUDIT_SESSION_KEY_FREE, m); return 0; } + +int +mm_answer_audit_server_key_free(int sock, Buffer *m) +{ + int len; + char *fp; + pid_t pid; + uid_t uid; + + fp = buffer_get_string(m, &len); + pid = buffer_get_int64(m); + uid = buffer_get_int64(m); + + audit_destroy_sensitive_data(fp, pid, uid); + + free(fp); + buffer_clear(m); + + mm_request_send(sock, MONITOR_ANS_AUDIT_SERVER_KEY_FREE, m); + return 0; +} #endif /* SSH_AUDIT_EVENTS */ diff --git a/openssh-6.5p1/monitor.h b/openssh-6.5p1/monitor.h --- a/openssh-6.5p1/monitor.h +++ b/openssh-6.5p1/monitor.h @@ -68,16 +68,17 @@ enum monitor_reqtype { MONITOR_REQ_PAM_QUERY = 106, MONITOR_ANS_PAM_QUERY = 107, MONITOR_REQ_PAM_RESPOND = 108, MONITOR_ANS_PAM_RESPOND = 109, MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111, MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113, MONITOR_ANS_AUDIT_COMMAND = 114, MONITOR_REQ_AUDIT_END_COMMAND = 115, MONITOR_REQ_AUDIT_UNSUPPORTED = 116, MONITOR_ANS_AUDIT_UNSUPPORTED = 117, MONITOR_REQ_AUDIT_KEX = 118, MONITOR_ANS_AUDIT_KEX = 119, MONITOR_REQ_AUDIT_SESSION_KEY_FREE = 120, MONITOR_ANS_AUDIT_SESSION_KEY_FREE = 121, + MONITOR_REQ_AUDIT_SERVER_KEY_FREE = 122, MONITOR_ANS_AUDIT_SERVER_KEY_FREE = 123, }; struct mm_master; struct monitor { int m_recvfd; int m_sendfd; int m_log_recvfd; diff --git a/openssh-6.5p1/monitor_wrap.c b/openssh-6.5p1/monitor_wrap.c --- a/openssh-6.5p1/monitor_wrap.c +++ b/openssh-6.5p1/monitor_wrap.c @@ -1537,9 +1537,25 @@ mm_audit_session_key_free_body(int ctos, buffer_put_int(&m, ctos); buffer_put_int64(&m, pid); buffer_put_int64(&m, uid); mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SESSION_KEY_FREE, &m); mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_SESSION_KEY_FREE, &m); buffer_free(&m); } + +void +mm_audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid) +{ + Buffer m; + + buffer_init(&m); + buffer_put_cstring(&m, fp); + buffer_put_int64(&m, pid); + buffer_put_int64(&m, uid); + + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SERVER_KEY_FREE, &m); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_SERVER_KEY_FREE, + &m); + buffer_free(&m); +} #endif /* SSH_AUDIT_EVENTS */ diff --git a/openssh-6.5p1/monitor_wrap.h b/openssh-6.5p1/monitor_wrap.h --- a/openssh-6.5p1/monitor_wrap.h +++ b/openssh-6.5p1/monitor_wrap.h @@ -75,16 +75,17 @@ void mm_sshpam_free_ctx(void *); #ifdef SSH_AUDIT_EVENTS #include "audit.h" void mm_audit_event(ssh_audit_event_t); int mm_audit_run_command(const char *); void mm_audit_end_command(int, const char *); void mm_audit_unsupported_body(int); void mm_audit_kex_body(int, char *, char *, char *, pid_t, uid_t); void mm_audit_session_key_free_body(int, pid_t, uid_t); +void mm_audit_destroy_sensitive_data(const char *, pid_t, uid_t); #endif struct Session; void mm_terminate(void); int mm_pty_allocate(int *, int *, char *, size_t); void mm_session_pty_cleanup2(struct Session *); /* SSHv1 interfaces */ diff --git a/openssh-6.5p1/session.c b/openssh-6.5p1/session.c --- a/openssh-6.5p1/session.c +++ b/openssh-6.5p1/session.c @@ -132,17 +132,17 @@ static int session_pty_req(Session *); /* import */ extern ServerOptions options; extern char *__progname; extern int log_stderr; extern int debug_flag; extern u_int utmp_len; extern int startup_pipe; -extern void destroy_sensitive_data(void); +extern void destroy_sensitive_data(int); extern Buffer loginmsg; /* original command from peer. */ const char *original_command = NULL; /* data */ static int sessions_first_unused = -1; static int sessions_nalloc = 0; @@ -1688,17 +1688,17 @@ do_child(Session *s, const char *command char **env; int env_size; char *argv[ARGV_MAX]; const char *shell, *shell0, *hostname = NULL; struct passwd *pw = s->pw; int r = 0; /* remove hostkey from the child's memory */ - destroy_sensitive_data(); + destroy_sensitive_data(1); /* Don't audit this - both us and the parent would be talking to the monitor over a single socket, with no synchronization. */ packet_destroy_all(0, 1); /* Force a password change */ if (s->authctxt->force_pwchange) { do_setusercontext(pw); child_close_fds(); diff --git a/openssh-6.5p1/sshd.c b/openssh-6.5p1/sshd.c --- a/openssh-6.5p1/sshd.c +++ b/openssh-6.5p1/sshd.c @@ -256,17 +256,17 @@ Buffer cfg; /* message to be displayed after login */ Buffer loginmsg; /* Unprivileged user */ struct passwd *privsep_pw = NULL; /* Prototypes for various functions defined later in this file. */ -void destroy_sensitive_data(void); +void destroy_sensitive_data(int); void demote_sensitive_data(void); static void do_ssh1_kex(void); static void do_ssh2_kex(void); /* * Close all listening sockets */ @@ -275,16 +275,25 @@ close_listen_socks(void) { int i; for (i = 0; i < num_listen_socks; i++) close(listen_socks[i]); num_listen_socks = -1; } +/* + * Is this process listening for clients (i.e. not specific to any specific + * client connection?) + */ +int listening_for_clients(void) +{ + return num_listen_socks > 0; +} + static void close_startup_pipes(void) { int i; if (startup_pipes) for (i = 0; i < options.max_startups; i++) if (startup_pipes[i] != -1) @@ -554,60 +563,99 @@ sshd_exchange_identification(int sock_in close(sock_out); logit("Protocol major versions differ for %s: %.200s vs. %.200s", get_remote_ipaddr(), server_version_string, client_version_string); cleanup_exit(255); } } -/* Destroy the host and server keys. They will no longer be needed. */ +/* + * Destroy the host and server keys. They will no longer be needed. Careful, + * this can be called from cleanup_exit() - i.e. from just about anywhere. + */ void -destroy_sensitive_data(void) +destroy_sensitive_data(int privsep) { int i; + pid_t pid; + uid_t uid; if (sensitive_data.server_key) { key_free(sensitive_data.server_key); sensitive_data.server_key = NULL; } + pid = getpid(); + uid = getuid(); for (i = 0; i < options.num_host_key_files; i++) { if (sensitive_data.host_keys[i]) { + char *fp; + + if (key_is_private(sensitive_data.host_keys[i])) + fp = key_fingerprint(sensitive_data.host_keys[i], + key_fp_type_select(), SSH_FP_HEX); + else + fp = NULL; key_free(sensitive_data.host_keys[i]); sensitive_data.host_keys[i] = NULL; + if (fp != NULL) { + if (privsep) + PRIVSEP(audit_destroy_sensitive_data(fp, + pid, uid)); + else + audit_destroy_sensitive_data(fp, + pid, uid); + free(fp); + } } - if (sensitive_data.host_certificates[i]) { + if (sensitive_data.host_certificates + && sensitive_data.host_certificates[i]) { key_free(sensitive_data.host_certificates[i]); sensitive_data.host_certificates[i] = NULL; } } sensitive_data.ssh1_host_key = NULL; memset(sensitive_data.ssh1_cookie, 0, SSH_SESSION_KEY_LENGTH); } /* Demote private to public keys for network child */ void demote_sensitive_data(void) { Key *tmp; + pid_t pid; + uid_t uid; int i; if (sensitive_data.server_key) { tmp = key_demote(sensitive_data.server_key); key_free(sensitive_data.server_key); sensitive_data.server_key = tmp; } + pid = getpid(); + uid = getuid(); for (i = 0; i < options.num_host_key_files; i++) { if (sensitive_data.host_keys[i]) { + char *fp; + + if (key_is_private(sensitive_data.host_keys[i])) + fp = key_fingerprint(sensitive_data.host_keys[i], + key_fp_type_select(), SSH_FP_HEX); + else + fp = NULL; tmp = key_demote(sensitive_data.host_keys[i]); key_free(sensitive_data.host_keys[i]); sensitive_data.host_keys[i] = tmp; if (tmp->type == KEY_RSA1) sensitive_data.ssh1_host_key = tmp; + if (fp != NULL) { + audit_destroy_sensitive_data(fp, pid, uid); + free(fp); + } } /* Certs do not need demotion */ } /* We do not clear ssh1_host key and cookie. XXX - Okay Niels? */ } static void @@ -1192,16 +1240,17 @@ server_accept_loop(int *sock_in, int *so /* Wait in select until there is a connection. */ ret = select(maxfd+1, fdset, NULL, NULL, NULL); if (ret < 0 && errno != EINTR) error("select: %.100s", strerror(errno)); if (received_sigterm) { logit("Received signal %d; terminating.", (int) received_sigterm); + destroy_sensitive_data(0); close_listen_socks(); unlink(options.pid_file); exit(received_sigterm == SIGTERM ? 0 : 255); } if (key_used && key_do_regen) { generate_ephemeral_server_key(); key_used = 0; key_do_regen = 0; @@ -2153,27 +2202,28 @@ main(int ac, char **av) /* * In privilege separation, we fork another child and prepare * file descriptor passing. */ if (use_privsep) { privsep_postauth(authctxt); /* the monitor process [priv] will not return */ if (!compat20) - destroy_sensitive_data(); + destroy_sensitive_data(0); } packet_set_timeout(options.client_alive_interval, options.client_alive_count_max); /* Start session. */ do_authenticated(authctxt); /* The connection has been terminated. */ packet_destroy_all(1, 1); + destroy_sensitive_data(1); packet_get_state(MODE_IN, NULL, NULL, NULL, &ibytes); packet_get_state(MODE_OUT, NULL, NULL, NULL, &obytes); verbose("Transferred: sent %llu, received %llu bytes", (unsigned long long)obytes, (unsigned long long)ibytes); verbose("Closing connection to %.500s port %d", remote_ip, remote_port); @@ -2392,17 +2442,17 @@ do_ssh1_kex(void) MD5_Update(&md, sensitive_data.ssh1_cookie, SSH_SESSION_KEY_LENGTH); MD5_Final(session_key + 16, &md); memset(buf, 0, bytes); free(buf); for (i = 0; i < 16; i++) session_id[i] = session_key[i] ^ session_key[i + 16]; } /* Destroy the private and public keys. No longer. */ - destroy_sensitive_data(); + destroy_sensitive_data(0); if (use_privsep) mm_ssh1_session_id(session_id); /* Destroy the decrypted integer. It is no longer needed. */ BN_clear_free(session_key_int); /* Set the session key. From this on all communications will be encrypted. */ @@ -2527,16 +2577,18 @@ cleanup_exit(int i) debug("Killing privsep child %d", pmonitor->m_pid); if (kill(pmonitor->m_pid, SIGKILL) != 0 && errno != ESRCH) error("%s: kill(%d): %s", __func__, pmonitor->m_pid, strerror(errno)); } } is_privsep_child = use_privsep && (pmonitor != NULL) && !mm_is_monitor(); + if (sensitive_data.host_keys != NULL) + destroy_sensitive_data(is_privsep_child); packet_destroy_all(1, is_privsep_child); #ifdef SSH_AUDIT_EVENTS /* done after do_cleanup so it can cancel the PAM auth 'thread' */ if ((the_authctxt == NULL || !the_authctxt->authenticated) && (!use_privsep || mm_is_monitor())) audit_event(SSH_CONNECTION_ABANDON); #endif _exit(i);