/* end of serverinfo */
if (serverinfo_length == 0)
- return 0;
+ return -1; /* Extension not found */
/* read 2-byte type field */
if (serverinfo_length < 2)
- return 0; /* error */
+ return 0; /* Error */
type = (serverinfo[0] << 8) + serverinfo[1];
serverinfo += 2;
serverinfo_length -= 2;
/* read 2-byte len field */
if (serverinfo_length < 2)
- return 0; /* error */
+ return 0; /* Error */
len = (serverinfo[0] << 8) + serverinfo[1];
serverinfo += 2;
serverinfo_length -= 2;
if (len > serverinfo_length)
- return 0; /* error */
+ return 0; /* Error */
if (type == extension_type)
{
*extension_data = serverinfo;
*extension_length = len;
- return 1;
+ return 1; /* Success */
}
serverinfo += len;
serverinfo_length -= len;
}
- return 0;
+ return 0; /* Error */
}
-static int serverinfo_srv_cb(SSL *s, unsigned short ext_type,
- const unsigned char **out, unsigned short *outlen,
- void *arg)
+static int serverinfo_srv_first_cb(SSL *s, unsigned short ext_type,
+ const unsigned char *in,
+ unsigned short inlen, int *al,
+ void *arg)
+ {
+ if (inlen != 0)
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ return 1;
+ }
+
+static int serverinfo_srv_second_cb(SSL *s, unsigned short ext_type,
+ const unsigned char **out, unsigned short *outlen,
+ void *arg)
{
const unsigned char *serverinfo = NULL;
size_t serverinfo_length = 0;
- /* Is there a serverinfo for the chosen server cert? */
+ /* Is there serverinfo data for the chosen server cert? */
if ((ssl_get_server_cert_serverinfo(s, &serverinfo,
&serverinfo_length)) != 0)
{
/* Find the relevant extension from the serverinfo */
- serverinfo_find_extension(serverinfo, serverinfo_length,
- ext_type, out, outlen);
- }
- return 1;
+ int retval = serverinfo_find_extension(serverinfo, serverinfo_length,
+ ext_type, out, outlen);
+ if (retval == 0)
+ return 0; /* Error */
+ if (retval == -1)
+ return -1; /* No extension found, don't send extension */
+ return 1; /* Send extension */
+ }
+ return -1; /* No serverinfo data found, don't send extension */
}
-static int serverinfo_validate(const unsigned char *serverinfo,
- size_t serverinfo_length, SSL_CTX *ctx)
+/* With a NULL context, this function just checks that the serverinfo data
+ parses correctly. With a non-NULL context, it registers callbacks for
+ the included extensions. */
+static int serverinfo_process_buffer(const unsigned char *serverinfo,
+ size_t serverinfo_length, SSL_CTX *ctx)
{
if (serverinfo == NULL || serverinfo_length == 0)
return 0;
/* Register callbacks for extensions */
ext_type = (serverinfo[0] << 8) + serverinfo[1];
- if (ctx && !SSL_CTX_set_custom_srv_ext(ctx, ext_type, NULL,
- serverinfo_srv_cb, NULL))
+ if (ctx && !SSL_CTX_set_custom_srv_ext(ctx, ext_type,
+ serverinfo_srv_first_cb,
+ serverinfo_srv_second_cb, NULL))
return 0;
serverinfo += 2;
SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO,ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
- if (!serverinfo_validate(serverinfo, serverinfo_length, NULL))
+ if (!serverinfo_process_buffer(serverinfo, serverinfo_length, NULL))
{
SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO,SSL_R_INVALID_SERVERINFO_DATA);
return(0);
/* Now that the serverinfo is validated and stored, go ahead and
* register callbacks. */
- if (!serverinfo_validate(serverinfo, serverinfo_length, ctx))
+ if (!serverinfo_process_buffer(serverinfo, serverinfo_length, ctx))
{
SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO,SSL_R_INVALID_SERVERINFO_DATA);
return(0);
#endif
#define SCT_EXT_TYPE 18
+
+/* WARNING : below extension types are *NOT* IETF assigned, and
+ could conflict if these types are reassigned and handled
+ specially by OpenSSL in the future */
#define TACK_EXT_TYPE 62208
+#define CUSTOM_EXT_TYPE_0 1000
+#define CUSTOM_EXT_TYPE_1 1001
+#define CUSTOM_EXT_TYPE_2 1002
+#define CUSTOM_EXT_TYPE_3 1003
+
+const char custom_ext_cli_string[] = "abc";
+const char custom_ext_srv_string[] = "defg";
/* These set from cmdline */
char* serverinfo_file = NULL;
int serverinfo_sct = 0;
int serverinfo_tack = 0;
+
+/* These set based on extension callbacks */
int serverinfo_sct_seen = 0;
int serverinfo_tack_seen = 0;
int serverinfo_other_seen = 0;
+/* This set from cmdline */
+int custom_ext = 0;
+
+/* This set based on extension callbacks */
+int custom_ext_error = 0;
+
static int serverinfo_cli_cb(SSL* s, unsigned short ext_type,
- const unsigned char* in, unsigned short inlen,
- int* al, void* arg)
+ const unsigned char* in, unsigned short inlen,
+ int* al, void* arg)
{
- if (ext_type == SCT_EXT_TYPE)
- serverinfo_sct_seen++;
- else if (ext_type == TACK_EXT_TYPE)
- serverinfo_tack_seen++;
- else
- serverinfo_other_seen++;
- return 1;
+ if (ext_type == SCT_EXT_TYPE)
+ serverinfo_sct_seen++;
+ else if (ext_type == TACK_EXT_TYPE)
+ serverinfo_tack_seen++;
+ else
+ serverinfo_other_seen++;
+ return 1;
}
static int verify_serverinfo()
return 0;
}
+/* Four test cases for custom extensions:
+ * 0 - no ClientHello extension or ServerHello response
+ * 1 - ClientHello with "abc", no response
+ * 2 - ClientHello with "abc", empty response
+ * 3 - ClientHello with "abc", "defg" response
+ */
+
+static int custom_ext_0_cli_first_cb(SSL *s, unsigned short ext_type,
+ const unsigned char **out,
+ unsigned short *outlen, void *arg)
+ {
+ if (ext_type != CUSTOM_EXT_TYPE_0)
+ custom_ext_error = 1;
+ return -1; /* Don't send an extension */
+ }
+
+static int custom_ext_0_cli_second_cb(SSL *s, unsigned short ext_type,
+ const unsigned char *in,
+ unsigned short inlen, int *al,
+ void *arg)
+ {
+ custom_ext_error = 1; /* Shouldn't be called */
+ return 0;
+ }
+
+static int custom_ext_1_cli_first_cb(SSL *s, unsigned short ext_type,
+ const unsigned char **out,
+ unsigned short *outlen, void *arg)
+ {
+ if (ext_type != CUSTOM_EXT_TYPE_1)
+ custom_ext_error = 1;
+ *out = (const unsigned char*)custom_ext_cli_string;
+ *outlen = strlen(custom_ext_cli_string);
+ return 1; /* Send "abc" */
+ }
+
+static int custom_ext_1_cli_second_cb(SSL *s, unsigned short ext_type,
+ const unsigned char *in,
+ unsigned short inlen, int *al,
+ void *arg)
+ {
+ custom_ext_error = 1; /* Shouldn't be called */
+ return 0;
+ }
+
+static int custom_ext_2_cli_first_cb(SSL *s, unsigned short ext_type,
+ const unsigned char **out,
+ unsigned short *outlen, void *arg)
+ {
+ if (ext_type != CUSTOM_EXT_TYPE_2)
+ custom_ext_error = 1;
+ *out = (const unsigned char*)custom_ext_cli_string;
+ *outlen = strlen(custom_ext_cli_string);
+ return 1; /* Send "abc" */
+ }
+
+static int custom_ext_2_cli_second_cb(SSL *s, unsigned short ext_type,
+ const unsigned char *in,
+ unsigned short inlen, int *al,
+ void *arg)
+ {
+ if (ext_type != CUSTOM_EXT_TYPE_2)
+ custom_ext_error = 1;
+ if (inlen != 0)
+ custom_ext_error = 1; /* Should be empty response */
+ return 1;
+ }
+
+static int custom_ext_3_cli_first_cb(SSL *s, unsigned short ext_type,
+ const unsigned char **out,
+ unsigned short *outlen, void *arg)
+ {
+ if (ext_type != CUSTOM_EXT_TYPE_3)
+ custom_ext_error = 1;
+ *out = (const unsigned char*)custom_ext_cli_string;
+ *outlen = strlen(custom_ext_cli_string);
+ return 1; /* Send "abc" */
+ }
+
+static int custom_ext_3_cli_second_cb(SSL *s, unsigned short ext_type,
+ const unsigned char *in,
+ unsigned short inlen, int *al,
+ void *arg)
+ {
+ if (ext_type != CUSTOM_EXT_TYPE_3)
+ custom_ext_error = 1;
+ if (inlen != strlen(custom_ext_srv_string))
+ custom_ext_error = 1;
+ if (memcmp(custom_ext_srv_string, in, inlen) != 0)
+ custom_ext_error = 1; /* Check for "defg" */
+ return 1;
+ }
+
+
+static int custom_ext_0_srv_first_cb(SSL *s, unsigned short ext_type,
+ const unsigned char *in,
+ unsigned short inlen, int *al,
+ void *arg)
+ {
+ custom_ext_error = 1;
+ return 0; /* Shouldn't be called */
+ }
+
+static int custom_ext_0_srv_second_cb(SSL *s, unsigned short ext_type,
+ const unsigned char **out,
+ unsigned short *outlen, void *arg)
+ {
+ custom_ext_error = 1;
+ return 0; /* Shouldn't be called */
+ }
+
+static int custom_ext_1_srv_first_cb(SSL *s, unsigned short ext_type,
+ const unsigned char *in,
+ unsigned short inlen, int *al,
+ void *arg)
+ {
+ if (ext_type != CUSTOM_EXT_TYPE_1)
+ custom_ext_error = 1;
+ /* Check for "abc" */
+ if (inlen != strlen(custom_ext_cli_string))
+ custom_ext_error = 1;
+ if (memcmp(in, custom_ext_cli_string, inlen) != 0)
+ custom_ext_error = 1;
+ return 1;
+ }
+
+static int custom_ext_1_srv_second_cb(SSL *s, unsigned short ext_type,
+ const unsigned char **out,
+ unsigned short *outlen, void *arg)
+ {
+ return -1; /* Don't send an extension */
+ }
+
+static int custom_ext_2_srv_first_cb(SSL *s, unsigned short ext_type,
+ const unsigned char *in,
+ unsigned short inlen, int *al,
+ void *arg)
+ {
+ if (ext_type != CUSTOM_EXT_TYPE_2)
+ custom_ext_error = 1;
+ /* Check for "abc" */
+ if (inlen != strlen(custom_ext_cli_string))
+ custom_ext_error = 1;
+ if (memcmp(in, custom_ext_cli_string, inlen) != 0)
+ custom_ext_error = 1;
+ return 1;
+ }
+
+static int custom_ext_2_srv_second_cb(SSL *s, unsigned short ext_type,
+ const unsigned char **out,
+ unsigned short *outlen, void *arg)
+ {
+ *out = NULL;
+ *outlen = 0;
+ return 1; /* Send empty extension */
+ }
+
+static int custom_ext_3_srv_first_cb(SSL *s, unsigned short ext_type,
+ const unsigned char *in,
+ unsigned short inlen, int *al,
+ void *arg)
+ {
+ if (ext_type != CUSTOM_EXT_TYPE_3)
+ custom_ext_error = 1;
+ /* Check for "abc" */
+ if (inlen != strlen(custom_ext_cli_string))
+ custom_ext_error = 1;
+ if (memcmp(in, custom_ext_cli_string, inlen) != 0)
+ custom_ext_error = 1;
+ return 1;
+ }
+
+static int custom_ext_3_srv_second_cb(SSL *s, unsigned short ext_type,
+ const unsigned char **out,
+ unsigned short *outlen, void *arg)
+ {
+ *out = (const unsigned char*)custom_ext_srv_string;
+ *outlen = strlen(custom_ext_srv_string);
+ return 1; /* Send "defg" */
+ }
+
+
static char *cipher=NULL;
static int verbose=0;
static int debug=0;
fprintf(stderr," -npn_server - have server side offer NPN\n");
fprintf(stderr," -npn_server_reject - have server reject NPN\n");
#endif
- fprintf(stderr," -serverinfo_file - have server use this file\n");
+ fprintf(stderr," -serverinfo_file file - have server use this file\n");
fprintf(stderr," -serverinfo_sct - have client offer and expect SCT\n");
fprintf(stderr," -serverinfo_tack - have client offer and expect TACK\n");
+ fprintf(stderr," -custom_ext - try various custom extension callbacks\n");
}
static void print_details(SSL *c_ssl, const char *prefix)
if (--argc < 1) goto bad;
serverinfo_file = *(++argv);
}
+ else if (strcmp(*argv,"-custom_ext") == 0)
+ {
+ custom_ext = 1;
+ }
else
{
fprintf(stderr,"unknown option %s\n",*argv);
#endif
if (serverinfo_sct)
- SSL_CTX_set_custom_cli_ext(c_ctx, SCT_EXT_TYPE, NULL, serverinfo_cli_cb, NULL);
+ SSL_CTX_set_custom_cli_ext(c_ctx, SCT_EXT_TYPE, NULL,
+ serverinfo_cli_cb, NULL);
if (serverinfo_tack)
- SSL_CTX_set_custom_cli_ext(c_ctx, TACK_EXT_TYPE, NULL, serverinfo_cli_cb, NULL);
+ SSL_CTX_set_custom_cli_ext(c_ctx, TACK_EXT_TYPE, NULL,
+ serverinfo_cli_cb, NULL);
if (serverinfo_file)
if (!SSL_CTX_use_serverinfo_file(s_ctx, serverinfo_file))
goto end;
}
+ if (custom_ext)
+ {
+ SSL_CTX_set_custom_cli_ext(c_ctx, CUSTOM_EXT_TYPE_0,
+ custom_ext_0_cli_first_cb,
+ custom_ext_0_cli_second_cb, NULL);
+ SSL_CTX_set_custom_cli_ext(c_ctx, CUSTOM_EXT_TYPE_1,
+ custom_ext_1_cli_first_cb,
+ custom_ext_1_cli_second_cb, NULL);
+ SSL_CTX_set_custom_cli_ext(c_ctx, CUSTOM_EXT_TYPE_2,
+ custom_ext_2_cli_first_cb,
+ custom_ext_2_cli_second_cb, NULL);
+ SSL_CTX_set_custom_cli_ext(c_ctx, CUSTOM_EXT_TYPE_3,
+ custom_ext_3_cli_first_cb,
+ custom_ext_3_cli_second_cb, NULL);
+
+
+ SSL_CTX_set_custom_srv_ext(s_ctx, CUSTOM_EXT_TYPE_0,
+ custom_ext_0_srv_first_cb,
+ custom_ext_0_srv_second_cb, NULL);
+ SSL_CTX_set_custom_srv_ext(s_ctx, CUSTOM_EXT_TYPE_1,
+ custom_ext_1_srv_first_cb,
+ custom_ext_1_srv_second_cb, NULL);
+ SSL_CTX_set_custom_srv_ext(s_ctx, CUSTOM_EXT_TYPE_2,
+ custom_ext_2_srv_first_cb,
+ custom_ext_2_srv_second_cb, NULL);
+ SSL_CTX_set_custom_srv_ext(s_ctx, CUSTOM_EXT_TYPE_3,
+ custom_ext_3_srv_first_cb,
+ custom_ext_3_srv_second_cb, NULL);
+ }
+
c_ssl=SSL_new(c_ctx);
s_ssl=SSL_new(s_ctx);
goto err;
}
+ if (custom_ext_error)
+ {
+ ret = 1;
+ goto err;
+ }
+
end:
ret = 0;
ret = 1;
goto err;
}
+ if (custom_ext_error)
+ {
+ ret = 1;
+ goto err;
+ }
ret=0;
err:
/* We have to set the BIO's to NULL otherwise they will be