Adds no new files, and I've seen it before..

ok beck@ - get it in and we'll sort  it out in tree if anything further is
needed.


On Wed, Jul 27, 2016 at 10:59 AM, Joel Sing <j...@sing.id.au> wrote:

> The following diff adds ALPN support to libtls via:
>
> tls_config_set_alpn() - set the ALPN protocols supported by this
> client/server
> tls_conn_alpn_selected() - get the ALPN protocol selected for this
> connection
>
> ok?
>
> Index: tls.c
> ===================================================================
> RCS file: /cvs/src/lib/libtls/tls.c,v
> retrieving revision 1.41
> diff -u -p -r1.41 tls.c
> --- tls.c       7 Jul 2016 14:09:03 -0000       1.41
> +++ tls.c       27 Jul 2016 16:57:06 -0000
> @@ -310,6 +310,14 @@ tls_configure_ssl(struct tls *ctx)
>         if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_2) == 0)
>                 SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1_2);
>
> +       if (ctx->config->alpn != NULL) {
> +               if (SSL_CTX_set_alpn_protos(ctx->ssl_ctx,
> ctx->config->alpn,
> +                   ctx->config->alpn_len) != 0) {
> +                       tls_set_errorx(ctx, "failed to set alpn");
> +                       goto err;
> +               }
> +       }
> +
>         if (ctx->config->ciphers != NULL) {
>                 if (SSL_CTX_set_cipher_list(ctx->ssl_ctx,
>                     ctx->config->ciphers) != 1) {
> Index: tls.h
> ===================================================================
> RCS file: /cvs/src/lib/libtls/tls.h,v
> retrieving revision 1.29
> diff -u -p -r1.29 tls.h
> --- tls.h       27 May 2016 14:21:24 -0000      1.29
> +++ tls.h       27 Jul 2016 16:57:06 -0000
> @@ -52,6 +52,7 @@ const char *tls_error(struct tls *_ctx);
>  struct tls_config *tls_config_new(void);
>  void tls_config_free(struct tls_config *_config);
>
> +int tls_config_set_alpn(struct tls_config *_config, const char *_alpn);
>  int tls_config_set_ca_file(struct tls_config *_config, const char
> *_ca_file);
>  int tls_config_set_ca_path(struct tls_config *_config, const char
> *_ca_path);
>  int tls_config_set_ca_mem(struct tls_config *_config, const uint8_t *_ca,
> @@ -116,8 +117,9 @@ const char *tls_peer_cert_subject(struct
>  time_t tls_peer_cert_notbefore(struct tls *_ctx);
>  time_t tls_peer_cert_notafter(struct tls *_ctx);
>
> -const char *tls_conn_version(struct tls *_ctx);
> +const char *tls_conn_alpn_selected(struct tls *_ctx);
>  const char *tls_conn_cipher(struct tls *_ctx);
> +const char *tls_conn_version(struct tls *_ctx);
>
>  uint8_t *tls_load_file(const char *_file, size_t *_len, char *_password);
>
> Index: tls_config.c
> ===================================================================
> RCS file: /cvs/src/lib/libtls/tls_config.c,v
> retrieving revision 1.22
> diff -u -p -r1.22 tls_config.c
> --- tls_config.c        13 Jul 2016 16:30:48 -0000      1.22
> +++ tls_config.c        27 Jul 2016 16:57:06 -0000
> @@ -166,6 +166,7 @@ tls_config_free(struct tls_config *confi
>
>         free(config->error.msg);
>
> +       free(config->alpn);
>         free((char *)config->ca_file);
>         free((char *)config->ca_mem);
>         free((char *)config->ca_path);
> @@ -247,6 +248,72 @@ tls_config_parse_protocols(uint32_t *pro
>         free(s);
>
>         return (0);
> +}
> +
> +static int
> +tls_config_parse_alpn(struct tls_config *config, const char *alpn,
> +    char **alpn_data, size_t *alpn_len)
> +{
> +       size_t buf_len, i, len;
> +       char *buf = NULL;
> +       char *s = NULL;
> +       char *p, *q;
> +
> +       if ((buf_len = strlen(alpn) + 1) > 65535) {
> +               tls_config_set_errorx(config, "alpn too large");
> +               goto err;
> +       }
> +
> +       if ((buf = malloc(buf_len)) == NULL) {
> +               tls_config_set_errorx(config, "out of memory");
> +               goto err;
> +       }
> +
> +       if ((s = strdup(alpn)) == NULL) {
> +               tls_config_set_errorx(config, "out of memory");
> +               goto err;
> +       }
> +
> +       i = 0;
> +       q = s;
> +       while ((p = strsep(&q, ",")) != NULL) {
> +               if ((len = strlen(p)) == 0) {
> +                       tls_config_set_errorx(config,
> +                           "alpn protocol with zero length");
> +                       goto err;
> +               }
> +               if (len > 255) {
> +                       tls_config_set_errorx(config,
> +                           "alpn protocol too long");
> +                       goto err;
> +               }
> +               buf[i++] = len & 0xff;
> +               memcpy(&buf[i], p, len);
> +               i += len;
> +       }
> +
> +       free(s);
> +
> +       *alpn_data = buf;
> +       *alpn_len = buf_len;
> +
> +       return (0);
> +
> + err:
> +       free(buf);
> +       free(s);
> +
> +       *alpn_data = NULL;
> +       *alpn_len = 0;
> +
> +       return (-1);
> +}
> +
> +int
> +tls_config_set_alpn(struct tls_config *config, const char *alpn)
> +{
> +       return tls_config_parse_alpn(config, alpn, &config->alpn,
> +           &config->alpn_len);
>  }
>
>  int
> Index: tls_conninfo.c
> ===================================================================
> RCS file: /cvs/src/lib/libtls/tls_conninfo.c,v
> retrieving revision 1.5
> diff -u -p -r1.5 tls_conninfo.c
> --- tls_conninfo.c      7 Oct 2015 23:33:38 -0000       1.5
> +++ tls_conninfo.c      27 Jul 2016 16:57:06 -0000
> @@ -150,6 +150,26 @@ tls_get_peer_cert_times(struct tls *ctx,
>         return (rv);
>  }
>
> +static int
> +tls_conninfo_alpn_proto(struct tls *ctx)
> +{
> +       const unsigned char *p;
> +       unsigned int len;
> +
> +       free(ctx->conninfo->alpn);
> +       ctx->conninfo->alpn = NULL;
> +
> +       SSL_get0_alpn_selected(ctx->ssl_conn, &p, &len);
> +       if (len > 0) {
> +               if ((ctx->conninfo->alpn = malloc(len + 1)) == NULL)
> +                       return (-1);
> +               memcpy(ctx->conninfo->alpn, p, len);
> +               ctx->conninfo->alpn[len] = '\0';
> +       }
> +
> +       return (0);
> +}
> +
>  int
>  tls_get_conninfo(struct tls *ctx) {
>         const char * tmp;
> @@ -175,6 +195,9 @@ tls_get_conninfo(struct tls *ctx) {
>         ctx->conninfo->cipher = strdup(tmp);
>         if (ctx->conninfo->cipher == NULL)
>                 goto err;
> +       if (tls_conninfo_alpn_proto(ctx) == -1)
> +               goto err;
> +
>         return (0);
>  err:
>         tls_free_conninfo(ctx->conninfo);
> @@ -184,6 +207,8 @@ err:
>  void
>  tls_free_conninfo(struct tls_conninfo *conninfo) {
>         if (conninfo != NULL) {
> +               free(conninfo->alpn);
> +               conninfo->alpn = NULL;
>                 free(conninfo->hash);
>                 conninfo->hash = NULL;
>                 free(conninfo->subject);
> @@ -195,6 +220,14 @@ tls_free_conninfo(struct tls_conninfo *c
>                 free(conninfo->cipher);
>                 conninfo->cipher = NULL;
>         }
> +}
> +
> +const char *
> +tls_conn_alpn_selected(struct tls *ctx)
> +{
> +       if (ctx->conninfo == NULL)
> +               return (NULL);
> +       return (ctx->conninfo->alpn);
>  }
>
>  const char *
> Index: tls_init.3
> ===================================================================
> RCS file: /cvs/src/lib/libtls/tls_init.3,v
> retrieving revision 1.62
> diff -u -p -r1.62 tls_init.3
> --- tls_init.3  13 Jul 2016 16:30:48 -0000      1.62
> +++ tls_init.3  27 Jul 2016 16:57:06 -0000
> @@ -24,6 +24,7 @@
>  .Nm tls_config_new ,
>  .Nm tls_config_free ,
>  .Nm tls_config_parse_protocols ,
> +.Nm tls_config_set_alpn ,
>  .Nm tls_config_set_ca_file ,
>  .Nm tls_config_set_ca_path ,
>  .Nm tls_config_set_ca_mem ,
> @@ -54,8 +55,9 @@
>  .Nm tls_peer_cert_hash ,
>  .Nm tls_peer_cert_notbefore ,
>  .Nm tls_peer_cert_notafter ,
> -.Nm tls_conn_version ,
> +.Nm tls_conn_alpn_selected ,
>  .Nm tls_conn_cipher ,
> +.Nm tls_conn_version ,
>  .Nm tls_load_file ,
>  .Nm tls_client ,
>  .Nm tls_server ,
> @@ -88,6 +90,8 @@
>  .Ft "int"
>  .Fn tls_config_parse_protocols "uint32_t *protocols" "const char
> *protostr"
>  .Ft "int"
> +.Fn tls_config_set_alpn "struct tls_config *config" "const char *alpn"
> +.Ft "int"
>  .Fn tls_config_set_ca_file "struct tls_config *config" "const char
> *ca_file"
>  .Ft "int"
>  .Fn tls_config_set_ca_path "struct tls_config *config" "const char
> *ca_path"
> @@ -148,9 +152,11 @@
>  .Ft "time_t"
>  .Fn tls_peer_cert_notafter "struct tls *ctx"
>  .Ft "const char *"
> -.Fn tls_conn_version "struct tls *ctx"
> +.Fn tls_conn_alpn_selected "struct tls *ctx"
>  .Ft "const char *"
>  .Fn tls_conn_cipher "struct tls *ctx"
> +.Ft "const char *"
> +.Fn tls_conn_version "struct tls *ctx"
>  .Ft "uint8_t *"
>  .Fn tls_load_file "const char *file" "size_t *len" "char *password"
>  .Ft "struct tls *"
> @@ -295,6 +301,11 @@ The following functions modify a configu
>  Configuration options may apply to only clients or only servers or both.
>  .Bl -bullet -offset four
>  .It
> +.Fn tls_config_set_alpn
> +sets the ALPN protocols that are supported.
> +The alpn string is a comma separated list of protocols, in order of
> preference.
> +.Em (Client and Server)
> +.It
>  .Fn tls_config_set_ca_file
>  sets the filename used to load a file
>  containing the root certificates.
> @@ -480,13 +491,14 @@ the peer certificate from
>  will only succeed after the handshake is complete.
>  .Em (Server and client)
>  .It
> -.Fn tls_conn_version
> -returns a string
> -corresponding to a TLS version negotiated with the peer
> +.Fn tls_conn_alpn_selected
> +returns a string that specifies the ALPN protocol selected for use with
> the peer
>  connected to
>  .Ar ctx .
> -.Fn tls_conn_version
> +If no protocol was selected then NULL is returned.
> +.Fn tls_conn_alpn_selected
>  will only succeed after the handshake is complete.
> +.Em (Server and Client)
>  .It
>  .Fn tls_conn_cipher
>  returns a string
> @@ -496,6 +508,14 @@ connected to
>  .Fn tls_conn_cipher
>  will only succeed after the handshake is complete.
>  .Em (Server and client)
> +.It
> +.Fn tls_conn_version
> +returns a string
> +corresponding to a TLS version negotiated with the peer
> +connected to
> +.Ar ctx .
> +.Fn tls_conn_version
> +will only succeed after the handshake is complete.
>  .It
>  .Fn tls_load_file
>  loads a certificate or key from disk into memory to be loaded with
> Index: tls_internal.h
> ===================================================================
> RCS file: /cvs/src/lib/libtls/tls_internal.h,v
> retrieving revision 1.32
> diff -u -p -r1.32 tls_internal.h
> --- tls_internal.h      13 Jul 2016 16:30:48 -0000      1.32
> +++ tls_internal.h      27 Jul 2016 16:57:06 -0000
> @@ -55,6 +55,8 @@ struct tls_keypair {
>  struct tls_config {
>         struct tls_error error;
>
> +       char *alpn;
> +       size_t alpn_len;
>         const char *ca_file;
>         const char *ca_path;
>         char *ca_mem;
> @@ -73,6 +75,7 @@ struct tls_config {
>  };
>
>  struct tls_conninfo {
> +       char *alpn;
>         char *issuer;
>         char *subject;
>         char *hash;
> @@ -104,6 +107,7 @@ struct tls {
>         SSL *ssl_conn;
>         SSL_CTX *ssl_ctx;
>         X509 *ssl_peer_cert;
> +
>         struct tls_conninfo *conninfo;
>  };
>
> Index: tls_server.c
> ===================================================================
> RCS file: /cvs/src/lib/libtls/tls_server.c,v
> retrieving revision 1.19
> diff -u -p -r1.19 tls_server.c
> --- tls_server.c        28 Apr 2016 17:05:59 -0000      1.19
> +++ tls_server.c        27 Jul 2016 16:57:06 -0000
> @@ -48,6 +48,20 @@ tls_server_conn(struct tls *ctx)
>         return (conn_ctx);
>  }
>
> +static int
> +tls_server_alpn_cb(SSL *ssl, const unsigned char **out, unsigned char
> *outlen,
> +    const unsigned char *in, unsigned int inlen, void *arg)
> +{
> +       struct tls *ctx = arg;
> +
> +       if (SSL_select_next_proto((unsigned char**)out, outlen,
> +           ctx->config->alpn, ctx->config->alpn_len, in, inlen) ==
> +           OPENSSL_NPN_NEGOTIATED)
> +               return (SSL_TLSEXT_ERR_OK);
> +
> +       return (SSL_TLSEXT_ERR_NOACK);
> +}
> +
>  int
>  tls_configure_server(struct tls *ctx)
>  {
> @@ -70,6 +84,10 @@ tls_configure_server(struct tls *ctx)
>                 if (tls_configure_ssl_verify(ctx, verify) == -1)
>                         goto err;
>         }
> +
> +       if (ctx->config->alpn != NULL)
> +               SSL_CTX_set_alpn_select_cb(ctx->ssl_ctx,
> tls_server_alpn_cb,
> +                   ctx);
>
>         if (ctx->config->dheparams == -1)
>                 SSL_CTX_set_dh_auto(ctx->ssl_ctx, 1);
>
>
>
>

Reply via email to