Commit 835d104f authored by Ben Laurie's avatar Ben Laurie
Browse files

Rearrange and test authz extension.

parent aeba1ef3
Loading
Loading
Loading
Loading
+1 −32
Original line number Diff line number Diff line
@@ -312,8 +312,6 @@ static int cert_chain = 0;
#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
@@ -1488,33 +1486,6 @@ bad:
			next_proto.data = NULL;
			}
# 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 */
		}

@@ -1811,7 +1782,7 @@ 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))
	if (s_authz_file != NULL && !SSL_CTX_use_authz_file(ctx, s_authz_file))
		goto end;
#endif
#ifndef OPENSSL_NO_TLSEXT
@@ -1998,8 +1969,6 @@ 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
+10 −0
Original line number Diff line number Diff line
@@ -1773,8 +1773,16 @@ 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
/* Set authz data for the current active cert. */
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);
/* Get the authz of type 'type' associated with the current active cert. */
const unsigned char *SSL_CTX_get_authz_data(SSL_CTX *ctx, unsigned char type,
					    size_t *data_length);
#ifndef OPENSSL_NO_STDIO
int	SSL_CTX_use_authz_file(SSL_CTX *ctx, const char *file);
int	SSL_use_authz_file(SSL *ssl, const char *file);
#endif
#endif

#ifndef OPENSSL_NO_STDIO
@@ -2122,6 +2130,7 @@ void ERR_load_SSL_strings(void);
/* Error codes for the SSL functions. */

/* Function codes. */
#define SSL_F_AUTHZ_FIND_DATA				 330
#define SSL_F_AUTHZ_VALIDATE				 323
#define SSL_F_CLIENT_CERTIFICATE			 100
#define SSL_F_CLIENT_FINISHED				 167
@@ -2165,6 +2174,7 @@ void ERR_load_SSL_strings(void);
#define SSL_F_GET_SERVER_HELLO				 109
#define SSL_F_GET_SERVER_VERIFY				 110
#define SSL_F_I2D_SSL_SESSION				 111
#define SSL_F_READ_AUTHZ				 329
#define SSL_F_READ_N					 112
#define SSL_F_REQUEST_CERTIFICATE			 113
#define SSL_F_SERVER_FINISH				 239
+2 −0
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@

static ERR_STRING_DATA SSL_str_functs[]=
	{
{ERR_FUNC(SSL_F_AUTHZ_FIND_DATA),	"AUTHZ_FIND_DATA"},
{ERR_FUNC(SSL_F_AUTHZ_VALIDATE),	"AUTHZ_VALIDATE"},
{ERR_FUNC(SSL_F_CLIENT_CERTIFICATE),	"CLIENT_CERTIFICATE"},
{ERR_FUNC(SSL_F_CLIENT_FINISHED),	"CLIENT_FINISHED"},
@@ -113,6 +114,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
{ERR_FUNC(SSL_F_GET_SERVER_HELLO),	"GET_SERVER_HELLO"},
{ERR_FUNC(SSL_F_GET_SERVER_VERIFY),	"GET_SERVER_VERIFY"},
{ERR_FUNC(SSL_F_I2D_SSL_SESSION),	"i2d_SSL_SESSION"},
{ERR_FUNC(SSL_F_READ_AUTHZ),	"READ_AUTHZ"},
{ERR_FUNC(SSL_F_READ_N),	"READ_N"},
{ERR_FUNC(SSL_F_REQUEST_CERTIFICATE),	"REQUEST_CERTIFICATE"},
{ERR_FUNC(SSL_F_SERVER_FINISH),	"SERVER_FINISH"},
+126 −0
Original line number Diff line number Diff line
@@ -855,6 +855,46 @@ static char authz_validate(const unsigned char *authz, size_t length)
		}
	}

static const unsigned char *authz_find_data(const unsigned char *authz,
					    size_t authz_length,
					    unsigned char data_type,
					    size_t *data_length)
	{
	if (authz == NULL) return NULL;
	if (!authz_validate(authz, authz_length))
		{
		SSLerr(SSL_F_AUTHZ_FIND_DATA,SSL_R_INVALID_AUTHZ_DATA);
		return NULL;
		}

	for (;;)
		{
		unsigned char type;
		unsigned short len;
		if (!authz_length)
			return NULL;

		type = *(authz++);
		authz_length--;

		/* We've validated the authz data, so we don't have to
		 * check again that we have enough bytes left. */
		len = ((unsigned short) authz[0]) << 8 |
		      ((unsigned short) authz[1]);
		authz += 2;
		authz_length -= 2;
		if (type == data_type)
			{
			*data_length = len;
			return authz;
			}
		authz += len;
		authz_length -= len;
		}
	/* No match */
	return NULL;
	}

static int ssl_set_authz(CERT *c, unsigned char *authz, size_t authz_length)
	{
	CERT_PKEY *current_key = c->key;
@@ -901,4 +941,90 @@ int SSL_use_authz(SSL *ssl, unsigned char *authz, size_t authz_length)
		}
	return ssl_set_authz(ssl->cert, authz, authz_length);
	}

const unsigned char *SSL_CTX_get_authz_data(SSL_CTX *ctx, unsigned char type,
					    size_t *data_length)
	{
	CERT_PKEY *current_key;

	if (ctx->cert == NULL)
		return NULL;
	current_key = ctx->cert->key;
	if (current_key->authz == NULL)
		return NULL;
	return authz_find_data(current_key->authz,
		current_key->authz_length, type, data_length);
	}

#ifndef OPENSSL_NO_STDIO
/* read_authz returns a newly allocated buffer with authz data */
static unsigned char *read_authz(const char *file, size_t *authz_length)
	{
	BIO *authz_in = NULL;
	unsigned char *authz = NULL;
	/* Allow authzs up to 64KB. */
	static const size_t authz_limit = 65536;
	size_t read_length;
	unsigned char *ret = NULL;

	authz_in = BIO_new(BIO_s_file_internal());
	if (authz_in == NULL)
		{
		SSLerr(SSL_F_READ_AUTHZ,ERR_R_BUF_LIB);
		goto end;
		}

	if (BIO_read_filename(authz_in,file) <= 0)
		{
		SSLerr(SSL_F_READ_AUTHZ,ERR_R_SYS_LIB);
		goto end;
		}

	authz = OPENSSL_malloc(authz_limit);
	read_length = BIO_read(authz_in, authz, authz_limit);
	if (read_length == authz_limit || read_length <= 0)
		{
		SSLerr(SSL_F_READ_AUTHZ,SSL_R_AUTHZ_DATA_TOO_LARGE);
		OPENSSL_free(authz);
		goto end;
		}
	*authz_length = read_length;
	ret = authz;
end:
	if (authz_in != NULL) BIO_free(authz_in);
	return ret;
	}

int SSL_CTX_use_authz_file(SSL_CTX *ctx, const char *file)
	{
	unsigned char *authz = NULL;
	size_t authz_length = 0;
	int ret;

	authz = read_authz(file, &authz_length);
	if (authz == NULL)
		return 0;

	ret = SSL_CTX_use_authz(ctx, authz, authz_length);
	/* SSL_CTX_use_authz makes a local copy of the authz. */
	OPENSSL_free(authz);
	return ret;
	}

int SSL_use_authz_file(SSL *ssl, const char *file)
	{
	unsigned char *authz = NULL;
	size_t authz_length = 0;
	int ret;

	authz = read_authz(file, &authz_length);
	if (authz == NULL)
		return 0;

	ret = SSL_use_authz(ssl, authz, authz_length);
	/* SSL_use_authz makes a local copy of the authz. */
	OPENSSL_free(authz);
	return ret;
	}
#endif /* OPENSSL_NO_STDIO */
#endif /* OPENSSL_NO_TLSEXT */
+119 −0
Original line number Diff line number Diff line
@@ -369,6 +369,11 @@ static void sv_usage(void)
	               "                 (default is sect163r2).\n");
#endif
	fprintf(stderr," -test_cipherlist - verifies the order of the ssl cipher lists\n");
#ifndef OPENSSL_NO_TLSEXT
	fprintf(stderr," -server_authz arg - binary authz file for certificate\n");
	fprintf(stderr," -c_support_proof  - indicate client support for server_authz audit proofs\n");
	fprintf(stderr," -c_require_proof  - fail if no audit proof is sent\n");
#endif
	}

static void print_details(SSL *c_ssl, const char *prefix)
@@ -498,6 +503,56 @@ int opaque_prf_input_cb(SSL *ssl, void *peerinput, size_t len, void *arg_)
	}
#endif

#ifndef OPENSSL_NO_TLSEXT
struct audit_proof_cb_arg_st
	{
	unsigned char *expected_proof;
	size_t expected_proof_length;
	int require;
	};

struct audit_proof_cb_arg_st c_expected = { NULL, 0, 0 };

static int audit_proof_cb(SSL *s, void *arg)
	{
	const unsigned char *proof;
	size_t proof_len;
	SSL_SESSION *sess = SSL_get_session(s);
	struct audit_proof_cb_arg_st *cb_arg = (struct audit_proof_cb_arg_st*)arg;

	proof = SSL_SESSION_get_tlsext_authz_server_audit_proof(sess,
		&proof_len);
	if (proof != NULL)
		{
		if (proof_len == cb_arg->expected_proof_length &&
			cb_arg->expected_proof != NULL &&
			memcmp(proof, cb_arg->expected_proof, proof_len) == 0)
			{
			BIO_printf(bio_stdout, "Audit proof OK (%lu bytes).\n",
				   (long)proof_len);
			return 1;
			}
		else
			{
			BIO_printf(bio_stdout, "Audit proof mismatch.\n");
			/* Cause handshake failure. */
			return 0;
			}
		}

	else /* proof == NULL */
		{
		BIO_printf(bio_stdout, "No audit proof found.\n");
		if (cb_arg->require)
			{
			/* Cause handshake failure. */
			return 0;
			}
		return 1;
		}
	}
#endif

int main(int argc, char *argv[])
	{
	char *CApath=NULL,*CAfile=NULL;
@@ -549,6 +604,11 @@ int main(int argc, char *argv[])
#ifdef OPENSSL_FIPS
	int fips_mode=0;
#endif
#ifndef OPENSSL_NO_TLSEXT
	char *s_authz_file = NULL;
	int c_support_proof = 0;
	int c_require_proof = 0;
#endif

	verbose = 0;
	debug = 0;
@@ -765,6 +825,24 @@ int main(int argc, char *argv[])
			{
			test_cipherlist = 1;
			}
#ifndef OPENSSL_NO_TLSEXT
		else if(strcmp(*argv,"-server_authz") == 0)
			{
			if (--argc < 1) goto bad;
			s_authz_file = *(++argv);
			tls1 = 1;
			}
		else if (strcmp(*argv,"-c_support_proof") == 0)
			{
			c_support_proof = 1;
			tls1 = 1;
			}
		else if (strcmp(*argv,"-c_require_proof") == 0)
			{
			c_require_proof = 1;
			tls1 = 1;
			}
#endif
		else
			{
			fprintf(stderr,"unknown option %s\n",*argv);
@@ -798,6 +876,15 @@ bad:
			"to avoid protocol mismatch.\n");
		EXIT(1);
		}
	if (c_require_proof && s_authz_file == NULL && !force)
		{
		fprintf(stderr, "This case cannot work. -c_require_proof "
			"requires an audit proof, but none was supplied. "
			"Use -f to perform the test anyway (and\n-d to see "
			"what happens), or use -server_authz to supply an "
			"audit proof.\n");
		EXIT(1);
		}

#ifdef OPENSSL_FIPS
	if(fips_mode)
@@ -1063,6 +1150,34 @@ bad:
		SSL_CTX_set_srp_username_callback(s_ctx, ssl_srp_server_param_cb);
		}
#endif
#ifndef OPENSSL_NO_TLSEXT
	if (s_authz_file != NULL)
		{
		if(!SSL_CTX_use_authz_file(s_ctx, s_authz_file))
			{
			BIO_printf(bio_err, "Unable to set authz data\n");
			goto end;
			}
		}
	if (c_support_proof || c_require_proof)
		{
		size_t proof_length;
		const unsigned char *proof = SSL_CTX_get_authz_data(s_ctx,
			TLSEXT_AUTHZDATAFORMAT_audit_proof, &proof_length);
		if (proof != NULL)
			{
			/* Store a local copy. */
			c_expected.expected_proof = OPENSSL_malloc(proof_length);
			c_expected.expected_proof_length = proof_length;
			memcpy(c_expected.expected_proof, proof, proof_length);
			}
		c_expected.require = c_require_proof;
		SSL_CTX_set_tlsext_authz_server_audit_proof_cb(c_ctx,
			audit_proof_cb);
		SSL_CTX_set_tlsext_authz_server_audit_proof_cb_arg(c_ctx,
			&c_expected);
		}
#endif

	c_ssl=SSL_new(c_ctx);
	s_ssl=SSL_new(s_ctx);
@@ -1137,6 +1252,10 @@ end:
#endif
#ifndef OPENSSL_NO_ENGINE
	ENGINE_cleanup();
#endif
#ifndef OPENSSL_NO_TLSEXT
	if (c_expected.expected_proof != NULL)
		OPENSSL_free(c_expected.expected_proof);
#endif
	CRYPTO_cleanup_all_ex_data();
	ERR_free_strings();