From a9e1c50bb09a110d4774e6710f9322344684fa2d Mon Sep 17 00:00:00 2001
From: Ben Laurie <ben@openssl.org>
Date: Wed, 30 May 2012 10:10:58 +0000
Subject: [PATCH] RFC 5878 support.

---
 CHANGES         |   3 +
 apps/s_apps.h   |   4 +
 apps/s_cb.c     |  26 +++---
 apps/s_client.c |  30 +++++++
 apps/s_server.c |  51 +++++++++++-
 ssl/s23_clnt.c  |   2 +
 ssl/s3_clnt.c   | 140 ++++++++++++++++++++++++++++++++-
 ssl/s3_lib.c    |  11 +++
 ssl/s3_srvr.c   | 116 ++++++++++++++++++++++++++-
 ssl/ssl.h       |  39 ++++++++-
 ssl/ssl3.h      |  22 +++++-
 ssl/ssl_cert.c  |  20 +++++
 ssl/ssl_err.c   |  12 +++
 ssl/ssl_lib.c   |  79 +++++++++++++------
 ssl/ssl_locl.h  |  15 ++++
 ssl/ssl_rsa.c   | 120 ++++++++++++++++++++++++++--
 ssl/ssl_sess.c  |  11 +++
 ssl/t1_lib.c    | 205 +++++++++++++++++++++++++++++++++++++++++++++++-
 ssl/tls1.h      |  15 ++++
 19 files changed, 864 insertions(+), 57 deletions(-)

diff --git a/CHANGES b/CHANGES
index 7cca7f00a7..ec9291002b 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,9 @@
 
  Changes between 1.0.1 and 1.1.0  [xx XXX xxxx]
 
+  *) RFC 5878 support.
+     [Emilia Kasper, Adam Langley, Ben Laurie (Google)]
+
   *) Support for automatic EC temporary key parameter selection. If enabled
      the most preferred EC parameters are automatically used instead of
      hardcoded fixed parameters. Now a server just has to call:
diff --git a/apps/s_apps.h b/apps/s_apps.h
index 5de65329a9..4effcd21d7 100644
--- a/apps/s_apps.h
+++ b/apps/s_apps.h
@@ -156,6 +156,10 @@ int MS_CALLBACK verify_callback(int ok, X509_STORE_CTX *ctx);
 int set_cert_stuff(SSL_CTX *ctx, char *cert_file, char *key_file);
 int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key,
 							STACK_OF(X509) *chain);
+# ifndef OPENSSL_NO_TLSEXT
+int set_cert_key_and_authz(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key,
+                           unsigned char *authz, size_t authz_length);
+# endif
 int ssl_print_sigalgs(BIO *out, SSL *s);
 int ssl_print_curves(BIO *out, SSL *s);
 #endif
diff --git a/apps/s_cb.c b/apps/s_cb.c
index b21a4283df..c07066b6b6 100644
--- a/apps/s_cb.c
+++ b/apps/s_cb.c
@@ -237,8 +237,8 @@ int set_cert_stuff(SSL_CTX *ctx, char *cert_file, char *key_file)
 
 		/* If we are using DSA, we can copy the parameters from
 		 * the private key */
-		
-		
+
+
 		/* Now we know that a key and cert have been set against
 		 * the SSL context */
 		if (!SSL_CTX_check_private_key(ctx))
@@ -251,9 +251,9 @@ int set_cert_stuff(SSL_CTX *ctx, char *cert_file, char *key_file)
 	}
 
 int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key,
-							STACK_OF(X509) *chain)
+		       STACK_OF(X509) *chain)
 	{
-	if (cert ==  NULL)
+	if (cert == NULL)
 		return 1;
 	if (SSL_CTX_use_certificate(ctx,cert) <= 0)
 		{
@@ -261,16 +261,16 @@ int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key,
 		ERR_print_errors(bio_err);
 		return 0;
 		}
-	if (SSL_CTX_use_PrivateKey(ctx,key) <= 0)
-		{
-		BIO_printf(bio_err,"error setting private key\n");
-		ERR_print_errors(bio_err);
-		return 0;
-		}
 
-		
-		/* Now we know that a key and cert have been set against
-		 * the SSL context */
+ 	if (SSL_CTX_use_PrivateKey(ctx,key) <= 0)
+ 		{
+ 		BIO_printf(bio_err,"error setting private key\n");
+ 		ERR_print_errors(bio_err);
+ 		return 0;
+ 		}
+		 
+	/* Now we know that a key and cert have been set against
+ 	 * the SSL context */
 	if (!SSL_CTX_check_private_key(ctx))
 		{
 		BIO_printf(bio_err,"Private key does not match the certificate public key\n");
diff --git a/apps/s_client.c b/apps/s_client.c
index 16f1ac37db..8cbb46e540 100644
--- a/apps/s_client.c
+++ b/apps/s_client.c
@@ -202,6 +202,7 @@ static int c_debug=0;
 #ifndef OPENSSL_NO_TLSEXT
 static int c_tlsextdebug=0;
 static int c_status_req=0;
+static int c_proof_debug=0;
 #endif
 static int c_msg=0;
 static int c_showcerts=0;
@@ -213,6 +214,7 @@ static void sc_usage(void);
 static void print_stuff(BIO *berr,SSL *con,int full);
 #ifndef OPENSSL_NO_TLSEXT
 static int ocsp_resp_cb(SSL *s, void *arg);
+static int audit_proof_cb(SSL *s, void *arg);
 #endif
 static BIO *bio_c_out=NULL;
 static int c_quiet=0;
@@ -357,6 +359,7 @@ static void sc_usage(void)
 	BIO_printf(bio_err," -tlsextdebug      - hex dump of all TLS extensions received\n");
 	BIO_printf(bio_err," -status           - request certificate status from server\n");
 	BIO_printf(bio_err," -no_ticket        - disable use of RFC4507bis session tickets\n");
+	BIO_printf(bio_err," -proof_debug      - request an audit proof and print its hex dump\n");
 # ifndef OPENSSL_NO_NEXTPROTONEG
 	BIO_printf(bio_err," -nextprotoneg arg - enable NPN extension, considering named protocols supported (comma-separated list)\n");
 # endif
@@ -731,6 +734,8 @@ int MAIN(int argc, char **argv)
 			c_tlsextdebug=1;
 		else if	(strcmp(*argv,"-status") == 0)
 			c_status_req=1;
+		else if	(strcmp(*argv,"-proof_debug") == 0)
+			c_proof_debug=1;
 #endif
 #ifdef WATT32
 		else if (strcmp(*argv,"-wdebug") == 0)
@@ -1212,6 +1217,9 @@ bad:
 		}
 
 #endif
+	if (c_proof_debug)
+		SSL_CTX_set_tlsext_authz_server_audit_proof_cb(ctx,
+							       audit_proof_cb);
 #endif
 
 	con=SSL_new(ctx);
@@ -2147,4 +2155,26 @@ static int ocsp_resp_cb(SSL *s, void *arg)
 	return 1;
 	}
 
+static int audit_proof_cb(SSL *s, void *arg)
+	{
+	const unsigned char *proof;
+	size_t proof_len;
+	size_t i;
+	SSL_SESSION *sess = SSL_get_session(s);
+
+	proof = SSL_SESSION_get_tlsext_authz_server_audit_proof(sess,
+								&proof_len);
+	if (proof != NULL)
+		{
+		BIO_printf(bio_c_out, "Audit proof: ");
+		for (i = 0; i < proof_len; ++i)
+			BIO_printf(bio_c_out, "%02X", proof[i]);
+		BIO_printf(bio_c_out, "\n");
+		}
+	else
+		{
+		BIO_printf(bio_c_out, "No audit proof found.\n");
+		}
+	return 1;
+	}
 #endif
diff --git a/apps/s_server.c b/apps/s_server.c
index bb791e08e7..762757bf00 100644
--- a/apps/s_server.c
+++ b/apps/s_server.c
@@ -313,6 +313,12 @@ static long socket_mtu;
 static int cert_chain = 0;
 #endif
 
+#ifndef OPENSSL_NO_TLSEXT
+static BIO *authz_in = NULL;
+static const char *s_authz_file = NULL;
+static unsigned char *authz = NULL;
+static size_t authz_length;
+#endif
 
 #ifndef OPENSSL_NO_PSK
 static char *psk_identity="Client_identity";
@@ -473,6 +479,7 @@ static void sv_usage(void)
 	BIO_printf(bio_err," -Verify arg   - turn on peer certificate verification, must have a cert.\n");
 	BIO_printf(bio_err," -cert arg     - certificate file to use\n");
 	BIO_printf(bio_err,"                 (default is %s)\n",TEST_CERT);
+	BIO_printf(bio_err," -authz arg   -  binary authz file for certificate\n");
 	BIO_printf(bio_err," -crl_check    - check the peer certificate has not been revoked by its CA.\n" \
 	                   "                 The CRL(s) are appended to the certificate file\n");
 	BIO_printf(bio_err," -crl_check_all - check the peer certificate has not been revoked by its CA\n" \
@@ -1044,6 +1051,13 @@ int MAIN(int argc, char *argv[])
 			if (--argc < 1) goto bad;
 			s_cert_file= *(++argv);
 			}
+#ifndef OPENSSL_NO_TLSEXT
+		else if	(strcmp(*argv,"-authz") == 0)
+			{
+			if (--argc < 1) goto bad;
+			s_authz_file = *(++argv);
+			}
+#endif
 		else if	(strcmp(*argv,"-certform") == 0)
 			{
 			if (--argc < 1) goto bad;
@@ -1490,7 +1504,34 @@ bad:
 			next_proto.data = NULL;
 			}
 # endif
-#endif
+		if (s_authz_file != NULL)
+			{
+			/* Allow authzs up to 64KB bytes. */
+			static const size_t authz_limit = 65536;
+
+			authz_in = BIO_new(BIO_s_file_internal());
+			if (authz_in == NULL)
+				{
+				ERR_print_errors(bio_err);
+				goto end;
+				}
+
+			if (BIO_read_filename(authz_in, s_authz_file) <= 0)
+				{
+				ERR_print_errors(bio_err);
+				goto end;
+				}
+			authz = OPENSSL_malloc(authz_limit);
+			authz_length = BIO_read(authz_in, authz, authz_limit);
+			if (authz_length == authz_limit || authz_length <= 0)
+				{
+				BIO_printf(bio_err, "authz too large\n");
+				goto end;
+				}
+			BIO_free(authz_in);
+			authz_in = NULL;
+			}
+#endif /* OPENSSL_NO_TLSEXT */
 		}
 
 
@@ -1789,6 +1830,10 @@ bad:
 	
 	if (!set_cert_key_stuff(ctx, s_cert, s_key, s_chain))
 		goto end;
+#ifndef OPENSSL_NO_TLSEXT
+	if (authz != NULL && !SSL_CTX_use_authz(ctx, authz, authz_length))
+		goto end;
+#endif
 #ifndef OPENSSL_NO_TLSEXT
 	if (ctx2 && !set_cert_key_stuff(ctx2,s_cert2,s_key2, NULL))
 		goto end; 
@@ -1983,6 +2028,10 @@ end:
 		X509_free(s_cert2);
 	if (s_key2)
 		EVP_PKEY_free(s_key2);
+	if (authz != NULL)
+		OPENSSL_free(authz);
+	if (authz_in != NULL)
+		BIO_free(authz_in);
 #endif
 	if (bio_s_out != NULL)
 		{
diff --git a/ssl/s23_clnt.c b/ssl/s23_clnt.c
index 47673e740a..807dd0ba26 100644
--- a/ssl/s23_clnt.c
+++ b/ssl/s23_clnt.c
@@ -340,6 +340,8 @@ static int ssl23_client_hello(SSL *s)
 		if (s->ctx->tlsext_opaque_prf_input_callback != 0 || s->tlsext_opaque_prf_input != NULL)
 			ssl2_compat = 0;
 #endif
+                if (s->ctx->tlsext_authz_server_audit_proof_cb != NULL)
+			ssl2_compat = 0;
 		}
 #endif
 
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index cd4f0ad468..e8fe968e59 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -307,10 +307,27 @@ int ssl3_connect(SSL *s)
 #endif
 				}
 			else
-				s->state=SSL3_ST_CR_CERT_A;
+				{
+#ifndef OPENSSL_NO_TLSEXT
+				/* The server hello indicated that
+				 * an audit proof would follow. */
+				if (s->s3->tlsext_authz_server_promised)
+					s->state=SSL3_ST_CR_SUPPLEMENTAL_DATA_A;
+				else
+#endif
+					s->state=SSL3_ST_CR_CERT_A;
+				}
 			s->init_num=0;
 			break;
-
+#ifndef OPENSSL_NO_TLSEXT
+		case SSL3_ST_CR_SUPPLEMENTAL_DATA_A:
+		case SSL3_ST_CR_SUPPLEMENTAL_DATA_B:
+			ret = tls1_get_server_supplemental_data(s);
+			if (ret <= 0) goto end;
+			s->state=SSL3_ST_CR_CERT_A;
+			s->init_num = 0;
+			break;
+#endif
 		case SSL3_ST_CR_CERT_A:
 		case SSL3_ST_CR_CERT_B:
 #ifndef OPENSSL_NO_TLSEXT
@@ -1231,8 +1248,22 @@ int ssl3_get_server_certificate(SSL *s)
 	s->session->verify_result = s->verify_result;
 
 	x=NULL;
-	ret=1;
+#ifndef OPENSSL_NO_TLSEXT
+	/* Check the audit proof. */
+	if (s->ctx->tlsext_authz_server_audit_proof_cb)
+		{
+		ret = s->ctx->tlsext_authz_server_audit_proof_cb(s,
+			s->ctx->tlsext_authz_server_audit_proof_cb_arg);
+		if (ret <= 0)
+			{
+			al = SSL_AD_BAD_CERTIFICATE;
+			SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,SSL_R_INVALID_AUDIT_PROOF);
+			goto f_err;
+			}
+		}
 
+#endif
+	ret=1;
 	if (0)
 		{
 f_err:
@@ -3432,3 +3463,106 @@ int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey)
 		i = s->ctx->client_cert_cb(s,px509,ppkey);
 	return i;
 	}
+
+#ifndef OPENSSL_NO_TLSEXT
+int tls1_get_server_supplemental_data(SSL *s)
+	{
+	int al;
+	int ok;
+	unsigned long supp_data_len, authz_data_len;
+	long n;
+	unsigned short supp_data_type, authz_data_type, proof_len;
+	const unsigned char *p;
+	unsigned char *new_proof;
+
+	n=s->method->ssl_get_message(s,
+		SSL3_ST_CR_SUPPLEMENTAL_DATA_A,
+		SSL3_ST_CR_SUPPLEMENTAL_DATA_B,
+		SSL3_MT_SUPPLEMENTAL_DATA,
+		/* use default limit */
+		TLSEXT_MAXLEN_supplemental_data,
+		&ok);
+
+	if (!ok) return((int)n);
+
+	p = (unsigned char *)s->init_msg;
+
+	/* The message cannot be empty */
+	if (n < 3)
+		{
+		al = SSL_AD_DECODE_ERROR;
+		SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_LENGTH_MISMATCH);
+		goto f_err;
+		}
+	/* Length of supplemental data */
+	n2l3(p,supp_data_len);
+	n -= 3;
+	/* We must have at least one supplemental data entry
+	 * with type (1 byte) and length (2 bytes). */
+	if (supp_data_len != (unsigned long) n || n < 4)
+		{
+		al = SSL_AD_DECODE_ERROR;
+		SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_LENGTH_MISMATCH);
+		goto f_err;
+		}
+	/* Supplemental data type: must be authz_data */
+	n2s(p,supp_data_type);
+	n -= 2;
+	if (supp_data_type != TLSEXT_SUPPLEMENTALDATATYPE_authz_data)
+		{
+		al = SSL_AD_UNEXPECTED_MESSAGE;
+		SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_UNKNOWN_SUPPLEMENTAL_DATA_TYPE);
+		goto f_err;
+		}
+	/* Authz data length */
+	n2s(p, authz_data_len);
+	n -= 2;
+	if (authz_data_len != (unsigned long) n || n < 1)
+		{
+		al = SSL_AD_DECODE_ERROR;
+		SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_LENGTH_MISMATCH);
+		goto f_err;
+		}
+	/* Authz data type: must be audit_proof */
+	authz_data_type = *(p++);
+	n -= 1;
+	if (authz_data_type != TLSEXT_AUTHZDATAFORMAT_audit_proof)
+		{
+		al=SSL_AD_UNEXPECTED_MESSAGE;
+		SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_UNKNOWN_AUTHZ_DATA_TYPE);
+		goto f_err;
+		}
+	/* We have a proof: read its length */
+	if (n < 2)
+		{
+		al = SSL_AD_DECODE_ERROR;
+		SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_LENGTH_MISMATCH);
+		goto f_err;
+		}
+	n2s(p, proof_len);
+	n -= 2;
+	if (proof_len != (unsigned long) n)
+		{
+		al = SSL_AD_DECODE_ERROR;
+		SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,SSL_R_LENGTH_MISMATCH);
+		goto f_err;
+		}
+	/* Store the proof */
+	new_proof = OPENSSL_realloc(s->session->audit_proof,
+				    proof_len);
+	if (new_proof == NULL)
+		{
+		SSLerr(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA,ERR_R_MALLOC_FAILURE);
+		return 0;
+		}
+	s->session->audit_proof_length = proof_len;
+	s->session->audit_proof = new_proof;
+	memcpy(s->session->audit_proof, p, proof_len);
+
+	/* Got the proof, but can't verify it yet. */
+	return 1;
+f_err:
+	ssl3_send_alert(s,SSL3_AL_FATAL,al);
+	return -1;
+	}
+#endif
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 0456230fd3..9653de6eea 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -3684,6 +3684,11 @@ long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
 	case SSL_CTRL_SET_ECDH_AUTO:
 		ctx->cert->ecdh_tmp_auto = larg;
 		break;
+
+	case SSL_CTRL_SET_TLSEXT_AUTHZ_SERVER_AUDIT_PROOF_CB_ARG:
+		ctx->tlsext_authz_server_audit_proof_cb_arg = parg;
+		break;
+
 #endif /* !OPENSSL_NO_TLSEXT */
 
 	/* A Thawte special :-) */
@@ -3793,6 +3798,12 @@ long ssl3_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)(void))
 		ctx->srp_ctx.SRP_give_srp_client_pwd_callback=(char *(*)(SSL *,void *))fp;
 		break;
 #endif
+
+	case SSL_CTRL_SET_TLSEXT_AUTHZ_SERVER_AUDIT_PROOF_CB:
+		ctx->tlsext_authz_server_audit_proof_cb =
+			(int (*)(SSL *, void *))fp;
+		break;
+
 #endif
 	case SSL_CTRL_SET_NOT_RESUMABLE_SESS_CB:
 		{
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index 632b924ef2..ba324848c1 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -403,9 +403,30 @@ int ssl3_accept(SSL *s)
 					s->state=SSL3_ST_SW_CHANGE_A;
 #endif
 			else
-				s->state=SSL3_ST_SW_CERT_A;
-			s->init_num=0;
+#ifndef OPENSSL_NO_TLSEXT
+				s->state = SSL3_ST_SW_SUPPLEMENTAL_DATA_A;
+#else
+			s->state = SSL3_ST_SW_CERT_A;
+#endif
+			s->init_num = 0;
+			break;
+
+#ifndef OPENSSL_NO_TLSEXT
+		case SSL3_ST_SW_SUPPLEMENTAL_DATA_A:
+		case SSL3_ST_SW_SUPPLEMENTAL_DATA_B:
+			/* We promised to send an audit proof in the hello. */
+			if (s->s3->tlsext_authz_promised_to_client)
+				{
+				ret = tls1_send_server_supplemental_data(s);
+				if (ret <= 0) goto end;
+				}
+			else
+				skip = 1;
+
+			s->state = SSL3_ST_SW_CERT_A;
+			s->init_num = 0;
 			break;
+#endif
 
 		case SSL3_ST_SW_CERT_A:
 		case SSL3_ST_SW_CERT_B:
@@ -3629,4 +3650,95 @@ int ssl3_get_next_proto(SSL *s)
 	return 1;
 	}
 # endif
+
+int tls1_send_server_supplemental_data(SSL *s)
+	{
+	size_t length = 0;
+	const unsigned char *authz, *orig_authz;
+	unsigned char *p;
+	size_t authz_length, i;
+
+	if (s->state != SSL3_ST_SW_SUPPLEMENTAL_DATA_A)
+		return ssl3_do_write(s, SSL3_RT_HANDSHAKE);
+
+	orig_authz = authz = ssl_get_authz_data(s, &authz_length);
+	if (authz == NULL)
+		{
+		/* This should never occur. */
+		return 0;
+		}
+
+	/* First we walk over the authz data to see how long the handshake
+	 * message will be. */
+	for (i = 0; i < authz_length; i++)
+		{
+		unsigned short len;
+		unsigned char type;
+
+		type = *(authz++);
+		n2s(authz, len);
+
+		if (memchr(s->s3->tlsext_authz_client_types,
+			   type,
+			   s->s3->tlsext_authz_client_types_len) != NULL)
+			length += 1 /* authz type */ + 2 /* length */ + len;
+
+		authz += len;
+		i += len;
+		}
+
+	length += 1 /* handshake type */ +
+		  3 /* handshake length */ +
+		  3 /* supplemental data length */ +
+		  2 /* supplemental entry type */ +
+		  2 /* supplemental entry length */;
+
+	if (!BUF_MEM_grow_clean(s->init_buf, length))
+		{
+		SSLerr(SSL_F_TLS1_SEND_SERVER_SUPPLEMENTAL_DATA,ERR_R_BUF_LIB);
+		return 0;
+		}
+
+	p = (unsigned char *)s->init_buf->data;
+	*(p++) = SSL3_MT_SUPPLEMENTAL_DATA;
+	/* Handshake length */
+	l2n3(length - 4, p);
+	/* Length of supplemental data */
+	l2n3(length - 7, p);
+	/* Supplemental data type */
+	s2n(TLSEXT_SUPPLEMENTALDATATYPE_authz_data, p);
+	/* Its length */
+	s2n(length - 11, p);
+
+	authz = orig_authz;
+
+	/* Walk over the authz again and append the selected elements. */
+	for (i = 0; i < authz_length; i++)
+		{
+		unsigned short len;
+		unsigned char type;
+
+		type = *(authz++);
+		n2s(authz, len);
+
+		if (memchr(s->s3->tlsext_authz_client_types,
+			   type,
+			   s->s3->tlsext_authz_client_types_len) != NULL)
+			{
+			*(p++) = type;
+			s2n(len, p);
+			memcpy(p, authz, len);
+			p += len;
+			}
+
+		authz += len;
+		i += len;
+		}
+
+	s->state = SSL3_ST_SW_SUPPLEMENTAL_DATA_B;
+	s->init_num = length;
+	s->init_off = 0;
+
+	return ssl3_do_write(s, SSL3_RT_HANDSHAKE);
+	}
 #endif
diff --git a/ssl/ssl.h b/ssl/ssl.h
index 352e91b32a..31eccf904d 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -539,11 +539,18 @@ struct ssl_session_st
 #endif /* OPENSSL_NO_EC */
 	/* RFC4507 info */
 	unsigned char *tlsext_tick;	/* Session ticket */
-	size_t	tlsext_ticklen;		/* Session ticket length */	
+	size_t tlsext_ticklen;		/* Session ticket length */
 	long tlsext_tick_lifetime_hint;	/* Session lifetime hint in seconds */
 #endif
 #ifndef OPENSSL_NO_SRP
 	char *srp_username;
+#endif
+#ifndef OPENSSL_NO_TLSEXT
+	/* Used by client: the proof for this session.
+	 * We store it outside the sess_cert structure, since the proof
+	 * is received before the certificate. */
+	unsigned char *audit_proof;
+	size_t audit_proof_length;
 #endif
 	};
 
@@ -977,7 +984,7 @@ struct ssl_ctx_st
 	void *next_proto_select_cb_arg;
 # endif
         /* SRTP profiles we are willing to do from RFC 5764 */
-        STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles;  
+	STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles;  
 #endif
 	/* Callback for disabling session caching and ticket support
 	 * on a session basis, depending on the chosen cipher. */
@@ -989,6 +996,8 @@ struct ssl_ctx_st
 	size_t tlsext_ellipticcurvelist_length;
 	unsigned char *tlsext_ellipticcurvelist;
 #endif /* OPENSSL_NO_EC */
+	int (*tlsext_authz_server_audit_proof_cb)(SSL *s, void *arg);
+	void *tlsext_authz_server_audit_proof_cb_arg;
 	};
 
 #endif
@@ -1608,7 +1617,10 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
 #define SSL_CTRL_GET_TLS_EXT_HEARTBEAT_PENDING		86
 #define SSL_CTRL_SET_TLS_EXT_HEARTBEAT_NO_REQUESTS	87
 #endif
-#endif
+/* Callback for verifying audit proofs (client only) */
+#define SSL_CTRL_SET_TLSEXT_AUTHZ_SERVER_AUDIT_PROOF_CB 95
+#define SSL_CTRL_SET_TLSEXT_AUTHZ_SERVER_AUDIT_PROOF_CB_ARG 96
+#endif /* OPENSSL_NO_TLSEXT */
 
 #define DTLS_CTRL_GET_TIMEOUT		73
 #define DTLS_CTRL_HANDLE_TIMEOUT	74
@@ -1768,6 +1780,11 @@ int	SSL_use_PrivateKey_ASN1(int pk,SSL *ssl, const unsigned char *d, long len);
 int	SSL_use_certificate(SSL *ssl, X509 *x);
 int	SSL_use_certificate_ASN1(SSL *ssl, const unsigned char *d, int len);
 
+#ifndef OPENSSL_NO_TLSEXT
+int	SSL_CTX_use_authz(SSL_CTX *ctx, unsigned char *authz, size_t authz_length);
+int	SSL_use_authz(SSL *ssl, unsigned char *authz, size_t authz_length);
+#endif
+
 #ifndef OPENSSL_NO_STDIO
 int	SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, int type);
 int	SSL_use_PrivateKey_file(SSL *ssl, const char *file, int type);
@@ -1812,6 +1829,10 @@ int	SSL_SESSION_print_fp(FILE *fp,const SSL_SESSION *ses);
 #ifndef OPENSSL_NO_BIO
 int	SSL_SESSION_print(BIO *fp,const SSL_SESSION *ses);
 #endif
+#ifndef OPENSSL_NO_TLSEXT
+unsigned char *SSL_SESSION_get_tlsext_authz_server_audit_proof(SSL_SESSION *s,
+	size_t *proof_length);
+#endif
 void	SSL_SESSION_free(SSL_SESSION *ses);
 int	i2d_SSL_SESSION(SSL_SESSION *in,unsigned char **pp);
 int	SSL_set_session(SSL *to, SSL_SESSION *session);
@@ -2115,6 +2136,7 @@ void ERR_load_SSL_strings(void);
 /* Error codes for the SSL functions. */
 
 /* Function codes. */
+#define SSL_F_AUTHZ_VALIDATE				 323
 #define SSL_F_CLIENT_CERTIFICATE			 100
 #define SSL_F_CLIENT_FINISHED				 167
 #define SSL_F_CLIENT_HELLO				 101
@@ -2260,6 +2282,7 @@ void ERR_load_SSL_strings(void);
 #define SSL_F_SSL_CTX_SET_SESSION_ID_CONTEXT		 219
 #define SSL_F_SSL_CTX_SET_SSL_VERSION			 170
 #define SSL_F_SSL_CTX_SET_TRUST				 229
+#define SSL_F_SSL_CTX_USE_AUTHZ				 324
 #define SSL_F_SSL_CTX_USE_CERTIFICATE			 171
 #define SSL_F_SSL_CTX_USE_CERTIFICATE_ASN1		 172
 #define SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE	 220
@@ -2274,6 +2297,7 @@ void ERR_load_SSL_strings(void);
 #define SSL_F_SSL_DO_HANDSHAKE				 180
 #define SSL_F_SSL_GET_NEW_SESSION			 181
 #define SSL_F_SSL_GET_PREV_SESSION			 217
+#define SSL_F_SSL_GET_SERVER_CERT_INDEX			 329
 #define SSL_F_SSL_GET_SERVER_SEND_PKEY			 182
 #define SSL_F_SSL_GET_SIGN_PKEY				 183
 #define SSL_F_SSL_INIT_WBIO_BUFFER			 184
@@ -2297,6 +2321,7 @@ void ERR_load_SSL_strings(void);
 #define SSL_F_SSL_SESSION_PRINT_FP			 190
 #define SSL_F_SSL_SESSION_SET1_ID_CONTEXT		 312
 #define SSL_F_SSL_SESS_CERT_NEW				 225
+#define SSL_F_SSL_SET_AUTHZ				 325
 #define SSL_F_SSL_SET_CERT				 191
 #define SSL_F_SSL_SET_CIPHER_LIST			 271
 #define SSL_F_SSL_SET_FD				 192
@@ -2313,6 +2338,7 @@ void ERR_load_SSL_strings(void);
 #define SSL_F_SSL_UNDEFINED_CONST_FUNCTION		 243
 #define SSL_F_SSL_UNDEFINED_FUNCTION			 197
 #define SSL_F_SSL_UNDEFINED_VOID_FUNCTION		 244
+#define SSL_F_SSL_USE_AUTHZ				 328
 #define SSL_F_SSL_USE_CERTIFICATE			 198
 #define SSL_F_SSL_USE_CERTIFICATE_ASN1			 199
 #define SSL_F_SSL_USE_CERTIFICATE_FILE			 200
@@ -2330,16 +2356,19 @@ void ERR_load_SSL_strings(void);
 #define SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT		 274
 #define SSL_F_TLS1_ENC					 210
 #define SSL_F_TLS1_EXPORT_KEYING_MATERIAL		 314
+#define SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA		 326
 #define SSL_F_TLS1_HEARTBEAT				 315
 #define SSL_F_TLS1_PREPARE_CLIENTHELLO_TLSEXT		 275
 #define SSL_F_TLS1_PREPARE_SERVERHELLO_TLSEXT		 276
 #define SSL_F_TLS1_PRF					 284
+#define SSL_F_TLS1_SEND_SERVER_SUPPLEMENTAL_DATA	 327
 #define SSL_F_TLS1_SETUP_KEY_BLOCK			 211
 #define SSL_F_WRITE_PENDING				 212
 
 /* Reason codes. */
 #define SSL_R_APP_DATA_IN_HANDSHAKE			 100
 #define SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT 272
+#define SSL_R_AUTHZ_DATA_TOO_LARGE			 375
 #define SSL_R_BAD_ALERT_RECORD				 101
 #define SSL_R_BAD_AUTHENTICATION_TYPE			 102
 #define SSL_R_BAD_CHANGE_CIPHER_SPEC			 103
@@ -2428,6 +2457,8 @@ void ERR_load_SSL_strings(void);
 #define SSL_R_HTTP_REQUEST				 156
 #define SSL_R_ILLEGAL_PADDING				 283
 #define SSL_R_INCONSISTENT_COMPRESSION			 340
+#define SSL_R_INVALID_AUDIT_PROOF			 371
+#define SSL_R_INVALID_AUTHZ_DATA			 374
 #define SSL_R_INVALID_CHALLENGE_LENGTH			 158
 #define SSL_R_INVALID_COMMAND				 280
 #define SSL_R_INVALID_COMPRESSION_ALGORITHM		 341
@@ -2607,6 +2638,7 @@ void ERR_load_SSL_strings(void);
 #define SSL_R_UNEXPECTED_RECORD				 245
 #define SSL_R_UNINITIALIZED				 276
 #define SSL_R_UNKNOWN_ALERT_TYPE			 246
+#define SSL_R_UNKNOWN_AUTHZ_DATA_TYPE			 372
 #define SSL_R_UNKNOWN_CERTIFICATE_TYPE			 247
 #define SSL_R_UNKNOWN_CIPHER_RETURNED			 248
 #define SSL_R_UNKNOWN_CIPHER_TYPE			 249
@@ -2617,6 +2649,7 @@ void ERR_load_SSL_strings(void);
 #define SSL_R_UNKNOWN_REMOTE_ERROR_TYPE			 253
 #define SSL_R_UNKNOWN_SSL_VERSION			 254
 #define SSL_R_UNKNOWN_STATE				 255
+#define SSL_R_UNKNOWN_SUPPLEMENTAL_DATA_TYPE		 373
 #define SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED	 338
 #define SSL_R_UNSUPPORTED_CIPHER			 256
 #define SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM		 257
diff --git a/ssl/ssl3.h b/ssl/ssl3.h
index 4e72c1749b..84198ff501 100644
--- a/ssl/ssl3.h
+++ b/ssl/ssl3.h
@@ -540,6 +540,22 @@ typedef struct ssl3_state_st
 	   our peer. */
 	int next_proto_neg_seen;
 #endif
+
+#ifndef OPENSSL_NO_TLSEXT
+	/* tlsext_authz_client_types contains an array of supported authz
+	 * types, as advertised by the client. The array is sorted and
+	 * does not contain any duplicates. */
+	unsigned char *tlsext_authz_client_types;
+	size_t tlsext_authz_client_types_len;
+	/* tlsext_authz_promised_to_client is true iff we're a server and we
+	 * echoed the client's supplemental data extension and therefore must
+	 * send a supplemental data handshake message. */
+	char tlsext_authz_promised_to_client;
+	/* tlsext_authz_server_promised is true iff we're a client and the
+	 * server echoed our server_authz extension and therefore must send us
+	 * a supplemental data handshake message. */
+	char tlsext_authz_server_promised;
+#endif
 	} SSL3_STATE;
 
 #endif
@@ -568,6 +584,8 @@ typedef struct ssl3_state_st
 #define SSL3_ST_CR_CERT_REQ_B		(0x151|SSL_ST_CONNECT)
 #define SSL3_ST_CR_SRVR_DONE_A		(0x160|SSL_ST_CONNECT)
 #define SSL3_ST_CR_SRVR_DONE_B		(0x161|SSL_ST_CONNECT)
+#define SSL3_ST_CR_SUPPLEMENTAL_DATA_A	(0x210|SSL_ST_CONNECT)
+#define SSL3_ST_CR_SUPPLEMENTAL_DATA_B  (0x211|SSL_ST_CONNECT)
 /* write to server */
 #define SSL3_ST_CW_CERT_A		(0x170|SSL_ST_CONNECT)
 #define SSL3_ST_CW_CERT_B		(0x171|SSL_ST_CONNECT)
@@ -647,6 +665,8 @@ typedef struct ssl3_state_st
 #define SSL3_ST_SW_SESSION_TICKET_B	(0x1F1|SSL_ST_ACCEPT)
 #define SSL3_ST_SW_CERT_STATUS_A	(0x200|SSL_ST_ACCEPT)
 #define SSL3_ST_SW_CERT_STATUS_B	(0x201|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_SUPPLEMENTAL_DATA_A	(0x220|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_SUPPLEMENTAL_DATA_B	(0x221|SSL_ST_ACCEPT)
 
 #define SSL3_MT_HELLO_REQUEST			0
 #define SSL3_MT_CLIENT_HELLO			1
@@ -660,6 +680,7 @@ typedef struct ssl3_state_st
 #define SSL3_MT_CLIENT_KEY_EXCHANGE		16
 #define SSL3_MT_FINISHED			20
 #define SSL3_MT_CERTIFICATE_STATUS		22
+#define SSL3_MT_SUPPLEMENTAL_DATA		23
 #ifndef OPENSSL_NO_NEXTPROTONEG
 #define SSL3_MT_NEXT_PROTO			67
 #endif
@@ -682,4 +703,3 @@ typedef struct ssl3_state_st
 }
 #endif
 #endif
-
diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c
index 222f703284..fcf462d41a 100644
--- a/ssl/ssl_cert.c
+++ b/ssl/ssl_cert.c
@@ -334,6 +334,22 @@ CERT *ssl_cert_dup(CERT *cert)
 				CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
 				}
 			}
+                if (cert->pkeys[i].authz != NULL)
+			{
+			/* Just copy everything. */
+			ret->pkeys[i].authz_length =
+				cert->pkeys[i].authz_length;
+			ret->pkeys[i].authz =
+				OPENSSL_malloc(ret->pkeys[i].authz_length);
+			if (ret->pkeys[i].authz == NULL)
+				{
+				SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_MALLOC_FAILURE);
+				return(NULL);
+				}
+			memcpy(ret->pkeys[i].authz,
+			       cert->pkeys[i].authz,
+			       cert->pkeys[i].authz_length);
+			}
 		}
 	
 	ret->references=1;
@@ -421,6 +437,10 @@ void ssl_cert_free(CERT *c)
 #if 0
 		if (c->pkeys[i].publickey != NULL)
 			EVP_PKEY_free(c->pkeys[i].publickey);
+#endif
+#ifndef OPENSSL_NO_TLSEXT
+                if (c->pkeys[i].authz != NULL)
+			OPENSSL_free(c->pkeys[i].authz);
 #endif
 		}
 	if (c->sigalgs)
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index 0a43d249e8..ce004558a2 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -70,6 +70,7 @@
 
 static ERR_STRING_DATA SSL_str_functs[]=
 	{
+{ERR_FUNC(SSL_F_AUTHZ_VALIDATE),	"AUTHZ_VALIDATE"},
 {ERR_FUNC(SSL_F_CLIENT_CERTIFICATE),	"CLIENT_CERTIFICATE"},
 {ERR_FUNC(SSL_F_CLIENT_FINISHED),	"CLIENT_FINISHED"},
 {ERR_FUNC(SSL_F_CLIENT_HELLO),	"CLIENT_HELLO"},
@@ -215,6 +216,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
 {ERR_FUNC(SSL_F_SSL_CTX_SET_SESSION_ID_CONTEXT),	"SSL_CTX_set_session_id_context"},
 {ERR_FUNC(SSL_F_SSL_CTX_SET_SSL_VERSION),	"SSL_CTX_set_ssl_version"},
 {ERR_FUNC(SSL_F_SSL_CTX_SET_TRUST),	"SSL_CTX_set_trust"},
+{ERR_FUNC(SSL_F_SSL_CTX_USE_AUTHZ),	"SSL_CTX_use_authz"},
 {ERR_FUNC(SSL_F_SSL_CTX_USE_CERTIFICATE),	"SSL_CTX_use_certificate"},
 {ERR_FUNC(SSL_F_SSL_CTX_USE_CERTIFICATE_ASN1),	"SSL_CTX_use_certificate_ASN1"},
 {ERR_FUNC(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE),	"SSL_CTX_use_certificate_chain_file"},
@@ -229,6 +231,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
 {ERR_FUNC(SSL_F_SSL_DO_HANDSHAKE),	"SSL_do_handshake"},
 {ERR_FUNC(SSL_F_SSL_GET_NEW_SESSION),	"SSL_GET_NEW_SESSION"},
 {ERR_FUNC(SSL_F_SSL_GET_PREV_SESSION),	"SSL_GET_PREV_SESSION"},
+{ERR_FUNC(SSL_F_SSL_GET_SERVER_CERT_INDEX),	"SSL_GET_SERVER_CERT_INDEX"},
 {ERR_FUNC(SSL_F_SSL_GET_SERVER_SEND_PKEY),	"SSL_GET_SERVER_SEND_PKEY"},
 {ERR_FUNC(SSL_F_SSL_GET_SIGN_PKEY),	"SSL_GET_SIGN_PKEY"},
 {ERR_FUNC(SSL_F_SSL_INIT_WBIO_BUFFER),	"SSL_INIT_WBIO_BUFFER"},
@@ -252,6 +255,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
 {ERR_FUNC(SSL_F_SSL_SESSION_PRINT_FP),	"SSL_SESSION_print_fp"},
 {ERR_FUNC(SSL_F_SSL_SESSION_SET1_ID_CONTEXT),	"SSL_SESSION_set1_id_context"},
 {ERR_FUNC(SSL_F_SSL_SESS_CERT_NEW),	"SSL_SESS_CERT_NEW"},
+{ERR_FUNC(SSL_F_SSL_SET_AUTHZ),	"SSL_SET_AUTHZ"},
 {ERR_FUNC(SSL_F_SSL_SET_CERT),	"SSL_SET_CERT"},
 {ERR_FUNC(SSL_F_SSL_SET_CIPHER_LIST),	"SSL_set_cipher_list"},
 {ERR_FUNC(SSL_F_SSL_SET_FD),	"SSL_set_fd"},
@@ -268,6 +272,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
 {ERR_FUNC(SSL_F_SSL_UNDEFINED_CONST_FUNCTION),	"SSL_UNDEFINED_CONST_FUNCTION"},
 {ERR_FUNC(SSL_F_SSL_UNDEFINED_FUNCTION),	"SSL_UNDEFINED_FUNCTION"},
 {ERR_FUNC(SSL_F_SSL_UNDEFINED_VOID_FUNCTION),	"SSL_UNDEFINED_VOID_FUNCTION"},
+{ERR_FUNC(SSL_F_SSL_USE_AUTHZ),	"SSL_use_authz"},
 {ERR_FUNC(SSL_F_SSL_USE_CERTIFICATE),	"SSL_use_certificate"},
 {ERR_FUNC(SSL_F_SSL_USE_CERTIFICATE_ASN1),	"SSL_use_certificate_ASN1"},
 {ERR_FUNC(SSL_F_SSL_USE_CERTIFICATE_FILE),	"SSL_use_certificate_file"},
@@ -285,10 +290,12 @@ static ERR_STRING_DATA SSL_str_functs[]=
 {ERR_FUNC(SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT),	"TLS1_CHECK_SERVERHELLO_TLSEXT"},
 {ERR_FUNC(SSL_F_TLS1_ENC),	"TLS1_ENC"},
 {ERR_FUNC(SSL_F_TLS1_EXPORT_KEYING_MATERIAL),	"TLS1_EXPORT_KEYING_MATERIAL"},
+{ERR_FUNC(SSL_F_TLS1_GET_SERVER_SUPPLEMENTAL_DATA),	"TLS1_GET_SERVER_SUPPLEMENTAL_DATA"},
 {ERR_FUNC(SSL_F_TLS1_HEARTBEAT),	"SSL_F_TLS1_HEARTBEAT"},
 {ERR_FUNC(SSL_F_TLS1_PREPARE_CLIENTHELLO_TLSEXT),	"TLS1_PREPARE_CLIENTHELLO_TLSEXT"},
 {ERR_FUNC(SSL_F_TLS1_PREPARE_SERVERHELLO_TLSEXT),	"TLS1_PREPARE_SERVERHELLO_TLSEXT"},
 {ERR_FUNC(SSL_F_TLS1_PRF),	"tls1_prf"},
+{ERR_FUNC(SSL_F_TLS1_SEND_SERVER_SUPPLEMENTAL_DATA),	"TLS1_SEND_SERVER_SUPPLEMENTAL_DATA"},
 {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK),	"TLS1_SETUP_KEY_BLOCK"},
 {ERR_FUNC(SSL_F_WRITE_PENDING),	"WRITE_PENDING"},
 {0,NULL}
@@ -298,6 +305,7 @@ static ERR_STRING_DATA SSL_str_reasons[]=
 	{
 {ERR_REASON(SSL_R_APP_DATA_IN_HANDSHAKE) ,"app data in handshake"},
 {ERR_REASON(SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT),"attempt to reuse session in different context"},
+{ERR_REASON(SSL_R_AUTHZ_DATA_TOO_LARGE)  ,"authz data too large"},
 {ERR_REASON(SSL_R_BAD_ALERT_RECORD)      ,"bad alert record"},
 {ERR_REASON(SSL_R_BAD_AUTHENTICATION_TYPE),"bad authentication type"},
 {ERR_REASON(SSL_R_BAD_CHANGE_CIPHER_SPEC),"bad change cipher spec"},
@@ -386,6 +394,8 @@ static ERR_STRING_DATA SSL_str_reasons[]=
 {ERR_REASON(SSL_R_HTTP_REQUEST)          ,"http request"},
 {ERR_REASON(SSL_R_ILLEGAL_PADDING)       ,"illegal padding"},
 {ERR_REASON(SSL_R_INCONSISTENT_COMPRESSION),"inconsistent compression"},
+{ERR_REASON(SSL_R_INVALID_AUDIT_PROOF)   ,"invalid audit proof"},
+{ERR_REASON(SSL_R_INVALID_AUTHZ_DATA)    ,"invalid authz data"},
 {ERR_REASON(SSL_R_INVALID_CHALLENGE_LENGTH),"invalid challenge length"},
 {ERR_REASON(SSL_R_INVALID_COMMAND)       ,"invalid command"},
 {ERR_REASON(SSL_R_INVALID_COMPRESSION_ALGORITHM),"invalid compression algorithm"},
@@ -565,6 +575,7 @@ static ERR_STRING_DATA SSL_str_reasons[]=
 {ERR_REASON(SSL_R_UNEXPECTED_RECORD)     ,"unexpected record"},
 {ERR_REASON(SSL_R_UNINITIALIZED)         ,"uninitialized"},
 {ERR_REASON(SSL_R_UNKNOWN_ALERT_TYPE)    ,"unknown alert type"},
+{ERR_REASON(SSL_R_UNKNOWN_AUTHZ_DATA_TYPE),"unknown authz data type"},
 {ERR_REASON(SSL_R_UNKNOWN_CERTIFICATE_TYPE),"unknown certificate type"},
 {ERR_REASON(SSL_R_UNKNOWN_CIPHER_RETURNED),"unknown cipher returned"},
 {ERR_REASON(SSL_R_UNKNOWN_CIPHER_TYPE)   ,"unknown cipher type"},
@@ -575,6 +586,7 @@ static ERR_STRING_DATA SSL_str_reasons[]=
 {ERR_REASON(SSL_R_UNKNOWN_REMOTE_ERROR_TYPE),"unknown remote error type"},
 {ERR_REASON(SSL_R_UNKNOWN_SSL_VERSION)   ,"unknown ssl version"},
 {ERR_REASON(SSL_R_UNKNOWN_STATE)         ,"unknown state"},
+{ERR_REASON(SSL_R_UNKNOWN_SUPPLEMENTAL_DATA_TYPE),"unknown supplemental data type"},
 {ERR_REASON(SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED),"unsafe legacy renegotiation disabled"},
 {ERR_REASON(SSL_R_UNSUPPORTED_CIPHER)    ,"unsupported cipher"},
 {ERR_REASON(SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM),"unsupported compression algorithm"},
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 679894cb3d..cb098b3002 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -2323,15 +2323,10 @@ int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s)
 #endif
 
 /* THIS NEEDS CLEANING UP */
-CERT_PKEY *ssl_get_server_send_pkey(SSL *s)
+static int ssl_get_server_cert_index(SSL *s)
 	{
-	unsigned long alg_k,alg_a;
-	CERT *c;
-	int i;
+ 	unsigned long alg_k, alg_a;
 
-	c=s->cert;
-	ssl_set_cert_masks(c, s->s3->tmp.new_cipher);
-	
 	alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
 	alg_a = s->s3->tmp.new_cipher->algorithm_auth;
 
@@ -2348,42 +2343,53 @@ CERT_PKEY *ssl_get_server_send_pkey(SSL *s)
 		 * checks for SSL_kECDH before RSA
 		 * checks ensures the correct cert is chosen.
 		 */
-		i=SSL_PKEY_ECC;
+		return SSL_PKEY_ECC;
 		}
 	else if (alg_a & SSL_aECDSA)
-		{
-		i=SSL_PKEY_ECC;
-		}
+		return SSL_PKEY_ECC;
 	else if (alg_k & SSL_kDHr)
-		i=SSL_PKEY_DH_RSA;
+		return SSL_PKEY_DH_RSA;
 	else if (alg_k & SSL_kDHd)
-		i=SSL_PKEY_DH_DSA;
+		return SSL_PKEY_DH_DSA;
 	else if (alg_a & SSL_aDSS)
-		i=SSL_PKEY_DSA_SIGN;
+		return SSL_PKEY_DSA_SIGN;
 	else if (alg_a & SSL_aRSA)
 		{
-		if (c->pkeys[SSL_PKEY_RSA_ENC].x509 == NULL)
-			i=SSL_PKEY_RSA_SIGN;
+		if (s->cert->pkeys[SSL_PKEY_RSA_ENC].x509 == NULL)
+			return SSL_PKEY_RSA_SIGN;
 		else
-			i=SSL_PKEY_RSA_ENC;
+			return SSL_PKEY_RSA_ENC;
 		}
 	else if (alg_a & SSL_aKRB5)
-		{
 		/* VRS something else here? */
-		return(NULL);
-		}
+		return -1;
 	else if (alg_a & SSL_aGOST94) 
-		i=SSL_PKEY_GOST94;
+		return SSL_PKEY_GOST94;
 	else if (alg_a & SSL_aGOST01)
-		i=SSL_PKEY_GOST01;
+		return SSL_PKEY_GOST01;
 	else /* if (alg_a & SSL_aNULL) */
 		{
-		SSLerr(SSL_F_SSL_GET_SERVER_SEND_PKEY,ERR_R_INTERNAL_ERROR);
-		return(NULL);
+		SSLerr(SSL_F_SSL_GET_SERVER_CERT_INDEX,ERR_R_INTERNAL_ERROR);
+		return -1;
 		}
-	if (c->pkeys[i].x509 == NULL) return(NULL);
+	}
+
+CERT_PKEY *ssl_get_server_send_pkey(SSL *s)
+	{
+	CERT *c;
+	int i;
 
-	return(&c->pkeys[i]);
+	c = s->cert;
+	ssl_set_cert_masks(c, s->s3->tmp.new_cipher);
+
+	i = ssl_get_server_cert_index(s);
+
+	/* This may or may not be an error. */
+	if (i < 0)
+		return NULL;
+
+	/* May be NULL. */
+	return &c->pkeys[i];
 	}
 
 EVP_PKEY *ssl_get_sign_pkey(SSL *s,const SSL_CIPHER *cipher, const EVP_MD **pmd)
@@ -2418,6 +2424,27 @@ EVP_PKEY *ssl_get_sign_pkey(SSL *s,const SSL_CIPHER *cipher, const EVP_MD **pmd)
 	return c->pkeys[idx].privatekey;
 	}
 
+#ifndef OPENSSL_NO_TLSEXT
+unsigned char *ssl_get_authz_data(SSL *s, size_t *authz_length)
+	{
+	CERT *c;
+	int i;
+
+	c = s->cert;
+	i = ssl_get_server_cert_index(s);
+
+	if (i == -1)
+		return NULL;
+
+	*authz_length = 0;
+	if (c->pkeys[i].authz == NULL)
+		return(NULL);
+	*authz_length = c->pkeys[i].authz_length;
+
+	return c->pkeys[i].authz;
+	}
+#endif
+
 void ssl_update_cache(SSL *s,int mode)
 	{
 	int i;
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index b83b174da9..d0167e8283 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -474,6 +474,15 @@ typedef struct cert_pkey_st
 	const EVP_MD *digest;
 	/* Chain for this certificate */
 	STACK_OF(X509) *chain;
+#ifndef OPENSSL_NO_TLSEXT
+	/* authz/authz_length contain authz data for this certificate. The data
+	 * is in wire format, specifically it's a series of records like:
+	 *   uint8_t authz_type;  // (RFC 5878, AuthzDataFormat)
+	 *   uint16_t length;
+	 *   uint8_t data[length]; */
+	unsigned char *authz;
+	size_t authz_length;
+#endif
 	} CERT_PKEY;
 
 typedef struct cert_st
@@ -856,6 +865,7 @@ int ssl_undefined_function(SSL *s);
 int ssl_undefined_void_function(void);
 int ssl_undefined_const_function(const SSL *s);
 CERT_PKEY *ssl_get_server_send_pkey(SSL *);
+unsigned char *ssl_get_authz_data(SSL *s, size_t *authz_length);
 EVP_PKEY *ssl_get_sign_pkey(SSL *s,const SSL_CIPHER *c, const EVP_MD **pmd);
 int ssl_cert_type(X509 *x,EVP_PKEY *pkey);
 void ssl_set_cert_masks(CERT *c, const SSL_CIPHER *cipher);
@@ -1125,6 +1135,11 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **data, unsigned char *d,
 int ssl_prepare_clienthello_tlsext(SSL *s);
 int ssl_prepare_serverhello_tlsext(SSL *s);
 
+/* server only */
+int tls1_send_server_supplemental_data(SSL *s);
+/* client only */
+int tls1_get_server_supplemental_data(SSL *s);
+
 #ifndef OPENSSL_NO_HEARTBEATS
 int tls1_heartbeat(SSL *s);
 int dtls1_heartbeat(SSL *s);
diff --git a/ssl/ssl_rsa.c b/ssl/ssl_rsa.c
index b7c19051e9..855952d54c 100644
--- a/ssl/ssl_rsa.c
+++ b/ssl/ssl_rsa.c
@@ -66,6 +66,10 @@
 
 static int ssl_set_cert(CERT *c, X509 *x509);
 static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey);
+#ifndef OPENSSL_NO_TLSEXT
+static int ssl_set_authz(CERT *c, unsigned char *authz,
+			 size_t authz_length);
+#endif
 int SSL_use_certificate(SSL *ssl, X509 *x)
 	{
 	if (x == NULL)
@@ -459,6 +463,15 @@ static int ssl_set_cert(CERT *c, X509 *x)
 		X509_free(c->pkeys[i].x509);
 	CRYPTO_add(&x->references,1,CRYPTO_LOCK_X509);
 	c->pkeys[i].x509=x;
+#ifndef OPENSSL_NO_TLSEXT
+	/* Free the old authz data, if it exists. */
+	if (c->pkeys[i].authz != NULL)
+		{
+		OPENSSL_free(c->pkeys[i].authz);
+		c->pkeys[i].authz = NULL;
+		c->pkeys[i].authz_length = 0;
+		}
+#endif
 	c->key= &(c->pkeys[i]);
 
 	c->valid=0;
@@ -725,7 +738,7 @@ int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file)
 
 	ERR_clear_error(); /* clear error stack for SSL_CTX_use_certificate() */
 
-	in=BIO_new(BIO_s_file_internal());
+	in = BIO_new(BIO_s_file_internal());
 	if (in == NULL)
 		{
 		SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE,ERR_R_BUF_LIB);
@@ -738,14 +751,16 @@ int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file)
 		goto end;
 		}
 
-	x=PEM_read_bio_X509_AUX(in,NULL,ctx->default_passwd_callback,ctx->default_passwd_callback_userdata);
+	x=PEM_read_bio_X509_AUX(in,NULL,ctx->default_passwd_callback,
+				ctx->default_passwd_callback_userdata);
 	if (x == NULL)
 		{
 		SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE,ERR_R_PEM_LIB);
 		goto end;
 		}
 
-	ret=SSL_CTX_use_certificate(ctx,x);
+	ret = SSL_CTX_use_certificate(ctx, x);
+
 	if (ERR_peek_error() != 0)
 		ret = 0;  /* Key/certificate mismatch doesn't imply ret==0 ... */
 	if (ret)
@@ -757,13 +772,15 @@ int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file)
 		int r;
 		unsigned long err;
 		
-		if (ctx->extra_certs != NULL) 
+		if (ctx->extra_certs != NULL)
 			{
 			sk_X509_pop_free(ctx->extra_certs, X509_free);
 			ctx->extra_certs = NULL;
 			}
 
-		while ((ca = PEM_read_bio_X509(in,NULL,ctx->default_passwd_callback,ctx->default_passwd_callback_userdata))
+		while ((ca = PEM_read_bio_X509(in, NULL,
+					ctx->default_passwd_callback,
+					ctx->default_passwd_callback_userdata))
 			!= NULL)
 			{
 			r = SSL_CTX_add_extra_chain_cert(ctx, ca);
@@ -792,3 +809,96 @@ end:
 	return(ret);
 	}
 #endif
+
+#ifndef OPENSSL_NO_TLSEXT
+/* authz_validate returns true iff authz is well formed, i.e. that it meets the
+ * wire format as documented in the CERT_PKEY structure and that there are no
+ * duplicate entries. */
+static char authz_validate(const unsigned char *authz, size_t length)
+	{
+	unsigned char types_seen_bitmap[32];
+
+	if (!authz)
+		return 1;
+
+	memset(types_seen_bitmap, 0, sizeof(types_seen_bitmap));
+
+	for (;;)
+		{
+		unsigned char type, byte, bit;
+		unsigned short len;
+
+		if (!length)
+			return 1;
+
+		type = *(authz++);
+		length--;
+
+		byte = type / 8;
+		bit = type & 7;
+		if (types_seen_bitmap[byte] & (1 << bit))
+			return 0;
+		types_seen_bitmap[byte] |= (1 << bit);
+
+		if (length < 2)
+			return 0;
+		len = ((unsigned short) authz[0]) << 8 |
+		      ((unsigned short) authz[1]);
+		authz += 2;
+		length -= 2;
+
+		if (length < len)
+			return 0;
+
+		authz += len;
+		length -= len;
+		}
+	}
+
+static int ssl_set_authz(CERT *c, unsigned char *authz, size_t authz_length)
+	{
+	CERT_PKEY *current_key = c->key;
+	if (current_key == NULL)
+		return 0;
+	if (!authz_validate(authz, authz_length))
+		{
+		SSLerr(SSL_F_SSL_SET_AUTHZ,SSL_R_INVALID_AUTHZ_DATA);
+		return(0);
+		}
+	current_key->authz = OPENSSL_realloc(current_key->authz, authz_length);
+	current_key->authz_length = authz_length;
+	memcpy(current_key->authz, authz, authz_length);
+	return 1;
+	}
+
+int SSL_CTX_use_authz(SSL_CTX *ctx, unsigned char *authz,
+	size_t authz_length)
+	{
+	if (authz == NULL)
+		{
+		SSLerr(SSL_F_SSL_CTX_USE_AUTHZ,ERR_R_PASSED_NULL_PARAMETER);
+		return 0;
+		}
+	if (!ssl_cert_inst(&ctx->cert))
+		{
+		SSLerr(SSL_F_SSL_CTX_USE_AUTHZ,ERR_R_MALLOC_FAILURE);
+		return 0;
+		}
+	return ssl_set_authz(ctx->cert, authz, authz_length);
+	}
+
+int SSL_use_authz(SSL *ssl, unsigned char *authz, size_t authz_length)
+	{
+	if (authz == NULL)
+		{
+		SSLerr(SSL_F_SSL_USE_AUTHZ,ERR_R_PASSED_NULL_PARAMETER);
+		return 0;
+		}
+	if (!ssl_cert_inst(&ssl->cert))
+		{
+		SSLerr(SSL_F_SSL_USE_AUTHZ,ERR_R_MALLOC_FAILURE);
+		return 0;
+		}
+	return ssl_set_authz(ssl->cert, authz, authz_length);
+	}
+#endif /* OPENSSL_NO_TLSEXT */
diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c
index 9e8f2e4ece..093ea60ae6 100644
--- a/ssl/ssl_sess.c
+++ b/ssl/ssl_sess.c
@@ -739,6 +739,8 @@ void SSL_SESSION_free(SSL_SESSION *ss)
 	ss->tlsext_ellipticcurvelist_length = 0;
 	if (ss->tlsext_ellipticcurvelist != NULL) OPENSSL_free(ss->tlsext_ellipticcurvelist);
 #endif /* OPENSSL_NO_EC */
+	if (ss->audit_proof != NULL) OPENSSL_free(ss->audit_proof);
+	ss->audit_proof_length = 0;
 #endif
 #ifndef OPENSSL_NO_PSK
 	if (ss->psk_identity_hint != NULL)
@@ -860,6 +862,15 @@ int SSL_SESSION_set1_id_context(SSL_SESSION *s,const unsigned char *sid_ctx,
 	return 1;
 	}
 
+#ifndef OPENSSL_NO_TLSEXT
+unsigned char *SSL_SESSION_get_tlsext_authz_server_audit_proof(SSL_SESSION *s, size_t *proof_length)
+	{
+	if (s->audit_proof != NULL)
+		*proof_length = s->audit_proof_length;
+	return s->audit_proof;
+	}
+#endif
+
 long SSL_CTX_set_timeout(SSL_CTX *s, long t)
 	{
 	long l;
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index f62a004cf2..12230e8ae1 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -642,6 +642,19 @@ int tls12_get_req_sig_algs(SSL *s, unsigned char *p)
 	return (int)slen;
 	}
 
+/* byte_compare is a compare function for qsort(3) that compares bytes. */
+static int byte_compare(const void *in_a, const void *in_b)
+	{
+	unsigned char a = *((const unsigned char*) in_a);
+	unsigned char b = *((const unsigned char*) in_b);
+
+	if (a > b)
+		return 1;
+	else if (a < b)
+		return -1;
+	return 0;
+}
+
 unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit)
 	{
 	int extdatalen=0;
@@ -983,7 +996,27 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
                 ret += el;
                 }
 
-	if ((extdatalen = ret-p-2)== 0) 
+	/* Add TLS extension Server_Authz_DataFormats to the ClientHello */
+	/* 2 bytes for extension type */
+	/* 2 bytes for extension length */
+	/* 1 byte for the list length */
+	/* 1 byte for the list (we only support audit proofs) */
+	if (s->ctx->tlsext_authz_server_audit_proof_cb != NULL)
+		{
+		size_t lenmax;
+                const unsigned short ext_len = 2;
+                const unsigned char list_len = 1;
+
+		if ((lenmax = limit - ret - 6) < 0) return NULL;
+
+		s2n(TLSEXT_TYPE_server_authz, ret);
+                /* Extension length: 2 bytes */
+		s2n(ext_len, ret);
+		*(ret++) = list_len;
+		*(ret++) = TLSEXT_AUTHZDATAFORMAT_audit_proof;
+		}
+
+	if ((extdatalen = ret-p-2) == 0)
 		return p;
 
 	s2n(extdatalen,p);
@@ -1170,6 +1203,75 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
 		}
 #endif
 
+	/* If the client supports authz then see whether we have any to offer
+	 * to it. */
+	if (s->s3->tlsext_authz_client_types_len)
+		{
+		size_t authz_length;
+		/* By now we already know the new cipher, so we can look ahead
+		 * to see whether the cert we are going to send
+		 * has any authz data attached to it. */
+		const unsigned char* authz = ssl_get_authz_data(s, &authz_length);
+		const unsigned char* const orig_authz = authz;
+		size_t i;
+		unsigned authz_count = 0;
+
+		/* The authz data contains a number of the following structures:
+		 * 	uint8_t authz_type
+		 * 	uint16_t length
+		 * 	uint8_t data[length]
+		 *
+		 * First we walk over it to find the number of authz elements. */
+		for (i = 0; i < authz_length; i++)
+			{
+			unsigned short length;
+			unsigned char type;
+
+			type = *(authz++);
+			if (memchr(s->s3->tlsext_authz_client_types,
+				   type,
+				   s->s3->tlsext_authz_client_types_len) != NULL)
+				authz_count++;
+
+			n2s(authz, length);
+			authz += length;
+			i += length;
+			}
+
+		if (authz_count)
+			{
+			/* Add TLS extension server_authz to the ServerHello message
+			 * 2 bytes for extension type
+			 * 2 bytes for extension length
+			 * 1 byte for the list length
+			 * n bytes for the list */
+			const unsigned short ext_len = 1 + authz_count;
+
+			if ((long)(limit - ret - 4 - ext_len) < 0) return NULL;
+			s2n(TLSEXT_TYPE_server_authz, ret);
+			s2n(ext_len, ret);
+			*(ret++) = authz_count;
+			s->s3->tlsext_authz_promised_to_client = 1;
+			}
+
+		authz = orig_authz;
+		for (i = 0; i < authz_length; i++)
+			{
+			unsigned short length;
+			unsigned char type;
+
+			authz_count++;
+			type = *(authz++);
+			if (memchr(s->s3->tlsext_authz_client_types,
+				   type,
+				   s->s3->tlsext_authz_client_types_len) != NULL)
+				*(ret++) = type;
+			n2s(authz, length);
+			authz += length;
+			i += length;
+			}
+		}
+
 	if ((extdatalen = ret-p-2)== 0) 
 		return p;
 
@@ -1650,9 +1752,67 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char
 				return 0;
                         }
 
+		else if (type == TLSEXT_TYPE_server_authz)
+			{
+			unsigned char *sdata = data;
+			unsigned char server_authz_dataformatlist_length;
+
+			if (size == 0)
+				{
+				*al = TLS1_AD_DECODE_ERROR;
+				return 0;
+				}
+
+			server_authz_dataformatlist_length = *(sdata++);
+
+			if (server_authz_dataformatlist_length != size - 1)
+				{
+				*al = TLS1_AD_DECODE_ERROR;
+				return 0;
+				}
+
+			/* Successful session resumption uses the same authz
+			 * information as the original session so we ignore this
+			 * in the case of a session resumption. */
+			if (!s->hit)
+				{
+				size_t i;
+				s->s3->tlsext_authz_client_types =
+					OPENSSL_malloc(server_authz_dataformatlist_length);
+				if (!s->s3->tlsext_authz_client_types)
+					{
+					*al = TLS1_AD_INTERNAL_ERROR;
+					return 0;
+					}
+
+				s->s3->tlsext_authz_client_types_len =
+					server_authz_dataformatlist_length;
+				memcpy(s->s3->tlsext_authz_client_types,
+				       sdata,
+				       server_authz_dataformatlist_length);
+
+				/* Sort the types in order to check for duplicates. */
+				qsort(s->s3->tlsext_authz_client_types,
+				      server_authz_dataformatlist_length,
+				      1 /* element size */,
+				      byte_compare);
+
+				for (i = 0; i < server_authz_dataformatlist_length; i++)
+					{
+					if (i > 0 &&
+					    s->s3->tlsext_authz_client_types[i] ==
+					      s->s3->tlsext_authz_client_types[i-1])
+						{
+						*al = TLS1_AD_DECODE_ERROR;
+						return 0;
+						}
+					}
+				}
+			}
+
 		data+=size;
 		}
-				
+
 	*p = data;
 
 	ri_check:
@@ -1916,7 +2076,46 @@ static int ssl_scan_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char
                                 return 0;
                         }
 
-		data+=size;		
+		else if (type == TLSEXT_TYPE_server_authz)
+			{
+			/* We only support audit proofs. It's an error to send
+			 * an authz hello extension if the client
+			 * didn't request a proof. */
+			unsigned char *sdata = data;
+			unsigned char server_authz_dataformatlist_length;
+
+			if (!s->ctx->tlsext_authz_server_audit_proof_cb)
+				{
+				*al = TLS1_AD_UNSUPPORTED_EXTENSION;
+				return 0;
+				}
+
+			if (!size)
+				{
+				*al = TLS1_AD_DECODE_ERROR;
+				return 0;
+				}
+
+			server_authz_dataformatlist_length = *(sdata++);
+			if (server_authz_dataformatlist_length != size - 1)
+				{
+				*al = TLS1_AD_DECODE_ERROR;
+				return 0;
+				}
+
+			/* We only support audit proofs, so a legal ServerHello
+			 * authz list contains exactly one entry. */
+			if (server_authz_dataformatlist_length != 1 ||
+				sdata[0] != TLSEXT_AUTHZDATAFORMAT_audit_proof)
+				{
+				*al = TLS1_AD_UNSUPPORTED_EXTENSION;
+				return 0;
+				}
+
+			s->s3->tlsext_authz_server_promised = 1;
+			}
+ 
+		data += size;
 		}
 
 	if (data != d+n)
diff --git a/ssl/tls1.h b/ssl/tls1.h
index a11caf820a..dd1b4fb22d 100644
--- a/ssl/tls1.h
+++ b/ssl/tls1.h
@@ -281,6 +281,14 @@ extern "C" {
 
 #define TLSEXT_MAXLEN_host_name 255
 
+/* From RFC 5878 */
+#define TLSEXT_SUPPLEMENTALDATATYPE_authz_data 16386
+/* This is not IANA assigned. See
+ * https://www.iana.org/assignments/tls-parameters/tls-parameters.xml#authorization-data-rules */
+#define TLSEXT_AUTHZDATAFORMAT_audit_proof 182
+
+#define TLSEXT_MAXLEN_supplemental_data 1024*16 /* Let's limit to 16k */
+
 const char *SSL_get_servername(const SSL *s, const int type);
 int SSL_get_servername_type(const SSL *s);
 /* SSL_export_keying_material exports a value derived from the master secret,
@@ -360,6 +368,13 @@ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB_ARG, 0, arg)
 #define SSL_CTX_set_tlsext_ticket_key_cb(ssl, cb) \
 SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB,(void (*)(void))cb)
 
+/* Used by clients to process audit proofs. */
+#define SSL_CTX_set_tlsext_authz_server_audit_proof_cb(ctx, cb) \
+SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_TLSEXT_AUTHZ_SERVER_AUDIT_PROOF_CB,(void (*)(void))cb)
+
+#define SSL_CTX_set_tlsext_authz_server_audit_proof_cb_arg(ctx, arg) \
+SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TLSEXT_AUTHZ_SERVER_AUDIT_PROOF_CB_ARG, 0, arg);
+
 #ifndef OPENSSL_NO_HEARTBEATS
 #define SSL_TLSEXT_HB_ENABLED				0x01
 #define SSL_TLSEXT_HB_DONT_SEND_REQUESTS	0x02
-- 
2.25.1