# HG changeset patch
# Parent  698436ecccdffa303728550c187e50a49852e175
# key exhange auditing
# based on:
#   https://bugzilla.mindrot.org/show_bug.cgi?id=1402
#   https://bugzilla.mindrot.org/attachment.cgi?id=2013
#   (replaces: https://bugzilla.mindrot.org/attachment.cgi?id=1976)
#   by jchadima@redhat.com

diff --git a/openssh-6.6p1/audit-bsm.c b/openssh-6.6p1/audit-bsm.c
--- a/openssh-6.6p1/audit-bsm.c
+++ b/openssh-6.6p1/audit-bsm.c
@@ -468,9 +468,21 @@ audit_event(ssh_audit_event_t event)
 	case SSH_AUTH_FAIL_KBDINT:
 		bsm_audit_bad_login("interactive password entry");
 		break;
 
 	default:
 		debug("%s: unhandled event %d", __func__, event);
 	}
 }
+
+void
+audit_unsupported_body(int what)
+{
+	/* not implemented */
+}
+
+void
+audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid, uid_t uid)
+{
+	/* not implemented */
+}
 #endif /* BSM */
diff --git a/openssh-6.6p1/audit-linux.c b/openssh-6.6p1/audit-linux.c
--- a/openssh-6.6p1/audit-linux.c
+++ b/openssh-6.6p1/audit-linux.c
@@ -35,16 +35,18 @@
 
 #include "log.h"
 #include "audit.h"
 #include "key.h"
 #include "hostfile.h"
 #include "auth.h"
 #include "servconf.h"
 #include "canohost.h"
+#include "packet.h"
+#include "cipher.h"
 
 #define AUDIT_LOG_SIZE 128
 
 extern ServerOptions options;
 extern Authctxt *the_authctxt;
 extern u_int utmp_len;
 const char* audit_username(void);
 
@@ -264,9 +266,65 @@ audit_event(ssh_audit_event_t event)
 			get_remote_ipaddr(), "ssh", 0, AUDIT_USER_LOGIN);
 		break;
 
 	default:
 		debug("%s: unhandled event %d", __func__, event);
 	}
 }
 
+void
+audit_unsupported_body(int what)
+{
+#ifdef AUDIT_CRYPTO_SESSION
+	char buf[AUDIT_LOG_SIZE];
+	const static char *name[] = { "cipher", "mac", "comp" };
+	char *s;
+	int audit_fd;
+
+	snprintf(buf, sizeof(buf), "op=unsupported-%s direction=? cipher=? ksize=? rport=%d laddr=%s lport=%d ",
+		name[what], get_remote_port(), (s = get_local_ipaddr(packet_get_connection_in())),
+		get_local_port());
+	free(s);
+	audit_fd = audit_open();
+	if (audit_fd < 0)
+		/* no problem, the next instruction will be fatal() */
+		return;
+	audit_log_user_message(audit_fd, AUDIT_CRYPTO_SESSION,
+			buf, NULL, get_remote_ipaddr(), NULL, 0);
+	audit_close(audit_fd);
+#endif
+}
+
+void
+audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid,
+	       uid_t uid)
+{
+#ifdef AUDIT_CRYPTO_SESSION
+	char buf[AUDIT_LOG_SIZE];
+	int audit_fd, audit_ok;
+	const static char *direction[] = { "from-server", "from-client", "both" };
+	Cipher *cipher = cipher_by_name(enc);
+	char *s;
+
+	snprintf(buf, sizeof(buf), "op=start direction=%s cipher=%s ksize=%d spid=%jd suid=%jd rport=%d laddr=%s lport=%d ",
+		direction[ctos], enc, cipher ? 8 * cipher->key_len : 0,
+		(intmax_t)pid, (intmax_t)uid,
+		get_remote_port(), (s = get_local_ipaddr(packet_get_connection_in())), get_local_port());
+	free(s);
+	audit_fd = audit_open();
+	if (audit_fd < 0) {
+		if (errno == EINVAL || errno == EPROTONOSUPPORT ||
+					 errno == EAFNOSUPPORT)
+			return; /* No audit support in kernel */
+		else                                                                                                                                       
+			fatal("cannot open audit"); /* Must prevent login */
+	}
+	audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_SESSION,
+			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)))
+		fatal("cannot write into audit"); /* Must prevent login */
+#endif
+}
+
 #endif /* USE_LINUX_AUDIT */
diff --git a/openssh-6.6p1/audit.c b/openssh-6.6p1/audit.c
--- a/openssh-6.6p1/audit.c
+++ b/openssh-6.6p1/audit.c
@@ -23,24 +23,27 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include "includes.h"
 
 #include <stdarg.h>
 #include <string.h>
+#include <unistd.h>
 
 #ifdef SSH_AUDIT_EVENTS
 
 #include "audit.h"
 #include "log.h"
 #include "key.h"
 #include "hostfile.h"
 #include "auth.h"
+#include "ssh-gss.h"
+#include "monitor_wrap.h"
 #include "xmalloc.h"
 
 /*
  * Care must be taken when using this since it WILL NOT be initialized when
  * audit_connection_from() is called and MAY NOT be initialized when
  * audit_event(CONNECTION_ABANDON) is called.  Test for NULL before using.
  */
 extern Authctxt *the_authctxt;
@@ -123,16 +126,28 @@ audit_key(int host_user, int *rv, const 
 		crypto_name = "ssh-rsa1";
 	else
 		crypto_name = key_ssh_name(key);
 	if (audit_keyusage(host_user, crypto_name, key_size(key), fp, *rv) == 0)
 		*rv = 0;
 	free(fp);
 }
 
+void
+audit_unsupported(int what)
+{
+	PRIVSEP(audit_unsupported_body(what));
+}
+
+void
+audit_kex(int ctos, char *enc, char *mac, char *comp)
+{
+	PRIVSEP(audit_kex_body(ctos, enc, mac, comp, getpid(), getuid()));
+}
+
 # ifndef CUSTOM_SSH_AUDIT_EVENTS
 /*
  * Null implementations of audit functions.
  * These get used if SSH_AUDIT_EVENTS is defined but no audit module is enabled.
  */
 
 /*
  * Called after a connection has been accepted but before any authentication
@@ -233,10 +248,31 @@ audit_end_command(int handle, const char
  */
 int
 audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv)
 {
 	debug("audit %s key usage euid %d user %s key type %s key length %d fingerprint %s, result %d", 
 		host_user ? "pubkey" : "hostbased", geteuid(), audit_username(), type, bits,
 		fp, rv);
 }
+
+/*
+ * This will be called when the protocol negotiation fails.
+ */
+void
+audit_unsupported_body(int what)
+{
+	debug("audit unsupported protocol euid %d type %d", geteuid(), what);
+}
+
+/*
+ * This will be called on succesfull protocol negotiation.
+ */
+void
+audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid,
+	       uid_t uid)
+{
+	debug("audit protocol negotiation euid %d direction %d cipher %s mac %s compresion %s from pid %ld uid %u",
+		(unsigned)geteuid(), ctos, enc, mac, compress, (long)pid,
+	        (unsigned)uid);
+}
 # endif  /* !defined CUSTOM_SSH_AUDIT_EVENTS */
 #endif /* SSH_AUDIT_EVENTS */
diff --git a/openssh-6.6p1/audit.h b/openssh-6.6p1/audit.h
--- a/openssh-6.6p1/audit.h
+++ b/openssh-6.6p1/audit.h
@@ -53,10 +53,14 @@ 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);
 
 #endif /* _SSH_AUDIT_H */
diff --git a/openssh-6.6p1/auditstub.c b/openssh-6.6p1/auditstub.c
new file mode 100644
--- /dev/null
+++ b/openssh-6.6p1/auditstub.c
@@ -0,0 +1,39 @@
+/* $Id: auditstub.c,v 1.1 jfch Exp $ */
+
+/*
+ * Copyright 2010 Red Hat, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Red Hat author: Jan F. Chadima <jchadima@redhat.com>
+ */
+
+void
+audit_unsupported(int n)
+{
+}
+
+void
+audit_kex(int ctos, char *enc, char *mac, char *comp)
+{
+}
+
diff --git a/openssh-6.6p1/cipher.h b/openssh-6.6p1/cipher.h
--- a/openssh-6.6p1/cipher.h
+++ b/openssh-6.6p1/cipher.h
@@ -58,17 +58,30 @@
 #define SSH_CIPHER_MAX		31
 
 #define CIPHER_ENCRYPT		1
 #define CIPHER_DECRYPT		0
 
 typedef struct Cipher Cipher;
 typedef struct CipherContext CipherContext;
 
-struct Cipher;
+struct Cipher {
+	char	*name;
+	int	number;		/* for ssh1 only */
+	u_int	block_size;
+	u_int	key_len;
+	u_int	iv_len;		/* defaults to block_size */
+	u_int	auth_len;
+	u_int	discard_len;
+	u_int	flags;
+#define CFLAG_CBC		(1<<0)
+#define CFLAG_CHACHAPOLY	(1<<1)
+	const EVP_CIPHER	*(*evptype)(void);
+};
+
 struct CipherContext {
 	int	plaintext;
 	int	encrypt;
 	EVP_CIPHER_CTX evp;
 	struct chachapoly_ctx cp_ctx; /* XXX union with evp? */
 	const Cipher *cipher;
 };
 
diff --git a/openssh-6.6p1/kex.c b/openssh-6.6p1/kex.c
--- a/openssh-6.6p1/kex.c
+++ b/openssh-6.6p1/kex.c
@@ -45,16 +45,17 @@
 #include "kex.h"
 #include "log.h"
 #include "mac.h"
 #include "match.h"
 #include "dispatch.h"
 #include "monitor.h"
 #include "roaming.h"
 #include "digest.h"
+#include "audit.h"
 
 #include "fips.h"
 
 #if OPENSSL_VERSION_NUMBER >= 0x00907000L
 # if defined(HAVE_EVP_SHA256)
 # define evp_ssh_sha256 EVP_sha256
 # else
 extern const EVP_MD *evp_ssh_sha256(void);
@@ -384,53 +385,65 @@ kex_kexinit_finish(Kex *kex)
 		fatal("Unsupported key exchange %d", kex->kex_type);
 	}
 }
 
 static void
 choose_enc(Enc *enc, char *client, char *server)
 {
 	char *name = match_list(client, server, NULL);
-	if (name == NULL)
+	if (name == NULL) {
+#ifdef SSH_AUDIT_EVENTS
+		audit_unsupported(0);
+#endif
 		fatal("no matching cipher found: client %s server %s",
 		    client, server);
+	}
 	if ((enc->cipher = cipher_by_name(name)) == NULL)
 		fatal("matching cipher is not supported: %s", name);
 	enc->name = name;
 	enc->enabled = 0;
 	enc->iv = NULL;
 	enc->iv_len = cipher_ivlen(enc->cipher);
 	enc->key = NULL;
 	enc->key_len = cipher_keylen(enc->cipher);
 	enc->block_size = cipher_blocksize(enc->cipher);
 }
 
 static void
 choose_mac(Mac *mac, char *client, char *server)
 {
 	char *name = match_list(client, server, NULL);
-	if (name == NULL)
+	if (name == NULL) {
+#ifdef SSH_AUDIT_EVENTS
+		audit_unsupported(1);
+#endif
 		fatal("no matching mac found: client %s server %s",
 		    client, server);
+	}
 	if (mac_setup(mac, name) < 0)
 		fatal("unsupported mac %s", name);
 	/* truncate the key */
 	if (datafellows & SSH_BUG_HMAC)
 		mac->key_len = 16;
 	mac->name = name;
 	mac->key = NULL;
 	mac->enabled = 0;
 }
 
 static void
 choose_comp(Comp *comp, char *client, char *server)
 {
 	char *name = match_list(client, server, NULL);
-	if (name == NULL)
+	if (name == NULL) {
+#ifdef SSH_AUDIT_EVENTS
+		audit_unsupported(2);
+#endif
 		fatal("no matching comp found: client %s server %s", client, server);
+	}
 	if (strcmp(name, "zlib@openssh.com") == 0) {
 		comp->type = COMP_DELAYED;
 	} else if (strcmp(name, "zlib") == 0) {
 		comp->type = COMP_ZLIB;
 	} else if (strcmp(name, "none") == 0) {
 		comp->type = COMP_NONE;
 	} else {
 		fatal("unsupported comp %s", name);
@@ -535,16 +548,19 @@ kex_choose_conf(Kex *kex)
 		if (authlen == 0)
 			choose_mac(&newkeys->mac, cprop[nmac], sprop[nmac]);
 		choose_comp(&newkeys->comp, cprop[ncomp], sprop[ncomp]);
 		debug("kex: %s %s %s %s",
 		    ctos ? "client->server" : "server->client",
 		    newkeys->enc.name,
 		    authlen == 0 ? newkeys->mac.name : "<implicit>",
 		    newkeys->comp.name);
+#ifdef SSH_AUDIT_EVENTS
+		audit_kex(ctos, newkeys->enc.name, newkeys->mac.name, newkeys->comp.name);
+#endif
 	}
 	choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
 	choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
 	    sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
 	need = dh_need = 0;
 	for (mode = 0; mode < MODE_MAX; mode++) {
 		newkeys = kex->newkeys[mode];
 		need = MAX(need, newkeys->enc.key_len);
diff --git a/openssh-6.6p1/monitor.c b/openssh-6.6p1/monitor.c
--- a/openssh-6.6p1/monitor.c
+++ b/openssh-6.6p1/monitor.c
@@ -92,16 +92,17 @@
 #endif
 #include "monitor_wrap.h"
 #include "monitor_fdpass.h"
 #include "misc.h"
 #include "compat.h"
 #include "ssh2.h"
 #include "roaming.h"
 #include "authfd.h"
+#include "audit.h"
 
 #ifdef GSSAPI
 static Gssctxt *gsscontext = NULL;
 #endif
 
 /* Imports */
 extern ServerOptions options;
 extern u_int utmp_len;
@@ -176,16 +177,18 @@ int mm_answer_gss_accept_ctx(int, Buffer
 int mm_answer_gss_userok(int, Buffer *);
 int mm_answer_gss_checkmic(int, Buffer *);
 #endif
 
 #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 *);
 #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 */
@@ -227,16 +230,18 @@ struct mon_table mon_dispatch_proto20[] 
     {MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account},
     {MONITOR_REQ_PAM_INIT_CTX, MON_ISAUTH, mm_answer_pam_init_ctx},
     {MONITOR_REQ_PAM_QUERY, MON_ISAUTH, mm_answer_pam_query},
     {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},
 #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},
@@ -257,16 +262,18 @@ struct mon_table mon_dispatch_postauth20
     {MONITOR_REQ_SIGN, 0, mm_answer_sign},
     {MONITOR_REQ_PTY, 0, mm_answer_pty},
     {MONITOR_REQ_PTYCLEANUP, 0, 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, 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},
 #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},
@@ -288,28 +295,32 @@ struct mon_table mon_dispatch_proto15[] 
     {MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account},
     {MONITOR_REQ_PAM_INIT_CTX, MON_ISAUTH, mm_answer_pam_init_ctx},
     {MONITOR_REQ_PAM_QUERY, MON_ISAUTH, mm_answer_pam_query},
     {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},
 #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},
 #endif
     {0, 0, NULL}
 };
 
 struct mon_table *mon_dispatch;
 
 /* Specifies if a certain message is allowed at the moment */
 
@@ -2187,8 +2198,52 @@ mm_answer_gss_userok(int sock, Buffer *m
 
 	auth_method = "gssapi-with-mic";
 
 	/* Monitor loop will terminate if authenticated */
 	return (authenticated);
 }
 #endif /* GSSAPI */
 
+#ifdef SSH_AUDIT_EVENTS
+int
+mm_answer_audit_unsupported_body(int sock, Buffer *m)
+{
+	int what;
+
+	what = buffer_get_int(m);
+
+	audit_unsupported_body(what);
+
+	buffer_clear(m);
+
+	mm_request_send(sock, MONITOR_ANS_AUDIT_UNSUPPORTED, m);
+	return 0;
+}
+
+int
+mm_answer_audit_kex_body(int sock, Buffer *m)
+{
+	int ctos, len;
+	char *cipher, *mac, *compress;
+	pid_t pid;
+	uid_t uid;
+
+	ctos = buffer_get_int(m);
+	cipher = buffer_get_string(m, &len);
+	mac = buffer_get_string(m, &len);
+	compress = buffer_get_string(m, &len);
+	pid = buffer_get_int64(m);
+	uid = buffer_get_int64(m);
+
+	audit_kex_body(ctos, cipher, mac, compress, pid, uid);
+
+	free(cipher);
+	free(mac);
+	free(compress);
+	buffer_clear(m);
+
+	mm_request_send(sock, MONITOR_ANS_AUDIT_KEX, m);
+	return 0;
+}
+
+#endif /* SSH_AUDIT_EVENTS */
+
diff --git a/openssh-6.6p1/monitor.h b/openssh-6.6p1/monitor.h
--- a/openssh-6.6p1/monitor.h
+++ b/openssh-6.6p1/monitor.h
@@ -60,16 +60,18 @@ enum monitor_reqtype {
 	MONITOR_REQ_PAM_START = 100,
 	MONITOR_REQ_PAM_ACCOUNT = 102, MONITOR_ANS_PAM_ACCOUNT = 103,
 	MONITOR_REQ_PAM_INIT_CTX = 104, MONITOR_ANS_PAM_INIT_CTX = 105,
 	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,
 
 };
 
 struct mm_master;
 struct monitor {
 	int			 m_recvfd;
 	int			 m_sendfd;
 	int			 m_log_recvfd;
diff --git a/openssh-6.6p1/monitor_wrap.c b/openssh-6.6p1/monitor_wrap.c
--- a/openssh-6.6p1/monitor_wrap.c
+++ b/openssh-6.6p1/monitor_wrap.c
@@ -1320,8 +1320,46 @@ mm_ssh_gssapi_userok(char *user)
 	authenticated = buffer_get_int(&m);
 
 	buffer_free(&m);
 	debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not ");
 	return (authenticated);
 }
 #endif /* GSSAPI */
 
+#ifdef SSH_AUDIT_EVENTS
+void
+mm_audit_unsupported_body(int what)
+{
+	Buffer m;
+
+	buffer_init(&m);
+	buffer_put_int(&m, what);
+
+	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_UNSUPPORTED, &m);
+	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_UNSUPPORTED,
+				  &m);
+
+	buffer_free(&m);
+}
+
+void
+mm_audit_kex_body(int ctos, char *cipher, char *mac, char *compress, pid_t pid,
+		  uid_t uid)
+{
+	Buffer m;
+
+	buffer_init(&m);
+	buffer_put_int(&m, ctos);
+	buffer_put_cstring(&m, cipher ? cipher : "");
+	buffer_put_cstring(&m, mac ? mac : "");
+	buffer_put_cstring(&m, compress ? compress : "");
+	buffer_put_int64(&m, pid);
+	buffer_put_int64(&m, uid);
+
+	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_KEX, &m);
+	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_KEX,
+				  &m);
+
+	buffer_free(&m);
+}
+#endif /* SSH_AUDIT_EVENTS */
+
diff --git a/openssh-6.6p1/monitor_wrap.h b/openssh-6.6p1/monitor_wrap.h
--- a/openssh-6.6p1/monitor_wrap.h
+++ b/openssh-6.6p1/monitor_wrap.h
@@ -72,16 +72,18 @@ int mm_sshpam_respond(void *, u_int, cha
 void mm_sshpam_free_ctx(void *);
 #endif
 
 #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);
 #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.6p1/sshd.c b/openssh-6.6p1/sshd.c
--- a/openssh-6.6p1/sshd.c
+++ b/openssh-6.6p1/sshd.c
@@ -2328,16 +2328,20 @@ do_ssh1_kex(void)
 		packet_disconnect("Warning: client selects unsupported cipher.");
 
 	/* Get check bytes from the packet.  These must match those we
 	   sent earlier with the public key packet. */
 	for (i = 0; i < 8; i++)
 		if (cookie[i] != packet_get_char())
 			packet_disconnect("IP Spoofing check bytes do not match.");
 
+#ifdef SSH_AUDIT_EVENTS
+	audit_kex(2, cipher_name(cipher_type), "crc", "none");
+#endif
+
 	debug("Encryption type: %.200s", cipher_name(cipher_type));
 
 	/* Get the encrypted integer. */
 	if ((session_key_int = BN_new()) == NULL)
 		fatal("do_ssh1_kex: BN_new failed");
 	packet_get_bignum(session_key_int);
 
 	protocol_flags = packet_get_int();
