- size_t serverinfo_length,
- unsigned short extension_type,
- const unsigned char **extension_data,
- unsigned short *extension_length)
- {
- *extension_data = NULL;
- *extension_length = 0;
- if (serverinfo == NULL || serverinfo_length == 0)
- return 0;
- for (;;)
- {
- unsigned short type = 0; /* uint16 */
- unsigned short len = 0; /* uint16 */
-
- /* end of serverinfo */
- if (serverinfo_length == 0)
- return -1; /* Extension not found */
-
- /* read 2-byte type field */
- if (serverinfo_length < 2)
- 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 */
- len = (serverinfo[0] << 8) + serverinfo[1];
- serverinfo += 2;
- serverinfo_length -= 2;
-
- if (len > serverinfo_length)
- return 0; /* Error */
-
- if (type == extension_type)
- {
- *extension_data = serverinfo;
- *extension_length = len;
- return 1; /* Success */
- }
-
- serverinfo += len;
- serverinfo_length -= len;
- }
- return 0; /* Error */
- }
-
-static int serverinfo_srv_first_cb(SSL *s, unsigned short ext_type,
- const unsigned char *in,
- unsigned short inlen, int *al,
- void *arg)
- {
- size_t i = 0;
- if (inlen != 0)
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
- //if already in list, error out
- for (i = 0; i < s->s3->serverinfo_client_tlsext_custom_types_count; i++)
- {
- if (s->s3->serverinfo_client_tlsext_custom_types[i] == ext_type)
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
- }
- s->s3->serverinfo_client_tlsext_custom_types_count++;
- s->s3->serverinfo_client_tlsext_custom_types = OPENSSL_realloc(
- s->s3->serverinfo_client_tlsext_custom_types,
- s->s3->serverinfo_client_tlsext_custom_types_count * 2);
- if (s->s3->serverinfo_client_tlsext_custom_types == NULL)
- {
- s->s3->serverinfo_client_tlsext_custom_types_count = 0;
- *al = TLS1_AD_INTERNAL_ERROR;
+ size_t serverinfo_length,
+ unsigned int extension_type,
+ const unsigned char **extension_data,
+ size_t *extension_length)
+{
+ PACKET pkt, data;
+
+ *extension_data = NULL;
+ *extension_length = 0;
+ if (serverinfo == NULL || serverinfo_length == 0)
+ return -1;
+
+ if (!PACKET_buf_init(&pkt, serverinfo, serverinfo_length))
+ return -1;
+
+ for (;;) {
+ unsigned int type = 0;
+ unsigned long context = 0;
+
+ /* end of serverinfo */
+ if (PACKET_remaining(&pkt) == 0)
+ return 0; /* Extension not found */
+
+ if (!PACKET_get_net_4(&pkt, &context)
+ || !PACKET_get_net_2(&pkt, &type)
+ || !PACKET_get_length_prefixed_2(&pkt, &data))
+ return -1;
+
+ if (type == extension_type) {
+ *extension_data = PACKET_data(&data);
+ *extension_length = PACKET_remaining(&data);;
+ return 1; /* Success */
+ }
+ }
+ /* Unreachable */
+}
+
+static int serverinfoex_srv_parse_cb(SSL *s, unsigned int ext_type,
+ unsigned int context,
+ const unsigned char *in,
+ size_t inlen, X509 *x, size_t chainidx,
+ int *al, void *arg)
+{
+
+ if (inlen != 0) {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ return 1;
+}
+
+static int serverinfo_srv_parse_cb(SSL *s, unsigned int ext_type,
+ const unsigned char *in,
+ size_t inlen, int *al, void *arg)
+{
+ return serverinfoex_srv_parse_cb(s, ext_type, 0, in, inlen, NULL, 0, al,
+ arg);
+}
+
+static int serverinfoex_srv_add_cb(SSL *s, unsigned int ext_type,
+ unsigned int context,
+ const unsigned char **out,
+ size_t *outlen, X509 *x, size_t chainidx,
+ int *al, void *arg)
+{
+ const unsigned char *serverinfo = NULL;
+ size_t serverinfo_length = 0;
+
+ /* We only support extensions for the first Certificate */
+ if ((context & SSL_EXT_TLS1_3_CERTIFICATE) != 0 && chainidx > 0)
+ return 0;
+
+ /* 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 */
+ int retval = serverinfo_find_extension(serverinfo, serverinfo_length,
+ ext_type, out, outlen);
+ if (retval == -1) {
+ *al = SSL_AD_INTERNAL_ERROR;
+ return -1; /* Error */
+ }
+ if (retval == 0)
+ return 0; /* No extension found, don't send extension */
+ return 1; /* Send extension */
+ }
+ return 0; /* No serverinfo data found, don't send
+ * extension */
+}
+
+static int serverinfo_srv_add_cb(SSL *s, unsigned int ext_type,
+ const unsigned char **out, size_t *outlen,
+ int *al, void *arg)
+{
+ return serverinfoex_srv_add_cb(s, ext_type, 0, out, outlen, NULL, 0, al,
+ arg);
+}
+
+/*
+ * 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(unsigned int version,
+ const unsigned char *serverinfo,
+ size_t serverinfo_length, SSL_CTX *ctx)
+{
+ PACKET pkt;
+
+ if (serverinfo == NULL || serverinfo_length == 0)
+ return 0;
+
+ if (version != SSL_SERVERINFOV1 && version != SSL_SERVERINFOV2)
+ return 0;
+
+ if (!PACKET_buf_init(&pkt, serverinfo, serverinfo_length))
+ return 0;
+
+ while (PACKET_remaining(&pkt)) {
+ unsigned long context = 0;
+ unsigned int ext_type = 0;
+ PACKET data;
+
+ if ((version == SSL_SERVERINFOV2 && !PACKET_get_net_4(&pkt, &context))
+ || !PACKET_get_net_2(&pkt, &ext_type)
+ || !PACKET_get_length_prefixed_2(&pkt, &data))
+ return 0;
+
+ if (ctx == NULL)
+ continue;
+
+ /*
+ * The old style custom extensions API could be set separately for
+ * server/client, i.e. you could set one custom extension for a client,
+ * and *for the same extension in the same SSL_CTX* you could set a
+ * custom extension for the server as well. It seems quite weird to be
+ * setting a custom extension for both client and server in a single
+ * SSL_CTX - but theoretically possible. This isn't possible in the
+ * new API. Therefore, if we have V1 serverinfo we use the old API. We
+ * also use the old API even if we have V2 serverinfo but the context
+ * looks like an old style <= TLSv1.2 extension.
+ */
+ if (version == SSL_SERVERINFOV1 || context == SYNTHV1CONTEXT) {
+ if (!SSL_CTX_add_server_custom_ext(ctx, ext_type,
+ serverinfo_srv_add_cb,
+ NULL, NULL,
+ serverinfo_srv_parse_cb,
+ NULL))
+ return 0;
+ } else {
+ if (!SSL_CTX_add_custom_ext(ctx, ext_type, context,
+ serverinfoex_srv_add_cb,
+ NULL, NULL,
+ serverinfoex_srv_parse_cb,
+ NULL))