Skip to contentSkip to conversation

tls-crypt: introduce tls_crypt_kt()

PATCH Superseded Steffan Karger 3 participants 7 messages Jul 25, 2017 – Aug 16, 2017

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 tls-crypt: introduce tls_crypt_kt()

Reduces code duplication: less lines, same functionality.

Because cipher_ctx_block_size() is a static function we now need to include tls_crypt.c from the tests, rather than tls_crypt.h.

---
 src/openvpn/tls_crypt.c                   | 30 ++++++++++++++++++------------
 tests/unit_tests/openvpn/Makefile.am      |  3 +--
 tests/unit_tests/openvpn/test_tls_crypt.c | 18 ++----------------
 3 files changed, 21 insertions(+), 30 deletions(-)
src/openvpn/tls_crypt.c +18 -12
index e13bb4e..c8d26c7 100644
@@ -35,19 +35,9 @@
 
 #include "tls_crypt.h"
 
-int
-tls_crypt_buf_overhead(void)
+static struct key_type
+tls_crypt_kt(void)
 {
-    return packet_id_size(true) + TLS_CRYPT_TAG_SIZE + TLS_CRYPT_BLOCK_SIZE;
-}
-
-void
-tls_crypt_init_key(struct key_ctx_bi *key, const char *key_file,
-                   const char *key_inline, bool tls_server)
-{
-    const int key_direction = tls_server ?
-                              KEY_DIRECTION_NORMAL : KEY_DIRECTION_INVERSE;
-
     struct key_type kt;
     kt.cipher = cipher_kt_get("AES-256-CTR");
     kt.digest = md_kt_get("SHA256");
@@ -64,6 +54,22 @@ tls_crypt_init_key(struct key_ctx_bi *key, const char *key_file,
     kt.cipher_length = cipher_kt_key_size(kt.cipher);
     kt.hmac_length = md_kt_size(kt.digest);
 
+    return kt;
+}
+
+int
+tls_crypt_buf_overhead(void)
+{
+    return packet_id_size(true) + TLS_CRYPT_TAG_SIZE + TLS_CRYPT_BLOCK_SIZE;
+}
+
+void
+tls_crypt_init_key(struct key_ctx_bi *key, const char *key_file,
+                   const char *key_inline, bool tls_server)
+{
+    const int key_direction = tls_server ?
+                              KEY_DIRECTION_NORMAL : KEY_DIRECTION_INVERSE;
+    struct key_type kt = tls_crypt_kt();
     crypto_read_openvpn_key(&kt, key, key_file, key_inline, key_direction,
                             "Control Channel Encryption", "tls-crypt");
 }
tests/unit_tests/openvpn/Makefile.am +1 -2
index 3bd382c..7b44f42 100644
@@ -54,5 +54,4 @@ tls_crypt_testdriver_SOURCES = test_tls_crypt.c mock_msg.c \
 	$(openvpn_srcdir)/crypto_openssl.c \
 	$(openvpn_srcdir)/otime.c \
 	$(openvpn_srcdir)/packet_id.c \
-	$(openvpn_srcdir)/platform.c \
-	$(openvpn_srcdir)/tls_crypt.c
+	$(openvpn_srcdir)/platform.c
tests/unit_tests/openvpn/test_tls_crypt.c +2 -16
index 9b82035..0a58a7d 100644
@@ -39,7 +39,7 @@
 #include <setjmp.h>
 #include <cmocka.h>
 
-#include "tls_crypt.h"
+#include "tls_crypt.c"
 
 #include "mock_msg.h"
 
@@ -60,23 +60,9 @@ setup(void **state) {
     struct test_context *ctx = calloc(1, sizeof(*ctx));
     *state = ctx;
 
-    ctx->kt.cipher = cipher_kt_get("AES-256-CTR");
-    ctx->kt.digest = md_kt_get("SHA256");
-    if (!ctx->kt.cipher)
-    {
-        printf("No AES-256-CTR support, skipping test.\n");
-        return 0;
-    }
-    if (!ctx->kt.digest)
-    {
-        printf("No HMAC-SHA256 support, skipping test.\n");
-        return 0;
-    }
-    ctx->kt.cipher_length = cipher_kt_key_size(ctx->kt.cipher);
-    ctx->kt.hmac_length = md_kt_size(ctx->kt.digest);
-
     struct key key = { 0 };
 
+    ctx->kt = tls_crypt_kt();
     init_key_ctx(&ctx->co.key_ctx_bi.encrypt, &key, &ctx->kt, true, "TEST");
     init_key_ctx(&ctx->co.key_ctx_bi.decrypt, &key, &ctx->kt, false, "TEST");
 
Signature · 1 line
2.7.4
#1 lore raw
Quoted 2 lines · Steffan Karger

Because cipher_ctx_block_size() is a static function we now need to include tls_crypt.c from the tests, rather than tls_crypt.h.

Hm, something went wrong with the paste buffers.
s/cipher_ctx_block_size/tls_crypt_kt/

-Steffan

#2 lore raw
In reply to Steffan Karger

Hi,

Quoted 97 lines · Steffan Karger

Reduces code duplication: less lines, same functionality.

Because cipher_ctx_block_size() is a static function we now need to include tls_crypt.c from the tests, rather than tls_crypt.h.

---
 src/openvpn/tls_crypt.c                   | 30 ++++++++++++++++++------------
 tests/unit_tests/openvpn/Makefile.am      |  3 +--
 tests/unit_tests/openvpn/test_tls_crypt.c | 18 ++----------------
 3 files changed, 21 insertions(+), 30 deletions(-)
src/openvpn/tls_crypt.c +18 -12
index e13bb4e..c8d26c7 100644
@@ -35,19 +35,9 @@
 
 #include "tls_crypt.h"
 
-int
-tls_crypt_buf_overhead(void)
+static struct key_type
+tls_crypt_kt(void)
 {
-    return packet_id_size(true) + TLS_CRYPT_TAG_SIZE + TLS_CRYPT_BLOCK_SIZE;
-}
-
-void
-tls_crypt_init_key(struct key_ctx_bi *key, const char *key_file,
-                   const char *key_inline, bool tls_server)
-{
-    const int key_direction = tls_server ?
-                              KEY_DIRECTION_NORMAL : KEY_DIRECTION_INVERSE;
-
     struct key_type kt;
     kt.cipher = cipher_kt_get("AES-256-CTR");
     kt.digest = md_kt_get("SHA256");
@@ -64,6 +54,22 @@ tls_crypt_init_key(struct key_ctx_bi *key, const char *key_file,
     kt.cipher_length = cipher_kt_key_size(kt.cipher);
     kt.hmac_length = md_kt_size(kt.digest);
 
+    return kt;
+}
+
+int
+tls_crypt_buf_overhead(void)
+{
+    return packet_id_size(true) + TLS_CRYPT_TAG_SIZE + TLS_CRYPT_BLOCK_SIZE;
+}
+
+void
+tls_crypt_init_key(struct key_ctx_bi *key, const char *key_file,
+                   const char *key_inline, bool tls_server)
+{
+    const int key_direction = tls_server ?
+                              KEY_DIRECTION_NORMAL : KEY_DIRECTION_INVERSE;
+    struct key_type kt = tls_crypt_kt();
     crypto_read_openvpn_key(&kt, key, key_file, key_inline, key_direction,
                             "Control Channel Encryption", "tls-crypt");
 }
tests/unit_tests/openvpn/Makefile.am +1 -2
index 3bd382c..7b44f42 100644
@@ -54,5 +54,4 @@ tls_crypt_testdriver_SOURCES = test_tls_crypt.c mock_msg.c \
 	$(openvpn_srcdir)/crypto_openssl.c \
 	$(openvpn_srcdir)/otime.c \
 	$(openvpn_srcdir)/packet_id.c \
-	$(openvpn_srcdir)/platform.c \
-	$(openvpn_srcdir)/tls_crypt.c
+	$(openvpn_srcdir)/platform.c
tests/unit_tests/openvpn/test_tls_crypt.c +1 -9
index 9b82035..0a58a7d 100644
@@ -39,7 +39,7 @@
 #include <setjmp.h>
 #include <cmocka.h>
 
-#include "tls_crypt.h"
+#include "tls_crypt.c"
 
 #include "mock_msg.h"
 
@@ -60,23 +60,9 @@ setup(void **state) {
     struct test_context *ctx = calloc(1, sizeof(*ctx));
     *state = ctx;
 
-    ctx->kt.cipher = cipher_kt_get("AES-256-CTR");
-    ctx->kt.digest = md_kt_get("SHA256");
-    if (!ctx->kt.cipher)
-    {
-        printf("No AES-256-CTR support, skipping test.\n");
-        return 0;
-    }
-    if (!ctx->kt.digest)

tests/unit_tests/openvpn/test_tls_crypt.c setup(void **state) { · line 65

Quoted 10 lines
tests/unit_tests/openvpn/test_tls_crypt.c +1 -7
-    {
-        printf("No HMAC-SHA256 support, skipping test.\n");
-        return 0;
-    }
-    ctx->kt.cipher_length = cipher_kt_key_size(ctx->kt.cipher);
-    ctx->kt.hmac_length = md_kt_size(ctx->kt.digest);
-
     struct key key = { 0 };
 
+    ctx->kt = tls_crypt_kt();

Now we don't have the NULL checks on ctx->kt.digest and ctx->kt.cipher anymore.
I understand this there is no variable involved as we statically search for "AES-256-CTR" and "SHA256", however, shouldn't we at least assert for them being not NULL ? Somebody may mess up the main code and the unitest should properly detect the wrong condition instead of segfaulting.

tests/unit_tests/openvpn/test_tls_crypt.c setup(void **state) { · line 68

Quoted 4 lines
tests/unit_tests/openvpn/test_tls_crypt.c +0 -0
     init_key_ctx(&ctx->co.key_ctx_bi.encrypt, &key, &ctx->kt, true, "TEST");
     init_key_ctx(&ctx->co.key_ctx_bi.decrypt, &key, &ctx->kt, false, "TEST");
 

the rest looks good!

Cheers,

Signature · 1 line
Antonio Quartulli
#3 lore raw

Hi,

Quoted 22 lines · Antonio Quartulli
Quoted 21 lines · Steffan Karger
tests/unit_tests/openvpn/test_tls_crypt.c +0 -15
@@ -60,23 +60,9 @@ setup(void **state) {
     struct test_context *ctx = calloc(1, sizeof(*ctx));
     *state = ctx;
 
-    ctx->kt.cipher = cipher_kt_get("AES-256-CTR");
-    ctx->kt.digest = md_kt_get("SHA256");
-    if (!ctx->kt.cipher)
-    {
-        printf("No AES-256-CTR support, skipping test.\n");
-        return 0;
-    }
-    if (!ctx->kt.digest)
-    {
-        printf("No HMAC-SHA256 support, skipping test.\n");
-        return 0;
-    }
-    ctx->kt.cipher_length = cipher_kt_key_size(ctx->kt.cipher);
-    ctx->kt.hmac_length = md_kt_size(ctx->kt.digest);
-
     struct key key = { 0 };
 
Quoted 8 lines

tests/unit_tests/openvpn/test_tls_crypt.c setup(void **state) { · line 65

Quoted 1 line
tests/unit_tests/openvpn/test_tls_crypt.c +1 -0
+    ctx->kt = tls_crypt_kt();

Now we don't have the NULL checks on ctx->kt.digest and ctx->kt.cipher anymore.
I understand this there is no variable involved as we statically search for "AES-256-CTR" and "SHA256", however, shouldn't we at least assert for them being not NULL ? Somebody may mess up the main code and the unitest should properly detect the wrong condition instead of segfaulting.

Actually, we do, because tls_crypt_kt() exits through msg(M_FATAL, ...) if kt.cipher or kt.cipher is NULL.

But thanks to this remark, I realized that this will again break the unit tests on platform without AES-256-CTR or HMAC-SHA256 (like SLES11).
So I'll send a v2 with improved error handling shortly.

-Steffan

#4 lore raw

PATCH v2 1/1 tls-crypt: introduce tls_crypt_kt()

In reply to Antonio Quartulli

Reduces code duplication (and prepares for tls-crypt-v2, which needs the same functionality at more places).

Because tls_crypt_kt() is a static function we now need to include tls_crypt.c from the tests, rather than tls_crypt.h.

---
v2: improve error handling

 src/openvpn/tls_crypt.c                   | 40 ++++++++++++++++++++-----------
 tests/unit_tests/openvpn/Makefile.am      |  3 +--
 tests/unit_tests/openvpn/test_tls_crypt.c | 20 ++++------------
 3 files changed, 32 insertions(+), 31 deletions(-)
src/openvpn/tls_crypt.c +26 -14
index e13bb4e..403060d 100644
@@ -35,35 +35,47 @@
 
 #include "tls_crypt.h"
 
-int
-tls_crypt_buf_overhead(void)
-{
-    return packet_id_size(true) + TLS_CRYPT_TAG_SIZE + TLS_CRYPT_BLOCK_SIZE;
-}
-
-void
-tls_crypt_init_key(struct key_ctx_bi *key, const char *key_file,
-                   const char *key_inline, bool tls_server)
+static struct key_type
+tls_crypt_kt(void)
 {
-    const int key_direction = tls_server ?
-                              KEY_DIRECTION_NORMAL : KEY_DIRECTION_INVERSE;
-
     struct key_type kt;
     kt.cipher = cipher_kt_get("AES-256-CTR");
     kt.digest = md_kt_get("SHA256");
 
     if (!kt.cipher)
     {
-        msg(M_FATAL, "ERROR: --tls-crypt requires AES-256-CTR support.");
+        msg(M_WARN, "ERROR: --tls-crypt requires AES-256-CTR support.");
+        return (struct key_type) { 0 };
     }
     if (!kt.digest)
     {
-        msg(M_FATAL, "ERROR: --tls-crypt requires HMAC-SHA-256 support.");
+        msg(M_WARN, "ERROR: --tls-crypt requires HMAC-SHA-256 support.");
+        return (struct key_type) { 0 };
     }
 
     kt.cipher_length = cipher_kt_key_size(kt.cipher);
     kt.hmac_length = md_kt_size(kt.digest);
 
+    return kt;
+}
+
+int
+tls_crypt_buf_overhead(void)
+{
+    return packet_id_size(true) + TLS_CRYPT_TAG_SIZE + TLS_CRYPT_BLOCK_SIZE;
+}
+
+void
+tls_crypt_init_key(struct key_ctx_bi *key, const char *key_file,
+                   const char *key_inline, bool tls_server)
+{
+    const int key_direction = tls_server ?
+                              KEY_DIRECTION_NORMAL : KEY_DIRECTION_INVERSE;
+    struct key_type kt = tls_crypt_kt();
+    if (!kt.cipher || !kt.digest)
+    {
+        msg (M_FATAL, "ERROR: --tls-crypt not supported");
+    }
     crypto_read_openvpn_key(&kt, key, key_file, key_inline, key_direction,
                             "Control Channel Encryption", "tls-crypt");
 }
tests/unit_tests/openvpn/Makefile.am +1 -2
index 3bd382c..7b44f42 100644
@@ -54,5 +54,4 @@ tls_crypt_testdriver_SOURCES = test_tls_crypt.c mock_msg.c \
 	$(openvpn_srcdir)/crypto_openssl.c \
 	$(openvpn_srcdir)/otime.c \
 	$(openvpn_srcdir)/packet_id.c \
-	$(openvpn_srcdir)/platform.c \
-	$(openvpn_srcdir)/tls_crypt.c
+	$(openvpn_srcdir)/platform.c
tests/unit_tests/openvpn/test_tls_crypt.c +5 -15
index 9b82035..0a6a08f 100644
@@ -39,7 +39,7 @@
 #include <setjmp.h>
 #include <cmocka.h>
 
-#include "tls_crypt.h"
+#include "tls_crypt.c"
 
 #include "mock_msg.h"
 
@@ -60,23 +60,13 @@ setup(void **state) {
     struct test_context *ctx = calloc(1, sizeof(*ctx));
     *state = ctx;
 
-    ctx->kt.cipher = cipher_kt_get("AES-256-CTR");
-    ctx->kt.digest = md_kt_get("SHA256");
-    if (!ctx->kt.cipher)
-    {
-        printf("No AES-256-CTR support, skipping test.\n");
-        return 0;
-    }
-    if (!ctx->kt.digest)
+    struct key key = { 0 };
+
+    ctx->kt = tls_crypt_kt();
+    if (!ctx->kt.cipher || !ctx->kt.digest)
     {
-        printf("No HMAC-SHA256 support, skipping test.\n");
         return 0;
     }
-    ctx->kt.cipher_length = cipher_kt_key_size(ctx->kt.cipher);
-    ctx->kt.hmac_length = md_kt_size(ctx->kt.digest);
-
-    struct key key = { 0 };
-
     init_key_ctx(&ctx->co.key_ctx_bi.encrypt, &key, &ctx->kt, true, "TEST");
     init_key_ctx(&ctx->co.key_ctx_bi.decrypt, &key, &ctx->kt, false, "TEST");
 
Signature · 1 line
2.7.4
#5 lore raw

Hi,

Quoted 67 lines · Steffan Karger

Reduces code duplication (and prepares for tls-crypt-v2, which needs the same functionality at more places).

Because tls_crypt_kt() is a static function we now need to include tls_crypt.c from the tests, rather than tls_crypt.h.

---
v2: improve error handling

 src/openvpn/tls_crypt.c                   | 40 ++++++++++++++++++++-----------
 tests/unit_tests/openvpn/Makefile.am      |  3 +--
 tests/unit_tests/openvpn/test_tls_crypt.c | 20 ++++------------
 3 files changed, 32 insertions(+), 31 deletions(-)
src/openvpn/tls_crypt.c +15 -14
index e13bb4e..403060d 100644
@@ -35,35 +35,47 @@
 
 #include "tls_crypt.h"
 
-int
-tls_crypt_buf_overhead(void)
-{
-    return packet_id_size(true) + TLS_CRYPT_TAG_SIZE + TLS_CRYPT_BLOCK_SIZE;
-}
-
-void
-tls_crypt_init_key(struct key_ctx_bi *key, const char *key_file,
-                   const char *key_inline, bool tls_server)
+static struct key_type
+tls_crypt_kt(void)
 {
-    const int key_direction = tls_server ?
-                              KEY_DIRECTION_NORMAL : KEY_DIRECTION_INVERSE;
-
     struct key_type kt;
     kt.cipher = cipher_kt_get("AES-256-CTR");
     kt.digest = md_kt_get("SHA256");
 
     if (!kt.cipher)
     {
-        msg(M_FATAL, "ERROR: --tls-crypt requires AES-256-CTR support.");
+        msg(M_WARN, "ERROR: --tls-crypt requires AES-256-CTR support.");
+        return (struct key_type) { 0 };
     }
     if (!kt.digest)
     {
-        msg(M_FATAL, "ERROR: --tls-crypt requires HMAC-SHA-256 support.");
+        msg(M_WARN, "ERROR: --tls-crypt requires HMAC-SHA-256 support.");
+        return (struct key_type) { 0 };
     }
 
     kt.cipher_length = cipher_kt_key_size(kt.cipher);
     kt.hmac_length = md_kt_size(kt.digest);
 
+    return kt;
+}
+
+int
+tls_crypt_buf_overhead(void)
+{
+    return packet_id_size(true) + TLS_CRYPT_TAG_SIZE + TLS_CRYPT_BLOCK_SIZE;
+}
+

src/openvpn/tls_crypt.c line 77

Quoted 10 lines
src/openvpn/tls_crypt.c +10 -0
+void
+tls_crypt_init_key(struct key_ctx_bi *key, const char *key_file,
+                   const char *key_inline, bool tls_server)
+{
+    const int key_direction = tls_server ?
+                              KEY_DIRECTION_NORMAL : KEY_DIRECTION_INVERSE;
+    struct key_type kt = tls_crypt_kt();
+    if (!kt.cipher || !kt.digest)
+    {
+        msg (M_FATAL, "ERROR: --tls-crypt not supported");

there should be no space between 'msg' and '('.
I hope who will commit this patch will also be able to remove it.

Quoted 47 lines
src/openvpn/tls_crypt.c +1 -0
+    }
     crypto_read_openvpn_key(&kt, key, key_file, key_inline, key_direction,
                             "Control Channel Encryption", "tls-crypt");
 }
tests/unit_tests/openvpn/Makefile.am +1 -2
index 3bd382c..7b44f42 100644
@@ -54,5 +54,4 @@ tls_crypt_testdriver_SOURCES = test_tls_crypt.c mock_msg.c \
 	$(openvpn_srcdir)/crypto_openssl.c \
 	$(openvpn_srcdir)/otime.c \
 	$(openvpn_srcdir)/packet_id.c \
-	$(openvpn_srcdir)/platform.c \
-	$(openvpn_srcdir)/tls_crypt.c
+	$(openvpn_srcdir)/platform.c
tests/unit_tests/openvpn/test_tls_crypt.c +5 -10
index 9b82035..0a6a08f 100644
@@ -39,7 +39,7 @@
 #include <setjmp.h>
 #include <cmocka.h>
 
-#include "tls_crypt.h"
+#include "tls_crypt.c"
 
 #include "mock_msg.h"
 
@@ -60,23 +60,13 @@ setup(void **state) {
     struct test_context *ctx = calloc(1, sizeof(*ctx));
     *state = ctx;
 
-    ctx->kt.cipher = cipher_kt_get("AES-256-CTR");
-    ctx->kt.digest = md_kt_get("SHA256");
-    if (!ctx->kt.cipher)
-    {
-        printf("No AES-256-CTR support, skipping test.\n");
-        return 0;
-    }
-    if (!ctx->kt.digest)
+    struct key key = { 0 };
+
+    ctx->kt = tls_crypt_kt();
+    if (!ctx->kt.cipher || !ctx->kt.digest)
     {
-        printf("No HMAC-SHA256 support, skipping test.\n");

tests/unit_tests/openvpn/test_tls_crypt.c setup(void **state) { · line 72

Quoted 10 lines
tests/unit_tests/openvpn/test_tls_crypt.c +0 -5
         return 0;
     }
-    ctx->kt.cipher_length = cipher_kt_key_size(ctx->kt.cipher);
-    ctx->kt.hmac_length = md_kt_size(ctx->kt.digest);
-
-    struct key key = { 0 };
-
     init_key_ctx(&ctx->co.key_ctx_bi.encrypt, &key, &ctx->kt, true, "TEST");
     init_key_ctx(&ctx->co.key_ctx_bi.decrypt, &key, &ctx->kt, false, "TEST");
 

Much better error handling.
Even if I don't like the "return .. { 0 }" from a style perspective, the patch is fine and does what it says. ACK.

Cheers,

Signature · 1 line
Antonio Quartulli
#6 lore raw
In reply to Steffan Karger

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

Your patch has been applied to the following branches

commit 489c7bf93ec618e03dbd9618efbb6e251a65e76c (master) commit d47228e71de6cbbf860746a50a3ecf8025e35653 (release/2.4)

Author: Steffan Karger
Date:   Sat Aug 12 11:53:52 2017 +0200
     tls-crypt: introduce tls_crypt_kt()

     Signed-off-by: Steffan Karger <[email protected]...>
     Acked-by: Antonio Quartulli <[email protected]...>
     Message-Id: <[email protected]...>
     URL: https://www.mail-archive.com/[email protected]/msg15229.html
     Signed-off-by: David Sommerseth <[email protected]...>

- --
kind regards,

David Sommerseth

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.22 (GNU/Linux)

iQIcBAEBCgAGBQJZlGBTAAoJEIbPlEyWcf3ykpwP/3iuOWQMf6jgWs0ezR9A5YcT 08AjJ9aS5hfx/d8NWzuO6ZnOgm8AgepD+nnMbYSyBHWaRfkf1BOOHBeu7xuTXxA5 CpYWjEtAVA+cDlqn/BYjiT3mtTcg4ghX8itrSws2VLmVeg7LNy3zpvbkCZKcBfVR P/XjHdMQFTRlAYYsllKlIXYz94HawtjCti3ijCkMqUNekle7ufHQog8RDC0LJr8i bPRqxoIiqUrZVs/PUqdGbggWu/UiEzwgeAIBY4J2/0YC1ZVYWv18kbOatNIpGIbb wIH9T4+kvaiZ840+SaPmcZA1LRjsyxsEj8WwS6os3dmFp9H58PCO/Uyu/lvPRR8E 7o6kvdbFXoYsQMIpHwyUV025kIDPj+bWDSF4K3pTcb0yHr8cXqPpWqO6K7r9NqEc CTpWWNuD1Fy3gEAV8HYn5hM2yCQDzJmkHXnjQrb2ER3re2yB+4kFNiaZwmZd0Gmi uKBq0DP6qGEzSfxPpZdYHEoqHJ5pm9HavZIvG+5mt95rvwqBIvuVU8PdQ9g1qUzc nOKSYErbs0vvEVXlLWl2vWo3xwcsdMI4ut6nR0fxA1YQTwPyuh8+gbPgkBRB8DUk SjlJ5WcmWWbfN6L8IGpGCZMpjlcSwA/lTygzyqcFGvWHruap1J8qNMLrj2Gec7Dp 3D8sygBqVNi5Mrrxj/hh
=W/rQ
-----END PGP SIGNATURE-----