diff -up openssh-5.8p1/audit-bsm.c.audit5a openssh-5.8p1/audit-bsm.c --- openssh-5.8p1/audit-bsm.c.audit5a 2011-02-21 19:11:32.000000000 +0100 +++ openssh-5.8p1/audit-bsm.c 2011-02-21 19:11:32.000000000 +0100 @@ -407,4 +407,16 @@ audit_destroy_sensitive_data(const char { /* 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 -up openssh-5.8p1/audit.c.audit5a openssh-5.8p1/audit.c --- openssh-5.8p1/audit.c.audit5a 2011-02-21 19:11:32.000000000 +0100 +++ openssh-5.8p1/audit.c 2011-02-21 19:11:32.000000000 +0100 @@ -268,9 +268,19 @@ audit_session_key_free_body(int ctos, pi * This will be called on destroy private part of the server key */ void -audit_destroy_sensitive_data(const char *fp) +audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid) { - debug("audit destroy sensitive data euid %d fingerprint %s", geteuid(), fp); + 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 -up openssh-5.8p1/audit.h.audit5a openssh-5.8p1/audit.h --- openssh-5.8p1/audit.h.audit5a 2011-02-21 19:11:32.000000000 +0100 +++ openssh-5.8p1/audit.h 2011-02-21 19:11:32.000000000 +0100 @@ -48,6 +48,8 @@ enum ssh_audit_event_type { }; 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_session_open(struct logininfo *); @@ -62,6 +64,7 @@ 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 *); +void audit_destroy_sensitive_data(const char *, pid_t, uid_t); +void audit_generate_ephemeral_server_key(const char *); #endif /* _SSH_AUDIT_H */ diff -up openssh-5.8p1/audit-linux.c.audit5a openssh-5.8p1/audit-linux.c --- openssh-5.8p1/audit-linux.c.audit5a 2011-02-21 19:11:32.000000000 +0100 +++ openssh-5.8p1/audit-linux.c 2011-02-21 19:11:32.000000000 +0100 @@ -317,7 +317,9 @@ audit_session_key_free_body(int ctos, pi return; } audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, - buf, NULL, get_remote_ipaddr(), NULL, 1); + 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))) @@ -325,12 +327,13 @@ audit_session_key_free_body(int ctos, pi } void -audit_destroy_sensitive_data(const char *fp) +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=?", fp); + 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 && @@ -346,4 +349,25 @@ audit_destroy_sensitive_data(const char 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 -up openssh-5.8p1/key.c.audit5a openssh-5.8p1/key.c --- openssh-5.8p1/key.c.audit5a 2011-02-04 01:48:34.000000000 +0100 +++ openssh-5.8p1/key.c 2011-02-21 19:15:28.000000000 +0100 @@ -1769,6 +1769,30 @@ key_demote(const Key *k) } 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); + return 1; + } +} + +int key_is_cert(const Key *k) { if (k == NULL) diff -up openssh-5.8p1/key.h.audit5a openssh-5.8p1/key.h --- openssh-5.8p1/key.h.audit5a 2010-11-05 00:19:49.000000000 +0100 +++ openssh-5.8p1/key.h 2011-02-21 19:15:34.000000000 +0100 @@ -106,6 +106,7 @@ 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_plain(int); int key_to_certified(Key *, int); int key_drop_cert(Key *); diff -up openssh-5.8p1/monitor.c.audit5a openssh-5.8p1/monitor.c --- openssh-5.8p1/monitor.c.audit5a 2011-02-21 19:11:32.000000000 +0100 +++ openssh-5.8p1/monitor.c 2011-02-21 19:11:32.000000000 +0100 @@ -2291,10 +2291,14 @@ mm_answer_audit_server_key_free(int sock { 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); + audit_destroy_sensitive_data(fp, pid, uid); buffer_clear(m); diff -up openssh-5.8p1/monitor_wrap.c.audit5a openssh-5.8p1/monitor_wrap.c --- openssh-5.8p1/monitor_wrap.c.audit5a 2011-02-21 19:11:32.000000000 +0100 +++ openssh-5.8p1/monitor_wrap.c 2011-02-21 19:11:32.000000000 +0100 @@ -1466,12 +1466,14 @@ mm_audit_session_key_free_body(int ctos, } void -mm_audit_destroy_sensitive_data(const char *fp) +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, diff -up openssh-5.8p1/monitor_wrap.h.audit5a openssh-5.8p1/monitor_wrap.h --- openssh-5.8p1/monitor_wrap.h.audit5a 2011-02-21 19:11:32.000000000 +0100 +++ openssh-5.8p1/monitor_wrap.h 2011-02-21 19:11:32.000000000 +0100 @@ -77,7 +77,7 @@ void mm_audit_run_command(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 *); +void mm_audit_destroy_sensitive_data(const char *, pid_t, uid_t); #endif struct Session; diff -up openssh-5.8p1/sshd.c.audit5a openssh-5.8p1/sshd.c --- openssh-5.8p1/sshd.c.audit5a 2011-02-21 19:11:32.000000000 +0100 +++ openssh-5.8p1/sshd.c 2011-02-21 19:11:32.000000000 +0100 @@ -272,6 +272,15 @@ close_listen_socks(void) 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) { @@ -532,30 +541,47 @@ sshd_exchange_identification(int sock_in } } -/* 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(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; - fp = key_fingerprint(sensitive_data.host_keys[i], - FIPS_mode() ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX); + if (key_is_private(sensitive_data.host_keys[i])) + fp = key_fingerprint(sensitive_data.host_keys[i], + FIPS_mode() ? SSH_FP_SHA1 : SSH_FP_MD5, + SSH_FP_HEX); + else + fp = NULL; key_free(sensitive_data.host_keys[i]); sensitive_data.host_keys[i] = NULL; - if (privsep) - PRIVSEP(audit_destroy_sensitive_data(fp)); - else - audit_destroy_sensitive_data(fp); + if (fp != NULL) { + if (privsep) + PRIVSEP(audit_destroy_sensitive_data(fp, + pid, uid)); + else + audit_destroy_sensitive_data(fp, + pid, uid); + xfree(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; } @@ -569,6 +595,8 @@ void demote_sensitive_data(void) { Key *tmp; + pid_t pid; + uid_t uid; int i; if (sensitive_data.server_key) { @@ -577,19 +605,27 @@ demote_sensitive_data(void) 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; - fp = key_fingerprint(sensitive_data.host_keys[i], - FIPS_mode() ? SSH_FP_SHA1 : SSH_FP_MD5, SSH_FP_HEX); + if (key_is_private(sensitive_data.host_keys[i])) + fp = key_fingerprint(sensitive_data.host_keys[i], + FIPS_mode() ? SSH_FP_SHA1 : SSH_FP_MD5, + 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; - audit_destroy_sensitive_data(fp); - xfree(fp); + if (fp != NULL) { + audit_destroy_sensitive_data(fp, pid, uid); + xfree(fp); + } } /* Certs do not need demotion */ } @@ -1134,6 +1170,7 @@ server_accept_loop(int *sock_in, int *so if (received_sigterm) { logit("Received signal %d; terminating.", (int) received_sigterm); + destroy_sensitive_data(0); close_listen_socks(); unlink(options.pid_file); exit(255); @@ -2370,6 +2407,9 @@ cleanup_exit(int i) { if (the_authctxt) do_cleanup(the_authctxt); + if (sensitive_data.host_keys != NULL) + destroy_sensitive_data(use_privsep && pmonitor != NULL && + !mm_is_monitor()); #ifdef SSH_AUDIT_EVENTS /* done after do_cleanup so it can cancel the PAM auth 'thread' */ if (!use_privsep || mm_is_monitor())