Commit a398f821 authored by Trevor's avatar Trevor Committed by Ben Laurie
Browse files

Add support for arbitrary TLS extensions.

Contributed by Trevor Perrin.
parent 6d84daa5
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -4,6 +4,9 @@

 Changes between 1.0.x and 1.1.0  [xx XXX xxxx]

  *) Add callbacks for arbitrary TLS extensions.
     [Trevor Perrin <trevp@trevp.net> and Ben Laurie]

  *) Support for DTLS 1.2. This adds two sets of DTLS methods: DTLS_*_method()
     supports both DTLS 1.2 and 1.0 and should use whatever version the peer
     supports and DTLSv1_2_*_method() which supports DTLS 1.2 only.
+62 −0
Original line number Diff line number Diff line
@@ -365,6 +365,9 @@ static void sc_usage(void)
# ifndef OPENSSL_NO_NEXTPROTONEG
	BIO_printf(bio_err," -nextprotoneg arg - enable NPN extension, considering named protocols supported (comma-separated list)\n");
# endif
#ifndef OPENSSL_NO_TLSEXT
	BIO_printf(bio_err," -serverinfo types - send empty ClientHello extensions (comma-separated numbers)\n");
#endif
#endif
	BIO_printf(bio_err," -legacy_renegotiation - enable use of legacy renegotiation (dangerous)\n");
	BIO_printf(bio_err," -use_srtp profiles - Offer SRTP key management with a colon-separated profile list\n");
@@ -542,6 +545,26 @@ static int next_proto_cb(SSL *s, unsigned char **out, unsigned char *outlen, con
	return SSL_TLSEXT_ERR_OK;
	}
# endif  /* ndef OPENSSL_NO_NEXTPROTONEG */

static int serverinfo_cli_cb(SSL* s, unsigned short ext_type,
			     const unsigned char* in, unsigned short inlen, 
			     int* al, void* arg)
	{
	char pem_name[100];
	unsigned char ext_buf[4 + 65536];

	/* Reconstruct the type/len fields prior to extension data */
	ext_buf[0] = ext_type >> 8;
	ext_buf[1] = ext_type & 0xFF;
	ext_buf[2] = inlen >> 8;
	ext_buf[3] = inlen & 0xFF;
	memcpy(ext_buf+4, in, inlen);

	BIO_snprintf(pem_name, sizeof(pem_name), "SERVER_INFO %d", ext_type);
	PEM_write_bio(bio_c_out, pem_name, "", ext_buf, 4 + inlen);
	return 1;
	}

#endif

enum
@@ -614,6 +637,9 @@ int MAIN(int argc, char **argv)
# ifndef OPENSSL_NO_NEXTPROTONEG
	const char *next_proto_neg_in = NULL;
# endif
# define MAX_SI_TYPES 100
	unsigned short serverinfo_types[MAX_SI_TYPES];
	int serverinfo_types_count = 0;
#endif
	char *sess_in = NULL;
	char *sess_out = NULL;
@@ -968,6 +994,29 @@ static char *jpake_secret = NULL;
			next_proto_neg_in = *(++argv);
			}
# endif
		else if (strcmp(*argv,"-serverinfo") == 0)
			{
			char *c;
			int start = 0;
			int len;

			if (--argc < 1) goto bad;
			c = *(++argv);
			serverinfo_types_count = 0;
			len = strlen(c);
			for (i = 0; i <= len; ++i)
				{
				if (i == len || c[i] == ',')
					{
					serverinfo_types[serverinfo_types_count]
					    = atoi(c+start);
					serverinfo_types_count++;
					start = i+1;
					}
				if (serverinfo_types_count == MAX_SI_TYPES)
					break;
				}
			}
#endif
#ifdef FIONBIO
		else if (strcmp(*argv,"-nbio") == 0)
@@ -1261,6 +1310,19 @@ bad:
	if (next_proto.data)
		SSL_CTX_set_next_proto_select_cb(ctx, next_proto_cb, &next_proto);
#endif
#ifndef OPENSSL_NO_TLSEXT
		if (serverinfo_types_count)
			{
			for (i = 0; i < serverinfo_types_count; i++)
				{
				SSL_CTX_set_custom_cli_ext(ctx,
							   serverinfo_types[i],
							   NULL, 
							   serverinfo_cli_cb,
							   NULL);
				}
			}
#endif

	if (state) SSL_CTX_set_info_callback(ctx,apps_ssl_info_callback);
#if 0
+15 −0
Original line number Diff line number Diff line
@@ -318,6 +318,8 @@ static int cert_chain = 0;
#ifndef OPENSSL_NO_TLSEXT
static BIO *authz_in = NULL;
static const char *s_authz_file = NULL;
static BIO *serverinfo_in = NULL;
static const char *s_serverinfo_file = NULL;
#endif

#ifndef OPENSSL_NO_PSK
@@ -479,6 +481,9 @@ static void sv_usage(void)
	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");
#ifndef OPENSSL_NO_TLSEXT
	BIO_printf(bio_err," -serverinfo arg - PEM serverinfo file for certificate\n");
#endif
	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" \
@@ -1093,6 +1098,11 @@ int MAIN(int argc, char *argv[])
			if (--argc < 1) goto bad;
			s_authz_file = *(++argv);
			}
		else if	(strcmp(*argv,"-serverinfo") == 0)
			{
			if (--argc < 1) goto bad;
			s_serverinfo_file = *(++argv);
			}
#endif
		else if	(strcmp(*argv,"-certform") == 0)
			{
@@ -1853,6 +1863,9 @@ bad:
#ifndef OPENSSL_NO_TLSEXT
	if (s_authz_file != NULL && !SSL_CTX_use_authz_file(ctx, s_authz_file))
		goto end;
	if (s_serverinfo_file != NULL
	    && !SSL_CTX_use_serverinfo_file(ctx, s_serverinfo_file))
		goto end;
#endif
#ifndef OPENSSL_NO_TLSEXT
	if (ctx2 && !set_cert_key_stuff(ctx2,s_cert2,s_key2, NULL, build_chain))
@@ -2032,6 +2045,8 @@ end:
		EVP_PKEY_free(s_key2);
	if (authz_in != NULL)
		BIO_free(authz_in);
	if (serverinfo_in != NULL)
		BIO_free(serverinfo_in);
#endif
	ssl_excert_free(exc);
	if (ssl_args)
+8 −0
Original line number Diff line number Diff line
@@ -3026,6 +3026,8 @@ void ssl3_free(SSL *s)
#ifndef OPENSSL_NO_TLSEXT
	if (s->s3->tlsext_authz_client_types != NULL)
		OPENSSL_free(s->s3->tlsext_authz_client_types);
	if (s->s3->tlsext_custom_types != NULL)
		OPENSSL_free(s->s3->tlsext_custom_types);
#endif
	OPENSSL_cleanse(s->s3,sizeof *s->s3);
	OPENSSL_free(s->s3);
@@ -3076,6 +3078,12 @@ void ssl3_clear(SSL *s)
		OPENSSL_free(s->s3->tlsext_authz_client_types);
		s->s3->tlsext_authz_client_types = NULL;
		}
	if (s->s3->tlsext_custom_types != NULL)
		{
		OPENSSL_free(s->s3->tlsext_custom_types);
		s->s3->tlsext_custom_types = NULL;
		}
	s->s3->tlsext_custom_types_count = 0;	
#endif

	rp = s->s3->rbuf.buf;
+94 −0
Original line number Diff line number Diff line
@@ -383,6 +383,56 @@ DECLARE_STACK_OF(SRTP_PROTECTION_PROFILE)
typedef int (*tls_session_ticket_ext_cb_fn)(SSL *s, const unsigned char *data, int len, void *arg);
typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);

#ifndef OPENSSL_NO_TLSEXT
/* Callbacks and structures for handling custom TLS Extensions: 
 *   cli_ext_first_cb  - sends data for ClientHello TLS Extension
 *   cli_ext_second_cb - receives data from ServerHello TLS Extension
 *   srv_ext_first_cb  - receives data from ClientHello TLS Extension
 *   srv_ext_second_cb - sends data for ServerHello TLS Extension
 *
 *   All these functions return nonzero on success.  Zero will terminate
 *   the handshake (and return a specific TLS Fatal alert, if the function
 *   declaration has an "al" parameter).
 * 
 *   "ext_type" is a TLS "ExtensionType" from 0-65535.
 *   "in" is a pointer to TLS "extension_data" being provided to the cb.
 *   "out" is used by the callback to return a pointer to "extension data"
 *     which OpenSSL will later copy into the TLS handshake.  The contents
 *     of this buffer should not be changed until the handshake is complete.
 *   "inlen" and "outlen" are TLS Extension lengths from 0-65535.
 *   "al" is a TLS "AlertDescription" from 0-255 which WILL be sent as a 
 *     fatal TLS alert, if the callback returns zero.
 */
typedef int (*custom_cli_ext_first_cb_fn)(SSL *s, unsigned short ext_type,
					  const unsigned char **out,
					  unsigned short *outlen, void *arg);
typedef int (*custom_cli_ext_second_cb_fn)(SSL *s, unsigned short ext_type,
					   const unsigned char *in,
					   unsigned short inlen, int *al,
					   void *arg); 

typedef int (*custom_srv_ext_first_cb_fn)(SSL *s, unsigned short ext_type,
					  const unsigned char *in,
					  unsigned short inlen, int *al,
					  void *arg);
typedef int (*custom_srv_ext_second_cb_fn)(SSL *s, unsigned short ext_type,
					   const unsigned char **out,
					   unsigned short *outlen, void *arg); 

typedef struct {
	unsigned short ext_type;
	custom_cli_ext_first_cb_fn fn1; 
	custom_cli_ext_second_cb_fn fn2; 
	void *arg;
} custom_cli_ext_record;

typedef struct {
	unsigned short ext_type;
	custom_srv_ext_first_cb_fn fn1; 
	custom_srv_ext_second_cb_fn fn2; 
	void *arg;
} custom_srv_ext_record;
#endif

#ifndef OPENSSL_NO_SSL_INTERN

@@ -1064,6 +1114,12 @@ struct ssl_ctx_st
# endif /* OPENSSL_NO_EC */
	int (*tlsext_authz_server_audit_proof_cb)(SSL *s, void *arg);
	void *tlsext_authz_server_audit_proof_cb_arg;

	/* Arrays containing the callbacks for custom TLS Extensions. */
	custom_cli_ext_record *custom_cli_ext_records;
	size_t custom_cli_ext_records_count;
	custom_srv_ext_record *custom_srv_ext_records;
	size_t custom_srv_ext_records_count;
	};

#endif
@@ -1170,6 +1226,33 @@ const char *SSL_get_psk_identity_hint(const SSL *s);
const char *SSL_get_psk_identity(const SSL *s);
#endif

#ifndef OPENSSL_NO_TLSEXT
/* Register callbacks to handle custom TLS Extensions as client or server.
 * 
 * Returns nonzero on success.  You cannot register twice for the same 
 * extension number, and registering for an extension number already 
 * handled by OpenSSL will succeed, but the callbacks will not be invoked.
 *
 * NULL can be registered for any callback function.  For the client
 * functions, a NULL custom_cli_ext_first_cb_fn sends an empty ClientHello
 * Extension, and a NULL custom_cli_ext_second_cb_fn ignores the ServerHello
 * response (if any).
 *
 * For the server functions, a NULL custom_srv_ext_first_cb_fn means the
 * ClientHello extension's data will be ignored, but the extension will still
 * be noted and custom_srv_ext_second_cb_fn will still be invoked.  If 
 * custom_srv_ext_second_cb_fn is NULL, an empty ServerHello extension is 
 * sent.
 */
int SSL_CTX_set_custom_cli_ext(SSL_CTX *ctx, unsigned short ext_type,
			       custom_cli_ext_first_cb_fn fn1, 
			       custom_cli_ext_second_cb_fn fn2, void *arg);

int SSL_CTX_set_custom_srv_ext(SSL_CTX *ctx, unsigned short ext_type,
			       custom_srv_ext_first_cb_fn fn1, 
			       custom_srv_ext_second_cb_fn fn2, void *arg);
#endif

#define SSL_NOTHING	1
#define SSL_WRITING	2
#define SSL_READING	3
@@ -1934,6 +2017,14 @@ const unsigned char *SSL_CTX_get_authz_data(SSL_CTX *ctx, unsigned char type,
int	SSL_CTX_use_authz_file(SSL_CTX *ctx, const char *file);
int	SSL_use_authz_file(SSL *ssl, const char *file);
#endif

/* Set serverinfo data for the current active cert. */
int	SSL_CTX_use_serverinfo(SSL_CTX *ctx, const unsigned char *serverinfo,
			       size_t serverinfo_length);
#ifndef OPENSSL_NO_STDIO
int	SSL_CTX_use_serverinfo_file(SSL_CTX *ctx, const char *file);
#endif /* NO_STDIO */

#endif

#ifndef OPENSSL_NO_STDIO
@@ -2481,6 +2572,8 @@ void ERR_load_SSL_strings(void);
#define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY			 177
#define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_ASN1		 178
#define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_FILE		 179
#define SSL_F_SSL_CTX_USE_SERVERINFO			 336
#define SSL_F_SSL_CTX_USE_SERVERINFO_FILE		 337
#define SSL_F_SSL_DO_HANDSHAKE				 180
#define SSL_F_SSL_GET_NEW_SESSION			 181
#define SSL_F_SSL_GET_PREV_SESSION			 217
@@ -2655,6 +2748,7 @@ void ERR_load_SSL_strings(void);
#define SSL_R_INVALID_COMPRESSION_ALGORITHM		 341
#define SSL_R_INVALID_NULL_CMD_NAME			 385
#define SSL_R_INVALID_PURPOSE				 278
#define SSL_R_INVALID_SERVERINFO_DATA			 388
#define SSL_R_INVALID_SRP_USERNAME			 357
#define SSL_R_INVALID_STATUS_RESPONSE			 328
#define SSL_R_INVALID_TICKET_KEYS_LENGTH		 325
Loading