I forgot to add trac ticket to the commit message, so maybe @cron2
could do it, assuming v2 won't be needed.

Trac ticket with (lots of) context:
https://community.openvpn.net/openvpn/ticket/1259

pe 13. maalisk. 2020 klo 18.59 Lev Stipakov (lstipa...@gmail.com) kirjoitti:
>
> From: Lev Stipakov <l...@openvpn.net>
>
> With NCP and deferred auth, we perform cipher negotiation and
> generate data channel keys on incoming push request, assuming that auth
> succeeded. With async push, when auth succeeds in between push requests,
> we send push reply immediately.
>
> The code which generates data channel keys is only called on handling incoming
> push requests (incoming_push_message). It might not be called with NCP,
> deferred auth and async push because on incoming push request auth might not
> be complete yet. When auth is complete in between push requests, push reply
> is sent and it is assumed that connection is established. However, since data 
> channel keys
> are not generated on the server side, connection doesn't work.
>
> Fix by generating data channel keys when async push is triggered.
>
> Reported-by: smaxfi...@duosecurity.com
> Signed-off-by: Lev Stipakov <l...@openvpn.net>
> ---
>  src/openvpn/init.c  |  6 ++----
>  src/openvpn/multi.c | 24 +++++++++++++++++++++++-
>  src/openvpn/push.c  |  6 ++----
>  src/openvpn/ssl.c   |  6 ++++++
>  src/openvpn/ssl.h   |  5 +++--
>  5 files changed, 36 insertions(+), 11 deletions(-)
>
> diff --git a/src/openvpn/init.c b/src/openvpn/init.c
> index 824b6667..b3096dc8 100644
> --- a/src/openvpn/init.c
> +++ b/src/openvpn/init.c
> @@ -2343,10 +2343,8 @@ do_deferred_options(struct context *c, const unsigned 
> int found)
>          }
>  #endif
>
> -        /* Do not regenerate keys if server sends an extra push reply */
> -        if (!session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized
> -            && !tls_session_update_crypto_params(session, &c->options, 
> &c->c2.frame,
> -                                                 frame_fragment))
> +        if (!tls_session_update_crypto_params(session, &c->options, 
> &c->c2.frame,
> +                                              frame_fragment))
>          {
>              msg(D_TLS_ERRORS, "OPTIONS ERROR: failed to import crypto 
> options");
>              return false;
> diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c
> index da0aeeba..b42bcec9 100644
> --- a/src/openvpn/multi.c
> +++ b/src/openvpn/multi.c
> @@ -2137,8 +2137,30 @@ multi_process_file_closed(struct multi_context *m, 
> const unsigned int mpp_flags)
>          {
>              if (mi)
>              {
> -                /* continue authentication and send push_reply */
> +                /* continue authentication, perform NCP negotiation and send 
> push_reply */
>                  multi_process_post(m, mi, mpp_flags);
> +
> +                /* With NCP and deferred authentication, we perform cipher 
> negotiation and
> +                 * data channel keys generation on incoming push request, 
> assuming that auth
> +                 * succeeded. When auth succeeds in between push requests 
> and async push is used,
> +                 * we send push reply immediately. Above 
> multi_process_post() call performs
> +                 * NCP negotiation and here we do keys generation. */
> +
> +                struct context *c = &mi->context;
> +                struct frame *frame_fragment = NULL;
> +#ifdef ENABLE_FRAGMENT
> +                if (c->options.ce.fragment)
> +                {
> +                    frame_fragment = &c->c2.frame_fragment;
> +                }
> +#endif
> +                struct tls_session *session = 
> &c->c2.tls_multi->session[TM_ACTIVE];
> +                if (!tls_session_update_crypto_params(session, &c->options,
> +                                                      &c->c2.frame, 
> frame_fragment))
> +                {
> +                    msg(D_TLS_ERRORS, "TLS Error: initializing data channel 
> failed");
> +                    register_signal(c, SIGUSR1, "init-data-channel-failed");
> +                }
>              }
>              else
>              {
> diff --git a/src/openvpn/push.c b/src/openvpn/push.c
> index 71f22e94..aef00d34 100644
> --- a/src/openvpn/push.c
> +++ b/src/openvpn/push.c
> @@ -298,10 +298,8 @@ incoming_push_message(struct context *c, const struct 
> buffer *buffer)
>              }
>  #endif
>              struct tls_session *session = 
> &c->c2.tls_multi->session[TM_ACTIVE];
> -            /* Do not regenerate keys if client send a second push request */
> -            if 
> (!session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized
> -                && !tls_session_update_crypto_params(session, &c->options,
> -                                                     &c->c2.frame, 
> frame_fragment))
> +            if (!tls_session_update_crypto_params(session, &c->options,
> +                                                  &c->c2.frame, 
> frame_fragment))
>              {
>                  msg(D_TLS_ERRORS, "TLS Error: initializing data channel 
> failed");
>                  goto error;
> diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
> index e21279f1..56d0576a 100644
> --- a/src/openvpn/ssl.c
> +++ b/src/openvpn/ssl.c
> @@ -1956,6 +1956,12 @@ tls_session_update_crypto_params(struct tls_session 
> *session,
>                                   struct options *options, struct frame 
> *frame,
>                                   struct frame *frame_fragment)
>  {
> +    if (session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized)
> +    {
> +        /* keys already generated, nothing to do */
> +        return true;
> +    }
> +
>      if (!session->opt->server
>          && 0 != strcmp(options->ciphername, session->opt->config_ciphername)
>          && !tls_item_in_cipher_list(options->ciphername, 
> options->ncp_ciphers))
> diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h
> index 3449d91e..f0a8ef54 100644
> --- a/src/openvpn/ssl.h
> +++ b/src/openvpn/ssl.h
> @@ -474,7 +474,8 @@ void tls_update_remote_addr(struct tls_multi *multi,
>
>  /**
>   * Update TLS session crypto parameters (cipher and auth) and derive data
> - * channel keys based on the supplied options.
> + * channel keys based on the supplied options. Does nothing if keys are 
> already
> + * generated.
>   *
>   * @param session         The TLS session to update.
>   * @param options         The options to use when updating session.
> @@ -482,7 +483,7 @@ void tls_update_remote_addr(struct tls_multi *multi,
>   *                        adjusted based on the selected cipher/auth).
>   * @param frame_fragment  The fragment frame options.
>   *
> - * @return true if updating succeeded, false otherwise.
> + * @return true if updating succeeded or keys are already generated, false 
> otherwise.
>   */
>  bool tls_session_update_crypto_params(struct tls_session *session,
>                                        struct options *options,
> --
> 2.17.1
>


-- 
-Lev


_______________________________________________
Openvpn-devel mailing list
Openvpn-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openvpn-devel

Reply via email to