Re: [Openvpn-devel] [PATCH v3] Extend verify-hash to allow multiple hashes

2021-03-21 Thread Antonio Quartulli
Hi,

This patch looks good to me.
There is just one minor note below:

On 21/03/2021 15:25, Arne Schwabe wrote:
> This patch introduces support for verify-hash inlining.
> When inlined, this options now allows to specify multiple fingerprints,
> one per line.
> 
> Since this is a new syntax, there is no backwards compatibility to take
> care of, therefore we can drop support for SHA1. Inlined fingerprints
> are assumed be to SHA-256 only.
> 
> Also print a warning about SHA1 hash being deprecated to verify
> certificates as it is not "industry standard" anymore.
> 
> Patch v2: fix/clarify various comments, fix a few minor problems, allow
>   the option to be specified multiple times and have that
>   added to the list.
> 
> Patch v3: Remove leftover variable, always call
>   parse_hash_fingerprint_multiline, add comments clarifying list
>   appending
> 
> Signed-off-by: Arne Schwabe 
> ---
>  doc/man-sections/inline-files.rst |   4 +-
>  doc/man-sections/tls-options.rst  |  10 +++
>  src/openvpn/options.c | 102 ++
>  src/openvpn/options.h |  10 ++-
>  src/openvpn/ssl_common.h  |   2 +-
>  src/openvpn/ssl_verify.c  |  16 -
>  6 files changed, 127 insertions(+), 17 deletions(-)
> 
> diff --git a/doc/man-sections/inline-files.rst 
> b/doc/man-sections/inline-files.rst
> index 819bd3c8..303bb3c8 100644
> --- a/doc/man-sections/inline-files.rst
> +++ b/doc/man-sections/inline-files.rst
> @@ -4,8 +4,8 @@ INLINE FILE SUPPORT
>  OpenVPN allows including files in the main configuration for the ``--ca``,
>  ``--cert``, ``--dh``, ``--extra-certs``, ``--key``, ``--pkcs12``,
>  ``--secret``, ``--crl-verify``, ``--http-proxy-user-pass``, ``--tls-auth``,
> -``--auth-gen-token-secret``, ``--tls-crypt`` and ``--tls-crypt-v2``
> -options.
> +``--auth-gen-token-secret``, ``--tls-crypt``, ``--tls-crypt-v2`` and
> +``--verify-hash`` options.
>  
>  Each inline file started by the line  and ended by the line
>  
> diff --git a/doc/man-sections/tls-options.rst 
> b/doc/man-sections/tls-options.rst
> index e13fb3c8..d8f9800e 100644
> --- a/doc/man-sections/tls-options.rst
> +++ b/doc/man-sections/tls-options.rst
> @@ -582,6 +582,16 @@ certificates and keys: 
> https://github.com/OpenVPN/easy-rsa
>The ``algo`` flag can be either :code:`SHA1` or :code:`SHA256`. If not
>provided, it defaults to :code:`SHA1`.
>  
> +  This option can also be inlined
> +  ::
> +
> +
> +
> 00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff
> +
> 11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00
> +
> +
> +If the option is inlined, ``algo`` is always :code:`SHA256`.
> +
>  --verify-x509-name args
>Accept connections only if a host's X.509 name is equal to **name.** The
>remote host must also pass all other tests of verification.
> diff --git a/src/openvpn/options.c b/src/openvpn/options.c
> index 86e78b05..3b1c69ba 100644
> --- a/src/openvpn/options.c
> +++ b/src/openvpn/options.c
> @@ -1078,12 +1078,24 @@ string_substitute(const char *src, int from, int to, 
> struct gc_arena *gc)
>  return ret;
>  }
>  
> -static uint8_t *
> +/**
> + * Parses a hexstring and checks if the string has the correct length. Return
> + * a verify_hash_list containing the parsed hash string.
> + *
> + * @param   str String to check/parse
> + * @param   nbytes  Number of bytes expected in the hexstr (e.g. 20 for 
> SHA1)
> + * @param   msglevelmessage level to use when printing warnings/errors
> + * @param   gc  The returned object will be allocated in this gc
> + */
> +static struct verify_hash_list *
>  parse_hash_fingerprint(const char *str, int nbytes, int msglevel, struct 
> gc_arena *gc)
>  {
>  int i;
>  const char *cp = str;
> -uint8_t *ret = (uint8_t *) gc_malloc(nbytes, true, gc);
> +
> +struct verify_hash_list *ret;
> +ALLOC_OBJ_CLEAR_GC(ret, struct verify_hash_list, gc);
> +
>  char term = 1;
>  int byte;
>  char bs[3];
> @@ -1102,7 +1114,7 @@ parse_hash_fingerprint(const char *str, int nbytes, int 
> msglevel, struct gc_aren
>  {
>  msg(msglevel, "format error in hash fingerprint hex byte: %s", 
> str);
>  }
> -ret[i] = (uint8_t)byte;
> +ret->hash[i] = (uint8_t)byte;
>  term = *cp++;
>  if (term != ':' && term != 0)
>  {
> @@ -1116,10 +1128,55 @@ parse_hash_fingerprint(const char *str, int nbytes, 
> int msglevel, struct gc_aren
>  if (term != 0 || i != nbytes-1)
>  {
>  msg(msglevel, "hash fingerprint is different length than expected 
> (%d bytes): %s", nbytes, str);
> +return NULL;

The rest of this function assumes that msglevel is set to a FATAL level.

As you can also see in the hunk above, if blocks handling other errors
have no return statement, because they assume the progra

[Openvpn-devel] [PATCH v3] Extend verify-hash to allow multiple hashes

2021-03-21 Thread Arne Schwabe
This patch introduces support for verify-hash inlining.
When inlined, this options now allows to specify multiple fingerprints,
one per line.

Since this is a new syntax, there is no backwards compatibility to take
care of, therefore we can drop support for SHA1. Inlined fingerprints
are assumed be to SHA-256 only.

Also print a warning about SHA1 hash being deprecated to verify
certificates as it is not "industry standard" anymore.

Patch v2: fix/clarify various comments, fix a few minor problems, allow
  the option to be specified multiple times and have that
  added to the list.

Patch v3: Remove leftover variable, always call
  parse_hash_fingerprint_multiline, add comments clarifying list
  appending

Signed-off-by: Arne Schwabe 
---
 doc/man-sections/inline-files.rst |   4 +-
 doc/man-sections/tls-options.rst  |  10 +++
 src/openvpn/options.c | 102 ++
 src/openvpn/options.h |  10 ++-
 src/openvpn/ssl_common.h  |   2 +-
 src/openvpn/ssl_verify.c  |  16 -
 6 files changed, 127 insertions(+), 17 deletions(-)

diff --git a/doc/man-sections/inline-files.rst 
b/doc/man-sections/inline-files.rst
index 819bd3c8..303bb3c8 100644
--- a/doc/man-sections/inline-files.rst
+++ b/doc/man-sections/inline-files.rst
@@ -4,8 +4,8 @@ INLINE FILE SUPPORT
 OpenVPN allows including files in the main configuration for the ``--ca``,
 ``--cert``, ``--dh``, ``--extra-certs``, ``--key``, ``--pkcs12``,
 ``--secret``, ``--crl-verify``, ``--http-proxy-user-pass``, ``--tls-auth``,
-``--auth-gen-token-secret``, ``--tls-crypt`` and ``--tls-crypt-v2``
-options.
+``--auth-gen-token-secret``, ``--tls-crypt``, ``--tls-crypt-v2`` and
+``--verify-hash`` options.
 
 Each inline file started by the line  and ended by the line
 
diff --git a/doc/man-sections/tls-options.rst b/doc/man-sections/tls-options.rst
index e13fb3c8..d8f9800e 100644
--- a/doc/man-sections/tls-options.rst
+++ b/doc/man-sections/tls-options.rst
@@ -582,6 +582,16 @@ certificates and keys: https://github.com/OpenVPN/easy-rsa
   The ``algo`` flag can be either :code:`SHA1` or :code:`SHA256`. If not
   provided, it defaults to :code:`SHA1`.
 
+  This option can also be inlined
+  ::
+
+
+
00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff
+
11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:00
+
+
+If the option is inlined, ``algo`` is always :code:`SHA256`.
+
 --verify-x509-name args
   Accept connections only if a host's X.509 name is equal to **name.** The
   remote host must also pass all other tests of verification.
diff --git a/src/openvpn/options.c b/src/openvpn/options.c
index 86e78b05..3b1c69ba 100644
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -1078,12 +1078,24 @@ string_substitute(const char *src, int from, int to, 
struct gc_arena *gc)
 return ret;
 }
 
-static uint8_t *
+/**
+ * Parses a hexstring and checks if the string has the correct length. Return
+ * a verify_hash_list containing the parsed hash string.
+ *
+ * @param   str String to check/parse
+ * @param   nbytes  Number of bytes expected in the hexstr (e.g. 20 for 
SHA1)
+ * @param   msglevelmessage level to use when printing warnings/errors
+ * @param   gc  The returned object will be allocated in this gc
+ */
+static struct verify_hash_list *
 parse_hash_fingerprint(const char *str, int nbytes, int msglevel, struct 
gc_arena *gc)
 {
 int i;
 const char *cp = str;
-uint8_t *ret = (uint8_t *) gc_malloc(nbytes, true, gc);
+
+struct verify_hash_list *ret;
+ALLOC_OBJ_CLEAR_GC(ret, struct verify_hash_list, gc);
+
 char term = 1;
 int byte;
 char bs[3];
@@ -1102,7 +1114,7 @@ parse_hash_fingerprint(const char *str, int nbytes, int 
msglevel, struct gc_aren
 {
 msg(msglevel, "format error in hash fingerprint hex byte: %s", 
str);
 }
-ret[i] = (uint8_t)byte;
+ret->hash[i] = (uint8_t)byte;
 term = *cp++;
 if (term != ':' && term != 0)
 {
@@ -1116,10 +1128,55 @@ parse_hash_fingerprint(const char *str, int nbytes, int 
msglevel, struct gc_aren
 if (term != 0 || i != nbytes-1)
 {
 msg(msglevel, "hash fingerprint is different length than expected (%d 
bytes): %s", nbytes, str);
+return NULL;
 }
 return ret;
 }
 
+/**
+ * Parses a string consisting of multiple lines of hexstrings and checks if 
each
+ * string has the correct length. Empty lines are ignored. Returns
+ * a linked list of (possibly) multiple verify_hash_list objects.
+ *
+ * @param   str String to check/parse
+ * @param   nbytes  Number of bytes expected in the hexstring (e.g. 20 for 
SHA1)
+ * @param   msglevelmessage level to use when printing warnings/errors
+ * @param   gc  The returned list items will be allocated in this gc
+ */
+static str