+
+/* SSL_select_next_proto implements the standard protocol selection. It is
+ * expected that this function is called from the callback set by
+ * SSL_CTX_set_next_proto_select_cb.
+ *
+ * The protocol data is assumed to be a vector of 8-bit, length prefixed byte
+ * strings. The length byte itself is not included in the length. A byte
+ * string of length 0 is invalid. No byte string may be truncated.
+ *
+ * The current, but experimental algorithm for selecting the protocol is:
+ *
+ * 1) If the server doesn't support NPN then this is indicated to the
+ * callback. In this case, the client application has to abort the connection
+ * or have a default application level protocol.
+ *
+ * 2) If the server supports NPN, but advertises an empty list then the
+ * client selects the first protcol in its list, but indicates via the
+ * API that this fallback case was enacted.
+ *
+ * 3) Otherwise, the client finds the first protocol in the server's list
+ * that it supports and selects this protocol. This is because it's
+ * assumed that the server has better information about which protocol
+ * a client should use.
+ *
+ * 4) If the client doesn't support any of the server's advertised
+ * protocols, then this is treated the same as case 2.
+ *
+ * It returns either
+ * OPENSSL_NPN_NEGOTIATED if a common protocol was found, or
+ * OPENSSL_NPN_NO_OVERLAP if the fallback case was reached.
+ */
+int SSL_select_next_proto(unsigned char **out, unsigned char *outlen, const unsigned char *server, unsigned int server_len, const unsigned char *client, unsigned int client_len)
+ {
+ unsigned int i, j;
+ const unsigned char *result;
+ int status = OPENSSL_NPN_UNSUPPORTED;
+
+ /* For each protocol in server preference order, see if we support it. */
+ for (i = 0; i < server_len; )
+ {
+ for (j = 0; j < client_len; )
+ {
+ if (server[i] == client[j] &&
+ memcmp(&server[i+1], &client[j+1], server[i]) == 0)
+ {
+ /* We found a match */
+ result = &server[i];
+ status = OPENSSL_NPN_NEGOTIATED;
+ goto found;
+ }
+ j += client[j];
+ j++;
+ }
+ i += server[i];
+ i++;
+ }
+
+ /* There's no overlap between our protocols and the server's list. */
+ result = client;
+ status = OPENSSL_NPN_NO_OVERLAP;
+
+ found:
+ *out = (unsigned char *) result + 1;
+ *outlen = result[0];
+ return status;
+ }
+
+# ifndef OPENSSL_NO_NEXTPROTONEG
+/* SSL_get0_next_proto_negotiated sets *data and *len to point to the client's
+ * requested protocol for this connection and returns 0. If the client didn't
+ * request any protocol, then *data is set to NULL.
+ *
+ * Note that the client can request any protocol it chooses. The value returned
+ * from this function need not be a member of the list of supported protocols
+ * provided by the callback.
+ */
+void SSL_get0_next_proto_negotiated(const SSL *s, const unsigned char **data, unsigned *len)
+ {
+ *data = s->next_proto_negotiated;
+ if (!*data) {
+ *len = 0;
+ } else {
+ *len = s->next_proto_negotiated_len;
+ }
+}
+
+/* SSL_CTX_set_next_protos_advertised_cb sets a callback that is called when a
+ * TLS server needs a list of supported protocols for Next Protocol
+ * Negotiation. The returned list must be in wire format. The list is returned
+ * by setting |out| to point to it and |outlen| to its length. This memory will
+ * not be modified, but one should assume that the SSL* keeps a reference to
+ * it.
+ *
+ * The callback should return SSL_TLSEXT_ERR_OK if it wishes to advertise. Otherwise, no
+ * such extension will be included in the ServerHello. */
+void SSL_CTX_set_next_protos_advertised_cb(SSL_CTX *ctx, int (*cb) (SSL *ssl, const unsigned char **out, unsigned int *outlen, void *arg), void *arg)
+ {
+ ctx->next_protos_advertised_cb = cb;
+ ctx->next_protos_advertised_cb_arg = arg;
+ }
+
+/* SSL_CTX_set_next_proto_select_cb sets a callback that is called when a
+ * client needs to select a protocol from the server's provided list. |out|
+ * must be set to point to the selected protocol (which may be within |in|).
+ * The length of the protocol name must be written into |outlen|. The server's
+ * advertised protocols are provided in |in| and |inlen|. The callback can
+ * assume that |in| is syntactically valid.
+ *
+ * The client must select a protocol. It is fatal to the connection if this
+ * callback returns a value other than SSL_TLSEXT_ERR_OK.
+ */
+void SSL_CTX_set_next_proto_select_cb(SSL_CTX *ctx, int (*cb) (SSL *s, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg), void *arg)
+ {
+ ctx->next_proto_select_cb = cb;
+ ctx->next_proto_select_cb_arg = arg;
+ }
+# endif
+
+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)
+ {
+ size_t i;
+ custom_cli_ext_record* record;
+
+ /* Check for duplicates */
+ for (i=0; i < ctx->custom_cli_ext_records_count; i++)
+ if (ext_type == ctx->custom_cli_ext_records[i].ext_type)
+ return 0;
+
+ ctx->custom_cli_ext_records = OPENSSL_realloc(ctx->custom_cli_ext_records,
+ (ctx->custom_cli_ext_records_count + 1) *
+ sizeof(custom_cli_ext_record));
+ if (!ctx->custom_cli_ext_records) {
+ ctx->custom_cli_ext_records_count = 0;
+ return 0;
+ }
+ ctx->custom_cli_ext_records_count++;
+ record = &ctx->custom_cli_ext_records[ctx->custom_cli_ext_records_count - 1];
+ record->ext_type = ext_type;
+ record->fn1 = fn1;
+ record->fn2 = fn2;
+ record->arg = arg;
+ return 1;
+ }
+
+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)
+ {
+ size_t i;
+ custom_srv_ext_record* record;
+
+ /* Check for duplicates */
+ for (i=0; i < ctx->custom_srv_ext_records_count; i++)
+ if (ext_type == ctx->custom_srv_ext_records[i].ext_type)
+ return 0;
+
+ ctx->custom_srv_ext_records = OPENSSL_realloc(ctx->custom_srv_ext_records,
+ (ctx->custom_srv_ext_records_count + 1) *
+ sizeof(custom_srv_ext_record));
+ if (!ctx->custom_srv_ext_records) {
+ ctx->custom_srv_ext_records_count = 0;
+ return 0;
+ }
+ ctx->custom_srv_ext_records_count++;
+ record = &ctx->custom_srv_ext_records[ctx->custom_srv_ext_records_count - 1];
+ record->ext_type = ext_type;
+ record->fn1 = fn1;
+ record->fn2 = fn2;
+ record->arg = arg;
+ return 1;
+ }
+
+/* SSL_CTX_set_alpn_protos sets the ALPN protocol list on |ctx| to |protos|.
+ * |protos| must be in wire-format (i.e. a series of non-empty, 8-bit
+ * length-prefixed strings).
+ *
+ * Returns 0 on success. */
+int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const unsigned char* protos,
+ unsigned protos_len)
+ {
+ if (ctx->alpn_client_proto_list)
+ OPENSSL_free(ctx->alpn_client_proto_list);
+
+ ctx->alpn_client_proto_list = OPENSSL_malloc(protos_len);
+ if (!ctx->alpn_client_proto_list)
+ return 1;
+ memcpy(ctx->alpn_client_proto_list, protos, protos_len);
+ ctx->alpn_client_proto_list_len = protos_len;
+
+ return 0;
+ }
+
+/* SSL_set_alpn_protos sets the ALPN protocol list on |ssl| to |protos|.
+ * |protos| must be in wire-format (i.e. a series of non-empty, 8-bit
+ * length-prefixed strings).
+ *
+ * Returns 0 on success. */
+int SSL_set_alpn_protos(SSL *ssl, const unsigned char* protos,
+ unsigned protos_len)
+ {
+ if (ssl->alpn_client_proto_list)
+ OPENSSL_free(ssl->alpn_client_proto_list);
+
+ ssl->alpn_client_proto_list = OPENSSL_malloc(protos_len);
+ if (!ssl->alpn_client_proto_list)
+ return 1;
+ memcpy(ssl->alpn_client_proto_list, protos, protos_len);
+ ssl->alpn_client_proto_list_len = protos_len;
+
+ return 0;
+ }
+
+/* SSL_CTX_set_alpn_select_cb sets a callback function on |ctx| that is called
+ * during ClientHello processing in order to select an ALPN protocol from the
+ * client's list of offered protocols. */
+void SSL_CTX_set_alpn_select_cb(SSL_CTX* ctx,
+ int (*cb) (SSL *ssl,
+ const unsigned char **out,
+ unsigned char *outlen,
+ const unsigned char *in,
+ unsigned int inlen,
+ void *arg),
+ void *arg)
+ {
+ ctx->alpn_select_cb = cb;
+ ctx->alpn_select_cb_arg = arg;
+ }
+
+/* SSL_get0_alpn_selected gets the selected ALPN protocol (if any) from |ssl|.
+ * On return it sets |*data| to point to |*len| bytes of protocol name (not
+ * including the leading length-prefix byte). If the server didn't respond with
+ * a negotiated protocol then |*len| will be zero. */
+void SSL_get0_alpn_selected(const SSL *ssl, const unsigned char **data,
+ unsigned *len)
+ {
+ *data = NULL;
+ if (ssl->s3)
+ *data = ssl->s3->alpn_selected;
+ if (*data == NULL)
+ *len = 0;
+ else
+ *len = ssl->s3->alpn_selected_len;
+ }
+
+#endif /* !OPENSSL_NO_TLSEXT */
+
+int SSL_export_keying_material(SSL *s, unsigned char *out, size_t olen,
+ const char *label, size_t llen, const unsigned char *p, size_t plen,
+ int use_context)
+ {
+ if (s->version < TLS1_VERSION)
+ return -1;
+
+ return s->method->ssl3_enc->export_keying_material(s, out, olen, label,
+ llen, p, plen,
+ use_context);
+ }