diff options
author | Stefan Walter <stefw@src.gnome.org> | 2009-01-18 22:24:09 +0000 |
---|---|---|
committer | Stefan Walter <stefw@src.gnome.org> | 2009-01-18 22:24:09 +0000 |
commit | 300ee9603c89d801e16b5f4696927e1f36bed939 (patch) | |
tree | 3b2ec41f73e6a3398ca7d957620ea61de41ea521 | |
parent | 6611cd8c03723bf7e821098756ff34057c3fae22 (diff) |
Add new gcr library for crypto UI and related tasks. Implement GckParser
* egg/egg-asn1.c:
* egg/egg-hex.c: (split from pkcs11/gck/gck-util.c)
* egg/egg-hex.h: (split from pkcs11/gck/gck-util.h)
* egg/egg-openssl.c: (moved from pkcs11/gck/gck-data-openssl.c)
* egg/egg-openssl.h: (moved from pkcs11/gck/gck-data-openssl.h)
* egg/egg-symkey.c: (split from pkcs11/gck/gck-crypto.c)
* egg/egg-symkey.h: (split from pkcs11/gck/gck-crypto.h)
* egg/Makefile.am:
* egg/tests/Makefile.am:
* egg/tests/unit-test-asn1.c:
* egg/tests/unit-test-hex.c: (moved from pkcs11/gck/tests/unit-test-util.c)
* egg/tests/unit-test-openssl.c: (moved from pkcs11/gck/tests/unit-test-data-openssl.c)
* egg/tests/unit-test-symkey.c: (split from pkcs11/gck/tests/unit-test-crypto.c)
* gcr/gcr.pc.in: (added)
* gcr/gcr-internal.c: (added)
* gcr/gcr-internal.h: (added)
* gcr/gcr-marshal.list: (added)
* gcr/gcr-parser.c: (added)
* gcr/gcr-parser.h: (added)
* gcr/gcr-types.h: (added)
* gcr/Makefile.am: (added)
* gcr/template/*: (added)
* gcr/tests/Makefile.am: (added)
* gcr/tests/unit-test-parser.c: (added)
* gcr/tests/test-data: (copied from daemon/pkix/test/test-data)
* gp11/gp11.h:
* pkcs11/gck/gck-crypto.c:
* pkcs11/gck/gck-crypto.h:
* pkcs11/gck/gck-data-der.c:
* pkcs11/gck/gck-data-der.h:
* pkcs11/gck/gck-data-file.c:
* pkcs11/gck/gck-data-openssl.c: (moved)
* pkcs11/gck/gck-data-openssl.h: (moved)
* pkcs11/gck/gck-data-pem.c: (combined into egg/egg-openssl.c)
* pkcs11/gck/gck-data-pem.c: (combined into egg/egg-openssl.h)
* pkcs11/gck/gck-util.c:
* pkcs11/gck/gck-util.h:
* pkcs11/gck/Makefile.am:
* pkcs11/gck/tests/unit-test-crypto.c:
* pkcs11/gck/tests/unit-test-data-openssl.c: (moved)
* pkcs11/gck/tests/unit-test-util.c: (moved)
* pkcs11/roots-store/gck-roots-module.c:
* pkcs11/ssh-store/gck-ssh-openssh.c:
* pkcs11/user-store/gck-user-storage.c:
* configure.in:
* Makefile.am: Add new gcr library for crypto UI and related tasks. Implement
GckParser class.
svn path=/trunk/; revision=1463
78 files changed, 7664 insertions, 1830 deletions
@@ -1,5 +1,55 @@ 2009-01-17 Stef Walter <stef@memberwebs.com> + * egg/egg-asn1.c: + * egg/egg-hex.c: (split from pkcs11/gck/gck-util.c) + * egg/egg-hex.h: (split from pkcs11/gck/gck-util.h) + * egg/egg-openssl.c: (moved from pkcs11/gck/gck-data-openssl.c) + * egg/egg-openssl.h: (moved from pkcs11/gck/gck-data-openssl.h) + * egg/egg-symkey.c: (split from pkcs11/gck/gck-crypto.c) + * egg/egg-symkey.h: (split from pkcs11/gck/gck-crypto.h) + * egg/Makefile.am: + * egg/tests/Makefile.am: + * egg/tests/unit-test-asn1.c: + * egg/tests/unit-test-hex.c: (moved from pkcs11/gck/tests/unit-test-util.c) + * egg/tests/unit-test-openssl.c: (moved from pkcs11/gck/tests/unit-test-data-openssl.c) + * egg/tests/unit-test-symkey.c: (split from pkcs11/gck/tests/unit-test-crypto.c) + * gcr/gcr.pc.in: (added) + * gcr/gcr-internal.c: (added) + * gcr/gcr-internal.h: (added) + * gcr/gcr-marshal.list: (added) + * gcr/gcr-parser.c: (added) + * gcr/gcr-parser.h: (added) + * gcr/gcr-types.h: (added) + * gcr/Makefile.am: (added) + * gcr/template/*: (added) + * gcr/tests/Makefile.am: (added) + * gcr/tests/unit-test-parser.c: (added) + * gcr/tests/test-data: (copied from daemon/pkix/test/test-data) + * gp11/gp11.h: + * pkcs11/gck/gck-crypto.c: + * pkcs11/gck/gck-crypto.h: + * pkcs11/gck/gck-data-der.c: + * pkcs11/gck/gck-data-der.h: + * pkcs11/gck/gck-data-file.c: + * pkcs11/gck/gck-data-openssl.c: (moved) + * pkcs11/gck/gck-data-openssl.h: (moved) + * pkcs11/gck/gck-data-pem.c: (combined into egg/egg-openssl.c) + * pkcs11/gck/gck-data-pem.c: (combined into egg/egg-openssl.h) + * pkcs11/gck/gck-util.c: + * pkcs11/gck/gck-util.h: + * pkcs11/gck/Makefile.am: + * pkcs11/gck/tests/unit-test-crypto.c: + * pkcs11/gck/tests/unit-test-data-openssl.c: (moved) + * pkcs11/gck/tests/unit-test-util.c: (moved) + * pkcs11/roots-store/gck-roots-module.c: + * pkcs11/ssh-store/gck-ssh-openssh.c: + * pkcs11/user-store/gck-user-storage.c: + * configure.in: + * Makefile.am: Add new gcr library for crypto UI and related tasks. Implement + GckParser class. + +2009-01-17 Stef Walter <stef@memberwebs.com> + * egg/egg-asn1.c: (moved from pkcs11/gck/gck-data-asn1.c) * egg/egg-asn1.h: (moved from pkcs11/gck/gck-data-asn1.h) * egg/egg-buffer.c: (moved from common/gkr-buffer.c) diff --git a/Makefile.am b/Makefile.am index 04a9869b..2de8f7de 100644 --- a/Makefile.am +++ b/Makefile.am @@ -14,6 +14,7 @@ SUBDIRS = \ . \ gp11 \ egg \ + gcr \ common \ library \ pkcs11 \ diff --git a/configure.in b/configure.in index 6f22c6fb..65781eb6 100644 --- a/configure.in +++ b/configure.in @@ -4,12 +4,16 @@ AM_INIT_AUTOMAKE(gnome-keyring, 2.25.4.2) AM_CONFIG_HEADER(config.h) dnl **************************************************************************** -dnl GP11 library libtool versioning +dnl Library libtool versioning GP11_MAJOR=0 # Increment for major version number, breaks old apps. GP11_REVISION=0 # Increment for internal changes, nothing affected. GP11_AGE=0 # Increment for interface that doesn't break anything +GCR_MAJOR=0 # Increment for major version number, breaks old apps. +GCR_REVISION=0 # Increment for internal changes, nothing affected. +GCR_AGE=0 # Increment for interface that doesn't break anything + dnl **************************************************************************** AM_SANITY_CHECK @@ -469,6 +473,10 @@ GP11_LT_RELEASE=$GP11_MAJOR:$GP11_REVISION:$GP11_AGE AC_SUBST(GP11_LT_RELEASE) AC_SUBST(GP11_MAJOR) +GCR_LT_RELEASE=$GCR_MAJOR:$GCR_REVISION:$GCR_AGE +AC_SUBST(GCR_LT_RELEASE) +AC_SUBST(GCR_MAJOR) + AC_SUBST(DAEMON_CFLAGS) AC_SUBST(DAEMON_LIBS) @@ -497,6 +505,9 @@ daemon/ssh/tests/Makefile daemon/ui/Makefile egg/Makefile egg/tests/Makefile +gcr/gcr.pc +gcr/Makefile +gcr/tests/Makefile gp11/gp11.pc gp11/Makefile gp11/reference/Makefile diff --git a/egg/Makefile.am b/egg/Makefile.am index 4024b7a6..439a5891 100644 --- a/egg/Makefile.am +++ b/egg/Makefile.am @@ -19,8 +19,11 @@ libegg_la_CFLAGS = \ libegg_la_SOURCES = \ egg-asn1.c egg-asn1.h \ egg-buffer.c egg-buffer.h \ + egg-hex.c egg-hex.h \ + egg-openssl.c egg-openssl.h \ egg-unix-credentials.c egg-unix-credentials.h \ - egg-secure-memory.c egg-secure-memory.h + egg-secure-memory.c egg-secure-memory.h \ + egg-symkey.c egg-symkey.h asn1-def-pk.h: pk.asn asn1Parser -o asn1-def-pk.h pk.asn diff --git a/egg/egg-asn1.c b/egg/egg-asn1.c index 94f13316..2910ca02 100644 --- a/egg/egg-asn1.c +++ b/egg/egg-asn1.c @@ -335,12 +335,9 @@ egg_asn1_read_oid (ASN1_TYPE asn, const gchar *part) if (!buf) return 0; - quark = g_quark_try_string ((gchar*)buf); + quark = g_quark_from_string ((gchar*)buf); g_free (buf); - if (quark == 0) - quark = g_quark_from_static_string ("0.UNKNOWN.OID"); - return quark; } diff --git a/egg/egg-hex.c b/egg/egg-hex.c new file mode 100644 index 00000000..cdfc33e8 --- /dev/null +++ b/egg/egg-hex.c @@ -0,0 +1,104 @@ +/* + * gnome-keyring + * + * Copyright (C) 2008 Stefan Walter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General License for more details. + * + * You should have received a copy of the GNU Lesser General + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "config.h" + +#include "egg-hex.h" + +#include <string.h> + +static const char HEXC[] = "0123456789ABCDEF"; + +guchar* +egg_hex_decode (const gchar *data, gssize n_data, gsize *n_decoded) +{ + guchar *result; + guchar *decoded; + gushort j; + gint state = 0; + const gchar* pos; + + g_return_val_if_fail (data || !n_data, NULL); + g_return_val_if_fail (n_decoded, NULL); + + if (n_data == -1) + n_data = strlen (data); + + decoded = result = g_malloc0 ((n_data / 2) + 1); + *n_decoded = 0; + + while (n_data > 0) { + if (!g_ascii_isspace (*data)) { + + /* Find the position */ + pos = strchr (HEXC, g_ascii_toupper (*data)); + if (pos == 0) + break; + + j = pos - HEXC; + if(!state) { + *decoded = (j & 0xf) << 4; + state = 1; + } else { + *decoded |= (j & 0xf); + (*n_decoded)++; + decoded++; + state = 0; + } + } + + ++data; + --n_data; + } + + /* Parsing error */ + if (state != 0) { + g_free (result); + result = NULL; + } + + return result; +} + +gchar* +egg_hex_encode (const guchar *data, gsize n_data) +{ + gchar *result, *encoded; + guchar j; + + g_return_val_if_fail (data || !n_data, NULL); + + encoded = result = g_malloc0 (n_data * 2 + 1); + + while(n_data > 0) { + j = *(data) >> 4 & 0xf; + *(encoded++) = HEXC[j]; + + j = *(data++) & 0xf; + *(encoded++) = HEXC[j]; + + n_data--; + } + + /* Make sure still null terminated */ + g_assert (encoded[n_data * 2] == 0); + return result; +} diff --git a/egg/egg-hex.h b/egg/egg-hex.h new file mode 100644 index 00000000..ddcd9238 --- /dev/null +++ b/egg/egg-hex.h @@ -0,0 +1,34 @@ +/* + * gnome-keyring + * + * Copyright (C) 2008 Stefan Walter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General License for more details. + * + * You should have received a copy of the GNU Lesser General + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef EGG_HEX_H_ +#define EGG_HEX_H_ + +#include <glib.h> + +guchar* egg_hex_decode (const gchar *data, + gssize n_data, + gsize *n_decoded); + +gchar* egg_hex_encode (const guchar *data, + gsize n_data); + +#endif /* EGG_HEX_H_ */ diff --git a/pkcs11/gck/gck-data-openssl.c b/egg/egg-openssl.c index bb0f7a5a..9ac1e2ae 100644 --- a/pkcs11/gck/gck-data-openssl.c +++ b/egg/egg-openssl.c @@ -1,5 +1,5 @@ /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* gck-data-openssl.c - OpenSSL compatibility functionality +/* egg-openssl.c - OpenSSL compatibility functionality Copyright (C) 2007 Stefan Walter @@ -23,15 +23,331 @@ #include "config.h" -#include "gck-crypto.h" -#include "gck-data-openssl.h" -#include "gck-util.h" +#include "egg-hex.h" +#include "egg-openssl.h" +#include "egg-secure-memory.h" +#include "egg-symkey.h" #include <gcrypt.h> #include <libtasn1.h> #include <glib.h> +#include <ctype.h> +#include <string.h> + +/* + * PEM looks like: + * + * -----BEGIN RSA PRIVATE KEY----- + * Proc-Type: 4,ENCRYPTED + * DEK-Info: DES-EDE3-CBC,704CFFD62FBA03E9 + * + * 4AV/g0BiTeb07hzo4/Ct47HGhHEshMhBPGJ843QzuAinpZBbg3OxwPsQsLgoPhJL + * Bg6Oxyz9M4UN1Xlx6Lyo2lRT908mBP6dl/OItLsVArqAzM+e29KHQVNjV1h7xN9F + * u84tOgZftKun+ZkQUOoRvMLLu4yV4CUraks9tgyXquugGba/tbeyj2MYsC8wwSJX + * .... + * -----END RSA PRIVATE KEY----- + */ + +#define PEM_SUFF "-----" +#define PEM_SUFF_L 5 +#define PEM_PREF_BEGIN "-----BEGIN " +#define PEM_PREF_BEGIN_L 11 +#define PEM_PREF_END "-----END " +#define PEM_PREF_END_L 9 + +static void +parse_header_lines (const gchar *hbeg, const gchar *hend, GHashTable **result) +{ + gchar **lines, **l; + gchar *line, *name, *value; + gchar *copy; + + copy = g_strndup (hbeg, hend - hbeg); + lines = g_strsplit (copy, "\n", 0); + g_free (copy); + + for (l = lines; l && *l; ++l) { + line = *l; + g_strstrip (line); + + /* Look for the break between name: value */ + value = strchr (line, ':'); + if (value == NULL) + continue; + + *value = 0; + value = g_strdup (value + 1); + g_strstrip (value); + + name = g_strdup (line); + g_strstrip (name); + + if (!*result) + *result = egg_openssl_headers_new (); + g_hash_table_replace (*result, name, value); + } + + g_strfreev (lines); +} + +static const gchar* +pem_find_begin (const gchar *data, gsize n_data, GQuark *type) +{ + const gchar *pref, *suff; + gchar *stype; + + /* Look for a prefix */ + pref = g_strstr_len ((gchar*)data, n_data, PEM_PREF_BEGIN); + if (!pref) + return NULL; + + n_data -= (pref - data) + PEM_PREF_BEGIN_L; + data = pref + PEM_PREF_BEGIN_L; + + /* Look for the end of that begin */ + suff = g_strstr_len ((gchar*)data, n_data, PEM_SUFF); + if (!suff) + return NULL; + + /* Make sure on the same line */ + if (memchr (pref, '\n', suff - pref)) + return NULL; + + if (type) { + *type = 0; + pref += PEM_PREF_BEGIN_L; + g_assert (suff > pref); + stype = g_alloca (suff - pref + 1); + memcpy (stype, pref, suff - pref); + stype[suff - pref] = 0; + *type = g_quark_from_string (stype); + } + + /* The byte after this ---BEGIN--- */ + return suff + PEM_SUFF_L; +} + +static const gchar* +pem_find_end (const gchar *data, gsize n_data, GQuark type) +{ + const gchar *stype; + const gchar *pref; + gsize n_type; + + /* Look for a prefix */ + pref = g_strstr_len (data, n_data, PEM_PREF_END); + if (!pref) + return NULL; + + n_data -= (pref - data) + PEM_PREF_END_L; + data = pref + PEM_PREF_END_L; + + /* Next comes the type string */ + stype = g_quark_to_string (type); + n_type = strlen (stype); + if (strncmp ((gchar*)data, stype, n_type) != 0) + return NULL; + + n_data -= n_type; + data += n_type; + + /* Next comes the suffix */ + if (strncmp ((gchar*)data, PEM_SUFF, PEM_SUFF_L) != 0) + return NULL; + + /* The beginning of this ---END--- */ + return pref; +} + +static gboolean +pem_parse_block (const gchar *data, gsize n_data, guchar **decoded, gsize *n_decoded, + GHashTable **headers) +{ + const gchar *x, *hbeg, *hend; + const gchar *p, *end; + gint state = 0; + guint save = 0; + + g_assert (data); + g_assert (n_data); + + g_assert (decoded); + g_assert (n_decoded); + + p = data; + end = p + n_data; + + hbeg = hend = NULL; + + /* Try and find a pair of blank lines with only white space between */ + while (hend == NULL) { + x = memchr (p, '\n', end - p); + if (!x) + break; + ++x; + while (isspace (*x)) { + /* Found a second line, with only spaces between */ + if (*x == '\n') { + hbeg = data; + hend = x; + break; + /* Found a space between two lines */ + } else { + ++x; + } + } + + /* Try next line */ + p = x; + } + + /* Headers found? */ + if (hbeg && hend) { + data = hend; + n_data = end - data; + } + + *n_decoded = (n_data * 3) / 4 + 1; + if (egg_secure_check (data)) + *decoded = egg_secure_alloc (*n_decoded); + else + *decoded = g_malloc0 (*n_decoded); + g_return_val_if_fail (*decoded, FALSE); + + *n_decoded = g_base64_decode_step (data, n_data, *decoded, &state, &save); + if (!*n_decoded) { + egg_secure_free (*decoded); + return FALSE; + } + + if (headers && hbeg && hend) + parse_header_lines (hbeg, hend, headers); + + return TRUE; +} + +GHashTable* +egg_openssl_headers_new (void) +{ + return g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); +} + +guint +egg_openssl_pem_parse (const guchar *data, gsize n_data, + EggOpensslPemCallback callback, gpointer user_data) +{ + const gchar *beg, *end; + guint nfound = 0; + guchar *decoded = NULL; + gsize n_decoded = 0; + GHashTable *headers = NULL; + GQuark type; + + g_return_val_if_fail (data, 0); + g_return_val_if_fail (n_data, 0); + g_return_val_if_fail (callback, 0); + + while (n_data > 0) { + + /* This returns the first character after the PEM BEGIN header */ + beg = pem_find_begin ((const gchar*)data, n_data, &type); + if (!beg) + break; + + g_assert (type); + + /* This returns the character position before the PEM END header */ + end = pem_find_end ((const gchar*)beg, n_data - ((const guchar*)beg - data), type); + if (!end) + break; + + if (beg != end) { + if (pem_parse_block (beg, end - beg, &decoded, &n_decoded, &headers)) { + (callback) (type, decoded, n_decoded, headers, user_data); + ++nfound; + egg_secure_free (decoded); + if (headers) + g_hash_table_remove_all (headers); + } + } + + /* Try for another block */ + end += PEM_SUFF_L; + n_data -= (const guchar*)end - data; + data = (const guchar*)end; + } + + if (headers) + g_hash_table_destroy (headers); + + return nfound; +} + +#ifdef UNTESTED_CODE + +static void +append_each_header (gpointer key, gpointer value, gpointer user_data) +{ + GString *string = (GString*)user_data; + + g_string_append (string, (gchar*)key); + g_string_append (string, ": "); + g_string_append (string, (gchar*)value); + g_string_append_c (string, '\n'); +} + +guchar* +egg_openssl_pem_write (const guchar *data, gsize n_data, GQuark type, + GHashTable *headers, gsize *n_result) +{ + GString *string; + gint state, save; + gsize length, n_prefix; + + g_return_val_if_fail (data || !n_data, NULL); + g_return_val_if_fail (type, NULL); + g_return_val_if_fail (n_result, NULL); + + string = g_string_sized_new (4096); + + /* The prefix */ + g_string_append_len (string, PEM_PREF_BEGIN, PEM_PREF_BEGIN_L); + g_string_append (string, g_quark_to_string (type)); + g_string_append_len (string, PEM_SUFF, PEM_SUFF_L); + g_string_append_c (string, '\n'); + + /* The headers */ + if (headers && g_hash_table_size (headers) > 0) { + g_hash_table_foreach (headers, append_each_header, string); + g_string_append_c (string, '\n'); + } + + /* Resize string to fit the base64 data. Algorithm from Glib reference */ + length = n_data * 4 / 3 + n_data * 4 / (3 * 72) + 7; + n_prefix = string->len; + g_string_set_size (string, n_prefix + length); + + /* The actual base64 data */ + state = save = 0; + length = g_base64_encode_step (data, n_data, TRUE, + string->str + string->len, &state, &save); + g_string_set_size (string, n_prefix + length); + + /* The suffix */ + g_string_append_c (string, '\n'); + g_string_append_len (string, PEM_PREF_END, PEM_PREF_END_L); + g_string_append (string, g_quark_to_string (type)); + g_string_append_len (string, PEM_SUFF, PEM_SUFF_L); + g_string_append_c (string, '\n'); + + *n_result = string->len; + return (guchar*)g_string_free (string, FALSE); +} + +#endif /* UNTESTED_CODE */ + /* ---------------------------------------------------------------------------- * DEFINITIONS */ @@ -137,7 +453,7 @@ const static struct { /* ------------------------------------------------------------------------- */ int -gck_data_openssl_parse_algo (const char *name, int *mode) +egg_openssl_parse_algo (const char *name, int *mode) { static GQuark openssl_quarks[G_N_ELEMENTS(openssl_algos)] = { 0, }; static gsize openssl_quarks_inited = 0; @@ -176,7 +492,7 @@ parse_dekinfo (const gchar *dek, int *algo, int *mode, guchar **iv) goto done; /* Parse the algorithm name */ - *algo = gck_data_openssl_parse_algo (parts[0], mode); + *algo = egg_openssl_parse_algo (parts[0], mode); if (!*algo) goto done; @@ -188,7 +504,7 @@ parse_dekinfo (const gchar *dek, int *algo, int *mode, guchar **iv) /* Parse the IV */ ivlen = gcry_cipher_get_algo_blklen (*algo); - *iv = gck_util_hex_decode (parts[1], strlen(parts[1]), &len); + *iv = egg_hex_decode (parts[1], strlen(parts[1]), &len); if (!*iv || ivlen != len) { g_free (*iv); goto done; @@ -201,10 +517,10 @@ done: return success; } -GckDataResult -gck_data_openssl_decrypt_block (const gchar *dekinfo, const gchar *password, - gssize n_password, const guchar *data, gsize n_data, - guchar **decrypted, gsize *n_decrypted) +gboolean +egg_openssl_decrypt_block (const gchar *dekinfo, const gchar *password, + gssize n_password, const guchar *data, gsize n_data, + guchar **decrypted, gsize *n_decrypted) { gcry_cipher_hd_t ch; guchar *key = NULL; @@ -214,7 +530,7 @@ gck_data_openssl_decrypt_block (const gchar *dekinfo, const gchar *password, int mode = 0; if (!parse_dekinfo (dekinfo, &algo, &mode, &iv)) - return GCK_DATA_UNRECOGNIZED; + return FALSE; ivlen = gcry_cipher_get_algo_blklen (algo); @@ -222,42 +538,42 @@ gck_data_openssl_decrypt_block (const gchar *dekinfo, const gchar *password, g_return_val_if_fail (ivlen >= 8, FALSE); /* IV is already set from the DEK info */ - if (!gck_crypto_symkey_generate_simple (algo, GCRY_MD_MD5, password, + if (!egg_symkey_generate_simple (algo, GCRY_MD_MD5, password, n_password, iv, 8, 1, &key, NULL)) { g_free (iv); - return GCK_DATA_FAILURE; + return FALSE; } /* TODO: Use secure memory */ gcry = gcry_cipher_open (&ch, algo, mode, 0); - g_return_val_if_fail (!gcry, GCK_DATA_FAILURE); + g_return_val_if_fail (!gcry, FALSE); gcry = gcry_cipher_setkey (ch, key, gcry_cipher_get_algo_keylen (algo)); - g_return_val_if_fail (!gcry, GCK_DATA_UNRECOGNIZED); - gcry_free (key); + g_return_val_if_fail (!gcry, FALSE); + egg_secure_free (key); /* 16 = 128 bits */ gcry = gcry_cipher_setiv (ch, iv, ivlen); - g_return_val_if_fail (!gcry, GCK_DATA_UNRECOGNIZED); + g_return_val_if_fail (!gcry, FALSE); g_free (iv); /* Allocate output area */ *n_decrypted = n_data; - *decrypted = gcry_calloc_secure (n_data, 1); + *decrypted = egg_secure_alloc (n_data); gcry = gcry_cipher_decrypt (ch, *decrypted, *n_decrypted, (void*)data, n_data); if (gcry) { - gcry_free (*decrypted); - g_return_val_if_reached (GCK_DATA_FAILURE); + egg_secure_free (*decrypted); + g_return_val_if_reached (FALSE); } gcry_cipher_close (ch); - return GCK_DATA_SUCCESS; + return TRUE; } gboolean -gck_data_openssl_encrypt_block (const gchar *dekinfo, const gchar *password, +egg_openssl_encrypt_block (const gchar *dekinfo, const gchar *password, gssize n_password, const guchar *data, gsize n_data, guchar **encrypted, gsize *n_encrypted) { @@ -279,7 +595,7 @@ gck_data_openssl_encrypt_block (const gchar *dekinfo, const gchar *password, g_return_val_if_fail (ivlen >= 8, FALSE); /* IV is already set from the DEK info */ - if (!gck_crypto_symkey_generate_simple (algo, GCRY_MD_MD5, password, + if (!egg_symkey_generate_simple (algo, GCRY_MD_MD5, password, n_password, iv, 8, 1, &key, NULL)) g_return_val_if_reached (FALSE); @@ -288,7 +604,7 @@ gck_data_openssl_encrypt_block (const gchar *dekinfo, const gchar *password, gcry = gcry_cipher_setkey (ch, key, gcry_cipher_get_algo_keylen (algo)); g_return_val_if_fail (!gcry, FALSE); - gcry_free (key); + egg_secure_free (key); /* 16 = 128 bits */ gcry = gcry_cipher_setiv (ch, iv, ivlen); @@ -315,11 +631,11 @@ gck_data_openssl_encrypt_block (const gchar *dekinfo, const gchar *password, /* Encrypt the padded block */ if (n_overflow) { - padded = gcry_calloc_secure (ivlen, 1); + padded = egg_secure_alloc (ivlen); memset (padded, 0, ivlen); memcpy (padded, data + n_batch, n_overflow); gcry = gcry_cipher_encrypt (ch, *encrypted + n_batch, ivlen, padded, ivlen); - gcry_free (padded); + egg_secure_free (padded); if (gcry) { g_free (*encrypted); g_return_val_if_reached (FALSE); @@ -331,7 +647,7 @@ gck_data_openssl_encrypt_block (const gchar *dekinfo, const gchar *password, } const gchar* -gck_data_openssl_get_dekinfo (GHashTable *headers) +egg_openssl_get_dekinfo (GHashTable *headers) { const gchar *val; if (!headers) @@ -345,7 +661,7 @@ gck_data_openssl_get_dekinfo (GHashTable *headers) } const gchar* -gck_data_openssl_prep_dekinfo (GHashTable *headers) +egg_openssl_prep_dekinfo (GHashTable *headers) { gchar *dekinfo, *hex; gsize ivlen; @@ -358,7 +674,7 @@ gck_data_openssl_prep_dekinfo (GHashTable *headers) gcry_create_nonce (iv, ivlen); /* And encode it into the string */ - hex = gck_util_hex_encode (iv, ivlen); + hex = egg_hex_encode (iv, ivlen); g_return_val_if_fail (hex, NULL); dekinfo = g_strdup_printf ("DES-EDE3-CBC,%s", hex); g_free (hex); diff --git a/egg/egg-openssl.h b/egg/egg-openssl.h new file mode 100644 index 00000000..878cf589 --- /dev/null +++ b/egg/egg-openssl.h @@ -0,0 +1,56 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* egg-openssl.h - OpenSSL compatibility functionality + + Copyright (C) 2007 Stefan Walter + + The Gnome Keyring Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Gnome Keyring Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Gnome Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Stef Walter <stef@memberwebs.com> +*/ + +#ifndef EGG_OPENSSL_H_ +#define EGG_OPENSSL_H_ + +#include <glib.h> + +typedef void (*EggOpensslPemCallback) (GQuark type, const guchar *data, gsize n_data, + GHashTable *headers, gpointer user_data); + +GHashTable* egg_openssl_headers_new (void); + +guint egg_openssl_pem_parse (const guchar *data, gsize n_data, + EggOpensslPemCallback callback, + gpointer user_data); + +guchar* egg_openssl_pem_write (const guchar *data, gsize n_data, + GQuark type, GHashTable *headers, + gsize *n_result); + +int egg_openssl_parse_algo (const gchar *name, int *mode); + +gboolean egg_openssl_encrypt_block (const gchar *dekinfo, const gchar *password, + gssize n_password, const guchar *data, gsize n_data, + guchar **encrypted, gsize *n_encrypted); + +gboolean egg_openssl_decrypt_block (const gchar *dekinfo, const gchar *password, + gssize n_password, const guchar *data, gsize n_data, + guchar **decrypted, gsize *n_decrypted); + +const gchar* egg_openssl_get_dekinfo (GHashTable *headers); + +const gchar* egg_openssl_prep_dekinfo (GHashTable *headers); + +#endif /* EGG_OPENSSL_H_ */ diff --git a/egg/egg-symkey.c b/egg/egg-symkey.c new file mode 100644 index 00000000..426c7632 --- /dev/null +++ b/egg/egg-symkey.c @@ -0,0 +1,1027 @@ +/* + * gnome-keyring + * + * Copyright (C) 2008 Stefan Walter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General License for more details. + * + * You should have received a copy of the GNU Lesser General + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "config.h" + +#include "egg-asn1.h" +#include "egg-secure-memory.h" +#include "egg-symkey.h" + +/* ----------------------------------------------------------------------------- + * QUARKS + */ + +static GQuark OID_PBE_MD2_DES_CBC; +static GQuark OID_PBE_MD5_DES_CBC; +static GQuark OID_PBE_MD2_RC2_CBC; +static GQuark OID_PBE_MD5_RC2_CBC; +static GQuark OID_PBE_SHA1_DES_CBC; +static GQuark OID_PBE_SHA1_RC2_CBC; +static GQuark OID_PBES2; +static GQuark OID_PBKDF2; + +static GQuark OID_DES_CBC; +static GQuark OID_DES_RC2_CBC; +static GQuark OID_DES_EDE3_CBC; +static GQuark OID_DES_RC5_CBC; + +static GQuark OID_PKCS12_PBE_ARCFOUR_SHA1; +static GQuark OID_PKCS12_PBE_RC4_40_SHA1; +static GQuark OID_PKCS12_PBE_3DES_SHA1; +static GQuark OID_PKCS12_PBE_2DES_SHA1; +static GQuark OID_PKCS12_PBE_RC2_128_SHA1; +static GQuark OID_PKCS12_PBE_RC2_40_SHA1; + +static void +init_quarks (void) +{ + static volatile gsize quarks_inited = 0; + + if (g_once_init_enter (&quarks_inited)) { + + #define QUARK(name, value) \ + name = g_quark_from_static_string(value) + + QUARK (OID_PBE_MD2_DES_CBC, "1.2.840.113549.1.5.1"); + QUARK (OID_PBE_MD5_DES_CBC, "1.2.840.113549.1.5.3"); + QUARK (OID_PBE_MD2_RC2_CBC, "1.2.840.113549.1.5.4"); + QUARK (OID_PBE_MD5_RC2_CBC, "1.2.840.113549.1.5.6"); + QUARK (OID_PBE_SHA1_DES_CBC, "1.2.840.113549.1.5.10"); + QUARK (OID_PBE_SHA1_RC2_CBC, "1.2.840.113549.1.5.11"); + + QUARK (OID_PBES2, "1.2.840.113549.1.5.13"); + + QUARK (OID_PBKDF2, "1.2.840.113549.1.5.12"); + + QUARK (OID_DES_CBC, "1.3.14.3.2.7"); + QUARK (OID_DES_RC2_CBC, "1.2.840.113549.3.2"); + QUARK (OID_DES_EDE3_CBC, "1.2.840.113549.3.7"); + QUARK (OID_DES_RC5_CBC, "1.2.840.113549.3.9"); + + QUARK (OID_PKCS12_PBE_ARCFOUR_SHA1, "1.2.840.113549.1.12.1.1"); + QUARK (OID_PKCS12_PBE_RC4_40_SHA1, "1.2.840.113549.1.12.1.2"); + QUARK (OID_PKCS12_PBE_3DES_SHA1, "1.2.840.113549.1.12.1.3"); + QUARK (OID_PKCS12_PBE_2DES_SHA1, "1.2.840.113549.1.12.1.4"); + QUARK (OID_PKCS12_PBE_RC2_128_SHA1, "1.2.840.113549.1.12.1.5"); + QUARK (OID_PKCS12_PBE_RC2_40_SHA1, "1.2.840.113549.1.12.1.6"); + + #undef QUARK + + g_once_init_leave (&quarks_inited, 1); + } +} + +/* ----------------------------------------------------------------------------- + * PASSWORD TO KEY/IV + */ + +gboolean +egg_symkey_generate_simple (int cipher_algo, int hash_algo, + const gchar *password, gssize n_password, + const guchar *salt, gsize n_salt, int iterations, + guchar **key, guchar **iv) +{ + gcry_md_hd_t mdh; + gcry_error_t gcry; + guchar *digest; + guchar *digested; + guint n_digest; + gint pass, i; + gint needed_iv, needed_key; + guchar *at_iv, *at_key; + + g_assert (cipher_algo); + g_assert (hash_algo); + + g_return_val_if_fail (iterations >= 1, FALSE); + + if (!password) + n_password = 0; + if (n_password == -1) + n_password = strlen (password); + + /* + * If cipher algo needs more bytes than hash algo has available + * then the entire hashing process is done again (with the previous + * hash bytes as extra input), and so on until satisfied. + */ + + needed_key = gcry_cipher_get_algo_keylen (cipher_algo); + needed_iv = gcry_cipher_get_algo_blklen (cipher_algo); + + gcry = gcry_md_open (&mdh, hash_algo, 0); + if (gcry) { + g_warning ("couldn't create '%s' hash context: %s", + gcry_md_algo_name (hash_algo), gcry_strerror (gcry)); + return FALSE; + } + + n_digest = gcry_md_get_algo_dlen (hash_algo); + g_return_val_if_fail (n_digest > 0, FALSE); + + digest = egg_secure_alloc (n_digest); + g_return_val_if_fail (digest, FALSE); + if (key) { + *key = egg_secure_alloc (needed_key); + g_return_val_if_fail (*key, FALSE); + } + if (iv) + *iv = g_new0 (guchar, needed_iv); + + at_key = key ? *key : NULL; + at_iv = iv ? *iv : NULL; + + for (pass = 0; TRUE; ++pass) { + gcry_md_reset (mdh); + + /* Hash in the previous buffer on later passes */ + if (pass > 0) + gcry_md_write (mdh, digest, n_digest); + + if (password) + gcry_md_write (mdh, password, n_password); + if (salt && n_salt) + gcry_md_write (mdh, salt, n_salt); + gcry_md_final (mdh); + digested = gcry_md_read (mdh, 0); + g_return_val_if_fail (digested, FALSE); + memcpy (digest, digested, n_digest); + + for (i = 1; i < iterations; ++i) { + gcry_md_reset (mdh); + gcry_md_write (mdh, digest, n_digest); + gcry_md_final (mdh); + digested = gcry_md_read (mdh, 0); + g_return_val_if_fail (digested, FALSE); + memcpy (digest, digested, n_digest); + } + + /* Copy as much as possible into the destinations */ + i = 0; + while (needed_key && i < n_digest) { + if (at_key) + *(at_key++) = digest[i]; + needed_key--; + i++; + } + while (needed_iv && i < n_digest) { + if (at_iv) + *(at_iv++) = digest[i]; + needed_iv--; + i++; + } + + if (needed_key == 0 && needed_iv == 0) + break; + } + + egg_secure_free (digest); + gcry_md_close (mdh); + + return TRUE; +} + +gboolean +egg_symkey_generate_pbe (int cipher_algo, int hash_algo, const gchar *password, + gssize n_password, const guchar *salt, gsize n_salt, int iterations, + guchar **key, guchar **iv) +{ + gcry_md_hd_t mdh; + gcry_error_t gcry; + guchar *digest; + guchar *digested; + guint i, n_digest; + gint needed_iv, needed_key; + + g_assert (cipher_algo); + g_assert (hash_algo); + + g_return_val_if_fail (iterations >= 1, FALSE); + + if (!password) + n_password = 0; + if (n_password == -1) + n_password = strlen (password); + + /* + * We only do one pass here. + * + * The key ends up as the first needed_key bytes of the hash buffer. + * The iv ends up as the last needed_iv bytes of the hash buffer. + * + * The IV may overlap the key (which is stupid) if the wrong pair of + * hash/cipher algorithms are chosen. + */ + + n_digest = gcry_md_get_algo_dlen (hash_algo); + g_return_val_if_fail (n_digest > 0, FALSE); + + needed_key = gcry_cipher_get_algo_keylen (cipher_algo); + needed_iv = gcry_cipher_get_algo_blklen (cipher_algo); + if (needed_iv + needed_key > 16 || needed_iv + needed_key > n_digest) { + g_warning ("using PBE symkey generation with %s using an algorithm that needs " + "too many bytes of key and/or IV: %s", + gcry_cipher_algo_name (hash_algo), + gcry_cipher_algo_name (cipher_algo)); + return FALSE; + } + + gcry = gcry_md_open (&mdh, hash_algo, 0); + if (gcry) { + g_warning ("couldn't create '%s' hash context: %s", + gcry_md_algo_name (hash_algo), gcry_strerror (gcry)); + return FALSE; + } + + digest = egg_secure_alloc (n_digest); + g_return_val_if_fail (digest, FALSE); + if (key) { + *key = egg_secure_alloc (needed_key); + g_return_val_if_fail (*key, FALSE); + } + if (iv) + *iv = g_new0 (guchar, needed_iv); + + if (password) + gcry_md_write (mdh, password, n_password); + if (salt && n_salt) + gcry_md_write (mdh, salt, n_salt); + gcry_md_final (mdh); + digested = gcry_md_read (mdh, 0); + g_return_val_if_fail (digested, FALSE); + memcpy (digest, digested, n_digest); + + for (i = 1; i < iterations; ++i) + gcry_md_hash_buffer (hash_algo, digest, digest, n_digest); + + /* The first x bytes are the key */ + if (key) { + g_assert (needed_key <= n_digest); + memcpy (*key, digest, needed_key); + } + + /* The last 16 - x bytes are the iv */ + if (iv) { + g_assert (needed_iv <= n_digest && n_digest >= 16); + memcpy (*iv, digest + (16 - needed_iv), needed_iv); + } + + egg_secure_free (digest); + gcry_md_close (mdh); + + return TRUE; +} + +static gboolean +generate_pkcs12 (int hash_algo, int type, const gchar *utf8_password, + gssize n_password, const guchar *salt, gsize n_salt, + int iterations, guchar *output, gsize n_output) +{ + gcry_mpi_t num_b1, num_ij; + guchar *hash, *buf_i, *buf_b; + const gchar *end_password; + gcry_md_hd_t mdh; + const gchar *p2; + guchar *p; + gsize n_hash, i; + gunichar unich; + gcry_error_t gcry; + + num_b1 = num_ij = NULL; + + n_hash = gcry_md_get_algo_dlen (hash_algo); + g_return_val_if_fail (n_hash > 0, FALSE); + + if (!utf8_password) + n_password = 0; + if (n_password == -1) + end_password = utf8_password + strlen (utf8_password); + else + end_password = utf8_password + n_password; + + gcry = gcry_md_open (&mdh, hash_algo, 0); + if (gcry) { + g_warning ("couldn't create '%s' hash context: %s", + gcry_md_algo_name (hash_algo), gcry_strerror (gcry)); + return FALSE; + } + + /* Reqisition me a buffer */ + hash = egg_secure_alloc (n_hash); + buf_i = egg_secure_alloc (128); + buf_b = egg_secure_alloc (64); + g_return_val_if_fail (hash && buf_i && buf_b, FALSE); + + /* Bring in the salt */ + p = buf_i; + if (salt) { + for (i = 0; i < 64; ++i) + *(p++) = salt[i % n_salt]; + } else { + memset (p, 0, 64); + p += 64; + } + + /* Bring in the password, as 16bits per character BMP string, ie: UCS2 */ + if (utf8_password) { + p2 = utf8_password; + for (i = 0; i < 64; i += 2) { + + /* Get a character from the string */ + if (p2 < end_password) { + unich = g_utf8_get_char (p2); + p2 = g_utf8_next_char (p2); + + /* Get zero null terminator, and loop back to beginning */ + } else { + unich = 0; + p2 = utf8_password; + } + + /* Encode the bytes received */ + *(p++) = (unich & 0xFF00) >> 8; + *(p++) = (unich & 0xFF); + } + } else { + memset (p, 0, 64); + p += 64; + } + + /* Hash and bash */ + for (;;) { + gcry_md_reset (mdh); + + /* Put in the PKCS#12 type of key */ + for (i = 0; i < 64; ++i) + gcry_md_putc (mdh, type); + + /* Bring in the password */ + gcry_md_write (mdh, buf_i, utf8_password ? 128 : 64); + + /* First iteration done */ + memcpy (hash, gcry_md_read (mdh, hash_algo), n_hash); + + /* All the other iterations */ + for (i = 1; i < iterations; i++) + gcry_md_hash_buffer (hash_algo, hash, hash, n_hash); + + /* Take out as much as we need */ + for (i = 0; i < n_hash && n_output; ++i) { + *(output++) = hash[i]; + --n_output; + } + + /* Is that enough generated keying material? */ + if (!n_output) + break; + + /* Need more bytes, do some voodoo */ + for (i = 0; i < 64; ++i) + buf_b[i] = hash[i % n_hash]; + gcry = gcry_mpi_scan (&num_b1, GCRYMPI_FMT_USG, buf_b, 64, NULL); + g_return_val_if_fail (gcry == 0, FALSE); + gcry_mpi_add_ui (num_b1, num_b1, 1); + for (i = 0; i < 128; i += 64) { + gcry = gcry_mpi_scan (&num_ij, GCRYMPI_FMT_USG, buf_i + i, 64, NULL); + g_return_val_if_fail (gcry == 0, FALSE); + gcry_mpi_add (num_ij, num_ij, num_b1); + gcry_mpi_clear_highbit (num_ij, 64 * 8); + gcry = gcry_mpi_print (GCRYMPI_FMT_USG, buf_i + i, 64, NULL, num_ij); + g_return_val_if_fail (gcry == 0, FALSE); + gcry_mpi_release (num_ij); + } + } + + egg_secure_free (buf_i); + egg_secure_free (buf_b); + egg_secure_free (hash); + gcry_mpi_release (num_b1); + gcry_md_close (mdh); + + return TRUE; +} + +gboolean +egg_symkey_generate_pkcs12 (int cipher_algo, int hash_algo, const gchar *password, + gssize n_password, const guchar *salt, gsize n_salt, + int iterations, guchar **key, guchar **iv) +{ + gsize n_block, n_key; + gboolean ret = TRUE; + + g_return_val_if_fail (cipher_algo, FALSE); + g_return_val_if_fail (hash_algo, FALSE); + g_return_val_if_fail (iterations > 0, FALSE); + + n_key = gcry_cipher_get_algo_keylen (cipher_algo); + n_block = gcry_cipher_get_algo_blklen (cipher_algo); + + if (password && !g_utf8_validate (password, n_password, NULL)) { + g_warning ("invalid non-UTF8 password"); + g_return_val_if_reached (FALSE); + } + + if (key) + *key = NULL; + if (iv) + *iv = NULL; + + /* Generate us an key */ + if (key) { + *key = egg_secure_alloc (n_key); + g_return_val_if_fail (*key != NULL, FALSE); + ret = generate_pkcs12 (hash_algo, 1, password, n_password, salt, n_salt, + iterations, *key, n_key); + } + + /* Generate us an iv */ + if (ret && iv) { + if (n_block > 1) { + *iv = g_malloc (n_block); + ret = generate_pkcs12 (hash_algo, 2, password, n_password, salt, n_salt, + iterations, *iv, n_block); + } else { + *iv = NULL; + } + } + + /* Cleanup in case of failure */ + if (!ret) { + g_free (iv ? *iv : NULL); + egg_secure_free (key ? *key : NULL); + } + + return ret; +} + +static gboolean +generate_pbkdf2 (int hash_algo, const gchar *password, gsize n_password, + const guchar *salt, gsize n_salt, guint iterations, + guchar *output, gsize n_output) +{ + gcry_md_hd_t mdh; + guint u, l, r, i, k; + gcry_error_t gcry; + guchar *U, *T, *buf; + gsize n_buf, n_hash; + + g_return_val_if_fail (hash_algo > 0, FALSE); + g_return_val_if_fail (iterations > 0, FALSE); + g_return_val_if_fail (n_output > 0, FALSE); + g_return_val_if_fail (n_output < G_MAXUINT32, FALSE); + + n_hash = gcry_md_get_algo_dlen (hash_algo); + g_return_val_if_fail (n_hash > 0, FALSE); + + gcry = gcry_md_open (&mdh, hash_algo, GCRY_MD_FLAG_HMAC); + if (gcry != 0) { + g_warning ("couldn't create '%s' hash context: %s", + gcry_md_algo_name (hash_algo), gcry_strerror (gcry)); + return FALSE; + } + + /* Get us a temporary buffers */ + T = egg_secure_alloc (n_hash); + U = egg_secure_alloc (n_hash); + n_buf = n_salt + 4; + buf = egg_secure_alloc (n_buf); + g_return_val_if_fail (buf && T && U, FALSE); + + /* n_hash blocks in output, rounding up */ + l = ((n_output - 1) / n_hash) + 1; + + /* number of bytes in last, rounded up, n_hash block */ + r = n_output - (l - 1) * n_hash; + + memcpy (buf, salt, n_salt); + for (i = 1; i <= l; i++) { + memset (T, 0, n_hash); + for (u = 1; u <= iterations; u++) { + gcry_md_reset (mdh); + + gcry = gcry_md_setkey (mdh, password, n_password); + g_return_val_if_fail (gcry == 0, FALSE); + + /* For first iteration on each block add 4 extra bytes */ + if (u == 1) { + buf[n_salt + 0] = (i & 0xff000000) >> 24; + buf[n_salt + 1] = (i & 0x00ff0000) >> 16; + buf[n_salt + 2] = (i & 0x0000ff00) >> 8; + buf[n_salt + 3] = (i & 0x000000ff) >> 0; + + gcry_md_write (mdh, buf, n_buf); + + /* Other iterations, any block */ + } else { + gcry_md_write (mdh, U, n_hash); + } + + memcpy (U, gcry_md_read (mdh, hash_algo), n_hash); + + for (k = 0; k < n_hash; k++) + T[k] ^= U[k]; + } + + memcpy (output + (i - 1) * n_hash, T, i == l ? r : n_hash); + } + + egg_secure_free (T); + egg_secure_free (U); + egg_secure_free (buf); + gcry_md_close (mdh); + return TRUE; +} + +gboolean +egg_symkey_generate_pbkdf2 (int cipher_algo, int hash_algo, + const gchar *password, gssize n_password, + const guchar *salt, gsize n_salt, int iterations, + guchar **key, guchar **iv) +{ + gsize n_key, n_block; + gboolean ret = TRUE; + + g_return_val_if_fail (hash_algo, FALSE); + g_return_val_if_fail (cipher_algo, FALSE); + g_return_val_if_fail (iterations > 0, FALSE); + + n_key = gcry_cipher_get_algo_keylen (cipher_algo); + n_block = gcry_cipher_get_algo_blklen (cipher_algo); + + if (key) + *key = NULL; + if (iv) + *iv = NULL; + + if (!password) + n_password = 0; + if (n_password == -1) + n_password = strlen (password); + + /* Generate us an key */ + if (key) { + *key = egg_secure_alloc (n_key); + g_return_val_if_fail (*key != NULL, FALSE); + ret = generate_pbkdf2 (hash_algo, password, n_password, salt, n_salt, + iterations, *key, n_key); + } + + /* Generate us an iv */ + if (ret && iv) { + if (n_block > 1) { + *iv = g_malloc (n_block); + gcry_create_nonce (*iv, n_block); + } else { + *iv = NULL; + } + } + + /* Cleanup in case of failure */ + if (!ret) { + g_free (iv ? *iv : NULL); + egg_secure_free (key ? *key : NULL); + } + + return ret; +} + +/* ---------------------------------------------------------------------------- + * DER encoded cipher params + */ + + +static gboolean +read_cipher_pkcs5_pbe (int cipher_algo, int cipher_mode, int hash_algo, + const gchar *password, gsize n_password, const guchar *data, + gsize n_data, gcry_cipher_hd_t *cih) +{ + ASN1_TYPE asn = ASN1_TYPE_EMPTY; + gcry_error_t gcry; + const guchar *salt; + gsize n_salt; + gsize n_block, n_key; + guint iterations; + guchar *key = NULL; + guchar *iv = NULL; + gboolean ret; + + g_return_val_if_fail (cipher_algo != 0 && cipher_mode != 0, FALSE); + g_return_val_if_fail (cih != NULL, FALSE); + g_return_val_if_fail (data != NULL && n_data != 0, FALSE); + + *cih = NULL; + ret = FALSE; + + /* Check if we can use this algorithm */ + if (gcry_cipher_algo_info (cipher_algo, GCRYCTL_TEST_ALGO, NULL, 0) != 0 || + gcry_md_test_algo (hash_algo) != 0) + goto done; + + asn = egg_asn1_decode ("PKIX1.pkcs-5-PBE-params", data, n_data); + if (!asn) + goto done; + + salt = egg_asn1_read_content (asn, data, n_data, "salt", &n_salt); + if (!salt) + goto done; + if (!egg_asn1_read_uint (asn, "iterationCount", &iterations)) + iterations = 1; + + n_key = gcry_cipher_get_algo_keylen (cipher_algo); + g_return_val_if_fail (n_key > 0, FALSE); + n_block = gcry_cipher_get_algo_blklen (cipher_algo); + + if (!egg_symkey_generate_pbe (cipher_algo, hash_algo, password, n_password, salt, + n_salt, iterations, &key, n_block > 1 ? &iv : NULL)) + goto done; + + gcry = gcry_cipher_open (cih, cipher_algo, cipher_mode, 0); + if (gcry != 0) { + g_warning ("couldn't create cipher: %s", gcry_strerror (gcry)); + goto done; + } + + if (iv) + gcry_cipher_setiv (*cih, iv, n_block); + gcry_cipher_setkey (*cih, key, n_key); + + ret = TRUE; + +done: + g_free (iv); + egg_secure_free (key); + + if (asn) + asn1_delete_structure (&asn); + + return ret; +} + +static gboolean +setup_pkcs5_rc2_params (const guchar *data, guchar n_data, gcry_cipher_hd_t cih) +{ + ASN1_TYPE asn = ASN1_TYPE_EMPTY; + gcry_error_t gcry; + const guchar *iv; + gsize n_iv; + guint version; + + g_assert (data); + + asn = egg_asn1_decode ("PKIX1.pkcs-5-rc2-CBC-params", data, n_data); + if (!asn) + return FALSE; + + if (!egg_asn1_read_uint (asn, "rc2ParameterVersion", &version)) + return FALSE; + + iv = egg_asn1_read_content (asn, data, n_data, "iv", &n_iv); + asn1_delete_structure (&asn); + + if (!iv) + return FALSE; + + gcry = gcry_cipher_setiv (cih, iv, n_iv); + + if (gcry != 0) { + g_message ("couldn't set %lu byte iv on cipher", (gulong)n_iv); + return FALSE; + } + + return TRUE; +} + +static gboolean +setup_pkcs5_des_params (const guchar *data, guchar n_data, gcry_cipher_hd_t cih) +{ + ASN1_TYPE asn = ASN1_TYPE_EMPTY; + gcry_error_t gcry; + const guchar *iv; + gsize n_iv; + + g_assert (data); + + asn = egg_asn1_decode ("PKIX1.pkcs-5-des-EDE3-CBC-params", data, n_data); + if (!asn) + asn = egg_asn1_decode ("PKIX1.pkcs-5-des-CBC-params", data, n_data); + if (!asn) + return FALSE; + + iv = egg_asn1_read_content (asn, data, n_data, "", &n_iv); + asn1_delete_structure (&asn); + + if (!iv) + return FALSE; + + gcry = gcry_cipher_setiv (cih, iv, n_iv); + + if (gcry != 0) { + g_message ("couldn't set %lu byte iv on cipher", (gulong)n_iv); + return FALSE; + } + + return TRUE; +} + +static gboolean +setup_pkcs5_pbkdf2_params (const gchar *password, gsize n_password, const guchar *data, + gsize n_data, int cipher_algo, gcry_cipher_hd_t cih) +{ + ASN1_TYPE asn = ASN1_TYPE_EMPTY; + gboolean ret; + gcry_error_t gcry; + guchar *key = NULL; + const guchar *salt; + gsize n_salt, n_key; + guint iterations; + + g_assert (cipher_algo); + g_assert (data); + + ret = FALSE; + + asn = egg_asn1_decode ("PKIX1.pkcs-5-PBKDF2-params", data, n_data); + if (!asn) + goto done; + + if (!egg_asn1_read_uint (asn, "iterationCount", &iterations)) + iterations = 1; + salt = egg_asn1_read_content (asn, data, n_data, "salt.specified", &n_salt); + if (!salt) + goto done; + + if (!egg_symkey_generate_pbkdf2 (cipher_algo, GCRY_MD_SHA1, password, n_password, + salt, n_salt, iterations, &key, NULL)) + goto done; + + n_key = gcry_cipher_get_algo_keylen (cipher_algo); + g_return_val_if_fail (n_key > 0, FALSE); + + gcry = gcry_cipher_setkey (cih, key, n_key); + if (gcry != 0) { + g_message ("couldn't set %lu byte key on cipher", (gulong)n_key); + goto done; + } + + ret = TRUE; + +done: + egg_secure_free (key); + if (asn) + asn1_delete_structure (&asn); + return ret; +} + +static gboolean +read_cipher_pkcs5_pbes2 (const gchar *password, gsize n_password, const guchar *data, + gsize n_data, gcry_cipher_hd_t *cih) +{ + ASN1_TYPE asn = ASN1_TYPE_EMPTY; + gboolean r, ret; + GQuark key_deriv_algo, enc_oid; + gcry_error_t gcry; + int algo, mode; + int beg, end; + + g_return_val_if_fail (cih != NULL, FALSE); + g_return_val_if_fail (data != NULL && n_data != 0, FALSE); + + init_quarks (); + + *cih = NULL; + ret = FALSE; + + asn = egg_asn1_decode ("PKIX1.pkcs-5-PBES2-params", data, n_data); + if (!asn) + goto done; + + algo = mode = 0; + + /* Read in all the encryption type */ + enc_oid = egg_asn1_read_oid (asn, "encryptionScheme.algorithm"); + if (!enc_oid) + goto done; + if (enc_oid == OID_DES_EDE3_CBC) + algo = GCRY_CIPHER_3DES; + else if (enc_oid == OID_DES_CBC) + algo = GCRY_CIPHER_DES; + else if (enc_oid == OID_DES_RC2_CBC) + algo = GCRY_CIPHER_RFC2268_128; + else if (enc_oid == OID_DES_RC5_CBC) + /* RC5 doesn't exist in libgcrypt */; + + /* Unsupported? */ + if (algo == 0 || gcry_cipher_algo_info (algo, GCRYCTL_TEST_ALGO, NULL, 0) != 0) + goto done; + + /* Instantiate our cipher */ + gcry = gcry_cipher_open (cih, algo, GCRY_CIPHER_MODE_CBC, 0); + if (gcry != 0) { + g_warning ("couldn't create cipher: %s", gcry_cipher_algo_name (algo)); + goto done; + } + + /* Read out the parameters */ + if (asn1_der_decoding_startEnd (asn, data, n_data, "encryptionScheme.parameters", + &beg, &end) != ASN1_SUCCESS) + goto done; + + switch (algo) { + case GCRY_CIPHER_3DES: + case GCRY_CIPHER_DES: + r = setup_pkcs5_des_params (data + beg, end - beg + 1, *cih); + break; + case GCRY_CIPHER_RFC2268_128: + r = setup_pkcs5_rc2_params (data + beg, end - beg + 1, *cih); + break; + default: + /* Should have been caught on the oid check above */ + g_assert_not_reached (); + r = FALSE; + break; + }; + + if (r != TRUE) + goto done; + + /* Read out the key creation paramaters */ + key_deriv_algo = egg_asn1_read_oid (asn, "keyDerivationFunc.algorithm"); + if (!key_deriv_algo) + goto done; + if (key_deriv_algo != OID_PBKDF2) { + g_message ("unsupported key derivation algorithm: %s", g_quark_to_string (key_deriv_algo)); + goto done; + } + + if (asn1_der_decoding_startEnd (asn, data, n_data, "keyDerivationFunc.parameters", + &beg, &end) != ASN1_SUCCESS) + goto done; + + ret = setup_pkcs5_pbkdf2_params (password, n_password, data + beg, end - beg + 1, algo, *cih); + +done: + if (ret != TRUE && *cih) { + gcry_cipher_close (*cih); + *cih = NULL; + } + + if (asn) + asn1_delete_structure (&asn); + + return ret; +} + +static gboolean +read_cipher_pkcs12_pbe (int cipher_algo, int cipher_mode, const gchar *password, + gsize n_password, const guchar *data, gsize n_data, + gcry_cipher_hd_t *cih) +{ + ASN1_TYPE asn = ASN1_TYPE_EMPTY; + gcry_error_t gcry; + gboolean ret; + const guchar *salt; + gsize n_salt; + gsize n_block, n_key; + guint iterations; + guchar *key = NULL; + guchar *iv = NULL; + + g_return_val_if_fail (cipher_algo != 0 && cipher_mode != 0, FALSE); + g_return_val_if_fail (cih != NULL, FALSE); + g_return_val_if_fail (data != NULL && n_data != 0, FALSE); + + *cih = NULL; + ret = FALSE; + + /* Check if we can use this algorithm */ + if (gcry_cipher_algo_info (cipher_algo, GCRYCTL_TEST_ALGO, NULL, 0) != 0) + goto done; + + asn = egg_asn1_decode ("PKIX1.pkcs-12-PbeParams", data, n_data); + if (!asn) + goto done; + + salt = egg_asn1_read_content (asn, data, n_data, "salt", &n_salt); + if (!salt) + goto done; + if (!egg_asn1_read_uint (asn, "iterations", &iterations)) + goto done; + + n_block = gcry_cipher_get_algo_blklen (cipher_algo); + n_key = gcry_cipher_get_algo_keylen (cipher_algo); + + /* Generate IV and key using salt read above */ + if (!egg_symkey_generate_pkcs12 (cipher_algo, GCRY_MD_SHA1, password, + n_password, salt, n_salt, iterations, &key, + n_block > 1 ? &iv : NULL)) + goto done; + + gcry = gcry_cipher_open (cih, cipher_algo, cipher_mode, 0); + if (gcry != 0) { + g_warning ("couldn't create encryption cipher: %s", gcry_strerror (gcry)); + goto done; + } + + if (iv) + gcry_cipher_setiv (*cih, iv, n_block); + gcry_cipher_setkey (*cih, key, n_key); + + ret = TRUE; + +done: + if (ret != TRUE && *cih) { + gcry_cipher_close (*cih); + *cih = NULL; + } + + g_free (iv); + egg_secure_free (key); + + if (asn) + asn1_delete_structure (&asn); + + return ret; +} + +gboolean +egg_symkey_read_cipher (GQuark oid_scheme, const gchar *password, gsize n_password, + const guchar *data, gsize n_data, gcry_cipher_hd_t *cih) +{ + gboolean ret = FALSE; + + g_return_val_if_fail (oid_scheme != 0, FALSE); + g_return_val_if_fail (cih != NULL, FALSE); + g_return_val_if_fail (data != NULL && n_data != 0, FALSE); + + init_quarks (); + + /* PKCS#5 PBE */ + if (oid_scheme == OID_PBE_MD2_DES_CBC) + ret = read_cipher_pkcs5_pbe (GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CBC, + GCRY_MD_MD2, password, n_password, data, n_data, cih); + + else if (oid_scheme == OID_PBE_MD2_RC2_CBC) + /* RC2-64 has no implementation in libgcrypt */; + + else if (oid_scheme == OID_PBE_MD5_DES_CBC) + ret = read_cipher_pkcs5_pbe (GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CBC, + GCRY_MD_MD5, password, n_password, data, n_data, cih); + else if (oid_scheme == OID_PBE_MD5_RC2_CBC) + /* RC2-64 has no implementation in libgcrypt */; + + else if (oid_scheme == OID_PBE_SHA1_DES_CBC) + ret = read_cipher_pkcs5_pbe (GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CBC, + GCRY_MD_SHA1, password, n_password, data, n_data, cih); + else if (oid_scheme == OID_PBE_SHA1_RC2_CBC) + /* RC2-64 has no implementation in libgcrypt */; + + + /* PKCS#5 PBES2 */ + else if (oid_scheme == OID_PBES2) + ret = read_cipher_pkcs5_pbes2 (password, n_password, data, n_data, cih); + + + /* PKCS#12 PBE */ + else if (oid_scheme == OID_PKCS12_PBE_ARCFOUR_SHA1) + ret = read_cipher_pkcs12_pbe (GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, + password, n_password, data, n_data, cih); + else if (oid_scheme == OID_PKCS12_PBE_RC4_40_SHA1) + /* RC4-40 has no implementation in libgcrypt */; + + else if (oid_scheme == OID_PKCS12_PBE_3DES_SHA1) + ret = read_cipher_pkcs12_pbe (GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC, + password, n_password, data, n_data, cih); + else if (oid_scheme == OID_PKCS12_PBE_2DES_SHA1) + /* 2DES has no implementation in libgcrypt */; + + else if (oid_scheme == OID_PKCS12_PBE_RC2_128_SHA1) + ret = read_cipher_pkcs12_pbe (GCRY_CIPHER_RFC2268_128, GCRY_CIPHER_MODE_CBC, + password, n_password, data, n_data, cih); + + else if (oid_scheme == OID_PKCS12_PBE_RC2_40_SHA1) + ret = read_cipher_pkcs12_pbe (GCRY_CIPHER_RFC2268_40, GCRY_CIPHER_MODE_CBC, + password, n_password, data, n_data, cih); + + if (ret == FALSE) + g_message ("unsupported or invalid cipher: %s", g_quark_to_string (oid_scheme)); + + return ret; +} diff --git a/egg/egg-symkey.h b/egg/egg-symkey.h new file mode 100644 index 00000000..42317087 --- /dev/null +++ b/egg/egg-symkey.h @@ -0,0 +1,76 @@ +/* + * gnome-keyring + * + * Copyright (C) 2008 Stefan Walter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General License for more details. + * + * You should have received a copy of the GNU Lesser General + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef EGG_SYMKEY_H_ +#define EGG_SYMKEY_H_ + +#include <glib.h> + +#include <gcrypt.h> + +gboolean egg_symkey_generate_simple (int cipher_algo, + int hash_algo, + const gchar *password, + gssize n_password, + const guchar *salt, + gsize n_salt, + int iterations, + guchar **key, + guchar **iv); + +gboolean egg_symkey_generate_pbe (int cipher_algo, + int hash_algo, + const gchar *password, + gssize n_password, + const guchar *salt, + gsize n_salt, + int iterations, + guchar **key, + guchar **iv); + +gboolean egg_symkey_generate_pkcs12 (int cipher_algo, + int hash_algo, + const gchar *password, + gssize n_password, + const guchar *salt, + gsize n_salt, + int iterations, + guchar **key, + guchar **iv); + +gboolean egg_symkey_generate_pbkdf2 (int cipher_algo, + int hash_algo, + const gchar *password, + gssize n_password, + const guchar *salt, + gsize n_salt, + int iterations, + guchar **key, + guchar **iv); + +gboolean egg_symkey_read_cipher (GQuark oid_scheme, + const gchar *password, + gsize n_password, + const guchar *data, + gsize n_data, + gcry_cipher_hd_t *cih); + +#endif /* EGG_SYMKEY_H_ */ diff --git a/egg/tests/Makefile.am b/egg/tests/Makefile.am index 9b72249c..655c2c04 100644 --- a/egg/tests/Makefile.am +++ b/egg/tests/Makefile.am @@ -8,7 +8,10 @@ asn1-def-test.h: test.asn # Test files should be listed in order they need to run UNIT_AUTO = \ unit-test-asn1.c \ + unit-test-hex.c \ unit-test-secmem.c \ + unit-test-symkey.c \ + unit-test-openssl.c \ $(BUILT_SOURCES) UNIT_PROMPT = diff --git a/egg/tests/unit-test-asn1.c b/egg/tests/unit-test-asn1.c index 7728f8d3..f4cc44fe 100644 --- a/egg/tests/unit-test-asn1.c +++ b/egg/tests/unit-test-asn1.c @@ -274,11 +274,6 @@ DEFINE_TEST(oid) oid = egg_asn1_read_oid (asn, "nonExistant"); g_assert (oid == 0); - /* No quark of this has been defined, so should return an invalid OID */ - oid = egg_asn1_read_oid (asn, "data"); - g_assert (oid != 0); - g_assert_cmpstr (g_quark_to_string (oid), !=, "SOME DATA"); - /* Now a quark has been defined */ check = g_quark_from_static_string ("SOME DATA"); oid = egg_asn1_read_oid (asn, "data"); diff --git a/pkcs11/gck/tests/unit-test-util.c b/egg/tests/unit-test-hex.c index 409b5a53..1664ef71 100644 --- a/pkcs11/gck/tests/unit-test-util.c +++ b/egg/tests/unit-test-hex.c @@ -27,7 +27,7 @@ #include "run-auto-test.h" -#include "gck/gck-util.h" +#include "egg-hex.h" static const guchar TEST_DATA[] = { 0x05, 0xD6, 0x95, 0x96, 0x10, 0x12, 0xAE, 0x35 }; static const gchar *TEST_HEX = "05D695961012AE35"; @@ -37,7 +37,7 @@ DEFINE_TEST(hex_encode) { gchar *hex; - hex = gck_util_hex_encode (TEST_DATA, sizeof (TEST_DATA)); + hex = egg_hex_encode (TEST_DATA, sizeof (TEST_DATA)); g_assert (hex); g_assert_cmpstr (hex, ==, TEST_HEX); } @@ -47,23 +47,23 @@ DEFINE_TEST(hex_decode) guchar *data; gsize n_data; - data = gck_util_hex_decode (TEST_HEX, -1, &n_data); + data = egg_hex_decode (TEST_HEX, -1, &n_data); g_assert (data); g_assert (n_data == sizeof (TEST_DATA)); g_assert (memcmp (data, TEST_DATA, n_data) == 0); /* Spaces should be ignored */ - data = gck_util_hex_decode (TEST_HEX_SPACE, -1, &n_data); + data = egg_hex_decode (TEST_HEX_SPACE, -1, &n_data); g_assert (data); g_assert (n_data == sizeof (TEST_DATA)); g_assert (memcmp (data, TEST_DATA, n_data) == 0); /* Invalid input, null out */ - data = gck_util_hex_decode ("AB", 1, &n_data); + data = egg_hex_decode ("AB", 1, &n_data); g_assert (!data); /* Nothing in, empty out */ - data = gck_util_hex_decode ("AB", 0, &n_data); + data = egg_hex_decode ("AB", 0, &n_data); g_assert (data); g_assert (n_data == 0); } diff --git a/pkcs11/gck/tests/unit-test-data-openssl.c b/egg/tests/unit-test-openssl.c index 91bf7bc9..514e9b70 100644 --- a/pkcs11/gck/tests/unit-test-data-openssl.c +++ b/egg/tests/unit-test-openssl.c @@ -25,9 +25,8 @@ #include "run-auto-test.h" -#include "gck/gck-crypto.h" -#include "gck/gck-data-pem.h" -#include "gck/gck-data-openssl.h" +#include "egg-symkey.h" +#include "egg-openssl.h" #include <glib.h> @@ -51,7 +50,7 @@ static void parse_reference (GQuark type, const guchar *data, gsize n_data, GHashTable *headers, gpointer user_data) { - GckDataResult res; + gboolean res; const gchar *dekinfo; g_assert ("no data in PEM callback" && data != NULL); @@ -60,13 +59,13 @@ parse_reference (GQuark type, const guchar *data, gsize n_data, n_refenc = n_data; g_assert ("no headers present in file" && headers != NULL); - refheaders = gck_data_pem_headers_new (); + refheaders = egg_openssl_headers_new (); g_hash_table_foreach (headers, copy_each_key_value, refheaders); - dekinfo = gck_data_openssl_get_dekinfo (headers); + dekinfo = egg_openssl_get_dekinfo (headers); g_assert ("no dekinfo in headers" && dekinfo != NULL); - res = gck_data_openssl_decrypt_block (dekinfo, "booo", 4, data, n_data, &refdata, &n_refdata); - g_assert ("couldn't openssl decrypt block" && res == GCK_DATA_SUCCESS); + res = egg_openssl_decrypt_block (dekinfo, "booo", 4, data, n_data, &refdata, &n_refdata); + g_assert ("couldn't openssl decrypt block" && res == TRUE); g_assert ("no data returned from openssl decrypt" && refdata != NULL); g_assert ("invalid amount of data returned from openssl decrypt" && n_refdata == n_data); } @@ -79,7 +78,7 @@ DEFINE_TEST(parse_reference) input = test_read_testdata ("pem-rsa-enc.key", &n_input); - num = gck_data_pem_parse (input, n_input, parse_reference, NULL); + num = egg_openssl_pem_parse (input, n_input, parse_reference, NULL); g_assert ("couldn't PEM block in reference data" && num == 1); g_assert ("parse_reference() wasn't called" && refdata != NULL); @@ -92,10 +91,10 @@ DEFINE_TEST(write_reference) gsize n_encrypted; gboolean ret; - dekinfo = gck_data_openssl_get_dekinfo (refheaders); + dekinfo = egg_openssl_get_dekinfo (refheaders); g_assert ("no dekinfo in headers" && dekinfo != NULL); - ret = gck_data_openssl_encrypt_block (dekinfo, "booo", 4, refdata, n_refdata, &encrypted, &n_encrypted); + ret = egg_openssl_encrypt_block (dekinfo, "booo", 4, refdata, n_refdata, &encrypted, &n_encrypted); g_assert ("couldn't openssl encrypt block" && ret == TRUE); g_assert ("no data returned from openssl encrypt" && encrypted != NULL); g_assert ("invalid amount of data returned from openssl encrypt" && n_refdata <= n_encrypted); @@ -111,21 +110,21 @@ const gsize TEST_DATA_L = 29; DEFINE_TEST(openssl_roundtrip) { const gchar *dekinfo; - GckDataResult res; + gboolean res; gboolean ret; guchar *encrypted, *decrypted; gsize n_encrypted, n_decrypted; int i; - dekinfo = gck_data_openssl_prep_dekinfo (refheaders); + dekinfo = egg_openssl_prep_dekinfo (refheaders); - ret = gck_data_openssl_encrypt_block (dekinfo, "password", -1, TEST_DATA, TEST_DATA_L, &encrypted, &n_encrypted); + ret = egg_openssl_encrypt_block (dekinfo, "password", -1, TEST_DATA, TEST_DATA_L, &encrypted, &n_encrypted); g_assert ("couldn't openssl encrypt block" && ret == TRUE); g_assert ("no data returned from openssl encrypt" && encrypted != NULL); g_assert ("invalid amount of data returned from openssl encrypt" && TEST_DATA_L <= n_encrypted); - res = gck_data_openssl_decrypt_block (dekinfo, "password", 8, encrypted, n_encrypted, &decrypted, &n_decrypted); - g_assert ("couldn't openssl decrypt block" && res == GCK_DATA_SUCCESS); + res = egg_openssl_decrypt_block (dekinfo, "password", 8, encrypted, n_encrypted, &decrypted, &n_decrypted); + g_assert ("couldn't openssl decrypt block" && res == TRUE); g_assert ("no data returned from openssl decrypt" && decrypted != NULL); /* Check that the data was decrypted properly */ diff --git a/egg/tests/unit-test-symkey.c b/egg/tests/unit-test-symkey.c new file mode 100644 index 00000000..6b8d449a --- /dev/null +++ b/egg/tests/unit-test-symkey.c @@ -0,0 +1,226 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* unit-test-crypto.c: Test crypto stuff + + Copyright (C) 2007 Stefan Walter + + The Gnome Keyring Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Gnome Keyring Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Gnome Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Stef Walter <stef@memberwebs.com> +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "run-auto-test.h" + +#include "egg-symkey.h" + +#include <gcrypt.h> + +DEFINE_SETUP(crypto_setup) +{ + gcry_check_version (LIBGCRYPT_VERSION); +} + +DEFINE_TEARDOWN(crypto_setup) +{ + +} + +const static struct { + const gchar *password; + int cipher_algo; + int hash_algo; + int iterations; + const gchar *salt; + + const gchar *result_simple; + const gchar *result_pkcs12; + const gchar *result_pbkdf2; + const gchar *result_pbe; +} all_generation_tests[] = { + + { /* 24 byte output */ + "booo", GCRY_CIPHER_3DES, GCRY_MD_MD5, 1, + "\x70\x4C\xFF\xD6\x2F\xBA\x03\xE9", + "\x84\x12\xBB\x34\x94\x8C\x40\xAD\x97\x57\x96\x74\x5B\x6A\xFB\xF8\xD6\x61\x33\x51\xEA\x8C\xCF\xD8", + NULL, + NULL, + NULL + }, + + { /* 5 byte output */ + "booo", GCRY_CIPHER_RFC2268_40, GCRY_MD_SHA1, 2048, + "\x8A\x58\xC2\xE8\x7C\x1D\x80\x11", + NULL, + "\xD6\xA6\xF0\x76\x66", + NULL, + NULL + }, + + { /* Null Password, 5 byte output */ + NULL, GCRY_CIPHER_RFC2268_40, GCRY_MD_SHA1, 2000, + "\x04\xE0\x1C\x3E\xF8\xF2\xE9\xFD", + NULL, + "\x98\x7F\x20\x97\x1E", + NULL, + NULL + }, + + { /* 24 byte output */ + "booo", GCRY_CIPHER_3DES, GCRY_MD_SHA1, 2048, + "\xBD\xEE\x0B\xC6\xCF\x43\xAC\x25", + NULL, + "\x3F\x38\x1B\x0E\x87\xEB\x19\xBE\xD1\x39\xDC\x5B\xC2\xD2\xB3\x3C\x35\xA8\xB8\xF9\xEE\x66\x48\x94", + "\x20\x25\x90\xD8\xD6\x98\x3E\x71\x10\x17\x1F\x51\x49\x87\x27\xCA\x97\x27\xD1\xC9\x72\xF8\x11\xBB", + NULL + }, + + { /* Empty password, 24 byte output */ + "", GCRY_CIPHER_3DES, GCRY_MD_SHA1, 2048, + "\xF7\xCF\xD9\xCF\x1F\xF3\xAD\xF6", + NULL, + NULL, + "\x53\xE3\x35\x9E\x5D\xC1\x85\x1A\x71\x3A\x67\x4E\x80\x56\x13\xD6\x4E\x3E\x89\x43\xB7\x1D\x5F\x7F", + NULL + }, + + { /* Empty password, 24 byte output */ + "", GCRY_CIPHER_3DES, GCRY_MD_SHA1, 2048, + "\xD9\xB3\x2E\xC7\xBA\x1A\x8E\x15", + NULL, + "\x39\x70\x75\x7C\xF5\xE2\x13\x0B\x5D\xC2\x9D\x96\x8B\x71\xC7\xFC\x5B\x97\x1F\x79\x9F\x06\xFC\xA2", + NULL, + NULL + }, + + { /* 8 byte output */ + "booo", GCRY_CIPHER_DES, GCRY_MD_MD5, 2048, + "\x93\x4C\x3D\x29\xA2\x42\xB0\xF5", + NULL, + NULL, + NULL, + "\x8C\x67\x19\x7F\xB9\x23\xE2\x8D" + } +}; + +#define N_GENERATION_TESTS (sizeof (all_generation_tests) / sizeof (all_generation_tests[0])) + +DEFINE_TEST(generate_key_simple) +{ + int i; + gboolean ret; + guchar *key; + + for (i = 0; i < N_GENERATION_TESTS; ++i) { + + if (!all_generation_tests[i].result_simple) + continue; + + ret = egg_symkey_generate_simple (all_generation_tests[i].cipher_algo, + all_generation_tests[i].hash_algo, + all_generation_tests[i].password, -1, + (guchar*)all_generation_tests[i].salt, 8, + all_generation_tests[i].iterations, + &key, NULL); + g_assert (ret && "key generation failed"); + + ret = (memcmp (key, all_generation_tests[i].result_simple, + gcry_cipher_get_algo_keylen (all_generation_tests[i].cipher_algo)) == 0); + + g_assert (ret && "invalid simple key generated"); + } +} + +DEFINE_TEST(generate_key_pkcs12) +{ + int i; + gboolean ret; + guchar *key; + + for (i = 0; i < N_GENERATION_TESTS; ++i) { + + if (!all_generation_tests[i].result_pkcs12) + continue; + + ret = egg_symkey_generate_pkcs12 (all_generation_tests[i].cipher_algo, + all_generation_tests[i].hash_algo, + all_generation_tests[i].password, -1, + (guchar*)all_generation_tests[i].salt, 8, + all_generation_tests[i].iterations, + &key, NULL); + g_assert ("failed to generate pkcs12 key" && ret); + + ret = (memcmp (key, all_generation_tests[i].result_pkcs12, + gcry_cipher_get_algo_keylen (all_generation_tests[i].cipher_algo)) == 0); + + g_assert ("invalid pkcs12 key generated" && ret); + } +} + +DEFINE_TEST(generate_key_pbkdf2) +{ + int i; + gboolean ret; + guchar *key; + + for (i = 0; i < N_GENERATION_TESTS; ++i) { + + if (!all_generation_tests[i].result_pbkdf2) + continue; + + ret = egg_symkey_generate_pbkdf2 (all_generation_tests[i].cipher_algo, + all_generation_tests[i].hash_algo, + all_generation_tests[i].password, -1, + (guchar*)all_generation_tests[i].salt, 8, + all_generation_tests[i].iterations, + &key, NULL); + g_assert ("failed to generate pbkdf2 key" && ret); + + ret = (memcmp (key, all_generation_tests[i].result_pbkdf2, + gcry_cipher_get_algo_keylen (all_generation_tests[i].cipher_algo)) == 0); + + g_assert ("invalid pbkdf2 key generated" && ret); + } +} + +DEFINE_TEST(generate_key_pbe) +{ + int i; + gboolean ret; + guchar *key; + + for (i = 0; i < N_GENERATION_TESTS; ++i) { + + if (!all_generation_tests[i].result_pbe) + continue; + + ret = egg_symkey_generate_pbe (all_generation_tests[i].cipher_algo, + all_generation_tests[i].hash_algo, + all_generation_tests[i].password, -1, + (guchar*)all_generation_tests[i].salt, 8, + all_generation_tests[i].iterations, + &key, NULL); + g_assert ("failed to generate pbe key" && ret); + + ret = (memcmp (key, all_generation_tests[i].result_pbe, + gcry_cipher_get_algo_keylen (all_generation_tests[i].cipher_algo)) == 0); + + g_assert ("invalid pbe key generated" && ret); + + } +} diff --git a/gcr/Makefile.am b/gcr/Makefile.am new file mode 100644 index 00000000..fc6d492d --- /dev/null +++ b/gcr/Makefile.am @@ -0,0 +1,62 @@ +incdir = $(includedir)/gcr + +inc_HEADERS = \ + gcr-parser.h \ + gcr-types.h + +INCLUDES = \ + -I$(top_builddir) \ + -I$(top_srcdir) \ + $(GOBJECT_CFLAGS) \ + $(GLIB_CFLAGS) + +BUILT_SOURCES = \ + gcr-marshal.c gcr-marshal.h + +lib_LTLIBRARIES = libgcr.la + +libgcr_la_SOURCES = \ + gcr-internal.c gcr-internal.h \ + gcr-parser.c gcr-parser.h \ + gcr-types.h \ + $(BUILT_SOURCES) + +libgcr_la_LDFLAGS = \ + -version-info $(GCR_LT_RELEASE) \ + -no-undefined -export-symbols-regex 'gcr_*' + +libgcr_la_LIBADD = \ + $(top_builddir)/egg/libegg.la \ + $(top_builddir)/gp11/libgp11.la \ + $(GOBJECT_LIBS) \ + $(GLIB_LIBS) + +gcr-marshal.h: gcr-marshal.list $(GLIB_GENMARSHAL) + $(GLIB_GENMARSHAL) $< --header --prefix=_gcr_marshal > $@ + +gcr-marshal.c: gcr-marshal.list $(GLIB_GENMARSHAL) + echo "#include \"gcr-marshal.h\"" > $@ && \ + $(GLIB_GENMARSHAL) $< --body --prefix=_gcr_marshal >> $@ + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = gcr-$(GCR_MAJOR).pc + +EXTRA_DIST = \ + gcr.pc.in \ + gcr-marshal.list + +DISTCLEANFILES = \ + gcr-$(GCR_MAJOR).pc + +gcr-$(GCR_MAJOR).pc: gcr.pc + cp gcr.pc gcr-$(GCR_MAJOR).pc + +if WITH_TESTS +TESTS_DIR = tests +else +TESTS_DIR = +endif + +SUBDIRS = . \ + $(TESTS_DIR) +
\ No newline at end of file diff --git a/gcr/gcr-import-dialog.glade b/gcr/gcr-import-dialog.glade new file mode 100644 index 00000000..7da00a14 --- /dev/null +++ b/gcr/gcr-import-dialog.glade @@ -0,0 +1,167 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd"> +<!--Generated with glade3 3.4.5 on Sat Jan 17 14:53:28 2009 --> +<glade-interface> + <widget class="GtkDialog" id="dialog1"> + <property name="border_width">5</property> + <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> + <property name="has_separator">False</property> + <child internal-child="vbox"> + <widget class="GtkVBox" id="dialog-vbox1"> + <property name="visible">True</property> + <property name="spacing">2</property> + <child> + <widget class="GtkVBox" id="vbox1"> + <property name="visible">True</property> + <property name="spacing">6</property> + <child> + <widget class="GtkHBox" id="hbox2"> + <property name="visible">True</property> + <property name="spacing">12</property> + <child> + <widget class="GtkImage" id="image1"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="yalign">1</property> + <property name="stock">gtk-dialog-authentication</property> + <property name="icon_size">6</property> + </widget> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + <child> + <widget class="GtkVBox" id="vbox2"> + <property name="visible">True</property> + <property name="spacing">6</property> + <child> + <widget class="GtkLabel" id="primary-text"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes"><span size='large' weight='bold'>Import Certificates and Keys</span></property> + <property name="use_markup">True</property> + </widget> + </child> + <child> + <widget class="GtkLabel" id="secondary-text"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Secondary prompt text</property> + </widget> + <packing> + <property name="position">1</property> + </packing> + </child> + </widget> + <packing> + <property name="position">1</property> + </packing> + </child> + </widget> + <packing> + <property name="expand">False</property> + </packing> + </child> + <child> + <widget class="GtkTable" id="table1"> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">2</property> + <property name="column_spacing">12</property> + <property name="row_spacing">6</property> + <child> + <widget class="GtkEntry" id="password-entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + </packing> + </child> + <child> + <widget class="GtkComboBox" id="location-combo"> + <property name="visible">True</property> + <property name="button_sensitivity">GTK_SENSITIVITY_ON</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="label5"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Password:</property> + </widget> + <packing> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="label4"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Import Into:</property> + </widget> + <packing> + <property name="x_options">GTK_FILL</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + </widget> + <packing> + <property name="expand">False</property> + <property name="position">1</property> + </packing> + </child> + </widget> + <packing> + <property name="position">1</property> + </packing> + </child> + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="dialog-action_area1"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + <child> + <widget class="GtkButton" id="button1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="label" translatable="yes">gtk-cancel</property> + <property name="use_stock">True</property> + <property name="response_id">0</property> + </widget> + </child> + <child> + <widget class="GtkButton" id="button2"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="label" translatable="yes">gtk-ok</property> + <property name="use_stock">True</property> + <property name="response_id">0</property> + </widget> + <packing> + <property name="position">1</property> + </packing> + </child> + </widget> + <packing> + <property name="expand">False</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + </widget> + </child> + </widget> +</glade-interface> diff --git a/gcr/gcr-importer.c b/gcr/gcr-importer.c new file mode 100644 index 00000000..1ba00d6a --- /dev/null +++ b/gcr/gcr-importer.c @@ -0,0 +1,213 @@ +/* + * gnome-keyring + * + * Copyright (C) 2008 Stefan Walter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "config.h" + +#include "gcr-importer.h" + +enum { + PROP_0, + PROP_IMPORTER +}; + +enum { + SIGNAL, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +G_DEFINE_TYPE (GcrImporter, gcr_importer, G_TYPE_OBJECT); + +/* ----------------------------------------------------------------------------- + * INTERNAL + */ + +/* ----------------------------------------------------------------------------- + * OBJECT + */ + + +static GObject* +gcr_importer_constructor (GType type, guint n_props, GObjectConstructParam *props) +{ + GcrImporter *self = GCR_IMPORTER (G_OBJECT_CLASS (gcr_importer_parent_class)->constructor(type, n_props, props)); + g_return_val_if_fail (self, NULL); + + + + return G_OBJECT (self); +} + +static void +gcr_importer_init (GcrImporter *self) +{ + +} + +static void +gcr_importer_dispose (GObject *obj) +{ + GcrImporter *self = GCR_IMPORTER (obj); + + G_OBJECT_CLASS (gcr_importer_parent_class)->dispose (obj); +} + +static void +gcr_importer_finalize (GObject *obj) +{ + GcrImporter *self = GCR_IMPORTER (obj); + + G_OBJECT_CLASS (gcr_importer_parent_class)->finalize (obj); +} + +static void +gcr_importer_set_property (GObject *obj, guint prop_id, const GValue *value, + GParamSpec *pspec) +{ + GcrImporter *self = GCR_IMPORTER (obj); + + switch (prop_id) { + case PROP_IMPORTER: + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); + break; + } +} + +static void +gcr_importer_get_property (GObject *obj, guint prop_id, GValue *value, + GParamSpec *pspec) +{ + GcrImporter *self = GCR_IMPORTER (obj); + + switch (prop_id) { + case PROP_IMPORTER: + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); + break; + } +} + +static void +gcr_importer_class_init (GcrImporterClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->constructor = gcr_importer_constructor; + gobject_class->dispose = gcr_importer_dispose; + gobject_class->finalize = gcr_importer_finalize; + gobject_class->set_property = gcr_importer_set_property; + gobject_class->get_property = gcr_importer_get_property; + + g_object_class_install_property (gobject_class, PROP_IMPORTER, + g_param_spec_pointer ("importer", "Importer", "Importer.", G_PARAM_READWRITE)); + + signals[SIGNAL] = g_signal_new ("signal", GCR_TYPE_IMPORTER, + G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GcrImporterClass, signal), + NULL, NULL, g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 0); + + _gcr_initialize (); +} + +/* ----------------------------------------------------------------------------- + * PUBLIC + */ + +GcrImporter* +gcr_importer_new (void) +{ + return g_object_new (GCR_TYPE_IMPORTER, NULL); +} + +gboolean +gcr_importer_import_data (GcrImporter *self, const guchar *data, gsize n_data, + GError *err) +{ + GckParser *parser; + gulong parsed_conn; + gulong auth_conn; + gboolean ret; + + g_return_val_if_fail (GCR_IS_IMPORTER (self), FALSE); + g_return_val_if_fail (data || !n_data, FALSE); + g_return_val_if_fail (!error || !*error, FALSE); + + + xxxx; + + + /* + * Parse to see if it's something that needs a password + * if we can't prompt, + * return an error + * Possibly prompt, if password needed, with all information necessary + * + */ + + + g_object_ref (self); + + parser = gcr_importer_get_parser (self); + + /* Listen in to the parser */ + g_object_ref (parser); + parsed_conn = g_signal_connect (parser, "parsed-item", G_CALLBACK (parser_parsed_item), self); + auth_conn = g_signal_connect (parser, "authenticate", G_CALLBACK (parser_authenticate), self); + + /* Feed the parser the data */ + ret = gcr_parser_parse_data (parser, data, n_data, err); + + /* Now we should have all the data ready, check if we should prompt... */ + /* Import data one by one into module */ + + g_signal_handler_disconnect (parser, parsed_conn); + g_signal_handler_disconnect (parser, auth_conn); + g_object_unref (parser); + + g_object_unref (self); + + return ret; +} + +gboolean +gcr_importer_import_file (GcrImporter *self, const gchar *filename, + GError *err) +{ + gboolean ret; + gchar *data; + gsize n_data; + + g_return_val_if_fail (GCR_IS_IMPORTER (self), FALSE); + g_return_val_if_fail (filename, FALSE); + g_return_val_if_fail (!error || !*error, FALSE); + + if (!g_file_get_contents (filename, &data, &n_data, err)) + return FALSE; + + ret = gcr_importer_import_data (self, (const guchar*)data, n_data, error); + g_free (data); + + return ret; +} diff --git a/gcr/gcr-importer.h b/gcr/gcr-importer.h new file mode 100644 index 00000000..1fad27cf --- /dev/null +++ b/gcr/gcr-importer.h @@ -0,0 +1,81 @@ +/* + * gnome-keyring + * + * Copyright (C) 2008 Stefan Walter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef __GCR_IMPORTER_H__ +#define __GCR_IMPORTER_H__ + +#include <glib-object.h> + +#define GCR_TYPE_IMPORTER (gcr_importer_get_type ()) +#define GCR_IMPORTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_IMPORTER, GcrImporter)) +#define GCR_IMPORTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_IMPORTER, GcrImporterClass)) +#define GCR_IS_IMPORTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_IMPORTER)) +#define GCR_IS_IMPORTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_IMPORTER)) +#define GCR_IMPORTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_IMPORTER, GcrImporterClass)) + +typedef struct _GcrImporter GcrImporter; +typedef struct _GcrImporterClass GcrImporterClass; + +struct _GcrImporter { + GObject parent; +}; + +struct _GcrImporterClass { + GObjectClass parent_class; + + /* signals --------------------------------------------------------- */ + + void (*signal) (GcrImporter *self, GkrImportedItem *item); +}; + +GType gcr_importer_get_type (void); + +GcrImporter* gcr_importer_new (void); + +GcrImporter* gcr_importer_new_for_module (GP11Module *module); + +GcrImporter* gcr_importer_new_for_module_funcs (gpointer pkcs11_funcs); + +void gcr_importer_set_slot (GcrImporter *self, + GP11Slot *slot); + +void gcr_importer_set_slot_id (GcrImporter *self, + gulong slot_id); + +void gcr_importer_set_parser (GcrImporter *self, + GcrParser *parser); + +void gcr_importer_set_window (GcrImporter *self, + GtkWindow *window); + +void gcr_importer_set_prompt_behavior (GcrImporter *self, + GcrImporterPromptBehavior behavior); + +gboolean gcr_importer_import_data (GcrImporter *self, + const guchar *data, + gsize n_data, + GError *error); + +gboolean gcr_importer_import_file (GcrImporter *self, + const gchar *filename, + GError *error); + +#endif /* __GCR_IMPORTER_H__ */ diff --git a/gcr/gcr-internal.c b/gcr/gcr-internal.c new file mode 100644 index 00000000..2996208b --- /dev/null +++ b/gcr/gcr-internal.c @@ -0,0 +1,116 @@ +/* + * gnome-keyring + * + * Copyright (C) 2008 Stefan Walter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "config.h" + +#include "gcr-internal.h" + +#include "egg/egg-secure-memory.h" + +#include <gcrypt.h> + +static void +log_handler (gpointer unused, int unknown, const gchar *msg, va_list va) +{ + /* TODO: Figure out additional arguments */ + g_logv ("gcrypt", G_LOG_LEVEL_MESSAGE, msg, va); +} + +static int +no_mem_handler (gpointer unused, size_t sz, unsigned int unknown) +{ + /* TODO: Figure out additional arguments */ + g_error ("couldn't allocate %lu bytes of memory", + (unsigned long int)sz); + return 0; +} + +static void +fatal_handler (gpointer unused, int unknown, const gchar *msg) +{ + /* TODO: Figure out additional arguments */ + g_log ("gcrypt", G_LOG_LEVEL_ERROR, "%s", msg); +} + +static int +glib_thread_mutex_init (void **lock) +{ + *lock = g_mutex_new (); + return 0; +} + +static int +glib_thread_mutex_destroy (void **lock) +{ + g_mutex_free (*lock); + return 0; +} + +static int +glib_thread_mutex_lock (void **lock) +{ + g_mutex_lock (*lock); + return 0; +} + +static int +glib_thread_mutex_unlock (void **lock) +{ + g_mutex_unlock (*lock); + return 0; +} + +static struct gcry_thread_cbs glib_thread_cbs = { + GCRY_THREAD_OPTION_USER, NULL, + glib_thread_mutex_init, glib_thread_mutex_destroy, + glib_thread_mutex_lock, glib_thread_mutex_unlock, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; + +void +_gcr_initialize (void) +{ + static gsize gcrypt_initialized = FALSE; + unsigned seed; + + if (g_once_init_enter (&gcrypt_initialized)) { + + /* Only initialize libgcrypt if it hasn't already been initialized */ + if (!gcry_control (GCRYCTL_INITIALIZATION_FINISHED_P)) { + gcry_control (GCRYCTL_SET_THREAD_CBS, &glib_thread_cbs); + gcry_check_version (LIBGCRYPT_VERSION); + gcry_set_log_handler (log_handler, NULL); + gcry_set_outofcore_handler (no_mem_handler, NULL); + gcry_set_fatalerror_handler (fatal_handler, NULL); + gcry_set_allocation_handler ((gcry_handler_alloc_t)g_malloc, + (gcry_handler_alloc_t)egg_secure_alloc, + egg_secure_check, + (gcry_handler_realloc_t)egg_secure_realloc, + egg_secure_free); + gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); + } + + gcry_create_nonce (&seed, sizeof (seed)); + srand (seed); + + g_once_init_leave (&gcrypt_initialized, 1); + } +} diff --git a/gcr/gcr-internal.h b/gcr/gcr-internal.h new file mode 100644 index 00000000..daad9903 --- /dev/null +++ b/gcr/gcr-internal.h @@ -0,0 +1,8 @@ +#ifndef GCR_INTERNAL_H_ +#define GCR_INTERNAL_H_ + +#include <glib.h> + +void _gcr_initialize (void); + +#endif /* GCR_INTERNAL_H_ */ diff --git a/gcr/gcr-marshal.list b/gcr/gcr-marshal.list new file mode 100644 index 00000000..8ff8506f --- /dev/null +++ b/gcr/gcr-marshal.list @@ -0,0 +1 @@ +BOOLEAN:INT diff --git a/gcr/gcr-parser.c b/gcr/gcr-parser.c new file mode 100644 index 00000000..0c58ce39 --- /dev/null +++ b/gcr/gcr-parser.c @@ -0,0 +1,1710 @@ +/* + * gnome-keyring + * + * Copyright (C) 2008 Stefan Walter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "config.h" + +#include "gp11/gp11.h" + +#include "gcr-internal.h" +#include "gcr-marshal.h" +#include "gcr-parser.h" +#include "gcr-types.h" + +#include "egg/egg-asn1.h" +#include "egg/egg-openssl.h" +#include "egg/egg-secure-memory.h" +#include "egg/egg-symkey.h" + +#include <glib/gi18n-lib.h> + +#include <stdlib.h> +#include <gcrypt.h> +#include <libtasn1.h> + +enum { + PROP_0, + PROP_PARSED_LABEL, + PROP_PARSED_ATTRIBUTES, + PROP_PARSED_DESCRIPTION +}; + +enum { + AUTHENTICATE, + PARSED, + LAST_SIGNAL +}; + +#define SUCCESS 0 + +static guint signals[LAST_SIGNAL] = { 0 }; + +struct _GcrParserPrivate { + GTree *specific_formats; + gboolean normal_formats; + GPtrArray *passwords; + + GP11Attributes *parsed_attrs; + const gchar *parsed_desc; + gchar *parsed_label; +}; + +G_DEFINE_TYPE (GcrParser, gcr_parser, G_TYPE_OBJECT); + +typedef struct { + gint ask_state; + gint seen; +} PasswordState; + +#define PASSWORD_STATE_INIT { 0, 0 } + +typedef struct _ParserFormat { + gint format_id; + gint (*function) (GcrParser *self, const guchar *data, gsize n_data); +} ParserFormat; + +/* Forward declarations */ +static const ParserFormat parser_normal[]; +static const ParserFormat parser_formats[]; +static ParserFormat* parser_format_lookup (gint format_id); + +/* ----------------------------------------------------------------------------- + * QUARK DEFINITIONS + */ + +/* + * PEM STRINGS + * The xxxxx in: ----- BEGIN xxxxx ------ + */ + +static GQuark PEM_CERTIFICATE; +static GQuark PEM_RSA_PRIVATE_KEY; +static GQuark PEM_DSA_PRIVATE_KEY; +static GQuark PEM_ANY_PRIVATE_KEY; +static GQuark PEM_ENCRYPTED_PRIVATE_KEY; +static GQuark PEM_PRIVATE_KEY; +static GQuark PEM_PKCS7; +static GQuark PEM_PKCS12; + +/* + * OIDS + */ + +static GQuark OID_PKIX1_RSA; +static GQuark OID_PKIX1_DSA; +static GQuark OID_PKCS7_DATA; +static GQuark OID_PKCS7_SIGNED_DATA; +static GQuark OID_PKCS7_ENCRYPTED_DATA; +static GQuark OID_PKCS12_BAG_PKCS8_KEY; +static GQuark OID_PKCS12_BAG_PKCS8_ENCRYPTED_KEY; +static GQuark OID_PKCS12_BAG_CERTIFICATE; +static GQuark OID_PKCS12_BAG_CRL; + +static void +init_quarks (void) +{ + static volatile gsize quarks_inited = 0; + + if (g_once_init_enter (&quarks_inited)) { + + #define QUARK(name, value) \ + name = g_quark_from_static_string(value) + + QUARK (OID_PKIX1_RSA, "1.2.840.113549.1.1.1"); + QUARK (OID_PKIX1_DSA, "1.2.840.10040.4.1"); + QUARK (OID_PKCS7_DATA, "1.2.840.113549.1.7.1"); + QUARK (OID_PKCS7_SIGNED_DATA, "1.2.840.113549.1.7.2"); + QUARK (OID_PKCS7_ENCRYPTED_DATA, "1.2.840.113549.1.7.6"); + QUARK (OID_PKCS12_BAG_PKCS8_KEY, "1.2.840.113549.1.12.10.1.1"); + QUARK (OID_PKCS12_BAG_PKCS8_ENCRYPTED_KEY, "1.2.840.113549.1.12.10.1.2"); + QUARK (OID_PKCS12_BAG_CERTIFICATE, "1.2.840.113549.1.12.10.1.3"); + QUARK (OID_PKCS12_BAG_CRL, "1.2.840.113549.1.12.10.1.4"); + + QUARK (PEM_CERTIFICATE, "CERTIFICATE"); + QUARK (PEM_PRIVATE_KEY, "PRIVATE KEY"); + QUARK (PEM_RSA_PRIVATE_KEY, "RSA PRIVATE KEY"); + QUARK (PEM_DSA_PRIVATE_KEY, "DSA PRIVATE KEY"); + QUARK (PEM_ANY_PRIVATE_KEY, "ANY PRIVATE KEY"); + QUARK (PEM_ENCRYPTED_PRIVATE_KEY, "ENCRYPTED PRIVATE KEY"); + QUARK (PEM_PKCS7, "PKCS7"); + QUARK (PEM_PKCS12, "PKCS12"); + + #undef QUARK + + g_once_init_leave (&quarks_inited, 1); + } +} + +/* ----------------------------------------------------------------------------- + * INTERNAL + */ + +static gboolean +parsed_asn1_attribute (GcrParser *self, ASN1_TYPE asn, const guchar *data, gsize n_data, + const gchar *part, CK_ATTRIBUTE_TYPE type) +{ + const guchar *value; + gsize n_value; + + g_assert (GCR_IS_PARSER (self)); + g_assert (asn); + g_assert (data); + g_assert (part); + g_assert (self->pv->parsed_attrs); + + value = egg_asn1_read_content (asn, data, n_data, part, &n_value); + if (value == NULL) + return FALSE; + + gp11_attributes_add_data (self->pv->parsed_attrs, type, value, n_value); + return TRUE; +} + +static void +parsed_clear (GcrParser *self, CK_OBJECT_CLASS klass) +{ + if (self->pv->parsed_attrs) + gp11_attributes_unref (self->pv->parsed_attrs); + if (klass == CKO_PRIVATE_KEY) + self->pv->parsed_attrs = gp11_attributes_new_full ((GP11Allocator)egg_secure_realloc); + else + self->pv->parsed_attrs = gp11_attributes_new (); + gp11_attributes_add_ulong (self->pv->parsed_attrs, CKA_CLASS, klass); + + g_free (self->pv->parsed_label); + self->pv->parsed_label = NULL; + + switch (klass) { + case CKO_PRIVATE_KEY: + self->pv->parsed_desc = _("Private Key"); + break; + case CKO_CERTIFICATE: + self->pv->parsed_desc = _("Certificate"); + break; + case CKO_PUBLIC_KEY: + self->pv->parsed_desc = _("Public Key"); + break; + default: + self->pv->parsed_desc = NULL; + break; + } +} + +static void +parsed_label (GcrParser *self, const gchar *label) +{ + g_free (self->pv->parsed_label); + self->pv->parsed_label = g_strdup (label); +} + +static void +parsed_attribute (GcrParser *self, CK_ATTRIBUTE_TYPE type, gconstpointer data, gsize n_data) +{ + g_assert (GCR_IS_PARSER (self)); + g_assert (self->pv->parsed_attrs); + gp11_attributes_add_data (self->pv->parsed_attrs, type, data, n_data); +} + +static void +parsed_ulong (GcrParser *self, CK_ATTRIBUTE_TYPE type, gulong value) +{ + g_assert (GCR_IS_PARSER (self)); + g_assert (self->pv->parsed_attrs); + gp11_attributes_add_ulong (self->pv->parsed_attrs, type, value); +} + +static gint +enum_next_password (GcrParser *self, PasswordState *state, const gchar **password) +{ + gboolean result; + + /* + * Next passes we look through all the passwords that the parser + * has seen so far. This is because different parts of a encrypted + * container (such as PKCS#12) often use the same password even + * if with different algorithms. + * + * If we didn't do this and the user chooses enters a password, + * but doesn't save it, they would get prompted for the same thing + * over and over, dumb. + */ + + /* Look in our list of passwords */ + if (state->seen < self->pv->passwords->len) { + g_assert (state->seen >= 0); + *password = g_ptr_array_index (self->pv->passwords, state->seen); + ++state->seen; + return SUCCESS; + } + + /* Fire off all the parsed property signals so anyone watching can update their state */ + g_object_notify (G_OBJECT (self), "parsed-description"); + g_object_notify (G_OBJECT (self), "parsed-attributes"); + g_object_notify (G_OBJECT (self), "parsed-label"); + + g_signal_emit (self, signals[AUTHENTICATE], 0, state->ask_state, &result); + ++state->ask_state; + + if (!result) + return GCR_PARSE_CANCELLED; + + /* Return any passwords added */ + if (state->seen < self->pv->passwords->len) { + g_assert (state->seen >= 0); + *password = g_ptr_array_index (self->pv->passwords, state->seen); + ++state->seen; + return SUCCESS; + } + + return GCR_PARSE_LOCKED; +} + +static void +parsed_fire (GcrParser *self) +{ + g_object_notify (G_OBJECT (self), "parsed-description"); + g_object_notify (G_OBJECT (self), "parsed-attributes"); + g_object_notify (G_OBJECT (self), "parsed-label"); + + g_signal_emit (self, signals[PARSED], 0); +} + +/* ----------------------------------------------------------------------------- + * RSA PRIVATE KEY + */ + +static gint +parse_der_private_key_rsa (GcrParser *self, const guchar *data, gsize n_data) +{ + gint res = GCR_PARSE_UNRECOGNIZED; + ASN1_TYPE asn = ASN1_TYPE_EMPTY; + guint version; + + asn = egg_asn1_decode ("PK.RSAPrivateKey", data, n_data); + if (!asn) + goto done; + + parsed_clear (self, CKO_PRIVATE_KEY); + parsed_ulong (self, CKA_KEY_TYPE, CKK_RSA); + res = GCR_PARSE_FAILURE; + + if (!egg_asn1_read_uint (asn, "version", &version)) + goto done; + + /* We only support simple version */ + if (version != 0) { + res = GCR_PARSE_UNRECOGNIZED; + g_message ("unsupported version of RSA key: %u", version); + goto done; + } + + if (!parsed_asn1_attribute (self, asn, data, n_data, "modulus", CKA_MODULUS) || + !parsed_asn1_attribute (self, asn, data, n_data, "publicExponent", CKA_PUBLIC_EXPONENT) || + !parsed_asn1_attribute (self, asn, data, n_data, "privateExponent", CKA_PRIVATE_EXPONENT) || + !parsed_asn1_attribute (self, asn, data, n_data, "prime1", CKA_PRIME_1) || + !parsed_asn1_attribute (self, asn, data, n_data, "prime2", CKA_PRIME_2) || + !parsed_asn1_attribute (self, asn, data, n_data, "coefficient", CKA_COEFFICIENT)) + goto done; + + parsed_fire (self); + res = SUCCESS; + +done: + if (asn) + asn1_delete_structure (&asn); + + if (res == GCR_PARSE_FAILURE) + g_message ("invalid RSA key"); + + return res; +} + +/* ----------------------------------------------------------------------------- + * DSA PRIVATE KEY + */ + +static gint +parse_der_private_key_dsa (GcrParser *self, const guchar *data, gsize n_data) +{ + gint ret = GCR_PARSE_UNRECOGNIZED; + int res; + ASN1_TYPE asn; + + asn = egg_asn1_decode ("PK.DSAPrivateKey", data, n_data); + if (!asn) + goto done; + + parsed_clear (self, CKO_PRIVATE_KEY); + parsed_ulong (self, CKA_KEY_TYPE, CKK_DSA); + res = GCR_PARSE_FAILURE; + + if (!parsed_asn1_attribute (self, asn, data, n_data, "p", CKA_PRIME) || + !parsed_asn1_attribute (self, asn, data, n_data, "q", CKA_SUBPRIME) || + !parsed_asn1_attribute (self, asn, data, n_data, "g", CKA_BASE) || + !parsed_asn1_attribute (self, asn, data, n_data, "priv", CKA_VALUE)) + goto done; + + parsed_fire (self); + ret = SUCCESS; + +done: + if (asn) + asn1_delete_structure (&asn); + + if (ret == GCR_PARSE_FAILURE) + g_message ("invalid DSA key"); + + return ret; +} + +static gint +parse_der_private_key_dsa_parts (GcrParser *self, const guchar *keydata, gsize n_keydata, + const guchar *params, gsize n_params) +{ + gint ret = GCR_PARSE_UNRECOGNIZED; + int res; + ASN1_TYPE asn_params = ASN1_TYPE_EMPTY; + ASN1_TYPE asn_key = ASN1_TYPE_EMPTY; + + asn_params = egg_asn1_decode ("PK.DSAParameters", params, n_params); + asn_key = egg_asn1_decode ("PK.DSAPrivatePart", keydata, n_keydata); + if (!asn_params || !asn_key) + goto done; + + parsed_clear (self, CKO_PRIVATE_KEY); + parsed_ulong (self, CKA_KEY_TYPE, CKK_DSA); + res = GCR_PARSE_FAILURE; + + if (!parsed_asn1_attribute (self, asn_params, params, n_params, "p", CKA_PRIME) || + !parsed_asn1_attribute (self, asn_params, params, n_params, "q", CKA_SUBPRIME) || + !parsed_asn1_attribute (self, asn_params, params, n_params, "g", CKA_BASE) || + !parsed_asn1_attribute (self, asn_key, keydata, n_keydata, "", CKA_VALUE)) + goto done; + + parsed_fire (self); + ret = SUCCESS; + +done: + if (asn_key) + asn1_delete_structure (&asn_key); + if (asn_params) + asn1_delete_structure (&asn_params); + + if (ret == GCR_PARSE_FAILURE) + g_message ("invalid DSA key"); + + return ret; +} + +/* ----------------------------------------------------------------------------- + * PRIVATE KEY + */ + +static gint +parse_der_private_key (GcrParser *self, const guchar *data, gsize n_data) +{ + gint res; + + res = parse_der_private_key_rsa (self, data, n_data); + if (res == GCR_PARSE_UNRECOGNIZED) + res = parse_der_private_key_dsa (self, data, n_data); + + return res; +} + +/* ----------------------------------------------------------------------------- + * PKCS8 + */ + +static gint +parse_der_pkcs8_plain (GcrParser *self, const guchar *data, gsize n_data) +{ + ASN1_TYPE asn = ASN1_TYPE_EMPTY; + gint ret; + CK_KEY_TYPE key_type; + GQuark key_algo; + const guchar *keydata; + gsize n_keydata; + const guchar *params; + gsize n_params; + + ret = GCR_PARSE_UNRECOGNIZED; + + asn = egg_asn1_decode ("PKIX1.pkcs-8-PrivateKeyInfo", data, n_data); + if (!asn) + goto done; + + ret = GCR_PARSE_FAILURE; + key_type = GP11_INVALID; + + key_algo = egg_asn1_read_oid (asn, "privateKeyAlgorithm.algorithm"); + if (!key_algo) + goto done; + else if (key_algo == OID_PKIX1_RSA) + key_type = CKK_RSA; + else if (key_algo == OID_PKIX1_DSA) + key_type = CKK_DSA; + + if (key_type == GP11_INVALID) { + ret = GCR_PARSE_UNRECOGNIZED; + goto done; + } + + keydata = egg_asn1_read_content (asn, data, n_data, "privateKey", &n_keydata); + if (!keydata) + goto done; + + params = egg_asn1_read_element (asn, data, n_data, "privateKeyAlgorithm.parameters", + &n_params); + + ret = SUCCESS; + +done: + if (ret == SUCCESS) { + switch (key_type) { + case CKK_RSA: + ret = parse_der_private_key_rsa (self, keydata, n_keydata); + break; + case CKK_DSA: + /* Try the normal sane format */ + ret = parse_der_private_key_dsa (self, keydata, n_keydata); + + /* Otherwise try the two part format that everyone seems to like */ + if (ret == GCR_PARSE_UNRECOGNIZED && params && n_params) + ret = parse_der_private_key_dsa_parts (self, keydata, n_keydata, + params, n_params); + break; + default: + g_message ("invalid or unsupported key type in PKCS#8 key"); + ret = GCR_PARSE_UNRECOGNIZED; + break; + }; + + } else if (ret == GCR_PARSE_FAILURE) { + g_message ("invalid PKCS#8 key"); + } + + if (asn) + asn1_delete_structure (&asn); + return ret; +} + +static gint +parse_der_pkcs8_encrypted (GcrParser *self, const guchar *data, gsize n_data) +{ + PasswordState pstate = PASSWORD_STATE_INIT; + ASN1_TYPE asn = ASN1_TYPE_EMPTY; + gcry_cipher_hd_t cih = NULL; + gcry_error_t gcry; + gint ret, r; + GQuark scheme; + guchar *crypted = NULL; + const guchar *params; + gsize n_crypted, n_params; + const gchar *password; + gint l; + + ret = GCR_PARSE_UNRECOGNIZED; + + asn = egg_asn1_decode ("PKIX1.pkcs-8-EncryptedPrivateKeyInfo", data, n_data); + if (!asn) + goto done; + + ret = GCR_PARSE_FAILURE; + + /* Figure out the type of encryption */ + scheme = egg_asn1_read_oid (asn, "encryptionAlgorithm.algorithm"); + if (!scheme) + goto done; + + params = egg_asn1_read_element (asn, data, n_data, "encryptionAlgorithm.parameters", &n_params); + + parsed_clear (self, CKO_PRIVATE_KEY); + + /* Loop to try different passwords */ + for (;;) { + + g_assert (cih == NULL); + + r = enum_next_password (self, &pstate, &password); + if (r != SUCCESS) { + ret = r; + break; + } + + /* Parse the encryption stuff into a cipher. */ + if (!egg_symkey_read_cipher (scheme, password, -1, params, n_params, &cih)) + break; + + crypted = egg_asn1_read_value (asn, "encryptedData", &n_crypted, egg_secure_realloc); + if (!crypted) + break; + + gcry = gcry_cipher_decrypt (cih, crypted, n_crypted, NULL, 0); + gcry_cipher_close (cih); + cih = NULL; + + if (gcry != 0) { + g_warning ("couldn't decrypt pkcs8 data: %s", gcry_strerror (gcry)); + break; + } + + /* Unpad the DER data */ + l = egg_asn1_element_length (crypted, n_crypted); + if (l > 0) + n_crypted = l; + + /* Try to parse the resulting key */ + r = parse_der_pkcs8_plain (self, crypted, n_crypted); + egg_secure_free (crypted); + crypted = NULL; + + if (r != GCR_PARSE_UNRECOGNIZED) { + ret = r; + break; + } + + /* We assume unrecognized data, is a bad encryption key */ + } + +done: + if (cih) + gcry_cipher_close (cih); + if (asn) + asn1_delete_structure (&asn); + egg_secure_free (crypted); + + return ret; +} + +static gint +parse_der_pkcs8 (GcrParser *self, const guchar *data, gsize n_data) +{ + gint ret; + + ret = parse_der_pkcs8_plain (self, data, n_data); + if (ret == GCR_PARSE_UNRECOGNIZED) + ret = parse_der_pkcs8_encrypted (self, data, n_data); + + return ret; +} + +/* ----------------------------------------------------------------------------- + * CERTIFICATE + */ + +static gint +parse_der_certificate (GcrParser *self, const guchar *data, gsize n_data) +{ + ASN1_TYPE asn; + gchar *name; + + asn = egg_asn1_decode ("PKIX1.Certificate", data, n_data); + if (asn == NULL) + return GCR_PARSE_UNRECOGNIZED; + + parsed_clear (self, CKO_CERTIFICATE); + parsed_ulong (self, CKA_CERTIFICATE_TYPE, CKC_X_509); + + name = egg_asn1_read_dn_part (asn, "tbsCertificate.subject.rdnSequence", "CN"); + asn1_delete_structure (&asn); + + if (name != NULL) { + parsed_label (self, name); + g_free (name); + } + + parsed_attribute (self, CKA_VALUE, data, n_data); + parsed_fire (self); + + return SUCCESS; +} + +/* ----------------------------------------------------------------------------- + * PKCS7 + */ + +static gint +handle_pkcs7_signed_data (GcrParser *self, const guchar *data, gsize n_data) +{ + ASN1_TYPE asn = ASN1_TYPE_EMPTY; + gint ret; + gchar *part; + const guchar *certificate; + gsize n_certificate; + int i; + + ret = GCR_PARSE_UNRECOGNIZED; + + asn = egg_asn1_decode ("PKIX1.pkcs-7-SignedData", data, n_data); + if (!asn) + goto done; + + ret = GCR_PARSE_FAILURE; + + for (i = 0; TRUE; ++i) { + + part = g_strdup_printf ("certificates.?%u", i + 1); + certificate = egg_asn1_read_element (asn, data, n_data, part, &n_certificate); + g_free (part); + + /* No more certificates? */ + if (!certificate) + break; + + ret = parse_der_certificate (self, certificate, n_certificate); + if (ret != SUCCESS) + goto done; + } + + /* TODO: Parse out all the CRLs */ + + ret = SUCCESS; + +done: + if (asn) + asn1_delete_structure (&asn); + + return ret; +} + +static gint +parse_der_pkcs7 (GcrParser *self, const guchar *data, gsize n_data) +{ + ASN1_TYPE asn = ASN1_TYPE_EMPTY; + gint ret; + const guchar* content = NULL; + gsize n_content; + GQuark oid; + + ret = GCR_PARSE_UNRECOGNIZED; + + asn = egg_asn1_decode ("PKIX1.pkcs-7-ContentInfo", data, n_data); + if (!asn) + goto done; + + ret = GCR_PARSE_FAILURE; + + oid = egg_asn1_read_oid (asn, "contentType"); + if (!oid) + goto done; + + /* Outer most one must just be plain data */ + if (oid != OID_PKCS7_SIGNED_DATA) { + g_message ("unsupported outer content type in pkcs7: %s", g_quark_to_string (oid)); + goto done; + } + + content = egg_asn1_read_content (asn, data, n_data, "content", &n_content); + if (!content) + goto done; + + ret = handle_pkcs7_signed_data (self, content, n_content); + +done: + if (asn) + asn1_delete_structure (&asn); + return ret; +} + +/* ----------------------------------------------------------------------------- + * PKCS12 + */ + +static gint +handle_pkcs12_cert_bag (GcrParser *self, const guchar *data, gsize n_data) +{ + ASN1_TYPE asn = ASN1_TYPE_EMPTY; + const guchar *certificate; + gsize n_certificate; + gint ret; + + ret = GCR_PARSE_UNRECOGNIZED; + + asn = egg_asn1_decode ("PKIX1.pkcs-12-CertBag", data, n_data); + if (!asn) + goto done; + + ret = GCR_PARSE_FAILURE; + + certificate = egg_asn1_read_content (asn, data, n_data, "certValue", &n_certificate); + if (!certificate) + goto done; + + /* + * Wrapped in an OCTET STRING, so unwrap here, rather than allocating + * a whole bunch more memory for a full ASN.1 parsing context. + */ + certificate = egg_asn1_element_content (certificate, n_certificate, &n_certificate); + if (!certificate) + goto done; + + ret = parse_der_certificate (self, certificate, n_certificate); + +done: + if (asn) + asn1_delete_structure (&asn); + + return ret; +} + +static gint +handle_pkcs12_bag (GcrParser *self, const guchar *data, gsize n_data) +{ + ASN1_TYPE asn = ASN1_TYPE_EMPTY; + gint ret, r; + int res, count = 0; + GQuark oid; + const guchar *element; + gsize n_element; + + ret = GCR_PARSE_UNRECOGNIZED; + + asn = egg_asn1_decode ("PKIX1.pkcs-12-SafeContents", data, n_data); + if (!asn) + goto done; + + ret = GCR_PARSE_FAILURE; + + /* Get the number of elements in this bag */ + res = asn1_number_of_elements (asn, "", &count); + if (res != ASN1_SUCCESS) + goto done; + + /* + * Now inside each bag are multiple elements. Who comes up + * with this stuff? + * + * But this is where we draw the line. We only support one + * element per bag, not multiple elements, not strange + * nested bags, not fairy queens with magical wands in bags... + * + * Just one element per bag. + */ + if (count >= 1) { + + oid = egg_asn1_read_oid (asn, "?1.bagId"); + if (!oid) + goto done; + + element = egg_asn1_read_content (asn, data, n_data, "?1.bagValue", &n_element); + if (!element) + goto done; + + /* A normal unencrypted key */ + if (oid == OID_PKCS12_BAG_PKCS8_KEY) { + r = parse_der_pkcs8_plain (self, element, n_element); + + /* A properly encrypted key */ + } else if (oid == OID_PKCS12_BAG_PKCS8_ENCRYPTED_KEY) { + r = parse_der_pkcs8_encrypted (self, element, n_element); + + /* A certificate */ + } else if (oid == OID_PKCS12_BAG_CERTIFICATE) { + r = handle_pkcs12_cert_bag (self, element, n_element); + + /* TODO: OID_PKCS12_BAG_CRL */ + } else { + r = GCR_PARSE_UNRECOGNIZED; + } + + if (r == GCR_PARSE_FAILURE || r == GCR_PARSE_CANCELLED) { + ret = r; + goto done; + } + } + + ret = SUCCESS; + +done: + if (asn) + asn1_delete_structure (&asn); + + return ret; +} + +static gint +handle_pkcs12_encrypted_bag (GcrParser *self, const guchar *data, gsize n_data) +{ + PasswordState pstate = PASSWORD_STATE_INIT; + ASN1_TYPE asn = ASN1_TYPE_EMPTY; + gcry_cipher_hd_t cih = NULL; + gcry_error_t gcry; + guchar *crypted = NULL; + const guchar *params; + gsize n_params, n_crypted; + const gchar *password; + GQuark scheme; + gint ret, r; + gint l; + + ret = GCR_PARSE_UNRECOGNIZED; + + asn = egg_asn1_decode ("PKIX1.pkcs-7-EncryptedData", data, n_data); + if (!asn) + goto done; + + ret = GCR_PARSE_FAILURE; + + /* Check the encryption schema OID */ + scheme = egg_asn1_read_oid (asn, "encryptedContentInfo.contentEncryptionAlgorithm.algorithm"); + if (!scheme) + goto done; + + params = egg_asn1_read_element (asn, data, n_data, "encryptedContentInfo.contentEncryptionAlgorithm.parameters", &n_params); + if (!params) + goto done; + + parsed_clear (self, 0); + + /* Loop to try different passwords */ + for (;;) { + + g_assert (cih == NULL); + + r = enum_next_password (self, &pstate, &password); + if (r != SUCCESS) { + ret = r; + goto done; + } + + /* Parse the encryption stuff into a cipher. */ + if (!egg_symkey_read_cipher (scheme, password, -1, params, n_params, &cih)) { + ret = GCR_PARSE_FAILURE; + goto done; + } + + crypted = egg_asn1_read_value (asn, "encryptedContentInfo.encryptedContent", + &n_crypted, egg_secure_realloc); + if (!crypted) + goto done; + + gcry = gcry_cipher_decrypt (cih, crypted, n_crypted, NULL, 0); + gcry_cipher_close (cih); + cih = NULL; + + if (gcry != 0) { + g_warning ("couldn't decrypt pkcs7 data: %s", gcry_strerror (gcry)); + goto done; + } + + /* Unpad the DER data */ + l = egg_asn1_element_length (crypted, n_crypted); + if (l > 0) + n_crypted = l; + + /* Try to parse the resulting key */ + r = handle_pkcs12_bag (self, crypted, n_crypted); + egg_secure_free (crypted); + crypted = NULL; + + if (r != GCR_PARSE_UNRECOGNIZED) { + ret = r; + break; + } + + /* We assume unrecognized data is a bad encryption key */ + } + +done: + if (cih) + gcry_cipher_close (cih); + if (asn) + asn1_delete_structure (&asn); + egg_secure_free (crypted); + + return ret; +} + +static gint +handle_pkcs12_safe (GcrParser *self, const guchar *data, gsize n_data) +{ + ASN1_TYPE asn = ASN1_TYPE_EMPTY; + gint ret, r; + const guchar *bag; + gsize n_bag; + gchar *part; + GQuark oid; + guint i; + + ret = GCR_PARSE_UNRECOGNIZED; + + asn = egg_asn1_decode ("PKIX1.pkcs-12-AuthenticatedSafe", data, n_data); + if (!asn) + goto done; + + ret = GCR_PARSE_FAILURE; + + /* + * Inside each PKCS12 safe there are multiple bags. + */ + for (i = 0; TRUE; ++i) { + + part = g_strdup_printf ("?%u.contentType", i + 1); + oid = egg_asn1_read_oid (asn, part); + g_free (part); + + /* All done? no more bags */ + if (!oid) + break; + + part = g_strdup_printf ("?%u.content", i + 1); + bag = egg_asn1_read_content (asn, data, n_data, part, &n_bag); + g_free (part); + + if (!bag) /* A parse error */ + goto done; + + /* A non encrypted bag, just parse */ + if (oid == OID_PKCS7_DATA) { + + /* + * Wrapped in an OCTET STRING, so unwrap here, rather than allocating + * a whole bunch more memory for a full ASN.1 parsing context. + */ + bag = egg_asn1_element_content (bag, n_bag, &n_bag); + if (!bag) + goto done; + + r = handle_pkcs12_bag (self, bag, n_bag); + + /* Encrypted data first needs decryption */ + } else if (oid == OID_PKCS7_ENCRYPTED_DATA) { + r = handle_pkcs12_encrypted_bag (self, bag, n_bag); + + /* Hmmmm, not sure what this is */ + } else { + g_warning ("unrecognized type of safe content in pkcs12: %s", g_quark_to_string (oid)); + r = GCR_PARSE_UNRECOGNIZED; + } + + if (r == GCR_PARSE_FAILURE || r == GCR_PARSE_CANCELLED) { + ret = r; + goto done; + } + } + + ret = SUCCESS; + +done: + if (asn) + asn1_delete_structure (&asn); + + return ret; +} + +static gint +parse_der_pkcs12 (GcrParser *self, const guchar *data, gsize n_data) +{ + ASN1_TYPE asn = ASN1_TYPE_EMPTY; + gint ret; + const guchar* content = NULL; + gsize n_content; + GQuark oid; + + ret = GCR_PARSE_UNRECOGNIZED; + + asn = egg_asn1_decode ("PKIX1.pkcs-12-PFX", data, n_data); + if (!asn) + goto done; + + oid = egg_asn1_read_oid (asn, "authSafe.contentType"); + if (!oid) + goto done; + + /* Outer most one must just be plain data */ + if (oid != OID_PKCS7_DATA) { + g_message ("unsupported safe content type in pkcs12: %s", g_quark_to_string (oid)); + goto done; + } + + content = egg_asn1_read_content (asn, data, n_data, "authSafe.content", &n_content); + if (!content) + goto done; + + /* + * Wrapped in an OCTET STRING, so unwrap here, rather than allocating + * a whole bunch more memory for a full ASN.1 parsing context. + */ + content = egg_asn1_element_content (content, n_content, &n_content); + if (!content) + goto done; + + ret = handle_pkcs12_safe (self, content, n_content); + +done: + if (asn) + asn1_delete_structure (&asn); + return ret; +} + +/* ----------------------------------------------------------------------------- + * PEM PARSING + */ + +static gint +handle_plain_pem (GcrParser *self, GQuark type, gint subformat, + const guchar *data, gsize n_data) +{ + ParserFormat *format; + gint format_id; + + if (type == PEM_RSA_PRIVATE_KEY) + format_id = GCR_FORMAT_DER_PRIVATE_KEY_RSA; + + else if (type == PEM_DSA_PRIVATE_KEY) + format_id = GCR_FORMAT_DER_PRIVATE_KEY_DSA; + + else if (type == PEM_ANY_PRIVATE_KEY) + format_id = GCR_FORMAT_DER_PRIVATE_KEY; + + else if (type == PEM_PRIVATE_KEY) + format_id = GCR_FORMAT_DER_PKCS8_PLAIN; + + else if (type == PEM_ENCRYPTED_PRIVATE_KEY) + format_id = GCR_FORMAT_DER_PKCS8_ENCRYPTED; + + else if (type == PEM_CERTIFICATE) + format_id = GCR_FORMAT_DER_CERTIFICATE_X509; + + else if (type == PEM_PKCS7) + format_id = GCR_FORMAT_DER_PKCS7; + + else if (type == PEM_PKCS12) + format_id = GCR_FORMAT_DER_PKCS12; + + else + return GCR_PARSE_UNRECOGNIZED; + + if (subformat != 0 && subformat != format_id) + return GCR_PARSE_UNRECOGNIZED; + + format = parser_format_lookup (format_id); + if (format == NULL) + return GCR_PARSE_UNRECOGNIZED; + + return (format->function) (self, data, n_data); +} + +static CK_OBJECT_CLASS +pem_type_to_class (gint type) +{ + if (type == PEM_RSA_PRIVATE_KEY || + type == PEM_DSA_PRIVATE_KEY || + type == PEM_ANY_PRIVATE_KEY || + type == PEM_PRIVATE_KEY || + type == PEM_ENCRYPTED_PRIVATE_KEY) + return CKO_PRIVATE_KEY; + + else if (type == PEM_CERTIFICATE) + return CKO_CERTIFICATE; + + else if (type == PEM_PKCS7 || + type == PEM_PKCS12) + return 0; + + return 0; +} + +static gint +handle_encrypted_pem (GcrParser *self, GQuark type, gint subformat, + GHashTable *headers, const guchar *data, gsize n_data) +{ + PasswordState pstate = PASSWORD_STATE_INIT; + const gchar *password; + guchar *decrypted; + gsize n_decrypted; + const gchar *val; + gboolean ret; + gint res; + gint l; + + g_assert (GCR_IS_PARSER (self)); + g_assert (headers); + g_assert (type); + + val = g_hash_table_lookup (headers, "DEK-Info"); + if (!val) { + g_message ("missing encryption header"); + return GCR_PARSE_FAILURE; + } + + /* Fill in information necessary for prompting */ + parsed_clear (self, pem_type_to_class (type)); + + for (;;) { + + res = enum_next_password (self, &pstate, &password); + if (res != SUCCESS) + return res; + + decrypted = NULL; + n_decrypted = 0; + + /* Decrypt, this will result in garble if invalid password */ + ret = egg_openssl_decrypt_block (val, password, -1, data, n_data, + &decrypted, &n_decrypted); + if (!ret) + return GCR_PARSE_FAILURE; + + g_assert (decrypted); + + /* Unpad the DER data */ + l = egg_asn1_element_length (decrypted, n_decrypted); + if (l > 0) + n_decrypted = l; + + /* Try to parse */ + res = handle_plain_pem (self, type, subformat, decrypted, n_decrypted); + egg_secure_free (decrypted); + + /* Unrecognized is a bad password */ + if (res != GCR_PARSE_UNRECOGNIZED) + return res; + } + + return GCR_PARSE_FAILURE; +} + +typedef struct { + GcrParser *parser; + gint result; + gint subformat; +} HandlePemArgs; + +static void +handle_pem_data (GQuark type, const guchar *data, gsize n_data, + GHashTable *headers, gpointer user_data) +{ + HandlePemArgs *args = (HandlePemArgs*)user_data; + gint res = GCR_PARSE_FAILURE; + gboolean encrypted = FALSE; + const gchar *val; + + /* Something already failed to parse */ + if (args->result == GCR_PARSE_FAILURE) + return; + + /* See if it's encrypted PEM all openssl like*/ + if (headers) { + val = g_hash_table_lookup (headers, "Proc-Type"); + if (val && strcmp (val, "4,ENCRYPTED") == 0) + encrypted = TRUE; + } + + if (encrypted) + res = handle_encrypted_pem (args->parser, type, args->subformat, + headers, data, n_data); + else + res = handle_plain_pem (args->parser, type, args->subformat, + data, n_data); + + if (res != GCR_PARSE_UNRECOGNIZED) { + if (args->result == GCR_PARSE_UNRECOGNIZED) + args->result = res; + else if (res > args->result) + args->result = res; + } +} + +static gint +handle_pem_format (GcrParser *self, gint subformat, const guchar *data, gsize n_data) +{ + HandlePemArgs ctx = { self, GCR_PARSE_UNRECOGNIZED, subformat }; + guint found; + + if (n_data == 0) + return GCR_PARSE_UNRECOGNIZED; + + found = egg_openssl_pem_parse (data, n_data, handle_pem_data, &ctx); + + if (found == 0) + return GCR_PARSE_UNRECOGNIZED; + + return ctx.result; +} + + +static gint +parse_pem (GcrParser *self, const guchar *data, gsize n_data) +{ + return handle_pem_format (self, 0, data, n_data); +} + +static gint +parse_pem_private_key_rsa (GcrParser *self, const guchar *data, gsize n_data) +{ + return handle_pem_format (self, GCR_FORMAT_DER_PRIVATE_KEY_RSA, data, n_data); +} + +static gint +parse_pem_private_key_dsa (GcrParser *self, const guchar *data, gsize n_data) +{ + return handle_pem_format (self, GCR_FORMAT_DER_PRIVATE_KEY_DSA, data, n_data); +} + +static gint +parse_pem_certificate (GcrParser *self, const guchar *data, gsize n_data) +{ + return handle_pem_format (self, GCR_FORMAT_PEM_CERTIFICATE_X509, data, n_data); +} + +static gint +parse_pem_pkcs8_plain (GcrParser *self, const guchar *data, gsize n_data) +{ + return handle_pem_format (self, GCR_FORMAT_PEM_PKCS8_PLAIN, data, n_data); +} + +static gint +parse_pem_pkcs8_encrypted (GcrParser *self, const guchar *data, gsize n_data) +{ + return handle_pem_format (self, GCR_FORMAT_PEM_PKCS8_ENCRYPTED, data, n_data); +} + +static gint +parse_pem_pkcs7 (GcrParser *self, const guchar *data, gsize n_data) +{ + return handle_pem_format (self, GCR_FORMAT_PEM_PKCS7, data, n_data); +} + +static gint +parse_pem_pkcs12 (GcrParser *self, const guchar *data, gsize n_data) +{ + return handle_pem_format (self, GCR_FORMAT_PEM_PKCS12, data, n_data); +} + +/* ----------------------------------------------------------------------------- + * FORMATS + */ + +/* In order of parsing when no formats specified */ +static const ParserFormat parser_normal[] = { + { GCR_FORMAT_PEM, parse_pem }, + { GCR_FORMAT_DER_PRIVATE_KEY_RSA, parse_der_private_key_rsa }, + { GCR_FORMAT_DER_PRIVATE_KEY_DSA, parse_der_private_key_dsa }, + { GCR_FORMAT_DER_CERTIFICATE_X509, parse_der_certificate }, + { GCR_FORMAT_DER_PKCS7, parse_der_pkcs7 }, + { GCR_FORMAT_DER_PKCS8_PLAIN, parse_der_pkcs8_plain }, + { GCR_FORMAT_DER_PKCS8_ENCRYPTED, parse_der_pkcs8_encrypted }, + { GCR_FORMAT_DER_PKCS12, parse_der_pkcs12 } +}; + +/* Must be in format_id numeric order */ +static const ParserFormat parser_formats[] = { + { GCR_FORMAT_DER_PRIVATE_KEY, parse_der_private_key }, + { GCR_FORMAT_DER_PRIVATE_KEY_RSA, parse_der_private_key_rsa }, + { GCR_FORMAT_DER_PRIVATE_KEY_DSA, parse_der_private_key_dsa }, + { GCR_FORMAT_DER_CERTIFICATE_X509, parse_der_certificate }, + { GCR_FORMAT_DER_PKCS7, parse_der_pkcs7 }, + { GCR_FORMAT_DER_PKCS8, parse_der_pkcs8 }, + { GCR_FORMAT_DER_PKCS8_PLAIN, parse_der_pkcs8_plain }, + { GCR_FORMAT_DER_PKCS8_ENCRYPTED, parse_der_pkcs8_encrypted }, + { GCR_FORMAT_DER_PKCS12, parse_der_pkcs12 }, + { GCR_FORMAT_PEM, parse_pem }, + { GCR_FORMAT_PEM_PRIVATE_KEY_RSA, parse_pem_private_key_rsa }, + { GCR_FORMAT_PEM_PRIVATE_KEY_DSA, parse_pem_private_key_dsa }, + { GCR_FORMAT_PEM_CERTIFICATE_X509, parse_pem_certificate }, + { GCR_FORMAT_PEM_PKCS7, parse_pem_pkcs7 }, + { GCR_FORMAT_PEM_PKCS8_PLAIN, parse_pem_pkcs8_plain }, + { GCR_FORMAT_PEM_PKCS8_ENCRYPTED, parse_pem_pkcs8_encrypted }, + { GCR_FORMAT_PEM_PKCS12, parse_pem_pkcs12 }, +}; + +static int +compar_id_to_parser_format (const void *a, const void *b) +{ + const gint *format_id = a; + const ParserFormat *format = b; + + g_assert (format_id); + g_assert (format); + + if (format->format_id == *format_id) + return 0; + return (*format_id < format->format_id) ? -1 : 1; +} + +static ParserFormat* +parser_format_lookup (gint format_id) +{ + return bsearch (&format_id, parser_formats, G_N_ELEMENTS (parser_formats), + sizeof (parser_formats[0]), compar_id_to_parser_format); +} + +static gint +compare_pointers (gconstpointer a, gconstpointer b) +{ + if (a == b) + return 0; + return a < b ? -1 : 1; +} + +typedef struct _ForeachArgs { + GcrParser *parser; + const guchar *data; + gsize n_data; + gint result; +} ForeachArgs; + +static gboolean +parser_format_foreach (gpointer key, gpointer value, gpointer data) +{ + ForeachArgs *args = data; + ParserFormat *format = key; + gint result; + + g_assert (format); + g_assert (format->function); + g_assert (GCR_IS_PARSER (args->parser)); + + result = (format->function) (args->parser, args->data, args->n_data); + if (result != GCR_PARSE_UNRECOGNIZED) { + args->result = result; + return TRUE; + } + + /* Keep going */ + return FALSE; +} + +/* ----------------------------------------------------------------------------- + * OBJECT + */ + + +static GObject* +gcr_parser_constructor (GType type, guint n_props, GObjectConstructParam *props) +{ + GcrParser *self = GCR_PARSER (G_OBJECT_CLASS (gcr_parser_parent_class)->constructor(type, n_props, props)); + g_return_val_if_fail (self, NULL); + + /* Always try to parse with NULL and empty passwords first */ + gcr_parser_add_password (self, NULL); + gcr_parser_add_password (self, ""); + + return G_OBJECT (self); +} + +static void +gcr_parser_init (GcrParser *self) +{ + self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_PARSER, GcrParserPrivate); + self->pv->passwords = g_ptr_array_new (); + self->pv->normal_formats = TRUE; +} + +static void +gcr_parser_dispose (GObject *obj) +{ + GcrParser *self = GCR_PARSER (obj); + gsize i; + + if (self->pv->parsed_attrs) + gp11_attributes_unref (self->pv->parsed_attrs); + self->pv->parsed_attrs = NULL; + + g_free (self->pv->parsed_label); + self->pv->parsed_label = NULL; + + for (i = 0; i < self->pv->passwords->len; ++i) + egg_secure_strfree (g_ptr_array_index (self->pv->passwords, i)); + g_ptr_array_set_size (self->pv->passwords, 0); + + G_OBJECT_CLASS (gcr_parser_parent_class)->dispose (obj); +} + +static void +gcr_parser_finalize (GObject *obj) +{ + GcrParser *self = GCR_PARSER (obj); + + g_assert (!self->pv->parsed_attrs); + g_assert (!self->pv->parsed_label); + + g_ptr_array_free (self->pv->passwords, TRUE); + self->pv->passwords = NULL; + + G_OBJECT_CLASS (gcr_parser_parent_class)->finalize (obj); +} + +static void +gcr_parser_set_property (GObject *obj, guint prop_id, const GValue *value, + GParamSpec *pspec) +{ +#if 0 + GcrParser *self = GCR_PARSER (obj); +#endif + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); + break; + } +} + +static void +gcr_parser_get_property (GObject *obj, guint prop_id, GValue *value, + GParamSpec *pspec) +{ + GcrParser *self = GCR_PARSER (obj); + + switch (prop_id) { + case PROP_PARSED_ATTRIBUTES: + g_value_set_boxed (value, gcr_parser_get_parsed_attributes (self)); + break; + case PROP_PARSED_LABEL: + g_value_set_string (value, gcr_parser_get_parsed_label (self)); + break; + case PROP_PARSED_DESCRIPTION: + g_value_set_string (value, gcr_parser_get_parsed_description (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); + break; + } +} + +static void +gcr_parser_class_init (GcrParserClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + gint i; + + gobject_class->constructor = gcr_parser_constructor; + gobject_class->dispose = gcr_parser_dispose; + gobject_class->finalize = gcr_parser_finalize; + gobject_class->set_property = gcr_parser_set_property; + gobject_class->get_property = gcr_parser_get_property; + + g_type_class_add_private (gobject_class, sizeof (GcrParserPrivate)); + + g_object_class_install_property (gobject_class, PROP_PARSED_ATTRIBUTES, + g_param_spec_boxed ("parsed-attributes", "Parsed Attributes", "Parsed PKCS#11 attributes", + GP11_TYPE_ATTRIBUTES, G_PARAM_READABLE)); + + g_object_class_install_property (gobject_class, PROP_PARSED_LABEL, + g_param_spec_string ("parsed-label", "Parsed Label", "Parsed item label", + "", G_PARAM_READABLE)); + + g_object_class_install_property (gobject_class, PROP_PARSED_DESCRIPTION, + g_param_spec_string ("parsed-description", "Parsed Description", "Parsed item description", + "", G_PARAM_READABLE)); + + signals[AUTHENTICATE] = g_signal_new ("authenticate", GCR_TYPE_PARSER, + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GcrParserClass, authenticate), + g_signal_accumulator_true_handled, NULL, _gcr_marshal_BOOLEAN__INT, + G_TYPE_BOOLEAN, 1, G_TYPE_POINTER); + + signals[PARSED] = g_signal_new ("parsed", GCR_TYPE_PARSER, + G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GcrParserClass, parsed), + NULL, NULL, g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + init_quarks (); + _gcr_initialize (); + + /* Check that the format tables are in order */ + for (i = 1; i < G_N_ELEMENTS (parser_formats); ++i) + g_assert (parser_formats[i].format_id >= parser_formats[i - 1].format_id); +} + +/* ----------------------------------------------------------------------------- + * PUBLIC + */ + +GcrParser* +gcr_parser_new (void) +{ + return g_object_new (GCR_TYPE_PARSER, NULL); +} + +GQuark +gcr_parser_get_error_domain (void) +{ + static GQuark domain = 0; + if (domain == 0) + domain = g_quark_from_static_string ("gcr-parser-error"); + return domain; +} + +void +gcr_parser_add_password (GcrParser *self, const gchar *password) +{ + g_return_if_fail (GCR_IS_PARSER (self)); + g_ptr_array_add (self->pv->passwords, egg_secure_strdup (password)); +} + +gboolean +gcr_parser_parse_data (GcrParser *self, const guchar *data, + gsize n_data, GError **err) +{ + ForeachArgs args = { self, data, n_data, GCR_PARSE_UNRECOGNIZED }; + const gchar *message; + gint i; + + g_return_val_if_fail (GCR_IS_PARSER (self), FALSE); + g_return_val_if_fail (data || !n_data, FALSE); + g_return_val_if_fail (!err || !*err, FALSE); + + /* Just the specific formats requested */ + if (self->pv->specific_formats) { + g_tree_foreach (self->pv->specific_formats, parser_format_foreach, &args); + + /* All the 'normal' formats */ + } else if (self->pv->normal_formats) { + for (i = 0; i < G_N_ELEMENTS (parser_normal); ++i) { + if (parser_format_foreach ((gpointer)(parser_normal + i), + (gpointer)(parser_normal + i), &args)) + break; + } + } + + switch (args.result) { + case SUCCESS: + return TRUE; + case GCR_PARSE_CANCELLED: + message = _("The operation was cancelled"); + break; + case GCR_PARSE_UNRECOGNIZED: + message = _("Unrecognized or unsupported data."); + break; + case GCR_PARSE_FAILURE: + message = _("Could not parse invalid or corrupted data."); + break; + case GCR_PARSE_LOCKED: + message = _("The data is locked"); + break; + default: + g_assert_not_reached (); + break; + }; + + g_set_error_literal (err, GCR_PARSER_ERROR, args.result, message); + return FALSE; +} + +gboolean +gcr_parser_parse_file (GcrParser *self, const gchar *filename, GError **err) +{ + GMappedFile *mapped; + gboolean ret; + const guchar *data; + gsize n_data; + + g_return_val_if_fail (GCR_IS_PARSER (self), FALSE); + g_return_val_if_fail (filename, FALSE); + g_return_val_if_fail (!err || !*err, FALSE); + + mapped = g_mapped_file_new (filename, FALSE, err); + if (mapped == NULL) + return FALSE; + + data = (const guchar*)g_mapped_file_get_contents (mapped); + n_data = g_mapped_file_get_length (mapped); + + ret = gcr_parser_parse_data (self, data, n_data, err); + + g_mapped_file_free (mapped); + + return ret; +} + +gboolean +gcr_parser_format_enable (GcrParser *self, gint format_id) +{ + ParserFormat *format; + + g_return_val_if_fail (GCR_IS_PARSER (self), FALSE); + + if (format_id == -1) { + if (self->pv->specific_formats) + g_tree_destroy (self->pv->specific_formats); + self->pv->specific_formats = NULL; + self->pv->normal_formats = TRUE; + return TRUE; + } + + format = parser_format_lookup (format_id); + if (format == NULL) + return FALSE; + + if (!self->pv->specific_formats) { + if (self->pv->normal_formats) + return TRUE; + self->pv->specific_formats = g_tree_new (compare_pointers); + } + + g_tree_insert (self->pv->specific_formats, format, format); + return TRUE; +} + +gboolean +gcr_parser_format_disable (GcrParser *self, gint format_id) +{ + ParserFormat *format; + + g_return_val_if_fail (GCR_IS_PARSER (self), FALSE); + + if (format_id == -1) { + if (self->pv->specific_formats) + g_tree_destroy (self->pv->specific_formats); + self->pv->specific_formats = NULL; + self->pv->normal_formats = FALSE; + return TRUE; + } + + if (!self->pv->specific_formats) + return TRUE; + + format = parser_format_lookup (format_id); + if (format == NULL) + return FALSE; + + g_tree_remove (self->pv->specific_formats, format); + return TRUE; +} + +gboolean +gcr_parser_format_supported (GcrParser *self, gint format_id) +{ + g_return_val_if_fail (GCR_IS_PARSER (self), FALSE); + g_return_val_if_fail (format_id != -1, FALSE); + return parser_format_lookup (format_id) ? TRUE : FALSE; +} + +const gchar* +gcr_parser_get_parsed_description (GcrParser *self) +{ + g_return_val_if_fail (GCR_IS_PARSER (self), NULL); + return self->pv->parsed_desc; +} + +GP11Attributes* +gcr_parser_get_parsed_attributes (GcrParser *self) +{ + g_return_val_if_fail (GCR_IS_PARSER (self), NULL); + return self->pv->parsed_attrs; +} + +const gchar* +gcr_parser_get_parsed_label (GcrParser *self) +{ + g_return_val_if_fail (GCR_IS_PARSER (self), NULL); + return self->pv->parsed_label; +} diff --git a/gcr/gcr-parser.h b/gcr/gcr-parser.h new file mode 100644 index 00000000..e4c3e248 --- /dev/null +++ b/gcr/gcr-parser.h @@ -0,0 +1,92 @@ +/* + * gnome-keyring + * + * Copyright (C) 2008 Stefan Walter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef __GCR_PARSER_H__ +#define __GCR_PARSER_H__ + +#include <glib-object.h> + +#include "gcr-types.h" + +#define GCR_PARSER_ERROR (gcr_parser_get_error_domain ()) + +#define GCR_TYPE_PARSER (gcr_parser_get_type ()) +#define GCR_PARSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_PARSER, GcrParser)) +#define GCR_PARSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_PARSER, GcrParserClass)) +#define GCR_IS_PARSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_PARSER)) +#define GCR_IS_PARSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_PARSER)) +#define GCR_PARSER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_PARSER, GcrParserClass)) + +typedef struct _GcrParser GcrParser; +typedef struct _GcrParsedItem GcrParsedItem; +typedef struct _GcrParserClass GcrParserClass; +typedef struct _GcrParserPrivate GcrParserPrivate; + +struct _GcrParser { + GObject parent; + GcrParserPrivate *pv; +}; + +struct _GcrParserClass { + GObjectClass parent_class; + + /* signals --------------------------------------------------------- */ + + /* A callback for each password needed */ + gboolean (*authenticate) (GcrParser *self, gint count); + + void (*parsed) (GcrParser *self); +}; + +GType gcr_parser_get_type (void); + +GQuark gcr_parser_get_error_domain (void) G_GNUC_CONST; + +GcrParser* gcr_parser_new (void); + +gboolean gcr_parser_format_enable (GcrParser *self, + gint format); + +gboolean gcr_parser_format_disable (GcrParser *self, + gint format); + +gboolean gcr_parser_format_supported (GcrParser *self, + gint format); + +gboolean gcr_parser_parse_data (GcrParser *self, + const guchar *data, + gsize n_data, + GError **err); + +gboolean gcr_parser_parse_file (GcrParser *self, + const gchar *filename, + GError **err); + +void gcr_parser_add_password (GcrParser *self, + const gchar *password); + +const gchar* gcr_parser_get_parsed_label (GcrParser *self); + +const gchar* gcr_parser_get_parsed_description (GcrParser *self); + +GP11Attributes* gcr_parser_get_parsed_attributes (GcrParser *self); + +#endif /* __GCR_PARSER_H__ */ diff --git a/gcr/gcr-types.h b/gcr/gcr-types.h new file mode 100644 index 00000000..edef49b5 --- /dev/null +++ b/gcr/gcr-types.h @@ -0,0 +1,45 @@ +#ifndef GCRTYPES_H_ +#define GCRTYPES_H_ + +enum { + GCR_PARSE_FAILURE = -1, + GCR_PARSE_UNRECOGNIZED = 1, + GCR_PARSE_CANCELLED = 2, + GCR_PARSE_LOCKED = 3 +}; + +enum { + GCR_FORMAT_INVALID = 0, + + GCR_FORMAT_DER_PRIVATE_KEY = 100, + GCR_FORMAT_DER_PRIVATE_KEY_RSA, + GCR_FORMAT_DER_PRIVATE_KEY_DSA, + + GCR_FORMAT_DER_CERTIFICATE_X509 = 200, + + GCR_FORMAT_DER_PKCS7 = 300, + + GCR_FORMAT_DER_PKCS8 = 400, + GCR_FORMAT_DER_PKCS8_PLAIN, + GCR_FORMAT_DER_PKCS8_ENCRYPTED, + + GCR_FORMAT_DER_PKCS12 = 500, + + GCR_FORMAT_PEM = 1000, + GCR_FORMAT_PEM_PRIVATE_KEY_RSA, + GCR_FORMAT_PEM_PRIVATE_KEY_DSA, + GCR_FORMAT_PEM_CERTIFICATE_X509, + GCR_FORMAT_PEM_PKCS7, + GCR_FORMAT_PEM_PKCS8_PLAIN, + GCR_FORMAT_PEM_PKCS8_ENCRYPTED, + GCR_FORMAT_PEM_PKCS12 +}; + +#ifndef GP11_H + +/* Forward declare some of the GP11 objects */ +typedef struct _GP11Attributes GP11Attributes; + +#endif /* GP11_H */ + +#endif /* GCRTYPES_H_ */ diff --git a/gcr/gcr.pc.in b/gcr/gcr.pc.in new file mode 100644 index 00000000..b0a812d4 --- /dev/null +++ b/gcr/gcr.pc.in @@ -0,0 +1,14 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ +datarootdir=@datarootdir@ +datadir=@datadir@ +sysconfdir=@sysconfdir@ + +Name: gp11 +Description: GObject bindings for PKCS#11 +Version: @VERSION@ +Requires: glib-2.0 +Libs: -L${libdir} -lgp11 +Cflags: -I${includedir}/gp11 diff --git a/gcr/template/gcr-xxx.c b/gcr/template/gcr-xxx.c new file mode 100644 index 00000000..91f7e6c6 --- /dev/null +++ b/gcr/template/gcr-xxx.c @@ -0,0 +1,146 @@ +/* + * gnome-keyring + * + * Copyright (C) 2008 Stefan Walter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "config.h" + +#include "gcr-xxx.h" + +enum { + PROP_0, + PROP_XXX +}; + +enum { + SIGNAL, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + + +struct _GcrXxxPrivate { +}; + +G_DEFINE_TYPE (GcrXxx, gcr_xxx, G_TYPE_OBJECT); + +/* ----------------------------------------------------------------------------- + * INTERNAL + */ + +/* ----------------------------------------------------------------------------- + * OBJECT + */ + + +static GObject* +gcr_xxx_constructor (GType type, guint n_props, GObjectConstructParam *props) +{ + GcrXxx *self = GCR_XXX (G_OBJECT_CLASS (gcr_xxx_parent_class)->constructor(type, n_props, props)); + g_return_val_if_fail (self, NULL); + + + + return G_OBJECT (self); +} + +static void +gcr_xxx_init (GcrXxx *self) +{ + self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_XXX, GcrXxxPrivate); +} + +static void +gcr_xxx_dispose (GObject *obj) +{ + GcrXxx *self = GCR_XXX (obj); + + G_OBJECT_CLASS (gcr_xxx_parent_class)->dispose (obj); +} + +static void +gcr_xxx_finalize (GObject *obj) +{ + GcrXxx *self = GCR_XXX (obj); + + G_OBJECT_CLASS (gcr_xxx_parent_class)->finalize (obj); +} + +static void +gcr_xxx_set_property (GObject *obj, guint prop_id, const GValue *value, + GParamSpec *pspec) +{ + GcrXxx *self = GCR_XXX (obj); + + switch (prop_id) { + case PROP_XXX: + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); + break; + } +} + +static void +gcr_xxx_get_property (GObject *obj, guint prop_id, GValue *value, + GParamSpec *pspec) +{ + GcrXxx *self = GCR_XXX (obj); + + switch (prop_id) { + case PROP_XXX: + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); + break; + } +} + +static void +gcr_xxx_class_init (GcrXxxClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->constructor = gcr_xxx_constructor; + gobject_class->dispose = gcr_xxx_dispose; + gobject_class->finalize = gcr_xxx_finalize; + gobject_class->set_property = gcr_xxx_set_property; + gobject_class->get_property = gcr_xxx_get_property; + + g_type_class_add_private (gobject_class, sizeof (GcrXxxPrivate)); + + g_object_class_install_property (gobject_class, PROP_XXX, + g_param_spec_pointer ("xxx", "Xxx", "Xxx.", G_PARAM_READWRITE)); + + signals[SIGNAL] = g_signal_new ("signal", GCR_TYPE_XXX, + G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GcrXxxClass, signal), + NULL, NULL, g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 0); +} + +/* ----------------------------------------------------------------------------- + * PUBLIC + */ + +GcrXxx* +gcr_xxx_new (void) +{ + return g_object_new (GCR_TYPE_XXX, NULL); +} diff --git a/gcr/template/gcr-xxx.h b/gcr/template/gcr-xxx.h new file mode 100644 index 00000000..b85cd95e --- /dev/null +++ b/gcr/template/gcr-xxx.h @@ -0,0 +1,55 @@ +/* + * gnome-keyring + * + * Copyright (C) 2008 Stefan Walter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef __GCR_XXX_H__ +#define __GCR_XXX_H__ + +#include <glib-object.h> + +#define GCR_TYPE_XXX (gcr_xxx_get_type ()) +#define GCR_XXX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_XXX, GcrXxx)) +#define GCR_XXX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_XXX, GcrXxxClass)) +#define GCR_IS_XXX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_XXX)) +#define GCR_IS_XXX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_XXX)) +#define GCR_XXX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_XXX, GcrXxxClass)) + +typedef struct _GcrXxx GcrXxx; +typedef struct _GcrXxxClass GcrXxxClass; +typedef struct _GcrXxxPrivate GcrXxxPrivate; + +struct _GcrXxx { + GObject parent; + GcrXxxPrivate *pv; +}; + +struct _GcrXxxClass { + GObjectClass parent_class; + + /* signals --------------------------------------------------------- */ + + void (*signal) (GcrXxx *self); +}; + +GType gcr_xxx_get_type (void); + +GcrXxx* gcr_xxx_new (void); + +#endif /* __GCR_XXX_H__ */ diff --git a/gcr/tests/Makefile.am b/gcr/tests/Makefile.am new file mode 100644 index 00000000..c746135a --- /dev/null +++ b/gcr/tests/Makefile.am @@ -0,0 +1,13 @@ + +# Test files should be listed in order they need to run +UNIT_AUTO = \ + unit-test-parser.c + +UNIT_PROMPT = + +UNIT_LIBS = \ + $(top_builddir)/gcr/libgcr.la \ + $(top_builddir)/egg/libegg.la \ + $(top_builddir)/gp11/libgp11.la + +include $(top_srcdir)/tests/gtest.make diff --git a/gcr/tests/test-data/RSA_Root_Certificate_1.pem b/gcr/tests/test-data/RSA_Root_Certificate_1.pem new file mode 100644 index 00000000..f6cdfcd0 --- /dev/null +++ b/gcr/tests/test-data/RSA_Root_Certificate_1.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlD +ZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu +Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRp +b24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNv +bS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYy +NjAwMjIzM1oXDTE5MDYyNjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 +IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4x +NTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24g +QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8x +IDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3 +DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+epvzzFlLWLU2f +NUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChM +MFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqYJJgpp0lZpd34 +t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliEZwgs3x/b +e0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJn0Wu +PIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/A +PhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu +-----END CERTIFICATE----- diff --git a/gcr/tests/test-data/RSA_Security_1024_v3.pem b/gcr/tests/test-data/RSA_Security_1024_v3.pem new file mode 100644 index 00000000..94e0ad13 --- /dev/null +++ b/gcr/tests/test-data/RSA_Security_1024_v3.pem @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE----- +MIICXDCCAcWgAwIBAgIQCgEBAQAAAnwAAAALAAAAAjANBgkqhkiG9w0BAQUF +ADA6MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0Eg +U2VjdXJpdHkgMTAyNCBWMzAeFw0wMTAyMjIyMTAxNDlaFw0yNjAyMjIyMDAx +NDlaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJT +QSBTZWN1cml0eSAxMDI0IFYzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB +gQDV3f5mCc8kPD6ugU5OisRpgFtZO9+5TUzKtS3DJy08rwBCbbwoppbPf9dY +rIMKo1W1exeQFYRMiu4mmdxY78c4pqqv0I5CyGLXq6yp+0p9v+r+Ek3d/yYt +bzZUaMjShFbuklNhCbM/OZuoyZu9zp9+1BlqFikYvtc6adwlWzMaUQIDAQAB +o2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSME +GDAWgBTEwBykB5T9zU0B1FTapQxf3q4FWjAdBgNVHQ4EFgQUxMAcpAeU/c1N +AdRU2qUMX96uBVowDQYJKoZIhvcNAQEFBQADgYEAPy1q4yZDlX2Jl2X7deRy +HUZXxGFraZ8SmyzVWujAovBDleMf6XbN3Ou8k6BlCsdNT1+nr6JGFLkM88y9 +am63nd4lQtBU/55oc2PcJOsiv6hy8l4A4Q1OOkNumU4/iXgDmMrzVcydro7B +qkWY+o8aoI2II/EVQQ2lRj6RP4vr93E= +-----END CERTIFICATE----- diff --git a/gcr/tests/test-data/RSA_Security_2048_v3.pem b/gcr/tests/test-data/RSA_Security_2048_v3.pem new file mode 100644 index 00000000..86c907eb --- /dev/null +++ b/gcr/tests/test-data/RSA_Security_2048_v3.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUF +ADA6MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0Eg +U2VjdXJpdHkgMjA0OCBWMzAeFw0wMTAyMjIyMDM5MjNaFw0yNjAyMjIyMDM5 +MjNaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJT +QSBTZWN1cml0eSAyMDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAt49VcdKA3XtpeafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37 +RqtBaB4Y6lXIL5F4iSj7Jylg/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E +0S1PRsNO3Ng3OTsor8udGuorryGlwSMiuLgbWhOHV4PR8CDn6E8jQrAApX2J +6elhc5SYcSa8LWrg903w8bYqODGBDSnhAMFRD0xS+ARaqn1y07iHKrtjEAMq +s6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2PcYJk5qjEoAAVZkZR73QpXzD +uvsf9/UP+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpuAWgXIszACwIDAQABo2Mw +YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAW +gBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4EFgQUB8NRMKSq6UWuNST6 +/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYcHnmYv/3V +EhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/Zb5g +EydxiKRz44Rj0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+ +f00/FGj1EVDVwfSQpQgdMWD/YIwjVAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJq +aHVOrSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395nzIlQnQFgCi/vcEk +llgVsRch6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kA +pKnXwiJPZ9d37CAFYd4= +-----END CERTIFICATE----- diff --git a/gcr/tests/test-data/Thawte_Personal_Basic_CA.pem b/gcr/tests/test-data/Thawte_Personal_Basic_CA.pem new file mode 100644 index 00000000..22c2a8db --- /dev/null +++ b/gcr/tests/test-data/Thawte_Personal_Basic_CA.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDITCCAoqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMC +WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du +MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm +aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFBl +cnNvbmFsIEJhc2ljIENBMSgwJgYJKoZIhvcNAQkBFhlwZXJzb25hbC1iYXNp +Y0B0aGF3dGUuY29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVow +gcsxCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNV +BAcTCUNhcGUgVG93bjEaMBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAm +BgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24xITAfBgNV +BAMTGFRoYXd0ZSBQZXJzb25hbCBCYXNpYyBDQTEoMCYGCSqGSIb3DQEJARYZ +cGVyc29uYWwtYmFzaWNAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOB +jQAwgYkCgYEAvLyTU23AUE+CFeZIlDWmWr5vQvoPR+53dXLdjUmbllegeNTK +P1GzaQuRdhciB5dqxFGTS+CN7zeVoQxN2jSQHReJl+A1OFdKwPQIcOk8RHtQ +fmGakOMj04gRRif1CwcOu93RfyAKiLlWCy4cgNrx454p7xS9CkT7G1sY0b8j +kyECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOB +gQAt4plrsD16iddZopQBHyvdEktTwq1/qqcAXJFAVyVKOKqEcLnZgA+le1z7 +c8a914phXAPjLSeoF+CEhULcXpvGt7Jtu3Sv5D/Lp7ew4F2+eIMllNLbgQ95 +B21P9DkVWlIBe94y1k049hJcBlDfBVu9FEuh3ym6O0GN92NWod8isQ== +-----END CERTIFICATE----- diff --git a/gcr/tests/test-data/Thawte_Personal_Freemail_CA.pem b/gcr/tests/test-data/Thawte_Personal_Freemail_CA.pem new file mode 100644 index 00000000..565a4be1 --- /dev/null +++ b/gcr/tests/test-data/Thawte_Personal_Freemail_CA.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDLTCCApagAwIBAgIBADANBgkqhkiG9w0BAQQFADCB0TELMAkGA1UEBhMC +WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du +MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm +aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEkMCIGA1UEAxMbVGhhd3RlIFBl +cnNvbmFsIEZyZWVtYWlsIENBMSswKQYJKoZIhvcNAQkBFhxwZXJzb25hbC1m +cmVlbWFpbEB0aGF3dGUuY29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIz +NTk1OVowgdExCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUx +EjAQBgNVBAcTCUNhcGUgVG93bjEaMBgGA1UEChMRVGhhd3RlIENvbnN1bHRp +bmcxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24x +JDAiBgNVBAMTG1RoYXd0ZSBQZXJzb25hbCBGcmVlbWFpbCBDQTErMCkGCSqG +SIb3DQEJARYccGVyc29uYWwtZnJlZW1haWxAdGhhd3RlLmNvbTCBnzANBgkq +hkiG9w0BAQEFAAOBjQAwgYkCgYEA1GnX1LCUZFtx6UfYDFG26nKRsIRefS0N +j3sS34UldSh0OkIsYyeflXtL734Zhx2G6qPduc6WZBrCFG5ErHzmj+hND3Ef +QDimAKOHePb5lIZererAXnbr2RSjXW56fAylS1V/Bhkpf56aJtVquzgkCGqY +x7Hao5iR/Xnb5VrEHLkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq +hkiG9w0BAQQFAAOBgQDH7JJ+Tvj1lqVnYiqk8E0RYNBvjWBYYawmu1I1XAjP +MPuoSpaKH2JCI4wXD/S6ZJwXrEcp352YXtJsYHFcoqzceePnbgBHH7UNKOgC +neSa/RP0ptl8sfjcXyMmCZGAc9AUG95DqYMl8uacLxXK/qarigd1iwzdUYRr +5PjRzneigQ== +-----END CERTIFICATE----- diff --git a/gcr/tests/test-data/Thawte_Personal_Premium_CA.pem b/gcr/tests/test-data/Thawte_Personal_Premium_CA.pem new file mode 100644 index 00000000..688c3ae1 --- /dev/null +++ b/gcr/tests/test-data/Thawte_Personal_Premium_CA.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDKTCCApKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBzzELMAkGA1UEBhMC +WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du +MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm +aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEjMCEGA1UEAxMaVGhhd3RlIFBl +cnNvbmFsIFByZW1pdW0gQ0ExKjAoBgkqhkiG9w0BCQEWG3BlcnNvbmFsLXBy +ZW1pdW1AdGhhd3RlLmNvbTAeFw05NjAxMDEwMDAwMDBaFw0yMDEyMzEyMzU5 +NTlaMIHPMQswCQYDVQQGEwJaQTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIw +EAYDVQQHEwlDYXBlIFRvd24xGjAYBgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5n +MSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMSMw +IQYDVQQDExpUaGF3dGUgUGVyc29uYWwgUHJlbWl1bSBDQTEqMCgGCSqGSIb3 +DQEJARYbcGVyc29uYWwtcHJlbWl1bUB0aGF3dGUuY29tMIGfMA0GCSqGSIb3 +DQEBAQUAA4GNADCBiQKBgQDJZtn4B0TPuYwu8KHvE0VsBd/eJxZRNkERbGw7 +7f4QfRKe5ZtCmv5gMcNmt3M6SK5O0DI3lIi1DbbZ8/JE2dWIEt12TfIa/G8j +Hnrx2JhFTgcQ7xZC0EN1bUre4qrJMf8fAHB8Zs8QJQi6+u4A6UYDZicRFTuq +W/KY3TZCstqIdQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 +DQEBBAUAA4GBAGk2ifc0KjNyL2071CKyuG+axTZmDhs8obF1Wub9NdP4qPIH +b4Vnjt4rueIXsDqg8A6iAJrf8xQVbrvIhVqYgPn/vnQdPfP+MCXRNzRn+qVx +eTBhKXLA4CxM+1bkOqhv5TJZUtt1KFBZDPgLGeSs2a+WjS9Q2wfD6h+rM+D1 +KzGJ +-----END CERTIFICATE----- diff --git a/gcr/tests/test-data/Thawte_Premium_Server_CA.pem b/gcr/tests/test-data/Thawte_Premium_Server_CA.pem new file mode 100644 index 00000000..aa37cfc9 --- /dev/null +++ b/gcr/tests/test-data/Thawte_Premium_Server_CA.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMC +WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du +MR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2Vy +dGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3Rl +IFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNl +cnZlckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1 +OVowgc4xCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQ +BgNVBAcTCUNhcGUgVG93bjEdMBsGA1UEChMUVGhhd3RlIENvbnN1bHRpbmcg +Y2MxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24x +ITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3 +DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0B +AQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhI +NTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQug2SBhRz1JPL +lyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMRuHM/qgeN +9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B +AQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI +hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZ +a4JMpAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcU +Qg== +-----END CERTIFICATE----- diff --git a/gcr/tests/test-data/Thawte_Server_CA.pem b/gcr/tests/test-data/Thawte_Server_CA.pem new file mode 100644 index 00000000..ac4e25bf --- /dev/null +++ b/gcr/tests/test-data/Thawte_Server_CA.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMC +WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du +MR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2Vy +dGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3Rl +IFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0 +ZS5jb20wHhcNOTYwODAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkG +A1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2Fw +ZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UE +CxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQ +VGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRz +QHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I +/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC +6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCXL+eQbcAoQpnX +TEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGjEzARMA8G +A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG7oWD +TSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e +QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdni +TCxZqdq5snUb9kLy78fyGPmJvKP/iiMucEc= +-----END CERTIFICATE----- diff --git a/gcr/tests/test-data/Thawte_Time_Stamping_CA.pem b/gcr/tests/test-data/Thawte_Time_Stamping_CA.pem new file mode 100644 index 00000000..fecbd15e --- /dev/null +++ b/gcr/tests/test-data/Thawte_Time_Stamping_CA.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIICoTCCAgqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBizELMAkGA1UEBhMC +WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmls +bGUxDzANBgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmlj +YXRpb24xHzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwHhcNOTcw +MTAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBizELMAkGA1UEBhMCWkExFTAT +BgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzAN +BgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24x +HzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwgZ8wDQYJKoZIhvcN +AQEBBQADgY0AMIGJAoGBANYrWHhhRYZT6jR7UZztsOYuGA7+4F+oJ9O0yeB8 +WU4WDnNUYMF/9p8u6TqFJBU820cEY8OexJQaWt9MevPZQx08EHp5JduQ/vBR +5zDWQQD9nyjfeb6Uu522FOMjhdepQeBMpHmwKxqL8vg7ij5FrHGSALSQQZj7 +X+36ty6K+Ig3AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN +AQEEBQADgYEAZ9viwuaHPUCDhjc1fR/OmsMMZiCouqoEiYbC9RAIDb/LogWK +0E02PvTX72nGXuSwlG9KuefeW4i2e9vjJ+V2w/A1wcu1J5szedyQpgCed/r8 +zSeUQhac0xxo7L9c3eWpexAKMnRUEzGLhQOEkbdYATAUOK8oyvyxUBkZCayJ +SdM= +-----END CERTIFICATE----- diff --git a/gcr/tests/test-data/ca-certificates.crt b/gcr/tests/test-data/ca-certificates.crt new file mode 100644 index 00000000..c30335f8 --- /dev/null +++ b/gcr/tests/test-data/ca-certificates.crt @@ -0,0 +1,2560 @@ +-----BEGIN CERTIFICATE----- +MIIEuDCCA6CgAwIBAgIBBDANBgkqhkiG9w0BAQUFADCBtDELMAkGA1UEBhMCQlIx +EzARBgNVBAoTCklDUC1CcmFzaWwxPTA7BgNVBAsTNEluc3RpdHV0byBOYWNpb25h +bCBkZSBUZWNub2xvZ2lhIGRhIEluZm9ybWFjYW8gLSBJVEkxETAPBgNVBAcTCEJy +YXNpbGlhMQswCQYDVQQIEwJERjExMC8GA1UEAxMoQXV0b3JpZGFkZSBDZXJ0aWZp +Y2Fkb3JhIFJhaXogQnJhc2lsZWlyYTAeFw0wMTExMzAxMjU4MDBaFw0xMTExMzAy +MzU5MDBaMIG0MQswCQYDVQQGEwJCUjETMBEGA1UEChMKSUNQLUJyYXNpbDE9MDsG +A1UECxM0SW5zdGl0dXRvIE5hY2lvbmFsIGRlIFRlY25vbG9naWEgZGEgSW5mb3Jt +YWNhbyAtIElUSTERMA8GA1UEBxMIQnJhc2lsaWExCzAJBgNVBAgTAkRGMTEwLwYD +VQQDEyhBdXRvcmlkYWRlIENlcnRpZmljYWRvcmEgUmFpeiBCcmFzaWxlaXJhMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwPMudwX/hvm+Uh2b/lQAcHVA +isamaLkWdkwP9/S/tOKIgRrL6Oy+ZIGlOUdd6uYtk9Ma/3pUpgcfNAj0vYm5gsyj +Qo9emsc+x6m4VWwk9iqMZSCK5EQkAq/Ut4n7KuLE1+gdftwdIgxfUsPt4CyNrY50 +QV57KM2UT8x5rrmzEjr7TICGpSUAl2gVqe6xaii+bmYR1QrmWaBSAG59LrkrjrYt +bRhFboUDe1DK+6T8s5L6k8c8okpbHpa9veMztDVC9sPJ60MWXh6anVKo1UcLcbUR +yEeNvZneVRKAAU6ouwdjDvwlsaKydFKwed0ToQ47bmUKgcm+wV3eTRk36UOnTwID +AQABo4HSMIHPME4GA1UdIARHMEUwQwYFYEwBAQAwOjA4BggrBgEFBQcCARYsaHR0 +cDovL2FjcmFpei5pY3BicmFzaWwuZ292LmJyL0RQQ2FjcmFpei5wZGYwPQYDVR0f +BDYwNDAyoDCgLoYsaHR0cDovL2FjcmFpei5pY3BicmFzaWwuZ292LmJyL0xDUmFj +cmFpei5jcmwwHQYDVR0OBBYEFIr68VeEERM1kEL6V0lUaQ2kxPA3MA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAZA5c1 +U/hgIh6OcgLAfiJgFWpvmDZWqlV30/bHFpj8iBobJSm5uDpt7TirYh1Uxe3fQaGl +YjJe+9zd+izPRbBqXPVQA34EXcwk4qpWuf1hHriWfdrx8AcqSqr6CuQFwSr75Fos +SzlwDADa70mT7wZjAmQhnZx2xJ6wfWlT9VQfS//JYeIc7Fue2JNLd00UOSMMaiK/ +t79enKNHEA2fupH3vEigf5Eh4bVAN5VohrTm6MY53x7XQZZr1ME7a55lFEnSeT0u +mlOAjR2mAbvSM5X5oSZNrmetdzyTj2flCM8CC7MLab0kkdngRIlUBGHF1/S5nmPb +K+9A46sd33oqK8n8 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290 +IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB +IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA +Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO +BgNVBAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEi +MCAGA1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJ +ARYSc3VwcG9ydEBjYWNlcnQub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC +CgKCAgEAziLA4kZ97DYoB1CW8qAzQIxL8TtmPzHlawI229Z89vGIj053NgVBlfkJ +8BLPRoZzYLdufujAWGSuzbCtRRcMY/pnCujW0r8+55jE8Ez64AO7NV1sId6eINm6 +zWYyN3L69wj1x81YyY7nDl7qPv4coRQKFWyGhFtkZip6qUtTefWIonvuLwphK42y +fk1WpRPs6tqSnqxEQR5YYGUFZvjARL3LlPdCfgv3ZWiYUQXw8wWRBB0bF4LsyFe7 +w2t6iPGwcswlWyCR7BYCEo8y6RcYSNDHBS4CMEK4JZwFaz+qOqfrU0j36NK2B5jc +G8Y0f3/JHIJ6BVgrCFvzOKKrF11myZjXnhCLotLddJr3cQxyYN/Nb5gznZY0dj4k +epKwDpUeb+agRThHqtdB7Uq3EvbXG4OKDy7YCbZZ16oE/9KTfWgu3YtLq1i6L43q +laegw1SJpfvbi1EinbLDvhG+LJGGi5Z4rSDTii8aP8bQUWWHIbEZAWV/RRyH9XzQ +QUxPKZgh/TMfdQwEUfoZd9vUFBzugcMd9Zi3aQaRIt0AUMyBMawSB3s42mhb5ivU +fslfrejrckzzAeVLIL+aplfKkQABi6F1ITe1Yw1nPkZPcCBnzsXWWdsC4PDSy826 +YreQQejdIOQpvGQpQsgi3Hia/0PsmBsJUUtaWsJx8cTLc6nloQsCAwEAAaOCAc4w +ggHKMB0GA1UdDgQWBBQWtTIb1Mfz4OaO873SsDrusjkY0TCBowYDVR0jBIGbMIGY +gBQWtTIb1Mfz4OaO873SsDrusjkY0aF9pHsweTEQMA4GA1UEChMHUm9vdCBDQTEe +MBwGA1UECxMVaHR0cDovL3d3dy5jYWNlcnQub3JnMSIwIAYDVQQDExlDQSBDZXJ0 +IFNpZ25pbmcgQXV0aG9yaXR5MSEwHwYJKoZIhvcNAQkBFhJzdXBwb3J0QGNhY2Vy +dC5vcmeCAQAwDwYDVR0TAQH/BAUwAwEB/zAyBgNVHR8EKzApMCegJaAjhiFodHRw +czovL3d3dy5jYWNlcnQub3JnL3Jldm9rZS5jcmwwMAYJYIZIAYb4QgEEBCMWIWh0 +dHBzOi8vd3d3LmNhY2VydC5vcmcvcmV2b2tlLmNybDA0BglghkgBhvhCAQgEJxYl +aHR0cDovL3d3dy5jYWNlcnQub3JnL2luZGV4LnBocD9pZD0xMDBWBglghkgBhvhC +AQ0ESRZHVG8gZ2V0IHlvdXIgb3duIGNlcnRpZmljYXRlIGZvciBGUkVFIGhlYWQg +b3ZlciB0byBodHRwOi8vd3d3LmNhY2VydC5vcmcwDQYJKoZIhvcNAQEEBQADggIB +ACjH7pyCArpcgBLKNQodgW+JapnM8mgPf6fhjViVPr3yBsOQWqy1YPaZQwGjiHCc +nWKdpIevZ1gNMDY75q1I08t0AoZxPuIrA2jxNGJARjtT6ij0rPtmlVOKTV39O9lg +18p5aTuxZZKmxoGCXJzN600BiqXfEVWqFcofN8CCmHBh22p8lqOOLlQ+TyGpkO/c +gr/c6EWtTZBzCDyUZbAEmXZ/4rzCahWqlwQ3JNgelE5tDlG+1sSPypZt90Pf6DBl +Jzt7u0NDY8RD97LsaMzhGY4i+5jhe1o+ATc7iwiwovOVThrLm82asduycPAtStvY +sONvRUgzEv/+PDIqVPfE94rwiCPCR/5kenHA0R6mY7AHfqQv0wGP3J8rtsYIqQ+T +SCX8Ev2fQtzzxD72V7DX3WnRBnc0CkvSyqD/HMaMyRa+xMwyN2hzXwj7UfdJUzYF +CpUCTPJ5GhD22Dp1nPMd8aINcGeGG7MW9S/lpOt5hvk9C8JzC6WZrG/8Z7jlLwum +GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk +zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW +omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDtTCCAp2gAwIBAgIRANAeQJAAAEZSAAAAAQAAAAQwDQYJKoZIhvcNAQEF +BQAwgYkxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJEQzETMBEGA1UEBxMKV2Fz +aGluZ3RvbjEXMBUGA1UEChMOQUJBLkVDT00sIElOQy4xGTAXBgNVBAMTEEFC +QS5FQ09NIFJvb3QgQ0ExJDAiBgkqhkiG9w0BCQEWFWFkbWluQGRpZ3NpZ3Ry +dXN0LmNvbTAeFw05OTA3MTIxNzMzNTNaFw0wOTA3MDkxNzMzNTNaMIGJMQsw +CQYDVQQGEwJVUzELMAkGA1UECBMCREMxEzARBgNVBAcTCldhc2hpbmd0b24x +FzAVBgNVBAoTDkFCQS5FQ09NLCBJTkMuMRkwFwYDVQQDExBBQkEuRUNPTSBS +b290IENBMSQwIgYJKoZIhvcNAQkBFhVhZG1pbkBkaWdzaWd0cnVzdC5jb20w +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx0xHgeVVDBwhMywVC +AOINg0Y95JO6tgbTDVm9PsHOQ2cBiiGo77zM0KLMsFWWU4RmBQDaREmA2FQK +pSWGlO1jVv9wbKOhGdJ4vmgqRF4vz8wYXke8OrFGPR7wuSw0X4x8TAgpnUBV +6zx9g9618PeKgw6hTLQ6pbNfWiKX7BmbwQVo/ea3qZGULOR4SCQaJRk665Wc +OQqKz0Ky8BzVX/tr7WhWezkscjiw7pOp03t3POtxA6k4ShZsiSrK2jMTecJV +jO2cu/LLWxD4LmE1xilMKtAqY9FlWbT4zfn0AIS2V0KFnTKo+SpU+/94Qby9 +cSj0u5C8/5Y0BONFnqFGKECBAgMBAAGjFjAUMBIGA1UdEwEB/wQIMAYBAf8C +AQgwDQYJKoZIhvcNAQEFBQADggEBAARvJYbk5pYntNlCwNDJALF/VD6Hsm0k +qS8Kfv2kRLD4VAe9G52dyntQJHsRW0mjpr8SdNWJt7cvmGQlFLdh6X9ggGvT +ZOirvRrWUfrAtF13Gn9kCF55xgVM8XrdTX3O5kh7VNJhkoHWG9YA8A6eKHeg +TYjHInYZw8eeG6Z3ePhfm1bR8PIXrI6dWeYf/le22V7hXZ9F7GFoGUHhsiAm +/lowdiT/QHI8eZ98IkirRs3bs4Ysj78FQdPB4xTjQRcm0HyncUwZ6EoPclgx +fexgeqMiKL0ZJGA/O4dzwGvky663qyVDslUte6sGDnVdNOVdc22esnVApVnJ +TzFxiNmIf1Q= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID5jCCAs6gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMC +VVMxHTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNB +bWVyaWNhIE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIg +Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyOTA2MDAw +MFoXDTM3MTEyMDE1MDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRB +T0wgVGltZSBXYXJuZXIgSW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUg +SW5jLjE3MDUGA1UEAxMuQU9MIFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAJnej8Mlo2k06AX3dLm/WpcZuS+U0pPlLYnKhHw/EEMbjIt8hFj4JHxI +zyr9wBXZGH6EGhfT257XyuTZ16pYUYfw8ItITuLCxFlpMGK2MKKMCxGZYTVt +fu/FsRkGIBKOQuHfD5YQUqjPnF+VFNivO3ULMSAfRC+iYkGzuxgh28pxPIzs +trkNn+9R7017EvILDOGsQI93f7DKeHEMXRZxcKLXwjqFzQ6axOAAsNUl6twr +5JQtOJyJQVdkKGUZHLZEtMgxa44Be3ZZJX8VHIQIfHNlIAqhBC4aMqiaILGc +LCFZ5/vP7nAtCMpjPiybkxlqpMKX/7eGV4iFbJ4VFitNLLMCAwEAAaNjMGEw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUoTYwFsuGkABFgFOxj8jYPXy+ +XxIwHwYDVR0jBBgwFoAUoTYwFsuGkABFgFOxj8jYPXy+XxIwDgYDVR0PAQH/ +BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQCKIBilvrMvtKaEAEAwKfq0FHNM +eUWn9nDg6H5kHgqVfGphwu9OH77/yZkfB2FK4V1Mza3u0FIy2VkyvNp5ctZ7 +CegCgTXTCt8RHcl5oIBN/lrXVtbtDyqvpxh1MwzqwWEFT2qaifKNuZ8u77Bf +WgDrvq2g+EQFZ7zLBO+eZMXpyD8Fv8YvBxzDNnGGyjhmSs3WuEvGbKeXO/oT +LW4jYYehY0KswsuXn2Fozy1MBJ3XJU8KDk2QixhWqJNIV9xvrr2eZ1d3iVCz +vhGbRWeDhhmH05i9CBoWH1iCC+GWaQVLjuyDUTEH1dSf/1l7qG6Fz9NLqUmw +X7A5KGgOc90lmt4S +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF5jCCA86gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMC +VVMxHTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNB +bWVyaWNhIE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIg +Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyOTA2MDAw +MFoXDTM3MDkyODIzNDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRB +T0wgVGltZSBXYXJuZXIgSW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUg +SW5jLjE3MDUGA1UEAxMuQU9MIFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC +ggIBALQ3WggWmRToVbEbJGv8x4vmh6mJ7ouZzU9AhqS2TcnZsdw8TQ2FTBVs +RotSeJ/4I/1n9SQ6aF3Q92RhQVSji6UI0ilbm2BPJoPRYxJWSXakFsKlnUWs +i4SVqBax7J/qJBrvuVdcmiQhLE0OcR+mrF1FdAOYxFSMFkpBd4aVdQxHAWZg +/BXxD+r1FHjHDtdugRxev17nOirYlxcwfACtCJ0zr7iZYYCLqJV+FNwSbKTQ +2O9ASQI2+W6p1h2WVgSysy0WVoaP2SBXgM1nEG2wTPDaRrbqJS5Gr42whTg0 +ixQmgiusrpkLjhTXUr2eacOGAgvqdnUxCc4zGSGFQ+aJLZ8lN2fxI2rSAG2X ++Z/nKcrdH9cG6rjJuQkhn8g/BsXS6RJGAE57COtCPStIbp1n3UsC5ETzkxml +J85per5n0/xQpCyrw2u544BMzwVhSyvcG7mm0tCq9Stz+86QNZ8MUhy/XCFh +EVsVS6kkUfykXPcXnbDS+gfpj1bkGoxoigTTfFrjnqKhynFbotSg5ymFXQNo +Kk/SBtc9+cMDLz9l+WceR0DTYw/j1Y75hauXTLPXJuuWCpTehTacyH+BCQJJ +Kg71ZDIMgtG6aoIbs0t0EfOMd9afv9w3pKdVBC/UMejTRrkDfNoSTllkt1Ex +MVCgyhwn2RAurda9EGYrw7AiShJbAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMB +Af8wHQYDVR0OBBYEFE9pbQN+nZ8HGEO8txBO1b+pxCAoMB8GA1UdIwQYMBaA +FE9pbQN+nZ8HGEO8txBO1b+pxCAoMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG +9w0BAQUFAAOCAgEAO/Ouyuguh4X7ZVnnrREUpVe8WJ8kEle7+z802u6teio0 +cnAxa8cZmIDJgt43d15Ui47y6mdPyXSEkVYJ1eV6moG2gcKtNuTxVBFT8zRF +ASbI5Rq8NEQh3q0l/HYWdyGQgJhXnU7q7C+qPBR7V8F+GBRn7iTGvboVsNIY +vbdVgaxTwOjdaRITQrcCtQVBynlQboIOcXKTRuidDV29rs4prWPVVRaAMCf/ +drr3uNZK49m1+VLQTkCpx+XCMseqdiThawVQ68W/ClTluUI8JPu3B5wwn3la +5uBAUhX0/Kr0VvlEl4ftDmVyXr4m+02kLQgH3thcoNyBM5kYJRF3p+v9WAks +mWsbivNSPxpNSGDxoPYzAlOL7SUJuA0t7Zdz7NeWH45gDtoQmy8YJPamTQr5 +O8t1wswvziRpyQoijlmn94IM19drNZxDAGrElWe6nEXLuA4399xOAU++CrYD +062KRffaJ00psUjf5BHklka9bAI+1lHIlRcBFanyqqryvy9lG2/QuRqT9Y41 +xICHPpQvZuTpqP9BnHAqTyo5GJUefvthATxRCC4oGKQWDzH9OmwjkyB24f0H +hdFbP9IcczLd+rn4jM8Ch3qaluTtT4mNU0OrDhPAARW0eTjb/G49nlG2uBOL +Z8/5fNkiHfZdxRwBL5joeiQYvITX+txyW/fBOmg= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJT +RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4 +dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5h +bCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzEL +MAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1B +ZGRUcnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1 +c3QgRXh0ZXJuYWwgQ0EgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBALf3GjPm8gAELTngTlvtH7xsD821+iO2zt6bETOXpClMfZOfvUq8 +k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfwTz/oMp50 +ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504 +B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDez +eWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5 +aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0WicCAwEAAaOB +3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0PBAQD +AgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6 +xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU +cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdv +cmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJ +KoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl +j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5R +xNKWt9x+Tu5w/Rw56wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjT +K3rMUUKhemPR5ruhxSvCNr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1 +n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHx +REzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49O +hgQ= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJT +RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU +UCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3Qw +HhcNMDAwNTMwMTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJT +RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU +UCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3Qw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwze +xODcEyPNwTXH+9ZOEQpnXvUGW2ulCDtbKRY654eyNAbFvAWlA3yCyykQruGI +gb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6ntGO0/7Gcrjyvd7ZWxbWroulpOj0O +M3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyldI+Yrsj5wAYi56xz36Uu+1Lc +sRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJchPXQhI2U0K7t4WaPW4XY5 +mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC+Mcdoq0Dlyz4zyXG +9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0OBBYEFJWxtPCU +tr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8EBTADAQH/ +MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBlMQsw +CQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk +ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAx +IENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0 +MkhHma6X7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0Ph +iVYrqW9yTkkz43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9 +tTEv2dB8Xfjea4MYeDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL +/bscVjby/rK25Xa71SJlpz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlV +g3sslgf/WSxEo8bl6ancoWOAWiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6 +tkD9xOQ14R0WHNC8K47Wcdk= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJT +RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU +UCBOZXR3b3JrMSAwHgYDVQQDExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAe +Fw0wMDA1MzAxMDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJBgNVBAYTAlNF +MRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQ +IE5ldHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+ +A3S72mnTRqX4jsIMEZBRpS9mVEBV6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c ++OLspoH4IcUkzBEMP9smcnrHAZcHF/nXGCwwfQ56HmIexkvA/X1id9NEHif2 +P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnPdzRGULD4EfL+OHn3Bzn+UZKX +C1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH1lWfl2royBFkuucZKT8R +s3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF62WUaUC6wNW0uLp9 +BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQWBBSBPjfYkrAf +d59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zCB +jgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDELMAkG +A1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRU +cnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3QgUHVibGljIENB +IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmu +G7jD8WS6IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL ++YPoRNWyQSW/iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbj +PGsye/Kf8Lb93/AoGEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bY +GozH7ZxOmuASu7VqTITh4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6 +NVDFSMwGR+gn2HCNX2TmoUQmXiLsks3/QppEIW1cxeMiHV9HEufOX1362Kqx +My3ZdvJOOjMMK7MtkAY= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJT +RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU +UCBOZXR3b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9v +dDAeFw0wMDA1MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYT +AlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3Qg +VFRQIE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBS +b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoek +n0e+EV+vhDTbYjx5eLfpMLXsDBwqxBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKk +IhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G87B4pfYOQnrjfxvM0PC3KP0q6p6z +sLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i2O+tCBGaKZnhqkRFmhJePp1t +UvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8UWfyEk9mHfExUE+uf0S0R ++Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c10cIDMzZbdSZtQvES +a0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0GA1UdDgQWBBQ5 +lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUw +AwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6FrpGkw +ZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL +ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVh +bGlmaWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2Vh +lRO6aQTvhsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxG +GuoYQ992zPlmhpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx9 +5dr6h+sNNVJn0J6XdgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKF +Yqa0p9m9N5xotS1WfbC3P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVA +wRv1cEWw3F369nJad9Jjzc9YiQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQw +dOUeqN48Jzd/g66ed8/wMLH/S5noxqE= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJV +UzEcMBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1l +cmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4X +DTAyMDUyODA2MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkGA1UEBhMCVVMx +HDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJp +Y2EgT25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCa +xlCyfqXfaE0bfA+2l2h9LaaLl+lkhsmj76CGv2BlnEtUiMJIxUo5vxTjWVXl +GbR0yLQFOVwWpeKVBeASrlmLojNoWBym1BW32J/X3HGrfpq/m44zDyL9Hy7n +BzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsWOqMFf6Dch9Wc/HKpoH145Lcx +VR5lu9RhsCFg7RAycsWSJR74kEoYeEfffjA3PlAb2xzTa5qGUwew76wGePiE +mf4hjUyAtgyC9mZweRrTT6PP8c9GsEsPPt2IYriMqQkoO3rHl+Ee5fSfwMCu +JKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAUAK3Zo/Z5 +9m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBBQUA +A4IBAQB8itEfGDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkF +Zu90821fnZmv9ov761KyBZiibyrFVL0lvV+uyIbqRizBs73B6UlwGBaXCBOM +IOAbLjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft3OJvx8Fi8eNy1gTI +dGcL+oiroQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43g +Kd8hdIaC2y+CMMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j +8uB9Gr784N/Xx6dssPmuujz9dLQR6FgNgLzTqIA6me11zEZ7 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJV +UzEcMBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1l +cmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4X +DTAyMDUyODA2MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkGA1UEBhMCVVMx +HDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJp +Y2EgT25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssN +t79Hc9PwVU3dxgz6sWYFas14tNwC206B89enfHG8dWOgXeMHDEjsJcQDIPT/ +DjsS/5uN4cbVG7RtIuOx238hZK+GvFciKtZHgVdEglZTvYYUAQv8f3SkWq7x +uhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2JxhP7JsowtS013wMPgwr38oE +18aO6lhOqKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9BoInLRBYBbV4Bbkv2wxr +kJB+FFk4u5QkE+XRnRTf04JNRvCAOVIyD+OEsnpD8l7eXz8d3eOyG6ChKiMD +bi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0gBe4lL8BPeraunzgWGcX +uVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67Xnfn6KVu +Y8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEqZ8A9 +W6Wa6897GqidFEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZ +o2C7HK2JNDJiuEMhBnIMoVxtRsX6Kc8w3onccVvdtjc+31D1uAclJuW8tf48 +ArO3+L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnjB453cMor9H124Hhn +AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3Op +aaEg5+31IqEjFNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNee +MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypL +M7PmG2tZTiLMubekJcmnxPBUlgtk87FYT15R/LKXeydlwuXK5w0MJXti4/qf +tIe3RUavg6WXSIylvfEWK5t2LHo1YGwRgJfMqZJS5ivmae2p+DYtLHe/YUjR +Ywu5W1LtGLBDQiKmsXeu3mnFzcccobGlHBD7GL4acN3Bkku+KVqdPzW+5X1R ++FXgJXUjhx5c3LqdsKyzadsXg8n33gy8CNyRnqjQ1xU3c6U1uPx+xURABsPr ++CKAXEfOAuMRn0T//ZoyzH1kUQ7rVyZ2OuMeIjzCpjbdGe+n/BLzJsBZMYVM +nNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgOZtMADjMSW7yV5TKQqLPGbIOt +d+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2FAjgQ5ANh1NolNscI +WC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUXOm/9riW99XJZ +ZLF0KjhfGEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPbAZO1XB4Y +3WRayhgoPmMEEf0cjQAPuDffZ4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQlZvqz +2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuPcX/9XhmgD0uRuMRUvAaw +RY8mkaKO/qk= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQG +EwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0 +MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUx +MjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNV +BAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZ +QmFsdGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAKMEuyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+h +Xe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gR +QKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/CG9VwcPCP +wBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1 +pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNT +Px8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkC +AwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1BE3wMBIGA1Ud +EwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUA +A4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkT +I7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx +jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/ +oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67 +G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H +RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYT +AlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNl +cnR1bSBDQTAeFw0wMjA2MTExMDQ2MzlaFw0yNzA2MTExMDQ2MzlaMD4xCzAJ +BgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNV +BAMTCUNlcnR1bSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AM6xwS7TT3zNJc4YPk/EjG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYV +M42sLQnFdvkrOYCJ5JdLkKWoePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/Ox +LjBos8Q82KxujZlakE403Daaj4GIULdtlkIJ89eVgw1BS7Bqa/j8D35in2fE +7SZfECYPCE/wpFcozo+47UX2bu4lXapuOb7kky/ZR6By6/qmW6/KUz/iDsaW +VhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUgAKpoC6EahQGcxEZjgoi2IrHu +/qpGWX7PNSzVttpd90gzFFS269lvzs2I1qsb2pY7HVkCAwEAAaMTMBEwDwYD +VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAuI3O7+cUus/usESS +bLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+GXYkHAQaTOs9qmdvLdTN +/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTgxSvgGrZg +FCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1qCjqT +E5s7FCMTY5w/0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5x +O/fIR/RpbxXyEV6DHpx8Uq79AtoSqFlnGNu8cN2bsWntgM6JQEhqDjXKKWYV +IZQs6GAqm4VKQPNriiTsBhYscw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJH +QjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxm +b3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFB +IENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIz +MTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFu +Y2hlc3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENB +IExpbWl0ZWQxITAfBgNVBAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL5AnfRu4ep2hxxNRUSO +vkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhGC1Pqy0wk +wLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfH +dr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf04 +9vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULi +mAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cmez6KJcfA3Z3m +NWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEKIz6W +8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB +Af8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v +QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwu +Y29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG +9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm +7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHC +v8S5dIa2LX1rzNLzRt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdV +CYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAV +GI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C12yxow+ev+to +51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJH +QjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxm +b3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEkMCIGA1UEAwwbU2Vj +dXJlIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4 +MTIzMTIzNTk1OVowfjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIg +TWFuY2hlc3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2Rv +IENBIExpbWl0ZWQxJDAiBgNVBAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2 +aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMBxM4KK0HDr +c4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPMcm3ye5drswfxdySRXyWP9nQ95IDC ++DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3SHpR7LZQdqnXXs5jLrLxkU0C8 +j6ysNstcrbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996CF23uPJAGysnnlDOXmWC +iIxe004MeuoIkbY2qitC++rCoznl2yY4rYsK7hljxxwk3wN42ubqwUcaCwtG +Cd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3Vp6ea5EQz6YiO/O1R65Nx +Tq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNVHQ4EFgQU +PNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB +/wQFMAMBAf8wgYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2Rv +Y2EuY29tL1NlY3VyZUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDmgN6A1hjNo +dHRwOi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlmaWNhdGVTZXJ2aWNl +cy5jcmwwDQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm +4J4oqF7Tt/Q05qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiF +Gv45jN5bBAS0VPmjZ55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXG +De+X3EyrEeFryzHRbPtIgKvcnDe4IRRLDXE97IMzbtFuMhbsmMcWi1mmNKsF +Vy2T96oTy9IT4rcuO81rUBcJaD61JlfutuC23bkpgHl9j6PwpCikFcSF9CfU +a7/lXORlAnZUtOM3ZiTTGWHIUhDlizeauan5Hb/qmZJhlv8BzaFfDbxxvA6s +Cx1HRR3B7Hzs/Sk= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJH +QjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxm +b3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDElMCMGA1UEAwwcVHJ1 +c3RlZCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEwMDAwMDBaFw0y +ODEyMzEyMzU5NTlaMH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVy +IE1hbmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9k +byBDQSBMaW1pdGVkMSUwIwYDVQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNl +cnZpY2VzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA33FvNlhT +WvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWWfnJSoBVC21ndZHoa0Lh73TkVvFVI +xO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMtTGo87IvDktJTdyR0nAducPy9 +C1t2ul/y/9c3S0pgePfw+spwtOpZqqPOSC+pw7ILfhdyFgymBwwbOM/JYrc/ +oJOlh0Hyt3BAd9i+FHzjqMB6juljatEPmsbS9Is6FARW1O24zG71++IsWL1/ +T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsSivnkBbA7kUlcsutT6vif +R4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0GA1UdDgQW +BBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21v +ZG9jYS5jb20vVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMuY3JsMDqgOKA2 +hjRodHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENlcnRpZmljYXRlU2Vy +dmljZXMuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8Ntw +uleGFTQQuS9/HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdT +mw7pSqBYaWcOrp32pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+C +l5EfKNsYEYwq5GWDVxISjBc/lDb+XbDABHcTuPQV1T84zJQ6VdCsmPW6AF/g +hhmBeC8owH7TzEIK9a5QoNE+xqFx7D+gIIxmOom0jtTYsU0lR+4viMi14QVF +wL4Ucd56/Y57fU0IlqUSc/AtyjcndBInTMu2l+nZrghtWjlA3QVHdWpaIbOj +GM9O9y5Xt5hwXsjEeLBi +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQG +EwJVUzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREw +DwYDVQQLEwhEU1RDQSBFMTAeFw05ODEyMTAxODEwMjNaFw0xODEyMTAxODQw +MjNaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVy +ZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUxMIGdMA0GCSqGSIb3DQEB +AQUAA4GLADCBhwKBgQCgbIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlR +EmlvMVW5SXIACH7TpWJENySZj9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+Lth +zfNHwJmm8fOR6Hh8AMthyUQncWlVSn5JTe2io74CTADKAqjuAQIxZA9SLRN0 +dja1erQtcQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBoBgNVHR8E +YTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwg +U2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTExDTALBgNV +BAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMTAxODEwMjNagQ8yMDE4MTIx +MDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFGp5fpFpRhgTCgJ3 +pVlbYJglDqL4MB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i+DAMBgNV +HRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3 +DQEBBQUAA4GBACIS2Hod3IEGtgllsofIH160L+nEHvI8wbsEkBFKg05+k7lN +QseSJqBcNJo4cvj9axY+IO6CizEqkzaFI4iKPANo08kJD038bKTaKHKTDomA +sH3+gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4RbyhkwS7hp86W0N6 +w4pl +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID2DCCAsACEQDQHkCLAAACfAAAAAIAAAABMA0GCSqGSIb3DQEBBQUAMIGp +MQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBM +YWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENv +LjERMA8GA1UECxMIRFNUQ0EgWDExFjAUBgNVBAMTDURTVCBSb290Q0EgWDEx +ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODEyMDEx +ODE4NTVaFw0wODExMjgxODE4NTVaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UE +CBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0Rp +Z2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgWDEx +FjAUBgNVBAMTDURTVCBSb290Q0EgWDExITAfBgkqhkiG9w0BCQEWEmNhQGRp +Z3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ANLGJrbnpT3BxGjVUG9TxW9JEwm4ryxIjRRqoxdfWvnTLnUv2Chi0ZMv/E3U +q4flCMeZ55I/db3rJbQVwZsZPdJEjdd0IG03Ao9pk1uKxBmd9LIO/BZsubEF +koPRhSxglD5FVaDZqwgh5mDoO3TymVBRaNADLbGAvqPYUrBEzUNKcI5YhZXh +TizWLUFv1oTnyJhEykfbLCSlaSbPa7gnYsP0yXqSI+0TZ4KuRS5F5X5yP4Wd +lGIQ5jyRoa13AOAV7POEgHJ6jm5gl8ckWRA0g1vhpaRptlc1HHhZxtMvOnNn +7pTKBBMFYgZwI7P0fO5F2WQLW0mqpEPOJsREEmy43XkCAwEAATANBgkqhkiG +9w0BAQUFAAOCAQEAojeyP2n714Z5VEkxlTMr89EJFEliYIalsBHiUMIdBlc+ +LegzZL6bqq1fG03UmZWii5rJYnK1aerZWKs17RWiQ9a2vAd5ZWRzfdd5ynvV +WlHG4VMElo04z6MXrDlxawHDi1M8Y+nuecDkvpIyZHqzH5eUYr3qsiAVlfuX +8ngvYzZAOONGDx3drJXK50uQe7FLqdTF65raqtWjlBRGjS0f8zrWkzr2Pnn8 +6Oawde3uPclwx12qgUtGJRzHbBXjlU4PqjI3lAoXJJIThFjSY28r9+ZbYgsT +F7ANUkz+/m9c4pFuHf2kYtdo+o56T9II2pPc8JIRetDccpMMc5NihWjQ9A== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQG +EwJVUzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREw +DwYDVQQLEwhEU1RDQSBFMjAeFw05ODEyMDkxOTE3MjZaFw0xODEyMDkxOTQ3 +MjZaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVy +ZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUyMIGdMA0GCSqGSIb3DQEB +AQUAA4GLADCBhwKBgQC/k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fB +w18DW9Fvrn5C6mYjuGODVvsoLeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87e +ZfCocfdPJmyMvMa1795JJ/9IKn3oTQPMx7JSxhcxEzu1TdvIxPbDDyQq2gyd +55FbgM2UnQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBoBgNVHR8E +YTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwg +U2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTIxDTALBgNV +BAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMDkxOTE3MjZagQ8yMDE4MTIw +OTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFB6CTShlgDzJQW6s +NS5ay97u+DlbMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5WzAMBgNV +HRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3 +DQEBBQUAA4GBAEeNg61i8tuwnkUiBbmi1gMOOHLnnvx75pO2mqWilMg0HZHR +xdf0CiUPPXiBng+xZ8SQTGPdXqfiup/1902lMXucKS1M/mQ+7LZT/uqb7YLb +dHVLB3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1mPnHfxsb1gYgAlih +w6ID +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID2DCCAsACEQDQHkCLAAB3bQAAAAEAAAAEMA0GCSqGSIb3DQEBBQUAMIGp +MQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBM +YWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENv +LjERMA8GA1UECxMIRFNUQ0EgWDIxFjAUBgNVBAMTDURTVCBSb290Q0EgWDIx +ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODExMzAy +MjQ2MTZaFw0wODExMjcyMjQ2MTZaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UE +CBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0Rp +Z2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgWDIx +FjAUBgNVBAMTDURTVCBSb290Q0EgWDIxITAfBgkqhkiG9w0BCQEWEmNhQGRp +Z3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ANx18IzAdZaawGIfJvfE4Zrq4FZzW5nNAUSoCLbVp9oaBBg5kkp4o4HC9Xd6 +ULRw/5qrxsfKboNPQpj7Jgva3G3WqZlVUmfpKAOS3OWwBZoPFflrWXJW8vo5 +/Kpo7g8fEIMv/J36F5bdguPmRX3AS4BEH+0s4IT9kVySVGkl5WJp3OXuAFK9 +MwutdQKFp2RQLcUZGTDAJtvJ0/0uma1ZtQtN1EGuhUhDWdy3qOKi3sOP17ih +YqZoUFLkzzGnlIXan0YyF1bl8utmPRL/Q9uY73fPy4GNNLHGUEom0eQ+QVCv +bK4iNC7Va26Dunm4dmVI2gkpZGMiuftHdoWMhkTLCdsCAwEAATANBgkqhkiG +9w0BAQUFAAOCAQEAtTYOXeFhKFoRZcA/gwN5Tb4opgsHAlKFzfiR0BBstWog +WxyQ2TA8xkieil5k+aFxd+8EJx8H6+Qm93N0yUQYGmbT4EOvkTvRyyzYdFQ6 +HE3K1GjNI3wdEJ5F6fYAbqbNGf9PLCmPV03Ed5K+4EwJ+11EhmYhqLkyolbV +6YyDfFk/xPEL553snr2cGA4+wjl5KLcDDQjLxufZATdQEOzMYRZA1K8xdHv8 +PzGn0EdzMzkbzE5q10mDEQb+64JYMzJM8FasHpwvVpp7wUocpf1VNs78lk30 +sPDst2yC7S8xmUJMqbINuBVd8d+6ybVK1GSYsyapMMj9puyrliGtf8J4tg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEgzCCA+ygAwIBAgIEOJ725DANBgkqhkiG9w0BAQQFADCBtDEUMBIGA1UE +ChMLRW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9HQ0NB +X0NQUyBpbmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsT +HChjKSAyMDAwIEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1 +c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMDAy +MDcxNjE2NDBaFw0yMDAyMDcxNjQ2NDBaMIG0MRQwEgYDVQQKEwtFbnRydXN0 +Lm5ldDFAMD4GA1UECxQ3d3d3LmVudHJ1c3QubmV0L0dDQ0FfQ1BTIGluY29y +cC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDIwMDAg +RW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2xp +ZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQCTdLS25MVL1qFof2LV7PdRV7NySpj10InJrWPNTTVRaoTU +rcloeW+46xHbh65cJFET8VQlhK8pK5/jgOLZy93GRUk0iJBeAZfv6lOm3fzB +3ksqJeTpNfpVBQbliXrqpBFXO/x8PTbNZzVtpKklWb1m9fkn5JVn1j+SgF7y +NH0rhQIDAQABo4IBnjCCAZowEQYJYIZIAYb4QgEBBAQDAgAHMIHdBgNVHR8E +gdUwgdIwgc+ggcyggcmkgcYwgcMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUAw +PgYDVQQLFDd3d3cuZW50cnVzdC5uZXQvR0NDQV9DUFMgaW5jb3JwLiBieSBy +ZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMjAwMCBFbnRydXN0 +Lm5ldCBMaW1pdGVkMTMwMQYDVQQDEypFbnRydXN0Lm5ldCBDbGllbnQgQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQw +IoAPMjAwMDAyMDcxNjE2NDBagQ8yMDIwMDIwNzE2NDY0MFowCwYDVR0PBAQD +AgEGMB8GA1UdIwQYMBaAFISLdP3FjcD/J20gN0V8/i3OutN9MB0GA1UdDgQW +BBSEi3T9xY3A/ydtIDdFfP4tzrrTfTAMBgNVHRMEBTADAQH/MB0GCSqGSIb2 +fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQQFAAOBgQBObzWA +O9GK9Q6nIMstZVXQkvTnhLUGJoMShAusO7JE7r3PQNsgDrpuFOow4DtifH+L +a3xKp9U1PL6oXOpLu5OOgGarDyn9TS2/GpsKkMWr2tGzhtQvJFJcem3G8v7l +TRowjJDyutdKPkN+1MhQGof4T4HHdguEOnKdzmVml64mXg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIElTCCA/6gAwIBAgIEOJsRPDANBgkqhkiG9w0BAQQFADCBujEUMBIGA1UE +ChMLRW50cnVzdC5uZXQxPzA9BgNVBAsUNnd3dy5lbnRydXN0Lm5ldC9TU0xf +Q1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc +KGMpIDIwMDAgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVz +dC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe +Fw0wMDAyMDQxNzIwMDBaFw0yMDAyMDQxNzUwMDBaMIG6MRQwEgYDVQQKEwtF +bnRydXN0Lm5ldDE/MD0GA1UECxQ2d3d3LmVudHJ1c3QubmV0L1NTTF9DUFMg +aW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykg +MjAwMCBFbnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5l +dCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0G +CSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHwV9OcfHO8GCGD9JYf9Mzly0XonUw +tZZkJi9ow0SrqHXmAGc0V55lxyKbc+bT3QgON1WqJUaBbL3+qPZ1V1eMkGxK +wz6LS0MKyRFWmponIpnPVZ5h2QLifLZ8OAfc439PmrkDQYC2dWcTC5/oVzbI +XQA23mYU2m52H083jIITiQIDAQABo4IBpDCCAaAwEQYJYIZIAYb4QgEBBAQD +AgAHMIHjBgNVHR8EgdswgdgwgdWggdKggc+kgcwwgckxFDASBgNVBAoTC0Vu +dHJ1c3QubmV0MT8wPQYDVQQLFDZ3d3cuZW50cnVzdC5uZXQvU1NMX0NQUyBp +bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAy +MDAwIEVudHJ1c3QubmV0IExpbWl0ZWQxOjA4BgNVBAMTMUVudHJ1c3QubmV0 +IFNlY3VyZSBTZXJ2ZXIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxDTALBgNV +BAMTBENSTDEwKwYDVR0QBCQwIoAPMjAwMDAyMDQxNzIwMDBagQ8yMDIwMDIw +NDE3NTAwMFowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFMtswGvjuz7L/CKc +/vuLkpyw8m4iMB0GA1UdDgQWBBTLbMBr47s+y/winP77i5KcsPJuIjAMBgNV +HRMEBTADAQH/MB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkq +hkiG9w0BAQQFAAOBgQBi24GRzsiad0Iv7L0no1MPUBvqTpLwqa+poLpIYcvv +yQbvH9X07t9WLebKahlzqlO+krNQAraFJnJj2HVQYnUUt7NQGj/KEQALhUVp +bbalrlHhStyCP2yMNLJ3a9kC9n8O6mUE8c1UyrrJzOCE98g+EZfTYAkYvAX/ +bIkz8OwVDw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UE +ChMLRW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNf +MjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsT +HChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1 +c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEy +MjQxNzUwNTFaFw0xOTEyMjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0 +Lm5ldDFAMD4GA1UECxQ3d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29y +cC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkg +RW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4 +QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/EC +DNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuXMlBvPci6Zgzj +/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzWnLLP +KQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZd +enoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH +4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB +0RGAvtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJ +FrlwMB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0B +AQUFAAOCAQEAWUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFh +fGPjK50xA3B20qMooPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVU +KcgF7bISKo30Axv/55IQh7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaoho +wXkCIryqptau37AUX7iH0N18f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2 ++z7pnIkPFc4YsIV4IU9rTw76NmfNB/L/CNDi3tm/Kq+4h4YhPATKt5Rof888 +6ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVyvUxFnmG6v4SBkgPR0ml8xQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIE7TCCBFagAwIBAgIEOAOR7jANBgkqhkiG9w0BAQQFADCByTELMAkGA1UE +BhMCVVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUgwRgYDVQQLFD93d3cuZW50 +cnVzdC5uZXQvQ2xpZW50X0NBX0luZm8vQ1BTIGluY29ycC4gYnkgcmVmLiBs +aW1pdHMgbGlhYi4xJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExp +bWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eTAeFw05OTEwMTIxOTI0MzBaFw0xOTEwMTIxOTU0MzBa +MIHJMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxSDBGBgNV +BAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0FfSW5mby9DUFMgaW5jb3Jw +LiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UECxMcKGMpIDE5OTkgRW50 +cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2xpZW50 +IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GL +ADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/Bo6oT9n3V5z8GKUZSv +x1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux5zDeg7K6PvHV +iTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zmAqTmT173 +iwIBA6OCAeAwggHcMBEGCWCGSAGG+EIBAQQEAwIABzCCASIGA1UdHwSCARkw +ggEVMIHkoIHhoIHepIHbMIHYMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50 +cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0Ff +SW5mby9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UE +CxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50 +cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYD +VQQDEwRDUkwxMCygKqAohiZodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9D +bGllbnQxLmNybDArBgNVHRAEJDAigA8xOTk5MTAxMjE5MjQzMFqBDzIwMTkx +MDEyMTkyNDMwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUxPucKXuXzUyW +/O5bs8qZdIuV6kwwHQYDVR0OBBYEFMT7nCl7l81MlvzuW7PKmXSLlepMMAwG +A1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI +hvcNAQEEBQADgYEAP66K8ddmAwWePvrqHEa7pFuPeJoSSJn59DXeDDYHAmsQ +OokUgZwxpnyyQbJq5wcBoUv5nyU7lsqZwz6hURzzwy5E97BnRqqS5TvaHBkU +ODDV4qIxJS7x7EU47fgGWANzYrAQMY9Av2TgXD7FTx/aEkP/TOYGJqibGapE +PHayXOw= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UE +BhMCVVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50 +cnVzdC5uZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl +MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UE +AxMxRW50cnVzdC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1 +dGhvcml0eTAeFw05OTA1MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQsw +CQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3 +dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlh +Yi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVkMTow +OAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp +b24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDNKIM0 +VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/I0dNxScZgSYMVHIN +iC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3wkrYKZImZNHk +mGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OCAdcwggHT +MBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHboIHY +pIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5 +BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChs +aW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBM +aW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNo +dHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAi +gA8xOTk5MDUyNTE2MDk0MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMC +AQYwHwYDVR0jBBgwFoAU8BdiE1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYE +FPAXYhNVPbP/CgBr+1CEl/PtYtAaMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9 +B0EABAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEFBQADgYEAkNwwAvpkdMKn +CqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN95K+8cPV1ZVqBLssziY2Zcgx +xufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd2cNgQ4xYDiKWL2KjLB+6 +rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQG +EwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1 +cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4 +MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgx +LTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0 +eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2R +FGiYCh7+2gRvE4RiIcPRfM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO +/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuv +K9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAGA1UdHwRp +MGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEt +MCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 +MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjAL +BgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gjIBBPM5iQn9Qw +HQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMBAf8w +GgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GB +AFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y +7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2u +FHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJV +UzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1 +aWZheCBTZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0 +MDAwMFoXDTIwMDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoT +E0VxdWlmYXggU2VjdXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJl +IEdsb2JhbCBlQnVzaW5lc3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw +gYkCgYEAuucXkAJlsTRVPEnCUdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQy +td4zjTov2/KaelpzmKNc6fuKcxtc58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORR +OhI8bIpaVIRw28HFkM9yRcuoWcDNM50/o5brhTMhHD4ePmBudpxnhcXIw2EC +AwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAHMA8GA1UdEwEB/wQFMAMBAf8w +HwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1draGwwHQYDVR0OBBYEFL6o +oHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUAA4GBADDiAVGqx+pf +2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkAZ70Br83gcfxa +z2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv8qIYNMR1 +pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJV +UzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1 +aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcN +MjAwNjIxMDQwMDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZh +eCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2lu +ZXNzIENBLTEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fe +k6lfWg0XTzQaDJj0ItlZ1MRoRvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5 +/VGcqiTZ9J2DKocKIdMSODRsjQBuWqDZQu4aIZX5UkxVWsUPOE9G+m34LjXW +HXzr4vCwdYDIqROsvojvOm6rXyo4YgKwEnv+j6YDAgMBAAGjZjBkMBEGCWCG +SAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEp4 +MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRKeDJSEdtZFjZe38EUNkBq +R3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZMzfmpTMANmvPMZWnm +JXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+WB5Hh1Q+WKG1 +tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN/Bf+KpYr +tWKmpj29f5JZzVoqgrI3eQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQG +EwJVUzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlm +YXggU2VjdXJlIGVCdXNpbmVzcyBDQS0yMB4XDTk5MDYyMzEyMTQ0NVoXDTE5 +MDYyMzEyMTQ0NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkVxdWlmYXgg +U2VjdXJlMSYwJAYDVQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0Et +MjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF +7Y6yEb3+6+e0dMKP/wXn2Z0GvxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKD +pkWNYmi7hRsgcDKqQM2mll/EcTc/BPO3QSQ5BxoeLmFYoBIL5aXfxavqN3HM +HMg3OrmXUqesxWoklE6ce8/AatbfIb0CAwEAAaOCAQkwggEFMHAGA1UdHwRp +MGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORXF1aWZheCBT +ZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJlIGVCdXNpbmVzcyBDQS0y +MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTkwNjIzMTIxNDQ1WjAL +BgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9euSBIplBqy/3YIHqngnYw +HQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQFMAMBAf8w +GgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GB +AAyGgq3oThr1jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy +0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkt +y3D1E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUmV+GRMOrN +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgw +FgYDVQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRy +dXN0IFNvbHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3Qg +R2xvYmFsIFJvb3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1 +MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYD +VQQLEx5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMT +GkdURSBDeWJlclRydXN0IEdsb2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4usJTQGz0O9pTAipTHBsiQl8i4 +ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcqlHHK6XALn +ZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8F +LztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3rGwnpXtlR22ciYaQqPEh3 +46B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l93PR2VX2bY1QY6fDq +81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0PlZPvy5TYnh+d +XIVtx6quTx8itc2VrbqnzPmrC3p/ +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIB+jCCAWMCAgGjMA0GCSqGSIb3DQEBBAUAMEUxCzAJBgNVBAYTAlVTMRgw +FgYDVQQKEw9HVEUgQ29ycG9yYXRpb24xHDAaBgNVBAMTE0dURSBDeWJlclRy +dXN0IFJvb3QwHhcNOTYwMjIzMjMwMTAwWhcNMDYwMjIzMjM1OTAwWjBFMQsw +CQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMRwwGgYDVQQD +ExNHVEUgQ3liZXJUcnVzdCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB +iQKBgQC45k+625h8cXyvRLfTD0bZZOWTwUKOx7pJjTUteueLveUFMVnGsS8K +DPufpz+iCWaEVh43KRuH6X4MypqfpX/1FZSj1aJGgthoTNE3FQZor734sLPw +KfWVWgkWYXcKIiXUT0Wqx73llt/51KiOQswkwB6RJ0q1bQaAYznEol44AwID +AQABMA0GCSqGSIb3DQEBBAUAA4GBABKzdcZfHeFhVYAA1IFLezEPI2PnPfMD ++fQ2qLvZ46WXTeorKeDWanOB5sCJo9Px4KWlIjeaY8JIILTbcuPI9tl8vrGv +U9oUtCG41tWW4/5ODFlitppK+ULdjG+BqXH/9ApybW1EDp3zdHSo1TRJ6V6e +6bR64eVaH4QwnNOfpSXY +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYT +AlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVz +dCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBC +MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UE +AxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEH +CIjaWC9mOSm9BXiLnTjoBbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlC +GDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet8u5fa9IAjbkU+BQVNdnARqN7 +csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+VcT4wt/lAj +Nvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdRe +JivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQAB +o1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9 +qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1luMrMTjANBgkq +hkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Qzxpe +R+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWV +Yrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF +PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot +2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeX +xx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm +Mw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILAgAAAAAA1ni3lAUwDQYJKoZIhvcNAQEEBQAwVzEL +MAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNV +BAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05 +ODA5MDExMjAwMDBaFw0xNDAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkw +FwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRsw +GQYDVQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQDaDuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR +4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc +71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4 +bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgK +OOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMW +ea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DP +AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIABjAdBgNVHQ4EFgQUYHtmGkUNl8qJ +UC99BM00qP/8/UswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOC +AQEArqqf/LfSyx9fOSkoGJ40yWxPbxrwZKJwSk8ThptgKJ7ogUmYfQq75bCd +PTbbjwVR/wkxKh/diXeeDy5slQTthsu0AD+EAk2AaioteAuubyuig0SDH81Q +gkwkr733pbTIWg/050deSY43lv6aiAU62cDbKYfmGZZHpzqmjIs8d/5GY6dT +2iHRrH5Jokvmw2dZL7OKDrssvamqQnw1wdh/1acxOk5jQzmvCLBhNIzTmKlD +NPYPhyk7ncJWWJh3w/cbrPad+D6qp1RF8PX51TFl/mtYnHGzHtdS6jIX/EBg +Hcl5JLL2bP2oZg6C3ZjL2sJETy6ge/L3ayx2EYRGinij4w== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIH6jCCB1OgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARIxCzAJBgNVBAYT +AkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEu +MCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5s +LjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1 +MjEuMCwGA1UECxMlSVBTIENBIENMQVNFMSBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eTEuMCwGA1UEAxMlSVBTIENBIENMQVNFMSBDZXJ0aWZpY2F0aW9uIEF1 +dGhvcml0eTEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwuaXBzLmVzMB4XDTAx +MTIyOTAwNTkzOFoXDTI1MTIyNzAwNTkzOFowggESMQswCQYDVQQGEwJFUzES +MBAGA1UECBMJQmFyY2Vsb25hMRIwEAYDVQQHEwlCYXJjZWxvbmExLjAsBgNV +BAoTJUlQUyBJbnRlcm5ldCBwdWJsaXNoaW5nIFNlcnZpY2VzIHMubC4xKzAp +BgNVBAoUImlwc0BtYWlsLmlwcy5lcyBDLkkuRi4gIEItNjA5Mjk0NTIxLjAs +BgNVBAsTJUlQUyBDQSBDTEFTRTEgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx +LjAsBgNVBAMTJUlQUyBDQSBDTEFTRTEgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkxHjAcBgkqhkiG9w0BCQEWD2lwc0BtYWlsLmlwcy5lczCBnzANBgkqhkiG +9w0BAQEFAAOBjQAwgYkCgYEA4FEnpwvdr9G5Q1uCN0VWcu+atsIS7ywSzHb5 +BlmvXSHU0lq4oNTzav3KaY1mSPd05u42veiWkXWmcSjK5yISMmmwPh5r9FBS +YmL9Yzt9fuzuOOpi9GyocY3h6YvJP8a1zZRCb92CRTzo3wno7wpVqVZHYUxJ +ZHMQKD/Kvwn/xi8CAwEAAaOCBEowggRGMB0GA1UdDgQWBBTrsxl588GlHKzc +uh9morKbadB4CDCCAUQGA1UdIwSCATswggE3gBTrsxl588GlHKzcuh9morKb +adB4CKGCARqkggEWMIIBEjELMAkGA1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNl +bG9uYTESMBAGA1UEBxMJQmFyY2Vsb25hMS4wLAYDVQQKEyVJUFMgSW50ZXJu +ZXQgcHVibGlzaGluZyBTZXJ2aWNlcyBzLmwuMSswKQYDVQQKFCJpcHNAbWFp +bC5pcHMuZXMgQy5JLkYuICBCLTYwOTI5NDUyMS4wLAYDVQQLEyVJUFMgQ0Eg +Q0xBU0UxIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVJUFMg +Q0EgQ0xBU0UxIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcN +AQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYDVR0TBAUwAwEB/zAMBgNVHQ8E +BQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUH +AwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIB +FgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhCAQEEBAMCAAcw +GgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGBD2lwc0Bt +YWlsLmlwcy5lczBBBglghkgBhvhCAQ0ENBYyQ0xBU0UxIENBIENlcnRpZmlj +YXRlIGlzc3VlZCBieSBodHRwOi8vd3d3Lmlwcy5lcy8wKQYJYIZIAYb4QgEC +BBwWGmh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvMDoGCWCGSAGG+EIBBAQt +FitodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJDTEFTRTEuY3Js +MD8GCWCGSAGG+EIBAwQyFjBodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL3Jl +dm9jYXRpb25DTEFTRTEuaHRtbD8wPAYJYIZIAYb4QgEHBC8WLWh0dHA6Ly93 +d3cuaXBzLmVzL2lwczIwMDIvcmVuZXdhbENMQVNFMS5odG1sPzA6BglghkgB +hvhCAQgELRYraHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9wb2xpY3lDTEFT +RTEuaHRtbDBzBgNVHR8EbDBqMDGgL6AthitodHRwOi8vd3d3Lmlwcy5lcy9p +cHMyMDAyL2lwczIwMDJDTEFTRTEuY3JsMDWgM6Axhi9odHRwOi8vd3d3YmFj +ay5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0xBU0UxLmNybDAvBggrBgEFBQcB +AQQjMCEwHwYIKwYBBQUHMAGGE2h0dHA6Ly9vY3NwLmlwcy5lcy8wDQYJKoZI +hvcNAQEFBQADgYEAK9Dr/drIyllq2tPMMi7JVBuKYn4VLenZMdMu9Ccj/1ur +xUq2ckCuU3T0vAW0xtnIyXf7t/k0f3gA+Nak5FI/LEpjV4F1Wo7ojPsCwJTG +Kbqz3Bzosq/SLmJbGqmODszFV0VRFOlOHIilkfSj945RyKm+hjM+5i9Ibq9U +kE6tsSU= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIH6jCCB1OgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARIxCzAJBgNVBAYT +AkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEu +MCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5s +LjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1 +MjEuMCwGA1UECxMlSVBTIENBIENMQVNFMyBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eTEuMCwGA1UEAxMlSVBTIENBIENMQVNFMyBDZXJ0aWZpY2F0aW9uIEF1 +dGhvcml0eTEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwuaXBzLmVzMB4XDTAx +MTIyOTAxMDE0NFoXDTI1MTIyNzAxMDE0NFowggESMQswCQYDVQQGEwJFUzES +MBAGA1UECBMJQmFyY2Vsb25hMRIwEAYDVQQHEwlCYXJjZWxvbmExLjAsBgNV +BAoTJUlQUyBJbnRlcm5ldCBwdWJsaXNoaW5nIFNlcnZpY2VzIHMubC4xKzAp +BgNVBAoUImlwc0BtYWlsLmlwcy5lcyBDLkkuRi4gIEItNjA5Mjk0NTIxLjAs +BgNVBAsTJUlQUyBDQSBDTEFTRTMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx +LjAsBgNVBAMTJUlQUyBDQSBDTEFTRTMgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkxHjAcBgkqhkiG9w0BCQEWD2lwc0BtYWlsLmlwcy5lczCBnzANBgkqhkiG +9w0BAQEFAAOBjQAwgYkCgYEAqxf+DrDGaBtT8FK+n/ra+osTBLsBjzLZH49N +zjaY2uQARIwo2BNEKqRrThckQpzTiKRBgtYj+4vJhuW5qYIF3PHeH+AMmVWY +8jjsbJ0gA8DvqqPGZARRLXgNo9KoOtYkTOmWehisEyMiG3zoMRGzXwmqMHBx +RiVrSXGAK5UBsh8CAwEAAaOCBEowggRGMB0GA1UdDgQWBBS4k/8uy9wsjqLn +ev42USGjmFsMNDCCAUQGA1UdIwSCATswggE3gBS4k/8uy9wsjqLnev42USGj +mFsMNKGCARqkggEWMIIBEjELMAkGA1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNl +bG9uYTESMBAGA1UEBxMJQmFyY2Vsb25hMS4wLAYDVQQKEyVJUFMgSW50ZXJu +ZXQgcHVibGlzaGluZyBTZXJ2aWNlcyBzLmwuMSswKQYDVQQKFCJpcHNAbWFp +bC5pcHMuZXMgQy5JLkYuICBCLTYwOTI5NDUyMS4wLAYDVQQLEyVJUFMgQ0Eg +Q0xBU0UzIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVJUFMg +Q0EgQ0xBU0UzIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcN +AQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYDVR0TBAUwAwEB/zAMBgNVHQ8E +BQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUH +AwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIB +FgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhCAQEEBAMCAAcw +GgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGBD2lwc0Bt +YWlsLmlwcy5lczBBBglghkgBhvhCAQ0ENBYyQ0xBU0UzIENBIENlcnRpZmlj +YXRlIGlzc3VlZCBieSBodHRwOi8vd3d3Lmlwcy5lcy8wKQYJYIZIAYb4QgEC +BBwWGmh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvMDoGCWCGSAGG+EIBBAQt +FitodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJDTEFTRTMuY3Js +MD8GCWCGSAGG+EIBAwQyFjBodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL3Jl +dm9jYXRpb25DTEFTRTMuaHRtbD8wPAYJYIZIAYb4QgEHBC8WLWh0dHA6Ly93 +d3cuaXBzLmVzL2lwczIwMDIvcmVuZXdhbENMQVNFMy5odG1sPzA6BglghkgB +hvhCAQgELRYraHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9wb2xpY3lDTEFT +RTMuaHRtbDBzBgNVHR8EbDBqMDGgL6AthitodHRwOi8vd3d3Lmlwcy5lcy9p +cHMyMDAyL2lwczIwMDJDTEFTRTMuY3JsMDWgM6Axhi9odHRwOi8vd3d3YmFj +ay5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0xBU0UzLmNybDAvBggrBgEFBQcB +AQQjMCEwHwYIKwYBBQUHMAGGE2h0dHA6Ly9vY3NwLmlwcy5lcy8wDQYJKoZI +hvcNAQEFBQADgYEAF2VcmZVDAyevJuXr0LMXI/dDqsfwfewPxqmurpYPdikc +4gYtfibFPPqhwYHOU7BC0ZdXGhd+pFFhxu7pXu8Fuuu9D6eSb9ijBmgpjnn1 +/7/5p6/ksc7C0YBCJwUENPjDfxZ4IwwHJPJGR607VNCv1TGyr33I6unUVtkO +E7LFRVA= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIH9zCCB2CgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARQxCzAJBgNVBAYT +AkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEu +MCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5s +LjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1 +MjEvMC0GA1UECxMmSVBTIENBIENMQVNFQTEgQ2VydGlmaWNhdGlvbiBBdXRo +b3JpdHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUExIENlcnRpZmljYXRpb24g +QXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMwHhcN +MDExMjI5MDEwNTMyWhcNMjUxMjI3MDEwNTMyWjCCARQxCzAJBgNVBAYTAkVT +MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwG +A1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjEr +MCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEv +MC0GA1UECxMmSVBTIENBIENMQVNFQTEgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUExIENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMwgZ8wDQYJ +KoZIhvcNAQEBBQADgY0AMIGJAoGBALsw19zQVL01Tp/FTILq0VA8R5j8m2md +d81u4D/u6zJfX5/S0HnllXNEITLgCtud186Nq1KLK3jgm1t99P1tCeWu4Wwd +ByOgF9H5fahGRpEiqLJpxq339fWUoTCUvQDMRH/uxJ7JweaPCjbB/SQ9AaD1 +e+J8eGZDi09Z8pvZ+kmzAgMBAAGjggRTMIIETzAdBgNVHQ4EFgQUZyaW56G/ +2LUDnf473P7yiuYV3TAwggFGBgNVHSMEggE9MIIBOYAUZyaW56G/2LUDnf47 +3P7yiuYV3TChggEcpIIBGDCCARQxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlC +YXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UEChMlSVBTIElu +dGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UEChQiaXBz +QG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEvMC0GA1UECxMmSVBT +IENBIENMQVNFQTEgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxLzAtBgNVBAMT +JklQUyBDQSBDTEFTRUExIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJ +KoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYDVR0TBAUwAwEB/zAM +BgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggrBgEFBQcDAgYI +KwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYB +BAGCNwIBFgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhCAQEE +BAMCAAcwGgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGB +D2lwc0BtYWlsLmlwcy5lczBCBglghkgBhvhCAQ0ENRYzQ0xBU0VBMSBDQSBD +ZXJ0aWZpY2F0ZSBpc3N1ZWQgYnkgaHR0cDovL3d3dy5pcHMuZXMvMCkGCWCG +SAGG+EIBAgQcFhpodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyLzA7BglghkgB +hvhCAQQELhYsaHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0xB +U0VBMS5jcmwwQAYJYIZIAYb4QgEDBDMWMWh0dHA6Ly93d3cuaXBzLmVzL2lw +czIwMDIvcmV2b2NhdGlvbkNMQVNFQTEuaHRtbD8wPQYJYIZIAYb4QgEHBDAW +Lmh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcmVuZXdhbENMQVNFQTEuaHRt +bD8wOwYJYIZIAYb4QgEIBC4WLGh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIv +cG9saWN5Q0xBU0VBMS5odG1sMHUGA1UdHwRuMGwwMqAwoC6GLGh0dHA6Ly93 +d3cuaXBzLmVzL2lwczIwMDIvaXBzMjAwMkNMQVNFQTEuY3JsMDagNKAyhjBo +dHRwOi8vd3d3YmFjay5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0xBU0VBMS5j +cmwwLwYIKwYBBQUHAQEEIzAhMB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5p +cHMuZXMvMA0GCSqGSIb3DQEBBQUAA4GBAH66iqyAAIQVCtWYUQxkxZwCWINm +yq0eB81+atqAB98DNEock8RLWCA1NnHtogo1EqWmZaeFaQoO42Hu6r4okzPV +7Oi+xNtff6j5YzHIa5biKcJboOeXNp13XjFr/tOn2yrb25aLH2betgPAK7N4 +1lUH5Y85UN4HI3LmvSAUS7SG +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIH9zCCB2CgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARQxCzAJBgNVBAYT +AkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEu +MCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5s +LjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1 +MjEvMC0GA1UECxMmSVBTIENBIENMQVNFQTMgQ2VydGlmaWNhdGlvbiBBdXRo +b3JpdHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUEzIENlcnRpZmljYXRpb24g +QXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMwHhcN +MDExMjI5MDEwNzUwWhcNMjUxMjI3MDEwNzUwWjCCARQxCzAJBgNVBAYTAkVT +MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwG +A1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjEr +MCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEv +MC0GA1UECxMmSVBTIENBIENMQVNFQTMgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUEzIENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMwgZ8wDQYJ +KoZIhvcNAQEBBQADgY0AMIGJAoGBAO6AAPYaZC6tasiDsYun7o/ZttvNG7uG +BiJ2MwwSbUhWYdLcgiViL5/SaTBlA0IjWLxH3GvWdV0XPOH/8lhneaDBgbHU +VqLyjRGZ/fZ98cfEXgIqmuJKtROKAP2Md4bm15T1IHUuDky/dMQ/gT6DtKM4 +Ninn6Cr1jIhBqoCm42zvAgMBAAGjggRTMIIETzAdBgNVHQ4EFgQUHp9XUEe2 +YZM50yz82l09BXW3mQIwggFGBgNVHSMEggE9MIIBOYAUHp9XUEe2YZM50yz8 +2l09BXW3mQKhggEcpIIBGDCCARQxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlC +YXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UEChMlSVBTIElu +dGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UEChQiaXBz +QG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEvMC0GA1UECxMmSVBT +IENBIENMQVNFQTMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxLzAtBgNVBAMT +JklQUyBDQSBDTEFTRUEzIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJ +KoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYDVR0TBAUwAwEB/zAM +BgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggrBgEFBQcDAgYI +KwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYB +BAGCNwIBFgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhCAQEE +BAMCAAcwGgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGB +D2lwc0BtYWlsLmlwcy5lczBCBglghkgBhvhCAQ0ENRYzQ0xBU0VBMyBDQSBD +ZXJ0aWZpY2F0ZSBpc3N1ZWQgYnkgaHR0cDovL3d3dy5pcHMuZXMvMCkGCWCG +SAGG+EIBAgQcFhpodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyLzA7BglghkgB +hvhCAQQELhYsaHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0xB +U0VBMy5jcmwwQAYJYIZIAYb4QgEDBDMWMWh0dHA6Ly93d3cuaXBzLmVzL2lw +czIwMDIvcmV2b2NhdGlvbkNMQVNFQTMuaHRtbD8wPQYJYIZIAYb4QgEHBDAW +Lmh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcmVuZXdhbENMQVNFQTMuaHRt +bD8wOwYJYIZIAYb4QgEIBC4WLGh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIv +cG9saWN5Q0xBU0VBMy5odG1sMHUGA1UdHwRuMGwwMqAwoC6GLGh0dHA6Ly93 +d3cuaXBzLmVzL2lwczIwMDIvaXBzMjAwMkNMQVNFQTMuY3JsMDagNKAyhjBo +dHRwOi8vd3d3YmFjay5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0xBU0VBMy5j +cmwwLwYIKwYBBQUHAQEEIzAhMB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5p +cHMuZXMvMA0GCSqGSIb3DQEBBQUAA4GBAEo9IEca2on0eisxeewBwMwB9dbB +/MjD81ACUZBYKp/nNQlbMAqBACVHr9QPDp5gJqiVp4MI3y2s6Q73nMify5NF +8bpqxmdRSmlPa/59Cy9SKcJQrSRE7SOzSMtEQMEDlQwKeAYSAfWRMS1Jjbs/ +RU4s4OjNtckUFQzjB4ObJnXv +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIH9zCCB2CgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARwxCzAJBgNVBAYT +AkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEu +MCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5s +LjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1 +MjEzMDEGA1UECxMqSVBTIENBIENoYWluZWQgQ0FzIENlcnRpZmljYXRpb24g +QXV0aG9yaXR5MTMwMQYDVQQDEypJUFMgQ0EgQ2hhaW5lZCBDQXMgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkxHjAcBgkqhkiG9w0BCQEWD2lwc0BtYWlsLmlw +cy5lczAeFw0wMTEyMjkwMDUzNThaFw0yNTEyMjcwMDUzNThaMIIBHDELMAkG +A1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNlbG9uYTESMBAGA1UEBxMJQmFyY2Vs +b25hMS4wLAYDVQQKEyVJUFMgSW50ZXJuZXQgcHVibGlzaGluZyBTZXJ2aWNl +cyBzLmwuMSswKQYDVQQKFCJpcHNAbWFpbC5pcHMuZXMgQy5JLkYuICBCLTYw +OTI5NDUyMTMwMQYDVQQLEypJUFMgQ0EgQ2hhaW5lZCBDQXMgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkxMzAxBgNVBAMTKklQUyBDQSBDaGFpbmVkIENBcyBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEeMBwGCSqGSIb3DQEJARYPaXBzQG1h +aWwuaXBzLmVzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcVpJJspQg +vJhPUOtopKdJC7/SMejHT8KGC/po/UNaivNgkjWZOLtNA1IhW/A3mTXhQSCB +hYEFcYGdtJUZqV92NC5jNzVXjrQfQj8VXOF6wV8TGDIxya2+o8eDZh65nAQT +y2nBBt4wBrszo7Uf8I9vzv+W6FS+ZoCua9tBhDaiPQIDAQABo4IEQzCCBD8w +HQYDVR0OBBYEFKGtMbH5PuEXpsirNPxShwkeYlJBMIIBTgYDVR0jBIIBRTCC +AUGAFKGtMbH5PuEXpsirNPxShwkeYlJBoYIBJKSCASAwggEcMQswCQYDVQQG +EwJFUzESMBAGA1UECBMJQmFyY2Vsb25hMRIwEAYDVQQHEwlCYXJjZWxvbmEx +LjAsBgNVBAoTJUlQUyBJbnRlcm5ldCBwdWJsaXNoaW5nIFNlcnZpY2VzIHMu +bC4xKzApBgNVBAoUImlwc0BtYWlsLmlwcy5lcyBDLkkuRi4gIEItNjA5Mjk0 +NTIxMzAxBgNVBAsTKklQUyBDQSBDaGFpbmVkIENBcyBDZXJ0aWZpY2F0aW9u +IEF1dGhvcml0eTEzMDEGA1UEAxMqSVBTIENBIENoYWluZWQgQ0FzIENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5p +cHMuZXOCAQAwDAYDVR0TBAUwAwEB/zAMBgNVHQ8EBQMDB/+AMGsGA1UdJQRk +MGIGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggr +BgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYK +KwYBBAGCNwoDBDARBglghkgBhvhCAQEEBAMCAAcwGgYDVR0RBBMwEYEPaXBz +QG1haWwuaXBzLmVzMBoGA1UdEgQTMBGBD2lwc0BtYWlsLmlwcy5lczBCBglg +hkgBhvhCAQ0ENRYzQ2hhaW5lZCBDQSBDZXJ0aWZpY2F0ZSBpc3N1ZWQgYnkg +aHR0cDovL3d3dy5pcHMuZXMvMCkGCWCGSAGG+EIBAgQcFhpodHRwOi8vd3d3 +Lmlwcy5lcy9pcHMyMDAyLzA3BglghkgBhvhCAQQEKhYoaHR0cDovL3d3dy5p +cHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0FDLmNybDA8BglghkgBhvhCAQMELxYt +aHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9yZXZvY2F0aW9uQ0FDLmh0bWw/ +MDkGCWCGSAGG+EIBBwQsFipodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL3Jl +bmV3YWxDQUMuaHRtbD8wNwYJYIZIAYb4QgEIBCoWKGh0dHA6Ly93d3cuaXBz +LmVzL2lwczIwMDIvcG9saWN5Q0FDLmh0bWwwbQYDVR0fBGYwZDAuoCygKoYo +aHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0FDLmNybDAyoDCg +LoYsaHR0cDovL3d3d2JhY2suaXBzLmVzL2lwczIwMDIvaXBzMjAwMkNBQy5j +cmwwLwYIKwYBBQUHAQEEIzAhMB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5p +cHMuZXMvMA0GCSqGSIb3DQEBBQUAA4GBAERyMJ1WWKJBGyi3leGmGpVfp3hA +K+/blkr8THFj2XOVvQLiogbHvpcqk4A0hgP63Ng9HgfNHnNDJGD1HWHc3Jag +vPsd4+cSACczAsDAK1M92GsDgaPb1pOVIO/Tln4mkImcJpvNb2ar7QMiRDjM +Wb2f2/YHogF/JsRj9SVCXmK9 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICtzCCAiACAQAwDQYJKoZIhvcNAQEEBQAwgaMxCzAJBgNVBAYTAkVTMRIw +EAYDVQQIEwlCQVJDRUxPTkExEjAQBgNVBAcTCUJBUkNFTE9OQTEZMBcGA1UE +ChMQSVBTIFNlZ3VyaWRhZCBDQTEYMBYGA1UECxMPQ2VydGlmaWNhY2lvbmVz +MRcwFQYDVQQDEw5JUFMgU0VSVklET1JFUzEeMBwGCSqGSIb3DQEJARYPaXBz +QG1haWwuaXBzLmVzMB4XDTk4MDEwMTIzMjEwN1oXDTA5MTIyOTIzMjEwN1ow +gaMxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlCQVJDRUxPTkExEjAQBgNVBAcT +CUJBUkNFTE9OQTEZMBcGA1UEChMQSVBTIFNlZ3VyaWRhZCBDQTEYMBYGA1UE +CxMPQ2VydGlmaWNhY2lvbmVzMRcwFQYDVQQDEw5JUFMgU0VSVklET1JFUzEe +MBwGCSqGSIb3DQEJARYPaXBzQG1haWwuaXBzLmVzMIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQCsT1J0nznqjtwlxLyYXZhkJAk8IbPMGbWOlI6H0fg3 +PqHILVikgDVboXVsHUUMH2Fjal5vmwpMwci4YSM1gf/+rHhwLWjhOgeYlQJU +3c0jt4BT18g3RXIGJBK6E2Ehim51KODFDzT9NthFf+G4Nu+z4cYgjui0OLzh +PvYR3oydAQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBACzzw3lYJN7GO9HgQmm4 +7mSzPWIBubOE3yN93ZjPEKn+ANgilgUTB1RXxafey9m4iEL2mdsUdx+2/iU9 +4aI+A6mB0i1sR/WWRowiq8jMDQ6XXotBtDvECgZAHd1G9AHduoIuPD14cJ58 +GNCr+Lh3B0Zx8coLY1xq+XKU1QFPoNtC +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIIODCCB6GgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCAR4xCzAJBgNVBAYT +AkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEu +MCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5s +LjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1 +MjE0MDIGA1UECxMrSVBTIENBIFRpbWVzdGFtcGluZyBDZXJ0aWZpY2F0aW9u +IEF1dGhvcml0eTE0MDIGA1UEAxMrSVBTIENBIFRpbWVzdGFtcGluZyBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eTEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwu +aXBzLmVzMB4XDTAxMTIyOTAxMTAxOFoXDTI1MTIyNzAxMTAxOFowggEeMQsw +CQYDVQQGEwJFUzESMBAGA1UECBMJQmFyY2Vsb25hMRIwEAYDVQQHEwlCYXJj +ZWxvbmExLjAsBgNVBAoTJUlQUyBJbnRlcm5ldCBwdWJsaXNoaW5nIFNlcnZp +Y2VzIHMubC4xKzApBgNVBAoUImlwc0BtYWlsLmlwcy5lcyBDLkkuRi4gIEIt +NjA5Mjk0NTIxNDAyBgNVBAsTK0lQUyBDQSBUaW1lc3RhbXBpbmcgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkxNDAyBgNVBAMTK0lQUyBDQSBUaW1lc3RhbXBp +bmcgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHjAcBgkqhkiG9w0BCQEWD2lw +c0BtYWlsLmlwcy5lczCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvLju +VqWajOY2ycJioGaBjRrVetJznw6EZLqVtJCneK/K/lRhW86yIFcBrkSSQxA4 +Efdo/BdApWgnMjvEp+ZCccWZ73b/K5Uk9UmSGGjKALWkWi9uy9YbLA1UZ2t6 +KaFYq6JaANZbuxjC3/YeE1Z2m6Vo4pjOxgOKNNtMg0GmqaMCAwEAAaOCBIAw +ggR8MB0GA1UdDgQWBBSL0BBQCYHynQnVDmB4AyKiP8jKZjCCAVAGA1UdIwSC +AUcwggFDgBSL0BBQCYHynQnVDmB4AyKiP8jKZqGCASakggEiMIIBHjELMAkG +A1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNlbG9uYTESMBAGA1UEBxMJQmFyY2Vs +b25hMS4wLAYDVQQKEyVJUFMgSW50ZXJuZXQgcHVibGlzaGluZyBTZXJ2aWNl +cyBzLmwuMSswKQYDVQQKFCJpcHNAbWFpbC5pcHMuZXMgQy5JLkYuICBCLTYw +OTI5NDUyMTQwMgYDVQQLEytJUFMgQ0EgVGltZXN0YW1waW5nIENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5MTQwMgYDVQQDEytJUFMgQ0EgVGltZXN0YW1waW5n +IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNA +bWFpbC5pcHMuZXOCAQAwDAYDVR0TBAUwAwEB/zAMBgNVHQ8EBQMDB/+AMGsG +A1UdJQRkMGIGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUF +BwMEBggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGC +NwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhCAQEEBAMCAAcwGgYDVR0RBBMw +EYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGBD2lwc0BtYWlsLmlwcy5l +czBHBglghkgBhvhCAQ0EOhY4VGltZXN0YW1waW5nIENBIENlcnRpZmljYXRl +IGlzc3VlZCBieSBodHRwOi8vd3d3Lmlwcy5lcy8wKQYJYIZIAYb4QgECBBwW +Gmh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvMEAGCWCGSAGG+EIBBAQzFjFo +dHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJUaW1lc3RhbXBpbmcu +Y3JsMEUGCWCGSAGG+EIBAwQ4FjZodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAy +L3Jldm9jYXRpb25UaW1lc3RhbXBpbmcuaHRtbD8wQgYJYIZIAYb4QgEHBDUW +M2h0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcmVuZXdhbFRpbWVzdGFtcGlu +Zy5odG1sPzBABglghkgBhvhCAQgEMxYxaHR0cDovL3d3dy5pcHMuZXMvaXBz +MjAwMi9wb2xpY3lUaW1lc3RhbXBpbmcuaHRtbDB/BgNVHR8EeDB2MDegNaAz +hjFodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJUaW1lc3RhbXBp +bmcuY3JsMDugOaA3hjVodHRwOi8vd3d3YmFjay5pcHMuZXMvaXBzMjAwMi9p +cHMyMDAyVGltZXN0YW1waW5nLmNybDAvBggrBgEFBQcBAQQjMCEwHwYIKwYB +BQUHMAGGE2h0dHA6Ly9vY3NwLmlwcy5lcy8wDQYJKoZIhvcNAQEFBQADgYEA +ZbrBzAAalZHK6Ww6vzoeFAh8+4Pua2JR0zORtWB5fgTYXXk36MNbsMRnLWha +sl8OCvrNPzpFoeo2zyYepxEoxZSPhExTCMWTs/zif/WN87GphV+I3pGW7hdb +rqXqcGV4LCFkAZXOzkw+UPS2Wctjjba9GNSHSl/c7+lW8AoM6HU= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQG +EwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9v +dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMg +Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNa +Fw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9W +YWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24g +QXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1 +lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMukJ0KX0J+D +isPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj18 +2d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Sp +x2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZ +yH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospUxbF6lR1xHkop +igPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4wPQYI +KwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFk +aXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw +ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlh +bmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBw +YXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJs +ZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRp +ZmljYXRpb24gcHJhY3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmlj +YXRlIFBvbGljeS4wIgYIKwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMu +Ym0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYw +gaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJN +MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290 +IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCLMA4GA1UdDwEB/wQEAwIB +BjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lofFIk3Wdv +OXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10 +buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe +/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6 +isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW +xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQ +NiOKSnQ2+Q== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlD +ZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu +Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRp +b24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNv +bS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYy +NjAwMjIzM1oXDTE5MDYyNjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 +IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4x +NTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24g +QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8x +IDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3 +DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+epvzzFlLWLU2f +NUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChM +MFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqYJJgpp0lZpd34 +t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliEZwgs3x/b +e0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJn0Wu +PIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/A +PhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICXDCCAcWgAwIBAgIQCgEBAQAAAnwAAAALAAAAAjANBgkqhkiG9w0BAQUF +ADA6MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0Eg +U2VjdXJpdHkgMTAyNCBWMzAeFw0wMTAyMjIyMTAxNDlaFw0yNjAyMjIyMDAx +NDlaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJT +QSBTZWN1cml0eSAxMDI0IFYzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB +gQDV3f5mCc8kPD6ugU5OisRpgFtZO9+5TUzKtS3DJy08rwBCbbwoppbPf9dY +rIMKo1W1exeQFYRMiu4mmdxY78c4pqqv0I5CyGLXq6yp+0p9v+r+Ek3d/yYt +bzZUaMjShFbuklNhCbM/OZuoyZu9zp9+1BlqFikYvtc6adwlWzMaUQIDAQAB +o2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSME +GDAWgBTEwBykB5T9zU0B1FTapQxf3q4FWjAdBgNVHQ4EFgQUxMAcpAeU/c1N +AdRU2qUMX96uBVowDQYJKoZIhvcNAQEFBQADgYEAPy1q4yZDlX2Jl2X7deRy +HUZXxGFraZ8SmyzVWujAovBDleMf6XbN3Ou8k6BlCsdNT1+nr6JGFLkM88y9 +am63nd4lQtBU/55oc2PcJOsiv6hy8l4A4Q1OOkNumU4/iXgDmMrzVcydro7B +qkWY+o8aoI2II/EVQQ2lRj6RP4vr93E= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUF +ADA6MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0Eg +U2VjdXJpdHkgMjA0OCBWMzAeFw0wMTAyMjIyMDM5MjNaFw0yNjAyMjIyMDM5 +MjNaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJT +QSBTZWN1cml0eSAyMDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAt49VcdKA3XtpeafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37 +RqtBaB4Y6lXIL5F4iSj7Jylg/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E +0S1PRsNO3Ng3OTsor8udGuorryGlwSMiuLgbWhOHV4PR8CDn6E8jQrAApX2J +6elhc5SYcSa8LWrg903w8bYqODGBDSnhAMFRD0xS+ARaqn1y07iHKrtjEAMq +s6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2PcYJk5qjEoAAVZkZR73QpXzD +uvsf9/UP+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpuAWgXIszACwIDAQABo2Mw +YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAW +gBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4EFgQUB8NRMKSq6UWuNST6 +/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYcHnmYv/3V +EhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/Zb5g +EydxiKRz44Rj0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+ +f00/FGj1EVDVwfSQpQgdMWD/YIwjVAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJq +aHVOrSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395nzIlQnQFgCi/vcEk +llgVsRch6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kA +pKnXwiJPZ9d37CAFYd4= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJK +UDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0 +eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMw +OTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1 +c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RD +QTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8 +V6UMbXaKL0u/ZPtM7orw8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpx +xpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uMDPpVmDvY6CKhS3E4eayXkmmz +iX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX5HA49LY6 +tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819 +uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/L +TX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZ +aNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g0dNq +/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94 +nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5 +Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNn +PaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfci +oU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi +FL39vmwLAw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDIDCCAgigAwIBAgIBJDANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJG +STEPMA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MxIENB +MB4XDTAxMDQwNjEwNDkxM1oXDTIxMDQwNjEwNDkxM1owOTELMAkGA1UEBhMC +RkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMSBD +QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALWJHytPZwp5/8Ue ++H887dF+2rDNbS82rDTG29lkFwhjMDMiikzujrsPDUJVyZ0upe/3p4zDq7mX +y47vPxVnqIJyY1MPQYx9EJUkoVqlBvqSV536pQHydekfvFYmUk54GWVYVQNY +wBSujHxVX3BbdyMGNpfzJLWaRpXk3w0LBUXl0fIdgrvGE+D+qnr9aTCU89JF +hfzyMlsy3uhsXR/LpCJ0sICOXZT3BgBLqdReLjVQCfOAl/QMF6452F/NM8Ec +yonCIvdFEu1eEpOdY6uCLrnrQkFEy0oaAIINnvmLVz5MxxftLItyM19yejhW +1ebZrgUaHXVFsculJRwSVzb9IjcCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB +/zARBgNVHQ4ECgQIR+IMi/ZTiFIwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEB +BQUAA4IBAQCLGrLJXWG04bkruVPRsoWdd44W7hE928Jj2VuXZfsSZ9gqXLar +5V7DtxYvyOirHYr9qxp81V9jz9yw3Xe5qObSIjiHBxTZ/75Wtf0HDjxVyhbM +p6Z3N/vbXB9OWQaHowND9Rart4S9Tu+fMTfwRvFAttEMpWT4Y14h21VOTzF2 +nBBhjrZTOqMRvq9tfB69ri3iDGnHhVNoomG6xT60eVR4ngrHAr5i0RGCS2Uv +kVrCqIexVmiUefkl98HVrhq4uz2PqYo4Ffdz0Fpg0YCw8NzVUM1O7pJIae2y +Ix4wzMiUyLb1O4Z/P6Yun/Y+LLWSlj7fLJOK/4GMDw9ZIRlXvVWa +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJG +STEPMA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENB +MB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMC +RkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBD +QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE ++hY3/Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gX +GM2RX/uJ4+q/Tl18GybTdXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQ +TiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMGf+dJQMjFAbJUWmYdPfz56TwK +noG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8PtOFCx4j1 +P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURr +BGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB +/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEB +BQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zilzqsWuasvfDXL +rNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEIcbCd +jdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr4 +50kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6 +Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkeja +nZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQG +EwJOTDEeMBwGA1UEChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQD +Ex1TdGFhdCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQTAeFw0wMjEyMTcwOTIz +NDlaFw0xNTEyMTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4wHAYDVQQKExVT +dGFhdCBkZXIgTmVkZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRl +cmxhbmRlbiBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAmNK1URF6gaYUmHFtvsznExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rF +DBKeNVU+LCeIQGv33N0iYfXCxw719tV2U02PjLwYdjeFnejKScfST5gTCaI+ +Ioicf9byEGW07l8Y1Rfj+MX94p2i71MOhXeiD+EwR+4A5zN9RGcaC1Hoi6Ce +UJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+UtFE5A3+y3qcym7RHjm+0Sq7l +r7HcsBthvJly3uSJt3omXdozSVtSnA71iq3DuD3oBmrC1SoLbHuEvVYFy4Zl +kuxEK7COudxwC0barbxjiDn622r+I/q85Ej0ZytqERAhSQIDAQABo4GRMIGO +MAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRVHSAAMDwwOgYIKwYBBQUH +AgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMvcm9vdC1w +b2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA7Jbg +0zTBLL9s+DANBgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k +/rvuFbQvBgwp8qiSpGEN/KtcCFtREytNwiphyPgJWPwtArI5fZlmgb9uXJVF +IGzmeafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbwMVcoEoJz6TMvplW0 +C5GUR5z6u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3y +nGQI0DvDKcWy7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBp +IzlWYGeQiy52OfsRiJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYV +wSR8MnwDHTuhWEUykw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDXDCCAsWgAwIBAgICA+owDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYT +AkRFMRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYD +VQQKEzFUQyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3 +b3JrcyBHbWJIMSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAyIENB +MSkwJwYJKoZIhvcNAQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAe +Fw05ODAzMDkxMTU5NTlaFw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJE +RTEQMA4GA1UECBMHSGFtYnVyZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UE +ChMxVEMgVHJ1c3RDZW50ZXIgZm9yIFNlY3VyaXR5IGluIERhdGEgTmV0d29y +a3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTEp +MCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVAdHJ1c3RjZW50ZXIuZGUwgZ8w +DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANo46O0yAClxgwENv4wB3NrGrTmk +qYov1YtcaF9QxmL1Zr3KkSLsqh1R1z2zUbKDTl3LSbDwTFXlay3HhQswHJJO +gtTKAu33b77c4OMUuAVT8pr0VotanoWT0bSCVq5Nu6hLVxa8/vhYnvgpjbB7 +zXjJT6yLZwzxnPv8V5tXXE8NAgMBAAGjazBpMA8GA1UdEwEB/wQFMAMBAf8w +DgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3LnRy +dXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G +CSqGSIb3DQEBBAUAA4GBAIRS+yjf/x91AbwBvgRWl2p0QiQxg/lGsQaKic+W +LDO/jLVfenKhhQbOhvgFjuj5Jcrag4wGrOs2bYWRNAQ29ELw+HkuCkhcq8xR +T3h2oNmsGb0q0WkEKJHKNhAngFdb0lz1wlurZIFjdFH0l7/NEij3TWZ/p/Ac +ASZ4smZHcFFk +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDXDCCAsWgAwIBAgICA+swDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYT +AkRFMRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYD +VQQKEzFUQyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3 +b3JrcyBHbWJIMSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAzIENB +MSkwJwYJKoZIhvcNAQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAe +Fw05ODAzMDkxMTU5NTlaFw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJE +RTEQMA4GA1UECBMHSGFtYnVyZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UE +ChMxVEMgVHJ1c3RDZW50ZXIgZm9yIFNlY3VyaXR5IGluIERhdGEgTmV0d29y +a3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTEp +MCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVAdHJ1c3RjZW50ZXIuZGUwgZ8w +DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALa0wTUFLg2N7KBAahwOJ6ZQkmtQ +GwfeLud2zODa/ISoXoxjaitN2U4CdhHBC/KNecoAtvGwDtf7pBc9r6tpepYn +v68zoZoqWarEtTcI8hKlMbZD9TKWcSgoq40oht+77uMMfTDWw1Krj10nnGvA +o+cFa1dJRLNu6mTP0o56UHd3AgMBAAGjazBpMA8GA1UdEwEB/wQFMAMBAf8w +DgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3LnRy +dXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G +CSqGSIb3DQEBBAUAA4GBABY9xs3Bu4VxhUafPiCPUSiZ7C1FIWMjWwS7TJC4 +iJIETb19AaM/9uzO8d7+feXhPrvGq14L3T2WxMup1Pkm5gZOngylerpuw3yC +GdHHsbHD2w2Om0B8NwvxXej9H5CIpQ5ON2QhqE6NtJ/x3kit1VYYUimLRzQS +CdS7kjXvD9s0 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQG +EwJESzEVMBMGA1UEChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50 +ZXJuZXQgUm9vdCBDQTAeFw0wMTA0MDUxNjMzMTdaFw0yMTA0MDUxNzAzMTda +MEMxCzAJBgNVBAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJuZXQxHTAbBgNV +BAsTFFREQyBJbnRlcm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAxLhAvJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4Nr +XceO+YQwzho7+vvOi20jxsNuZp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaq +HF1j4QeGDmUApy6mcca8uYGoOn0a0vnRrEvLznWv3Hv6gXPU/Lq9QYjUdLP5 +Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc14izbSysseLlJ28TQx5yc5IogCSEW +Vmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGNeGlVRGn1ypYcNIUXJXfi9i8n +mHj9eQY6otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcDR0G2l8ktCkEiu7vmpwID +AQABo4IBJTCCASEwEQYJYIZIAYb4QgEBBAQDAgAHMGUGA1UdHwReMFwwWqBY +oFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMMVERDIEludGVybmV0MR0w +GwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxMEQ1JMMTAr +BgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3WjAL +BgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAw +HQYDVR0OBBYEFGxkAcf9hW2syNqeUAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8w +HQYJKoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQBOQ8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540m +gwV5dOy0uaOXwTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKs +LtB9KOy282A4aW8+2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7T +mHnaCB4Mb7j4Fifvwm899qNLPg7kbWzbO0ESm70NRyN/PErQr8Cv9u8btRXE +64PECV90i9kR+8JWsTz4cMo0jUNAE4z9mQNUecYu6oah9jrUCbz0vGbMPVjQ +V0kK7iXiQe4T+Zs4NNEA9X7nlB38aQNiuJkFBT1reBK9sG9l +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFGTCCBAGgAwIBAgIEPki9xDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQG +EwJESzEMMAoGA1UEChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTAeFw0w +MzAyMTEwODM5MzBaFw0zNzAyMTEwOTA5MzBaMDExCzAJBgNVBAYTAkRLMQww +CgYDVQQKEwNUREMxFDASBgNVBAMTC1REQyBPQ0VTIENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEArGL2YSCyz8DGhdfjeebM7fI5kqSXLmSj +hFuHnEz9pPPEXyG9VhDr2y5h7JNp46PMvZnDBfwGuMo2HP6QjklMxFaaL1a8 +z3sM8W9Hpg1DTeLpHTk0zY0s2RKY+ePhwUp8hjjEqcRhiNJerxomTdXkoCJH +hNlktxmW/OwZ5LKXJk5KTMuPJItUGBxIYXvViGjaXbXqzRowwYCDdlCqT9HU +3Tjw7xb04QxQBr/q+3pJoSgrHPb8FTKjdGqPqcNiKXEx5TukYBdedObaE+3p +Hx8b0bJoc8YQNHVGEBDjkAB2QMuLt0MJIf+rTpPGWOmlgtt3xDqZsXKVSQTw +tyv6e1mO3QIDAQABo4ICNzCCAjMwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B +Af8EBAMCAQYwgewGA1UdIASB5DCB4TCB3gYIKoFQgSkBAQEwgdEwLwYIKwYB +BQUHAgEWI2h0dHA6Ly93d3cuY2VydGlmaWthdC5kay9yZXBvc2l0b3J5MIGd +BggrBgEFBQcCAjCBkDAKFgNUREMwAwIBARqBgUNlcnRpZmlrYXRlciBmcmEg +ZGVubmUgQ0EgdWRzdGVkZXMgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEuMS4x +LiBDZXJ0aWZpY2F0ZXMgZnJvbSB0aGlzIENBIGFyZSBpc3N1ZWQgdW5kZXIg +T0lEIDEuMi4yMDguMTY5LjEuMS4xLjARBglghkgBhvhCAQEEBAMCAAcwgYEG +A1UdHwR6MHgwSKBGoESkQjBAMQswCQYDVQQGEwJESzEMMAoGA1UEChMDVERD +MRQwEgYDVQQDEwtUREMgT0NFUyBDQTENMAsGA1UEAxMEQ1JMMTAsoCqgKIYm +aHR0cDovL2NybC5vY2VzLmNlcnRpZmlrYXQuZGsvb2Nlcy5jcmwwKwYDVR0Q +BCQwIoAPMjAwMzAyMTEwODM5MzBagQ8yMDM3MDIxMTA5MDkzMFowHwYDVR0j +BBgwFoAUYLWF7FZkfhIZJ2cdUBVLc647+RIwHQYDVR0OBBYEFGC1hexWZH4S +GSdnHVAVS3OuO/kSMB0GCSqGSIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIEkDAN +BgkqhkiG9w0BAQUFAAOCAQEACromJkbTc6gJ82sLMJn9iuFXehHTuJTXCRBu +o7E4A9G28kNBKWKnctj7fAXmMXAnVBhOinxO5dHKjHiIzxvTkIvmI/gLDjND +fZziChmPyQE+dF10yYscA+UYyAFMP8uXBV2YcaaYb7Z8vTd/vuGTJW1v8Aqt +FxjhA7wHKcitJuj4YfD9IQl+mo6paH1IYnK9AOoBmbgGglGBTvH1tJFUuSN6 +AJqfXY3gPGS5GhKSKseCRHI53OI8xthV9RVOyAUO28bQYqbsFbS1AoLbrIyi +gfCbmTH1ICCoiGEKB5+U/NDXG8wuF/MEJ3Zn61SD/aSQfgY9BKNDLdr8C2Lq +L19iUw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDITCCAoqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMC +WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du +MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm +aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFBl +cnNvbmFsIEJhc2ljIENBMSgwJgYJKoZIhvcNAQkBFhlwZXJzb25hbC1iYXNp +Y0B0aGF3dGUuY29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVow +gcsxCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNV +BAcTCUNhcGUgVG93bjEaMBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAm +BgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24xITAfBgNV +BAMTGFRoYXd0ZSBQZXJzb25hbCBCYXNpYyBDQTEoMCYGCSqGSIb3DQEJARYZ +cGVyc29uYWwtYmFzaWNAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOB +jQAwgYkCgYEAvLyTU23AUE+CFeZIlDWmWr5vQvoPR+53dXLdjUmbllegeNTK +P1GzaQuRdhciB5dqxFGTS+CN7zeVoQxN2jSQHReJl+A1OFdKwPQIcOk8RHtQ +fmGakOMj04gRRif1CwcOu93RfyAKiLlWCy4cgNrx454p7xS9CkT7G1sY0b8j +kyECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOB +gQAt4plrsD16iddZopQBHyvdEktTwq1/qqcAXJFAVyVKOKqEcLnZgA+le1z7 +c8a914phXAPjLSeoF+CEhULcXpvGt7Jtu3Sv5D/Lp7ew4F2+eIMllNLbgQ95 +B21P9DkVWlIBe94y1k049hJcBlDfBVu9FEuh3ym6O0GN92NWod8isQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDLTCCApagAwIBAgIBADANBgkqhkiG9w0BAQQFADCB0TELMAkGA1UEBhMC +WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du +MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm +aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEkMCIGA1UEAxMbVGhhd3RlIFBl +cnNvbmFsIEZyZWVtYWlsIENBMSswKQYJKoZIhvcNAQkBFhxwZXJzb25hbC1m +cmVlbWFpbEB0aGF3dGUuY29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIz +NTk1OVowgdExCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUx +EjAQBgNVBAcTCUNhcGUgVG93bjEaMBgGA1UEChMRVGhhd3RlIENvbnN1bHRp +bmcxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24x +JDAiBgNVBAMTG1RoYXd0ZSBQZXJzb25hbCBGcmVlbWFpbCBDQTErMCkGCSqG +SIb3DQEJARYccGVyc29uYWwtZnJlZW1haWxAdGhhd3RlLmNvbTCBnzANBgkq +hkiG9w0BAQEFAAOBjQAwgYkCgYEA1GnX1LCUZFtx6UfYDFG26nKRsIRefS0N +j3sS34UldSh0OkIsYyeflXtL734Zhx2G6qPduc6WZBrCFG5ErHzmj+hND3Ef +QDimAKOHePb5lIZererAXnbr2RSjXW56fAylS1V/Bhkpf56aJtVquzgkCGqY +x7Hao5iR/Xnb5VrEHLkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq +hkiG9w0BAQQFAAOBgQDH7JJ+Tvj1lqVnYiqk8E0RYNBvjWBYYawmu1I1XAjP +MPuoSpaKH2JCI4wXD/S6ZJwXrEcp352YXtJsYHFcoqzceePnbgBHH7UNKOgC +neSa/RP0ptl8sfjcXyMmCZGAc9AUG95DqYMl8uacLxXK/qarigd1iwzdUYRr +5PjRzneigQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDKTCCApKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBzzELMAkGA1UEBhMC +WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du +MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm +aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEjMCEGA1UEAxMaVGhhd3RlIFBl +cnNvbmFsIFByZW1pdW0gQ0ExKjAoBgkqhkiG9w0BCQEWG3BlcnNvbmFsLXBy +ZW1pdW1AdGhhd3RlLmNvbTAeFw05NjAxMDEwMDAwMDBaFw0yMDEyMzEyMzU5 +NTlaMIHPMQswCQYDVQQGEwJaQTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIw +EAYDVQQHEwlDYXBlIFRvd24xGjAYBgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5n +MSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMSMw +IQYDVQQDExpUaGF3dGUgUGVyc29uYWwgUHJlbWl1bSBDQTEqMCgGCSqGSIb3 +DQEJARYbcGVyc29uYWwtcHJlbWl1bUB0aGF3dGUuY29tMIGfMA0GCSqGSIb3 +DQEBAQUAA4GNADCBiQKBgQDJZtn4B0TPuYwu8KHvE0VsBd/eJxZRNkERbGw7 +7f4QfRKe5ZtCmv5gMcNmt3M6SK5O0DI3lIi1DbbZ8/JE2dWIEt12TfIa/G8j +Hnrx2JhFTgcQ7xZC0EN1bUre4qrJMf8fAHB8Zs8QJQi6+u4A6UYDZicRFTuq +W/KY3TZCstqIdQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 +DQEBBAUAA4GBAGk2ifc0KjNyL2071CKyuG+axTZmDhs8obF1Wub9NdP4qPIH +b4Vnjt4rueIXsDqg8A6iAJrf8xQVbrvIhVqYgPn/vnQdPfP+MCXRNzRn+qVx +eTBhKXLA4CxM+1bkOqhv5TJZUtt1KFBZDPgLGeSs2a+WjS9Q2wfD6h+rM+D1 +KzGJ +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMC +WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du +MR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2Vy +dGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3Rl +IFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNl +cnZlckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1 +OVowgc4xCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQ +BgNVBAcTCUNhcGUgVG93bjEdMBsGA1UEChMUVGhhd3RlIENvbnN1bHRpbmcg +Y2MxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24x +ITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3 +DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0B +AQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhI +NTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQug2SBhRz1JPL +lyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMRuHM/qgeN +9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B +AQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI +hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZ +a4JMpAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcU +Qg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMC +WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du +MR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2Vy +dGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3Rl +IFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0 +ZS5jb20wHhcNOTYwODAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkG +A1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2Fw +ZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UE +CxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQ +VGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRz +QHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I +/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC +6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCXL+eQbcAoQpnX +TEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGjEzARMA8G +A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG7oWD +TSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e +QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdni +TCxZqdq5snUb9kLy78fyGPmJvKP/iiMucEc= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICoTCCAgqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBizELMAkGA1UEBhMC +WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmls +bGUxDzANBgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmlj +YXRpb24xHzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwHhcNOTcw +MTAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBizELMAkGA1UEBhMCWkExFTAT +BgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzAN +BgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24x +HzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwgZ8wDQYJKoZIhvcN +AQEBBQADgY0AMIGJAoGBANYrWHhhRYZT6jR7UZztsOYuGA7+4F+oJ9O0yeB8 +WU4WDnNUYMF/9p8u6TqFJBU820cEY8OexJQaWt9MevPZQx08EHp5JduQ/vBR +5zDWQQD9nyjfeb6Uu522FOMjhdepQeBMpHmwKxqL8vg7ij5FrHGSALSQQZj7 +X+36ty6K+Ig3AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN +AQEEBQADgYEAZ9viwuaHPUCDhjc1fR/OmsMMZiCouqoEiYbC9RAIDb/LogWK +0E02PvTX72nGXuSwlG9KuefeW4i2e9vjJ+V2w/A1wcu1J5szedyQpgCed/r8 +zSeUQhac0xxo7L9c3eWpexAKMnRUEzGLhQOEkbdYATAUOK8oyvyxUBkZCayJ +SdM= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUF +ADCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0 +IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEw +HwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVU +Ti1VU0VSRmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0 +ODM5WhcNMTkwNzA5MTg1NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgT +AlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVT +RVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVz +dC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3QtTmV0d29yayBBcHBsaWNh +dGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCz+5Gh5DZV +hawGNFugmliy+LUPBXeDrjKxdpJo7CNKyXY/45y2N3kDuatpjQclthln5LAb +GHNhSuh+zdMvZOOmfAz6F4CjDUeJT1FxL+78P/m4FoCHiZMlIJpDgmkkdihZ +NaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXuOzr0hAReYFmnjDRy7rh4 +xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1axwiP8vv +/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6gyN7i +gEL66S/ozjIEj3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQD +AgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFPqGydvguul49Uuo1hXf +8NPhahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9jcmwudXNlcnRydXN0 +LmNvbS9VVE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0G +CSqGSIb3DQEBBQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXh +i6r/fWRRzwr/vH3YIWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUq +f9FuVSTiuwL7MT++6LzsQCv4AdRWOOTKRIK1YSAhZ2X28AvnNPilwpyjXEAf +hZOVBt5P1CeptqX8Fs1zMT+4ZSfP1FMa8Kxun08FDAOBp4QpxFq9ZFdyrTvP +NximmMatBrTcCKME1SmklpoSZ0qMYEWd8SOasACcaLWYUNPvji6SZbFIPiG+ +FTAqDbUMo2s/rn9X9R+WfN9v3YIwLGUbQErNaLly7HF27FSOH4UMAWr6pjis +H8SE +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUF +ADCBkzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0 +IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEw +HwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVU +TiAtIERBVEFDb3JwIFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2 +MzBaMIGTMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNh +bHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsx +ITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTEbMBkGA1UEAxMS +VVROIC0gREFUQUNvcnAgU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6E5Qbvfa2gI5lBZMAHryv4g+O +GQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZD0/Ww5y0vpQZY/KmEQrr +U0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK4ESGoE1O1kduSUrL +Z9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykqlXvY8qdOD1R8 +oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulWbfXv33i+ +Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQABo4Gr +MIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT +MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8v +Y3JsLnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUE +IzAhBggrBgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3 +DQEBBQUAA4IBAQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHc +rpY6CiM+iVnJowftGzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuM +FrMOoAyYUJuTqXAJyCyjj98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1 ++XtgHI3zzVAmbQQnmt/VDUVHKWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdO +jtd+D2JzHVImOBwYSf0wdJrE5SIv2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jF +VkwPDPafepE39peC4N1xaf92P2BNPM/3mfnGV/TJVTl4uix5yaaIK/QI +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEojCCA4qgAwIBAgIQRL4Mi1AAJLQR0zYlJWfJiTANBgkqhkiG9w0BAQUF +ADCBrjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0 +IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEw +HwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xNjA0BgNVBAMTLVVU +Ti1VU0VSRmlyc3QtQ2xpZW50IEF1dGhlbnRpY2F0aW9uIGFuZCBFbWFpbDAe +Fw05OTA3MDkxNzI4NTBaFw0xOTA3MDkxNzM2NThaMIGuMQswCQYDVQQGEwJV +UzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD +VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93 +d3cudXNlcnRydXN0LmNvbTE2MDQGA1UEAxMtVVROLVVTRVJGaXJzdC1DbGll +bnQgQXV0aGVudGljYXRpb24gYW5kIEVtYWlsMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAsjmFpPJ9q0E7YkY3rs3BYHW8OWX5ShpHornMSMxq +mNVNNRm5pELlzkniii8efNIxB8dOtINknS4p1aJkxIW9hVE1eaROaJB7HHqk +kqgX8pgV8pPMyaQylbsMTzC9mKALi+VuG6JG+ni8om+rWV6lL8/K2m2qL+us +obNqqrcuZzWLeeEeaYji5kbNoKXqvgvOdjp6Dpvq/NonWz1zHyLmSGHGTPNp +saguG7bUMSAsvIKKjqQOpdeJQ/wWWq8dcdcRWdq6hw2v+vPhwvCkxWeM1tZU +Ot4KpLoDd7NlyP0e03RiqhjKaJMeoYV+9Udly/hNVyh00jT/MLbu9mIwFIws +6wIDAQABo4G5MIG2MAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0G +A1UdDgQWBBSJgmd9xJ0mcABLtFBIfN49rgRufTBYBgNVHR8EUTBPME2gS6BJ +hkdodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLVVTRVJGaXJzdC1DbGll +bnRBdXRoZW50aWNhdGlvbmFuZEVtYWlsLmNybDAdBgNVHSUEFjAUBggrBgEF +BQcDAgYIKwYBBQUHAwQwDQYJKoZIhvcNAQEFBQADggEBALFtYV2mGn98q0rk +MPxTbyUkxsrt4jFcKw7u7mFVbwQ+zznexRtJlOTrIEy05p5QLnLZjfWqo7NK +2lYcYJeA3IKirUq9iiv/Cwm0xtcgBEXkzYABurorbs6q15L+5K/r9CYdFip/ +bDCVNy8zEqx/3cfREYxRmLLQo5HQrfafnoOTHh1CuEava2bwm3/q4wMC5QJR +warVNZ1yQAOJujEdxRBoUp7fooXFXAimeOZTT7Hot9MUnpOmw2TjrH5xzbyf +6QMbzPvprDHBr3wVdAKZw7JHpsIyYdfHb0gkUSeh1YdV8nuPmD0Wnu51tvjQ +jvLzxq4oW6fw8zYX/MMF08oDSlQ= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUF +ADCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0 +IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEw +HwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVU +Ti1VU0VSRmlyc3QtSGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5 +MTgxOTIyWjCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQH +Ew5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3 +b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNV +BAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn0G2f0v9Y8+efK+wNiVSZuTiZ +FvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJM6Rsl7HoxuzBdXmcRl6N +q9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4aMXcMmgF6sTLjKwEH +OG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNdoI6yqqr2jmmI +BsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqIDsjfPe58 +BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9KsyoUhb +AgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWG +M2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3 +YXJlLmNybDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUF +BwMGBggrBgEFBQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0o +XnWO6y1n7k57K9cM//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjA +bPLPSbtNk28GpgoiskliCE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59 +Ojg6FEgSxvunOxqNDYJAB+gECJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4f +Fm517zP4029bHpbj4HR3dHuKom4t3XbWOTCC8KucUvIqx69JXn7HaOWCgchq +J/kniCrVWFCVH/A7HFe7fRQ5YiuayZSSKqMiDP+JJn1fIytH1xUdqWqeUQ0q +UZ6B+dQ7XnASfxAynB67nfhmqA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEZjCCA06gAwIBAgIQRL4Mi1AAJLQR0zYt4LNfGzANBgkqhkiG9w0BAQUF +ADCBlTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0 +IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEw +HwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHTAbBgNVBAMTFFVU +Ti1VU0VSRmlyc3QtT2JqZWN0MB4XDTk5MDcwOTE4MzEyMFoXDTE5MDcwOTE4 +NDAzNlowgZUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMO +U2FsdCBMYWtlIENpdHkxHjAcBgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29y +azEhMB8GA1UECxMYaHR0cDovL3d3dy51c2VydHJ1c3QuY29tMR0wGwYDVQQD +ExRVVE4tVVNFUkZpcnN0LU9iamVjdDCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAM6qgT+jo2F4qjEAVZURnicPHxzfOpuCaDDASmEd8S8O+r55 +96Uj71VRloTN2+O5bj4x2AogZ8f02b+U60cEPgLOKqJdhwQJ9jCdGIqXsqoc +/EHSoTbL+z2RuufZcDX65OeQw5ujm9M89RKZd7G3CeBo5hy485RjiGpq/gt2 +yb70IuRnuasaXnfBhQfdDWy/7gbHd2pBnqcP1/vulBe3/IW+pKvEHDHd17bR +5PDv3xaPslKT16HUiaEHLr/hARJCHhrh2JU022R5KP+6LhHC5ehbkkj7RwvC +bNqtMoNB86XlQXD9ZZBt+vpRxPm9lisZBCzTbafc8H9vg2XiaquHhnUCAwEA +AaOBrzCBrDALBgNVHQ8EBAMCAcYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQU2u1kdBScFDyr3ZmpvVsoTYs8ydgwQgYDVR0fBDswOTA3oDWgM4YxaHR0 +cDovL2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmlyc3QtT2JqZWN0LmNy +bDApBgNVHSUEIjAgBggrBgEFBQcDAwYIKwYBBQUHAwgGCisGAQQBgjcKAwQw +DQYJKoZIhvcNAQEFBQADggEBAAgfUrE3RHjb/c652pWWmKpVZIC1WkDdIaXF +wfNfLEzIR1pp6ujwNTX00CXzyKakh0q9G7FzCL3Uw8q2NbtZhncxzaeAFK4T +7/yxSPlrJSUtUbYsbUXBmMiKVl0+7kNOPmsnjtA6S4ULX9Ptaqd1y9Fahy85 +dRNacrACgZ++8A+EVCBibGnU4U3GDZlDAQ0Slox4nb9QorFEqmrPF3rPbw/U ++CRVX/A0FklmPlBGyWNxODFiuGK581OtbLUrohKqGU8J2l7nk8aOFAj+8DCA +GKCGhU3IfdeLA/5u1fedFqySLKAj5ZyRUh+U3xeUc8OzwcFxBSAAeL0TUh2o +Ps0AH8g= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlD +ZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu +Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRp +b24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNv +bS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYy +NTIyMjM0OFoXDTE5MDYyNTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 +IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4x +NTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24g +QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8x +IDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3 +DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9YLqdUHAZu9OqNSLwxlBfw +8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+TunRf50sQB1ZaG6m ++FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8YTfwggtFzVXSN +dnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0LBwGlN+V +YH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLWI8so +gTLDAHkY7FkXicnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPw +nXS3qT6gpf+2SQMT2iLM7XGCK5nPOrf1LXLI +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlD +ZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu +Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRp +b24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNv +bS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYy +NjAwMTk1NFoXDTE5MDYyNjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 +IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4x +NTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24g +QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8x +IDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3 +DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZUcOBVXc +65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQ +b7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QSv4dk+NoS/zcn +wbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9vUJSZSWI4 +OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTuIYEZ +oDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC +W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICPTCCAaYCEQDNun9W8N/kvFT+IqyzcqpVMA0GCSqGSIb3DQEBAgUAMF8x +CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UE +CxMuQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eTAeFw05NjAxMjkwMDAwMDBaFw0yODA4MDEyMzU5NTlaMF8xCzAJBgNV +BAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xh +c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCB +nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Rm/baNWYS2ZSHH2Z965jeu3 +noaACpEO+jglr0aIguVzqKCbJF0NH8xlbgyw0FaEGIeaBpsQoXPftFg5a27B +9hXVqKg/qhIGjTGsf7A01480Z4gJzRQR4k5FVmkfeAKA2txHkSm7NsljXMXg +1y2He6G3MrB7MLoqLzGq7qNn2tsCAwEAATANBgkqhkiG9w0BAQIFAAOBgQBM +P7iLxmjf7kMzDl3ppssHhE16M/+SG/Q2rdiVIjZoEWx8QszznC7EBz8UsA9P +/5CSdvnivErpj82ggAr3xSnxgiJduLHdgSOjeyUVRjB5FvjqBUuUfx3CHMjj +t/QQQDwTw18fU+hI5Ia0e6E1sHslurjTjqs/OJ0ANACY89FxlA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDAjCCAmsCEEzH6qqYPnHTkxD4PTqJkZIwDQYJKoZIhvcNAQEFBQAwgcEx +CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UE +CxMzQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAt +IEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBU +cnVzdCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVow +gcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoG +A1UECxMzQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1 +dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5j +LiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2ln +biBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCq +0Lq+Fi24g9TK0g+8djHKlNgdk4xWArzZbxpvUjZudVYKVdPfQ4chEWWKfo+9 +Id5rMj8bhDSVBZ1BNeuS65bdqlk/AVNtmU/t5eIqWpDBucSmFc/IReumXY6c +PvBkJHalzasab7bYe1FhbqZ/h8jit+U03EGI6glAvnOSPWvndQIDAQABMA0G +CSqGSIb3DQEBBQUAA4GBAKlPww3HZ74sy9mozS11534Vnjty637rXC0Jh9Zr +bWB85a7FkCMMXErQr7Fd88e2CtvgFZMN3QO8x3aKtd1Pw5sTdbgBwObJW2ul +uIncrKTdcu1OofdPvAbT6shkdHvClUGcZXNY8ZCaPGqxmMnEh7zPRW1F4m4i +P/68DzFc6PLZ +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHK +MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNV +BAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5 +IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBD +BgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3 +MTYyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24s +IEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNV +BAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQg +dXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFBy +aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAN2E1Lm0+afY8wR4nN493GwTFtl63SRR +ZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/EbRrsC+MO8ESlV8dAWB6j +Rx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjVojYJrKsh +JlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjbPG7P +oBMAGrgnoeS+Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP2 +6KbqxzcSXKMpHgLZ2x87tNcPVkeBFQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHh +v2Vrn5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAq2aN17O6x5q25lXQ +BfGfMY1aqtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/N +y9Sn2WCVhDr4wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUf +xJM8/XmPBNQ+T+r3ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFM +DSZl4kSAHsef493oCtrspSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5 +SCJ5ShkPshw+IHTZasO+8ih4E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXV +OBRgmaNL3gaWcSzy27YfpO8/7g== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDnjCCAwegAwIBAgIQK2jUo0aexTsoCas4XX8nIDANBgkqhkiG9w0BAQUF +ADBfMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1 +BgNVBAsTLkNsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwHhcNMDAwODA0MDAwMDAwWhcNMDQwODAzMjM1OTU5WjCBpzEX +MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy +dXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczov +L3d3dy52ZXJpc2lnbi5jb20vUlBBIChjKTAwMS4wLAYDVQQDEyVDbGFzcyAx +IFB1YmxpYyBQcmltYXJ5IE9DU1AgUmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQC57V56Ondfzl86UvzNZPdxtW9qlsZZklWUXS9bLsER +6iaKy6eBPPZaRN56Ey/9WlHZezcmSsAnPwQDalbBgyzhb1upVFAkSsYuekyh +WzdUJCExH6F4GHansXDaItBq/gdiQMb39pt9DAa4S8co5GYjhFHvRreT2IEz +y+U2rMboBQIDAQABo4IBEDCCAQwwIAYDVR0RBBkwF6QVMBMxETAPBgNVBAMT +CE9DU1AgMS0xMDEGA1UdHwQqMCgwJqAkoCKGIGh0dHA6Ly9jcmwudmVyaXNp +Z24uY29tL3BjYTEuY3JsMBMGA1UdJQQMMAoGCCsGAQUFBwMJMEIGCCsGAQUF +BwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJpc2lnbi5j +b20vb2NzcC9zdGF0dXMwRAYDVR0gBD0wOzA5BgtghkgBhvhFAQcBATAqMCgG +CCsGAQUFBwIBFhxodHRwczovL3d3dy52ZXJpc2lnbi5jb20vUlBBMAkGA1Ud +EwQCMAAwCwYDVR0PBAQDAgeAMA0GCSqGSIb3DQEBBQUAA4GBAHCQ3bjkvlMX +fH8C6dX3i5mTMWCNfuZgayTvYKzSzpHegG0JpNO4OOVEynJeDS3Bd5y9LAN4 +KY2kpXeH9fErJq3MB2w6VFoo4AnzTQoEytRYaQuns/XdAaXn3PAfusFdkI2z +6k/BEVmXarIrE7HarZehs7GgIFvKMquNzxPwHynD +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICPDCCAaUCEC0b/EoXjaOR6+f/9YtFvgswDQYJKoZIhvcNAQECBQAwXzEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQL +Ey5DbGFzcyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y +aXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UE +BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz +cyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGf +MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2WoujDWojg4BrzzmH9CETMwZM +JaLtVRKXxaeAufqDwSCg+i8VDXyhYGt+eSz6Bg86rvYbb7HS/y8oUl+DfUvE +erf4Zh+AVPy3wo5ZShRXRtGak75BkQO7FYCTXOvnzAhsPz6zSvz/S2wj1VCC +JkQZjiPDceoZJEcEnnW/yKYAHwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBAIob +K/o5wXTXXtgZZKJYSi034DNHD6zt96rbHuSLBlxgJ8pFUs4W7z8GZOeUaHxg +MxURaa+dYo2jA1Rrpr7l7gUYYAS/QoD90KioHgE796Ncr6Pc5iaAIzy4RHT3 +Cq5Ji2F4zCS/iIqnDupzGUH9TQPwiNHleI2lKk/2lw0Xd8rY +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHB +MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNV +BAsTM0NsYXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRo +b3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIEluYy4g +LSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24g +VHJ1c3QgTmV0d29yazAeFw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTla +MIHBMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6 +BgNVBAsTM0NsYXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIElu +Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNp +Z24gVHJ1c3QgTmV0d29yazCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA +p4gBIXQs5xoD8JjhlzwPIQjxnNuX6Zr8wgQGE75fUsjMHiwSViy4AWkszJkf +rbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRCwiNPStjwDqL7MWzJ5m+Z +Jwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cCAwEAATAN +BgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9jinb3/ +7aHmZuovCfTK1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAX +rXfMSTWqz9iP0b63GJZHc2pUIjRkLbYWm1lbtFFZOrMLFPQS32eg9K0yZF6x +RnInjBJ7xUS0rg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcox +CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UE +CxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkg +VmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMG +A1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcx +NjIzNTk1OVowgcoxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwg +SW5jLjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UE +CxMxKGMpIDE5OTkgVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1 +c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJp +bWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEArwoNwtUs22e5LeWUJ92lvuCwTY+zYVY8 +1nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6tW8UvxDOJxOeBUebMXoT +2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUYwZF7C9UT +AJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9okoqQ +HgiBVrKtaaNS0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjN +qWm6o+sdDZykIKbBoMXRRkwXbdKsZj+WjOCE1Db/IlnF+RFgqF8EffIa9iVC +YQ/ESrg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0JhU8wI1NQ0kdvekh +ktdmnLfexbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf +0xwLRtxyID+u7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydE +p85EXdQbkJgNHkKUsQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377B +MnMiIYtYgXsVkXq642RIsH/7NiXaldDxJBQX3RiAa0YjOVT1jmIJBB2UkKab +5iXiQkWquJCtvgiPqQtCGJTPcjnhsUPgKM+351psE2tJs//jGHyJizNdrDPX +p/naOlXJWBD5qu9ats9LS98q +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDnjCCAwegAwIBAgIQCUYX5h3Y1BygDKBi6HmKpzANBgkqhkiG9w0BAQUF +ADBfMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1 +BgNVBAsTLkNsYXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwHhcNMDAwODAxMDAwMDAwWhcNMDQwNzMxMjM1OTU5WjCBpzEX +MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy +dXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczov +L3d3dy52ZXJpc2lnbi5jb20vUlBBIChjKTAwMS4wLAYDVQQDEyVDbGFzcyAy +IFB1YmxpYyBQcmltYXJ5IE9DU1AgUmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQDQymMxYX9ENHwFfQs9apDLeUt3Cj9LxyPlwGItfpx+ +PoiHkdCs6E1Jh6KWkIrdBKUCP4yb6Yn+YqDiWr3I3bR45qVCkwhnAcAgTddc +9F3as+M3plIaLExlTYqH2aij8UlUuzxcgFFoxvtJ/wtVqxXd+5rBuR10DbKM +RF2J/J/5gwIDAQABo4IBEDCCAQwwIAYDVR0RBBkwF6QVMBMxETAPBgNVBAMT +CE9DU1AgMS0yMDEGA1UdHwQqMCgwJqAkoCKGIGh0dHA6Ly9jcmwudmVyaXNp +Z24uY29tL3BjYTIuY3JsMBMGA1UdJQQMMAoGCCsGAQUFBwMJMEIGCCsGAQUF +BwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJpc2lnbi5j +b20vb2NzcC9zdGF0dXMwRAYDVR0gBD0wOzA5BgtghkgBhvhFAQcBATAqMCgG +CCsGAQUFBwIBFhxodHRwczovL3d3dy52ZXJpc2lnbi5jb20vUlBBMAkGA1Ud +EwQCMAAwCwYDVR0PBAQDAgeAMA0GCSqGSIb3DQEBBQUAA4GBAB99CW4kRnUE +nPMmm+M5bhfvvL2iG9IChIar0ECXLMRDiDcZayKoA3FQnSDcNmAgmnMtc1Vs +WJsswrQ0LHozQsqR2elDr88e4PXEeqs/cmMeqTfhWzuIsxOGgpBXy1f/9Fa+ +It3jl6jhvCJDwt1N2/aBnpIUnjkPE1TegtjAXjSN +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQL +Ey5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y +aXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UE +BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz +cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGf +MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69q +RUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94f56TuZoAqiN91qyFomNFx3In +zPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Olhec9vn2a +/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBALtM +EivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Dolbwdj2wsqFHMc9ikwFPw +TtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNycAA9WjQKZ7aKQRUzk +uxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcEx +CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UE +CxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAt +IEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBU +cnVzdCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVow +gcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoG +A1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1 +dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5j +LiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2ln +biBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDM +XtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4pO0M8RcPO/mn+SXX +wc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg013gfqLptQ5GV +j0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwIDAQABMA0G +CSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSkU01U +bSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i +F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo +1KpYoJ2daZH9 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHK +MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNV +BAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5 +IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBD +BgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3 +MTYyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24s +IEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNV +BAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQg +dXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFBy +aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2 +R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2tKmFZpGcmTNDo +vFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUccLwg +TS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+V +k7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ +Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJ +OxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my +/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f +j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoA +Wii/gt/4uhMdUIaC/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8S +GhJouPtmmRQURVyu565pF4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbb +o27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh +/sVFuq1ruQp6Tk9LhO5L8X3dEQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDojCCAwugAwIBAgIQLpaev7ZibOx76XPM42zBhDANBgkqhkiG9w0BAQUF +ADBfMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1 +BgNVBAsTLkNsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwHhcNMDAwODA0MDAwMDAwWhcNMDQwODAzMjM1OTU5WjCBpzEX +MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy +dXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczov +L3d3dy52ZXJpc2lnbi5jb20vUlBBIChjKTAwMS4wLAYDVQQDEyVDbGFzcyAz +IFB1YmxpYyBQcmltYXJ5IE9DU1AgUmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQDx5AgOg7t140jluNum8Lmr6Txix141W9ACVBHYydFW +uXZLuat65s269gwE1n7WsAplrE454/H3LaMlOe+wi8++2wxdbnD0B81w9zrA +PjUW7XiMQ8/CJi5H1oZ9nPG+1mcMIiWkymXmH3p4KC8/BdsEIb/hRWb+PLeC +7Vq4FhW5VQIDAQABo4IBFDCCARAwIAYDVR0RBBkwF6QVMBMxETAPBgNVBAMT +CE9DU1AgMS0zMDUGA1UdHwQuMCwwKqAooCaGJGh0dHA6Ly9jcmwudmVyaXNp +Z24uY29tL3BjYTMuMS4xLmNybDATBgNVHSUEDDAKBggrBgEFBQcDCTBCBggr +BgEFBQcBAQQ2MDQwMgYIKwYBBQUHMAGmJhYkaHR0cDovL29jc3AudmVyaXNp +Z24uY29tL29jc3Avc3RhdHVzMEQGA1UdIAQ9MDswOQYLYIZIAYb4RQEHAQEw +KjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL1JQQTAJ +BgNVHRMEAjAAMAsGA1UdDwQEAwIHgDANBgkqhkiG9w0BAQUFAAOBgQAC9lNj +wKke8tCLMzCPSJtMsFa0g3FKvtxQ2PW24AvbvXhP6c8JNNopSZ0Bc1qRkYJU +LBMK03cjzzf8Y96n4/a3tWlFKEnDkdyqRxypiJksBSqNjYr6YuJatwAgXTnE +KMLL/J6oia5bPY4S6jKy/OsU1wkVGsDNG9W1FU5B1ZbjTg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDAjCCAmsCEDKIjprS9esTR/h/xCA3JfgwDQYJKoZIhvcNAQEFBQAwgcEx +CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UE +CxMzQ2xhc3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAt +IEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBU +cnVzdCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVow +gcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoG +A1UECxMzQ2xhc3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1 +dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5j +LiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2ln +biBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6 +8OTP+cSuhVS5B1f5j8V/aBH4xBewRNzjMHPVKmIquNDMHO0oW369atyzkSTK +QWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDHqGKB3FtKqsGgtG7rL+VX +xbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHwIDAQABMA0G +CSqGSIb3DQEBBQUAA4GBAIWMEsGnuVAVess+rLhDityq3RS6iYF+ATwjcSGI +L4LcY/oCRaxFWdcqWERbt5+BO5JoPeI3JPV7bI92NZYJqFmduc4jq3TWg/0y +cyfYaT5DdPauxYma51N86Xv2S/PBZYPejYqcPIiNOVn8qj8ijaHBZlCBckzt +ImRPT8qAkbYp +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHK +MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNV +BAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5 +IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBD +BgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3 +MTYyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24s +IEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNV +BAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQg +dXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFBy +aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1GQ9Wzsy1HyDkniYl +S+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ+mGuqPKljYXC +KtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0GbdU6LM8BDc +VHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLmNxdL +MEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY +ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDD +Zq3/ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1Wr +IhVZPMq1CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXtt +mhwwjIDLk5Mqg6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csK +vE+MW8VLADsfKoKmfjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluP +QSjA1egtTaRezarZ7c7c2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kP +mF6Z6PDQpLv1U70qzlmwr25/bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr +9Xgn2uf3ZkPznoM+IKrDNWCRzg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICNDCCAaECEAKtZn5ORf5eV288mBle3cAwDQYJKoZIhvcNAQECBQAwXzEL +MAkGA1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMu +MS4wLAYDVQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9y +aXR5MB4XDTk0MTEwOTAwMDAwMFoXDTEwMDEwNzIzNTk1OVowXzELMAkGA1UE +BhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYD +VQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGb +MA0GCSqGSIb3DQEBAQUAA4GJADCBhQJ+AJLOesGugz5aqomDV6wlAXYMra6O +LDfO6zV4ZFQD5YRAUcm/jwjiioII0haGN1XpsSECrXZogZoFokvJSyVmIlZs +iAeP94FZbYQHZXATcXY+m3dM41CJVphIuR2nKRoTLkoRWZweFdVJVCxzOmmC +sZc5nG1wZ0jl3S3WyB57AgMBAAEwDQYJKoZIhvcNAQECBQADfgBl3X7hsuyw +4jrg7HFGmhkRuNPHoLQDQCYCPgmc4RKz0Vr2N6W3YQO2WxZpO8ZECAyIUwxr +l0nHPjXcbLm7qt9cuzovk2C2qUtN8iD3zV9/ZHuO3ABc1/p3yjkWWW8O6tO1 +g39NTUJWdrTJXwT4OPjr0l91X817/OWOgHz8UA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDnzCCAwygAwIBAgIRAP9F1SddJPuzwjkkU1fhT94wDQYJKoZIhvcNAQEF +BQAwXzELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5 +LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24g +QXV0aG9yaXR5MB4XDTAwMDgwNDAwMDAwMFoXDTA0MDgwMzIzNTk1OVowgZ4x +FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU +cnVzdCBOZXR3b3JrMTswOQYDVQQLEzJUZXJtcyBvZiB1c2UgYXQgaHR0cHM6 +Ly93d3cudmVyaXNpZ24uY29tL1JQQSAoYykwMDElMCMGA1UEAxMcU2VjdXJl +IFNlcnZlciBPQ1NQIFJlc3BvbmRlcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAw +gYkCgYEAuFGZZIUO7rMKaPC/Y3YdU/X8oXiMM+6f9L452psPTUepjyDoS0S9 +zs17kNEw6JDEJXuJKN699pMd/7n/krWpjeSuzOLDB4Nqo3IQASdiIqY1Jjkt +ns9gDPxHpNfQQninHWzQy08VpykKtJVFxLHnWgnXOZXYHTWewr2zXcEMSx8C +AwEAAaOCAR0wggEZMCAGA1UdEQQZMBekFTATMREwDwYDVQQDEwhPQ1NQIDEt +NDA+BgNVHR8ENzA1MDOgMaAvhi1odHRwOi8vY3JsLnZlcmlzaWduLmNvbS9S +U0FTZWN1cmVTZXJ2ZXItcC5jcmwwEwYDVR0lBAwwCgYIKwYBBQUHAwkwQgYI +KwYBBQUHAQEENjA0MDIGCCsGAQUFBzABpiYWJGh0dHA6Ly9vY3NwLnZlcmlz +aWduLmNvbS9vY3NwL3N0YXR1czBEBgNVHSAEPTA7MDkGC2CGSAGG+EUBBwEB +MCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LnZlcmlzaWduLmNvbS9SUEEw +CQYDVR0TBAIwADALBgNVHQ8EBAMCB4AwDQYJKoZIhvcNAQEFBQADfgAAsxBT +ZpxJky4xoAJC0lhXfmah/huKYRhQQCweK0Gl1tv/rAgcWgVtAlwqtpZPR9u+ +TtvOzLqGuBjOsRKRX2P380g+zPFNE+RtCZR4AJLLoyCdBgtqoEMHztEZbI8Y +dZqfFzP9qSa44+LewqjEWop/mNYHBmvMVp6GcM7U7w== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDzTCCAzagAwIBAgIQU2GyYK7bcY6nlLMTM/QHCTANBgkqhkiG9w0BAQUF +ADCBwTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTww +OgYDVQQLEzNDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24g +QXV0aG9yaXR5IC0gRzIxOjA4BgNVBAsTMShjKSAxOTk4IFZlcmlTaWduLCBJ +bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAsTFlZlcmlT +aWduIFRydXN0IE5ldHdvcmswHhcNMDAwOTI2MDAwMDAwWhcNMTAwOTI1MjM1 +OTU5WjCBpTEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl +cmlTaWduIFRydXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBh +dCBodHRwczovL3d3dy52ZXJpc2lnbi5jb20vcnBhIChjKTAwMSwwKgYDVQQD +EyNWZXJpU2lnbiBUaW1lIFN0YW1waW5nIEF1dGhvcml0eSBDQTCBnzANBgkq +hkiG9w0BAQEFAAOBjQAwgYkCgYEA0hmdZ8IAIVlizrQJIkRpivglWtvtDbc2 +fk7gu5Q+kCWHwmFHKdm9VLhjzCx9abQzNvQ3B5rB3UBU/OB4naCTuQk9I1F/ +RMIUdNsKvsvJMDRAmD7Q1yUQgZS9B0+c1lQn3y6ov8uQjI11S7zi6ESHzeZB +CiVu6PQkAsVSD27smHUCAwEAAaOB3zCB3DAPBgNVHRMECDAGAQH/AgEAMEUG +A1UdIAQ+MDwwOgYMYIZIAYb4RQEHFwEDMCowKAYIKwYBBQUHAgEWHGh0dHBz +Oi8vd3d3LnZlcmlzaWduLmNvbS9ycGEwMQYDVR0fBCowKDAmoCSgIoYgaHR0 +cDovL2NybC52ZXJpc2lnbi5jb20vcGNhMy5jcmwwCwYDVR0PBAQDAgEGMEIG +CCsGAQUFBwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJp +c2lnbi5jb20vb2NzcC9zdGF0dXMwDQYJKoZIhvcNAQEFBQADgYEAgnBold+2 +DcIBcBlK0lRWHqzyRUyHuPU163hLBanInTsZIS5wNEqi9YngFXVF5yg3ADQn +Keg3S/LvRJdrF1Eaw1adPBqK9kpGRjeM+sv1ZFo4aC4cw+9wzrhGBha/937n +tag+RaypJXUie28/sJyU58dzq6wf7iWbwBbtt8pb8BQ= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDgDCCAmigAwIBAgICAx4wDQYJKoZIhvcNAQEFBQAwYTELMAkGA1UEBhMC +VVMxDTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25h +bCBTZXJ2aWNlIEFzc29jaWF0aW9uMRIwEAYDVQQDEwlHUCBSb290IDIwHhcN +MDAwODE2MjI1MTAwWhcNMjAwODE1MjM1OTAwWjBhMQswCQYDVQQGEwJVUzEN +MAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNl +cnZpY2UgQXNzb2NpYXRpb24xEjAQBgNVBAMTCUdQIFJvb3QgMjCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBAKkBcLWqxEDwq2omYXkZAPy/mzdZ +DK9vZBv42pWUJGkzEXDK41Z0ohdXZFwgBuHW73G3O/erwWnQSaSxBNf0V2KJ +XLB1LRckaeNCYOTudNargFbYiCjh+20i/SN8RnNPflRzHqgsVVh1t0zzWkWl +Ahr62p3DRcMiXvOL8WAp0sdftAw6UYPvMPjU58fy+pmjIlC++QU3o63tmsPm +7IgbthknGziLgE3sucfFicv8GjLtI/C1AVj59o/ghalMCXI5Etuz9c9OYmTa +xhkVOmMd6RdVoUwiPDQyRvhlV7or7zaMavrZ2UT0qt2E1w0cslSsMoW0ZA3e +QbuxNMYBhjJk1Z8CAwEAAaNCMEAwHQYDVR0OBBYEFJ59SzS/ca3CBfYDdYDO +qU8axCRMMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqG +SIb3DQEBBQUAA4IBAQAhpXYUVfmtJ3CPPPTVbMjMCqujmAuKBiPFyWHbmQdp +NSYx/scuhMKZYdQN6X0uEyt8joW2hcdLzzW2LEc9zikv2G+fiRxkk78IvXbQ +kIqUs38oW26sTTMs7WXcFsziza6kPWKSBpUmv9+55CCmc2rBvveURNZNbyoL +axhNdBA2aGpawWqn3TYpjLgwi08hPwAuVDAHOrqK5MOeyti12HvOdUVmB/Rt +Ldh6yumJivIj2C/LbgA2T/vwLwHMD8AiZfSr4k5hLQOCfZEWtTDVFN5ex5D8 +ofyrEK9ca3CnB+8phuiyJccg/ybdd+95RBTEvd07xQObdyPsoOy7Wjm1zK0G +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUF +ADBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlz +YSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMT +E1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0 +MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UE +CxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAa +BgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh +28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8bRaVK7362 +rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81 +q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtF +Wsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0 +lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaLdXe6YJ2E5/4t +AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOC +AQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcR +zCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKht +cbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGI +xHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBu +YQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/ +hC3euiInlhBx6yLt398znM/jra6O1I7mT1GvFpLgXPYHDw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFajCCBFKgAwIBAgIEPLU9RjANBgkqhkiG9w0BAQUFADBmMRIwEAYDVQQK +EwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEzMDEG +A1UEAxMqYmVUUlVTVGVkIFJvb3QgQ0EtQmFsdGltb3JlIEltcGxlbWVudGF0 +aW9uMB4XDTAyMDQxMTA3Mzg1MVoXDTIyMDQxMTA3Mzg1MVowZjESMBAGA1UE +ChMJYmVUUlVTVGVkMRswGQYDVQQLExJiZVRSVVNUZWQgUm9vdCBDQXMxMzAx +BgNVBAMTKmJlVFJVU1RlZCBSb290IENBLUJhbHRpbW9yZSBJbXBsZW1lbnRh +dGlvbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALx+xDmcjOPW +HIb/ymKt4H8wRXqOGrO4x/nRNv8i805qX4QQ+2aBw5R5MdKR4XeOGCrDFN5R +9U+jK7wYFuK13XneIviCfsuBH/0nLI/6l2Qijvj/YaOcGx6Sj8CoCd8JEey3 +fTGaGuqDIQY8n7pc/5TqarjDa1U0Tz0yH92BFODEPM2dMPgwqZfT7syj0B9f +HBOB1BirlNFjw55/NZKeX0Tq7PQiXLfoPX2k+YmpkbIq2eszh+6l/ePazIjm +iSZuxyuC0F6dWdsU7JGDBcNeDsYq0ATdcT0gTlgn/FP7eHgZFLL8kFKJOGJg +B7Sg7KxrUNb9uShr71ItOrL/8QFArDcCAwEAAaOCAh4wggIaMA8GA1UdEwEB +/wQFMAMBAf8wggG1BgNVHSAEggGsMIIBqDCCAaQGDysGAQQBsT4AAAEJKIOR +MTCCAY8wggFIBggrBgEFBQcCAjCCAToaggE2UmVsaWFuY2Ugb24gb3IgdXNl +IG9mIHRoaXMgQ2VydGlmaWNhdGUgY3JlYXRlcyBhbiBhY2tub3dsZWRnbWVu +dCBhbmQgYWNjZXB0YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5k +YXJkIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHVzZSwgdGhlIENlcnRpZmlj +YXRpb24gUHJhY3RpY2UgU3RhdGVtZW50IGFuZCB0aGUgUmVseWluZyBQYXJ0 +eSBBZ3JlZW1lbnQsIHdoaWNoIGNhbiBiZSBmb3VuZCBhdCB0aGUgYmVUUlVT +VGVkIHdlYiBzaXRlLCBodHRwOi8vd3d3LmJldHJ1c3RlZC5jb20vcHJvZHVj +dHNfc2VydmljZXMvaW5kZXguaHRtbDBBBggrBgEFBQcCARY1aHR0cDovL3d3 +dy5iZXRydXN0ZWQuY29tL3Byb2R1Y3RzX3NlcnZpY2VzL2luZGV4Lmh0bWww +HQYDVR0OBBYEFEU9w6nR3D8kVpgccxiIav+DR+22MB8GA1UdIwQYMBaAFEU9 +w6nR3D8kVpgccxiIav+DR+22MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0B +AQUFAAOCAQEASZK8o+6svfoNyYt5hhwjdrCAWXf82n+0S9/DZEtqTg6t8n1Z +dwWtColzsPq8y9yNAIiPpqCy6qxSJ7+hSHyXEHu67RMdmgduyzFiEuhjA6p9 +beP4G3YheBufS0OM00mG9htc9i5gFdPp43t1P9ACg9AYgkHNZTfqjjJ+vWuZ +XTARyNtIVBw74acT02pIk/c9jH8F6M7ziCpjBLjqflh8AXtb4cV97yHgjQ5d +UX2xZ/2jvTg2xvI4hocalmhgRvsoFEdV4aeADGvi6t9NfJBIoDa9CReJf8Py +05yc493EG931t3GzUwWJBtDLSoDByFOQtTwxiBdQn8nEDovYqAJjDQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFLDCCBBSgAwIBAgIEOU99hzANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQG +EwJXVzESMBAGA1UEChMJYmVUUlVTVGVkMRswGQYDVQQDExJiZVRSVVNUZWQg +Um9vdCBDQXMxGjAYBgNVBAMTEWJlVFJVU1RlZCBSb290IENBMB4XDTAwMDYy +MDE0MjEwNFoXDTEwMDYyMDEzMjEwNFowWjELMAkGA1UEBhMCV1cxEjAQBgNV +BAoTCWJlVFJVU1RlZDEbMBkGA1UEAxMSYmVUUlVTVGVkIFJvb3QgQ0FzMRow +GAYDVQQDExFiZVRSVVNUZWQgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBANS0c3oTCjhVAb6JVuGUntS+WutKNHUbYSnE4a0IYCF4 +SP+00PpeQY1hRIfo7clY+vyTmt9P6j41ffgzeubx181vSUs9Ty1uDoM6GHh3 +o8/n9E1z2Jo7Gh2+lVPPIJfCzz4kUmwMjmVZxXH/YgmPqsWPzGCgc0rXOD8V +cr+il7dw6K/ifhYGTPWqZCZyByWtNfwYsSbX2P8ZDoMbjNx4RWc0PfSvHI3k +bWvtILNnmrRhyxdviTX/507AMhLn7uzf/5cwdO2NR47rtMNE5qdMf1ZD6Li8 +tr76g5fmu/vEtpO+GRg+jIG5c4gW9JZDnGdzF5DYCW5jrEq2I8QBoa2k5MUC +AwEAAaOCAfgwggH0MA8GA1UdEwEB/wQFMAMBAf8wggFZBgNVHSAEggFQMIIB +TDCCAUgGCisGAQQBsT4BAAAwggE4MIIBAQYIKwYBBQUHAgIwgfQagfFSZWxp +YW5jZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVz +IGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0 +ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGFuZCBjZXJ0aWZpY2F0aW9u +IHByYWN0aWNlIHN0YXRlbWVudCwgd2hpY2ggY2FuIGJlIGZvdW5kIGF0IGJl +VFJVU1RlZCdzIHdlYiBzaXRlLCBodHRwczovL3d3dy5iZVRSVVNUZWQuY29t +L3ZhdWx0L3Rlcm1zMDEGCCsGAQUFBwIBFiVodHRwczovL3d3dy5iZVRSVVNU +ZWQuY29tL3ZhdWx0L3Rlcm1zMDQGA1UdHwQtMCswKaAnoCWkIzAhMRIwEAYD +VQQKEwliZVRSVVNUZWQxCzAJBgNVBAYTAldXMB0GA1UdDgQWBBQquZtpLjub +2M3eKjEENGvKBxirZzAfBgNVHSMEGDAWgBQquZtpLjub2M3eKjEENGvKBxir +ZzAOBgNVHQ8BAf8EBAMCAf4wDQYJKoZIhvcNAQEFBQADggEBAHlh26Nebhax +6nZR+csVm8tpvuaBa58oH2U+3RGFktToQb9+M70j5/Egv6S0phkBxoyNNXxl +pE8JpNbYIxUFE6dDea/bow6be3ga8wSGWsb2jCBHOElQBp1yZzrwmAOtlmdE +/D8QDYZN5AA7KXvOOzuZhmElQITcE2K3+spZ1gMe1lMBzW1MaFVA4e5rxyoA +AEiCswoBw2AqDPeCNe5IhpbkdNQ96gFxugR1QKepfzk5mlWXKWWuGVUlBXJH +0+gY3Ljpr0NzARJ0o+FcXxVdJPP55PS2Z2cS52QiivalQaYctmBjRYoQtLpG +EK5BV2VsPyMQPyEQWbfkQN0mDCP2qq4= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIGUTCCBTmgAwIBAgIEPLVPQDANBgkqhkiG9w0BAQUFADBmMRIwEAYDVQQK +EwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEzMDEG +A1UEAxMqYmVUUlVTVGVkIFJvb3QgQ0EgLSBFbnRydXN0IEltcGxlbWVudGF0 +aW9uMB4XDTAyMDQxMTA4MjQyN1oXDTIyMDQxMTA4NTQyN1owZjESMBAGA1UE +ChMJYmVUUlVTVGVkMRswGQYDVQQLExJiZVRSVVNUZWQgUm9vdCBDQXMxMzAx +BgNVBAMTKmJlVFJVU1RlZCBSb290IENBIC0gRW50cnVzdCBJbXBsZW1lbnRh +dGlvbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALr0RAOqEmq1 +Q+xVkrYwfTVXDNvzDSduTPdQqJtOK2/b9a0cS12zqcH+e0TrW6MFDR/FNCsw +ACnxeECypP869AGIF37m1CbTukzqMvtDd5eHI8XbQ6P1KqNRXuE70mVpflUV +m3rnafdE4Fe1FehmYA8NA/uCjqPoEXtsvsdjDheT389Lrm5zdeDzqrmkwAkb +hepxKYhBMvnwKg5sCfJ0a2ZsUhMfGLzUPvfYbiCeyv78IZTuEyhL11xeDGbu +6bsPwTSxfwh28z0mcMmLJR1iJAzqHHVOwBLkuhMdMCktVjMFu5dZfsZJT4nX +LySotohAtWSSU1Yk5KKghbNekLQSM80CAwEAAaOCAwUwggMBMIIBtwYDVR0g +BIIBrjCCAaowggGmBg8rBgEEAbE+AAACCSiDkTEwggGRMIIBSQYIKwYBBQUH +AgIwggE7GoIBN1JlbGlhbmNlIG9uIG9yIHVzZSBvZiB0aGlzIENlcnRpZmlj +YXRlIGNyZWF0ZXMgYW4gYWNrbm93bGVkZ21lbnQgYW5kIGFjY2VwdGFuY2Ug +b2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29u +ZGl0aW9ucyBvZiB1c2UsIHRoZSBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0 +YXRlbWVudCBhbmQgdGhlIFJlbHlpbmcgUGFydHkgQWdyZWVtZW50LCB3aGlj +aCBjYW4gYmUgZm91bmQgYXQgdGhlIGJlVFJVU1RlZCB3ZWIgc2l0ZSwgaHR0 +cHM6Ly93d3cuYmV0cnVzdGVkLmNvbS9wcm9kdWN0c19zZXJ2aWNlcy9pbmRl +eC5odG1sMEIGCCsGAQUFBwIBFjZodHRwczovL3d3dy5iZXRydXN0ZWQuY29t +L3Byb2R1Y3RzX3NlcnZpY2VzL2luZGV4Lmh0bWwwEQYJYIZIAYb4QgEBBAQD +AgAHMIGJBgNVHR8EgYEwfzB9oHugeaR3MHUxEjAQBgNVBAoTCWJlVFJVU1Rl +ZDEbMBkGA1UECxMSYmVUUlVTVGVkIFJvb3QgQ0FzMTMwMQYDVQQDEypiZVRS +VVNUZWQgUm9vdCBDQSAtIEVudHJ1c3QgSW1wbGVtZW50YXRpb24xDTALBgNV +BAMTBENSTDEwKwYDVR0QBCQwIoAPMjAwMjA0MTEwODI0MjdagQ8yMDIyMDQx +MTA4NTQyN1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFH1w5a44iwY/qhwa +j/nPJDCqhIQWMB0GA1UdDgQWBBR9cOWuOIsGP6ocGo/5zyQwqoSEFjAMBgNV +HRMEBTADAQH/MB0GCSqGSIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIEkDANBgkq +hkiG9w0BAQUFAAOCAQEAKrgXzh8QlOu4mre5X+za95IkrNySO8cgjfKZ5V04 +ocI07cUTWVwFtStPYZuR+0H8/NU8TZh2BvWBfevdkObRVlTa4y0MnxEylCIB +evZsLHRnBMylj44ss0O1lKLQfelifwa+JwGDnjr9iu6YQ0pr17WXOzq/T220 +Y/ozADQuLW2WyXvKmWO6vvT2MKAtmJbpVkQFqUSjYRDrgqFnXbxdJ3Wqiig2 +KjiS2d2kXgClzMx8KSreKJCrt+G2/30lC0DYqjSjLd4H61/OCt3Kfjp9JsFi +aDrmLzfzgYYhxKlkqu9FNtEaZnz46TfW1mG+oq1I59/mdP7TbX3SJdysYlep +9w== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFaDCCBFCgAwIBAgIQO1nHe81bV569N1KsdrSqGjANBgkqhkiG9w0BAQUF +ADBiMRIwEAYDVQQKEwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBS +b290IENBczEvMC0GA1UEAxMmYmVUUlVTVGVkIFJvb3QgQ0EgLSBSU0EgSW1w +bGVtZW50YXRpb24wHhcNMDIwNDExMTExODEzWhcNMjIwNDEyMTEwNzI1WjBi +MRIwEAYDVQQKEwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290 +IENBczEvMC0GA1UEAxMmYmVUUlVTVGVkIFJvb3QgQ0EgLSBSU0EgSW1wbGVt +ZW50YXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkujQw +CY5X0LkGLG9uJIAiv11DpvpPrILnHGhwhRujbrWqeNluB0s/6d/16uhUoWGK +Di9pdRi3DOUUjXFumLhV/AyV0Jtu4S2I1DpAa5LxmZZk3tv/ePTulh1HiXzU +vrmIdyM6CeYEnm2qXtLIvZpOGd+J6lsOfsPktPDgaTuID0GQ+NRxQyTBjyZL +O1bp/4xsN+lFrYWMU8NghpBKlsmzVLC7F/AcRdnUGxlkVgoZ98zh/4avflhe +rHqQH8koOUV7orbHnB/ahdQhhlkwk75TMzf270HPM8ercmsl9fNTGwxMLvF1 +S++gh/f+ihXQbNXL+WhTuXAVE8L1LvtDNXUtAgMBAAGjggIYMIICFDAMBgNV +HRMEBTADAQH/MIIBtQYDVR0gBIIBrDCCAagwggGkBg8rBgEEAbE+AAADCSiD +kTEwggGPMEEGCCsGAQUFBwIBFjVodHRwOi8vd3d3LmJldHJ1c3RlZC5jb20v +cHJvZHVjdHNfc2VydmljZXMvaW5kZXguaHRtbDCCAUgGCCsGAQUFBwICMIIB +OhqCATZSZWxpYW5jZSBvbiBvciB1c2Ugb2YgdGhpcyBDZXJ0aWZpY2F0ZSBj +cmVhdGVzIGFuIGFja25vd2xlZGdtZW50IGFuZCBhY2NlcHRhbmNlIG9mIHRo +ZSB0aGVuIGFwcGxpY2FibGUgc3RhbmRhcmQgdGVybXMgYW5kIGNvbmRpdGlv +bnMgb2YgdXNlLCB0aGUgQ2VydGlmaWNhdGlvbiBQcmFjdGljZSBTdGF0ZW1l +bnQgYW5kIHRoZSBSZWx5aW5nIFBhcnR5IEFncmVlbWVudCwgd2hpY2ggY2Fu +IGJlIGZvdW5kIGF0IHRoZSBiZVRSVVNUZWQgd2ViIHNpdGUsIGh0dHA6Ly93 +d3cuYmV0cnVzdGVkLmNvbS9wcm9kdWN0c19zZXJ2aWNlcy9pbmRleC5odG1s +MAsGA1UdDwQEAwIBBjAfBgNVHSMEGDAWgBSp7BR++dlDzFMrFK3P9/BZiUHN +GTAdBgNVHQ4EFgQUqewUfvnZQ8xTKxStz/fwWYlBzRkwDQYJKoZIhvcNAQEF +BQADggEBANuXsHXqDMTBmMpWBcCorSZIry0g6IHHtt9DwSwddUvUQo3neqh0 +3GZCWYez9Wlt2ames30cMcH1VOJZJEnl7r05pmuKmET7m9cqg5c0Lcd9NUwt +NLg+DcTsiCevnpL9UGGCqGAHFFPMZRPB9kdEadIxyKbdLrML3kqNWz2rDcI1 +UqJWN8wyiyiFQpyRQHpwKzg21eFzGh/l+n5f3NacOzDq28BbJ1zTcwfBwvNM +m2+fG8oeqqg4MwlYsq78B+g23FW6L09A/nq9BqaBwZMifIYRCgZ3SK41ty8y +mmFei74pnykkiFY5LKjSq5YDWtRIn7lAhAuYaPsBQ9Yb4gmxlxw= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC +TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNaFw0yMTAzMTcxODMz +MzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUw +IwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVR +dW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Yp +li4kVEAkOPcahdxYTMukJ0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2D +rOpm2RgbaIr1VxqYuvXtdj182d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJ +WCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cug +F+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospU +xbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCC +Ak4wPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVv +dmFkaXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw +ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNl +IG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBh +c3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy +ZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh +Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYI +KwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3T +KbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rq +y+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1p +dGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYD +VQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCL +MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSk +fnIYj9lofFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf8 +7C9TqnN7Az10buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1R +cHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0y +mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW +xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK +SnQ2+Q== +-----END CERTIFICATE----- + +-----BEGIN CERTIFICATE----- +MIIETzCCAzegAwIBAgIEO63vKTANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQTDEfMB0GA1UE +ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg +U2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBSb290Q0EwHhcNMDEwOTIzMTQxODE3WhcNMTEw +OTIzMTMxODE3WjB1MQswCQYDVQQGEwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5v +LjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MR8wHQYDVQQDExZDQyBTaWdu +ZXQgLSBDQSBLbGFzYSAxMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC4SRW9Q58g5DY1Hw7h +gCRKBEdPdGn0MFHsfw7rlu/oQm7IChI/uWd9q5wwo77YojtTDjRnpgZsjqBeynX8T90vFILqsY2K +5CF1OESalwvVr3sZiQX79lisuFKat92u6hBFikFIVxfHHB67Af+g7u0dEHdDW7lwy81MwFYxBTRy +9wIDAQABo4IBbTCCAWkwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwggEEBgNVHSAE +gfwwgfkwgfYGDSsGAQQBvj8CAQoBAQAwgeQwgZoGCCsGAQUFBwICMIGNGoGKQ2VydHlmaWthdCB3 +eXN0YXdpb255IHpnb2RuaWUgeiBkb2t1bWVudGVtOiAiUG9saXR5a2EgQ2VydHlmaWthY2ppIGRs +YSBSb290Q0EiLiBDZXJ0eWZpa2F0IHd5c3Rhd2lvbnkgcHJ6ZXogUm9vdENBIHcgaGllcmFyY2hp +aSBDQyBTaWduZXQuMEUGCCsGAQUFBwIBFjlodHRwOi8vd3d3LnNpZ25ldC5wbC9yZXBvenl0b3Jp +dW0vZG9rdW1lbnR5L3BjX3Jvb3RjYS50eHQwHwYDVR0jBBgwFoAUwJvFIw0C4aZOSGsfAOnjmhQb +sa8wHQYDVR0OBBYEFMODHtVZd1T7TftXR/nEI1zR54njMA0GCSqGSIb3DQEBBQUAA4IBAQBRIHQB +FIGh8Jpxt87AgSLwIEEk4+oGy769u3NtoaR0R3WNMdmt7fXTi0tyTQ9V4AIszxVjhnUPaKnF1KYy +f8Tl+YTzk9ZfFkZ3kCdSaILZAOIrmqWNLPmjUQ5/JiMGho0e1YmWUcMci84+pIisTsytFzVP32/W ++sz2H4FQAvOIMmxB7EJX9AdbnXn9EXZ+4nCqi0ft5z96ZqOJJiCB3vSaoYg+wdkcvb6souMJzuc2 +uptXtR1Xf3ihlHaGW+hmnpcwFA6AoNrom6Vgzk6U1ienx0Cw28BhRSKqzKkyXkuK8gRflZUx84uf +tXncwKJrMiE3lvgOOBITRzcahirLer4c +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIE9zCCA9+gAwIBAgIEPL/xoTANBgkqhkiG9w0BAQUFADB2MQswCQYDVQQGEwJQTDEfMB0GA1UE +ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg +U2lnbmV0MSAwHgYDVQQDExdDQyBTaWduZXQgLSBQQ0EgS2xhc2EgMjAeFw0wMjA0MTkxMDI5NTNa +Fw0xNzA0MTgxMjUzMDdaMHUxCzAJBgNVBAYTAlBMMR8wHQYDVQQKExZUUCBJbnRlcm5ldCBTcC4g +eiBvLm8uMSQwIgYDVQQLExtDZW50cnVtIENlcnR5ZmlrYWNqaSBTaWduZXQxHzAdBgNVBAMTFkND +IFNpZ25ldCAtIENBIEtsYXNhIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqgLJu +QqY4yavbSgHg8CyfKTx4BokNSDOVz4eD9vptUr11Kqd06ED1hlH7Sg0goBFAfntNU/QTKwSBaNui +me7C4sSEdgsKrPoAhGb4Mq8y7Ty7RqZz7mkzNMqzL2L2U4yQ2QjvpH8MH0IBqOWEcpSkpwnrCDIm +RoTfd+YlZWKi2JceQixUUYIQ45Ox8+x8hHbvvZdgqtcvo8PW27qoHkp/7hMuJ44kDAGrmxffBXl/ +OBRZp0uO1CSLcMcVJzyr2phKhy406MYdWrtNPEluGs0GFDzd0nrIctiWAO4cmct4S72S9Q6e//0G +O9f3/Ca5Kb2I1xYLj/xE+HgjHX9aD2MhAgMBAAGjggGMMIIBiDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjCB4wYDVR0gBIHbMIHYMIHVBg0rBgEEAb4/AhQKAQEAMIHDMHUGCCsGAQUF +BwICMGkaZ0NlcnR5ZmlrYXQgd3lzdGF3aW9ueSB6Z29kbmllIHogZG9rdW1lbnRlbTogIlBvbGl0 +eWthIENlcnR5ZmlrYWNqaSBQQ0EyIC0gQ2VydHlmaWthdHkgVXJ6ZWRvdyBLbGFzeSAyIi4wSgYI +KwYBBQUHAgEWPmh0dHA6Ly93d3cuc2lnbmV0LnBsL3JlcG96eXRvcml1bS9kb2t1bWVudHkva2xh +c2EyL3BjX3BjYTIudHh0MD8GA1UdHwQ4MDYwNKAyoDCGLmh0dHA6Ly93d3cuc2lnbmV0LnBsL3Jl +cG96eXRvcml1bS9jcmwvcGNhMi5jcmwwHwYDVR0jBBgwFoAUwGxGyl2CfpYHRonE82AVXO08kMIw +HQYDVR0OBBYEFLtFBlILy4HNKVSzvHxBTM0HDowlMA0GCSqGSIb3DQEBBQUAA4IBAQBWTsCbqXrX +hBBev5v5cIuc6gJM8ww7oR0uMQRZoFSqvQUPWBYM2/TLI/f8UM9hSShUVj3zEsSj/vFHagUVmzuV +Xo5u0WK8iaqATSyEVBhADHrPG6wYcLKJlagge/ILA0m+SieyP2sjYD9MUB9KZIEyBKv0429UuDTw +6P7pslxMWJBSNyQxaLIs0SRKsqZZWkc7ZYAj2apSkBMX2Is1oHA+PwkF6jQMwCao/+CndXPUzfCF +6caa9WwW31W26MlXCvSmJgfiTPwGvm4PkPmOnmWZ3CczzhHl4q7ztHFzshJH3sZWDnrWwBFjzz5e +Pr3WHV1wA7EY6oT4zBx+2gT9XBTB +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEUzCCAzugAwIBAgIEPq+qjzANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQGEwJQTDE3MDUGA1UE +ChMuQ1ppQyBDZW50cmFzdCBTQSB3IGltaWVuaXUgTWluaXN0cmEgR29zcG9kYXJraTEZMBcGA1UE +AxMQQ1ppQyBDZW50cmFzdCBTQTAeFw0wMzA0MzAxMDUwNTVaFw0wODA0MjgxMDUwNTVaMGgxCzAJ +BgNVBAYTAlBMMR8wHQYDVQQKExZUUCBJbnRlcm5ldCBTcC4geiBvLm8uMR8wHQYDVQQDExZDQyBT +aWduZXQgLSBDQSBLbGFzYSAzMRcwFQYDVQQFEw5OdW1lciB3cGlzdTogNDCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBALVdeOM62cPH2NERFxbS5FIp/HSv3fgesdVsTUFxZbGtE+/E0RMl +KZQJHH9emx7vRYubsi4EOLCjYsCOTFvgGRIpZzx7R7T5c0Di5XFkRU4gjBl7aHJoKb5SLzGlWdoX +GsekVtl6keEACrizV2EafqjI8cnBWY7OxQ1ooLQp5AeFjXg+5PT0lO6TUZAubqjFbhVbxSWjqvdj +93RGfyYE76MnNn4c2xWySD07n7uno06TC0IJe6+3WSX1h+76VsIFouWBXOoM7cxxiLjoqdBVu24+ +P8e81SukE7qEvOwDPmk9ZJFtt1nBNg8a1kaixcljrA/43XwOPz6qnJ+cIj/xywECAwEAAaOCAQow +ggEGMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMDMGA1UdIAEB/wQpMCcwJQYEVR0g +ADAdMBsGCCsGAQUFBwIBFg93d3cuY2VudHJhc3QucGwwgY4GA1UdIwSBhjCBg4AU2a7r85Cp1iJN +W0Ca1LR6VG3996ShZaRjMGExCzAJBgNVBAYTAlBMMTcwNQYDVQQKEy5DWmlDIENlbnRyYXN0IFNB +IHcgaW1pZW5pdSBNaW5pc3RyYSBHb3Nwb2RhcmtpMRkwFwYDVQQDExBDWmlDIENlbnRyYXN0IFNB +ggQ9/0sQMB0GA1UdDgQWBBR7Y8wZkHq0zrY7nn1tFSdQ0PlJuTANBgkqhkiG9w0BAQUFAAOCAQEA +ldt/svO5c1MU08FKgrOXCGEbEPbQxhpM0xcd6Iv3dCo6qugEgjEs9Qm5CwUNKMnFsvR27cJWUvZb +MVcvwlwCwclOdwF6u/QRS8bC2HYErhYo9bp9yuxxzuow2A94c5fPqfVrjXy+vDouchAm6+A5Wjzv +J8wxVFDCs+9iGACmyUWr/JGXCYiQIbQkwlkRKHHlan9ymKf1NvIej/3EpeT8fKr6ywxGuhAfqofW +pg3WJY/RCB4lTzD8vZGNwfMFGkWhJkypad3i9w3lGmDVpsHaWtCgGfd0H7tUtWPkP+t7EjIRCD9J +HYnTR+wbbewc5vOI+UobR15ynGfFIaSIiMTVtQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEejCCA2KgAwIBAgIEP4vk6TANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJQ +TDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2Vu +dHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MR8wHQYDVQQDExZDQyBTaWduZXQgLSBD +QSBLbGFzYSAyMB4XDTAzMTAxNDExNTgyMloXDTE3MDQxODEyNTMwN1owdzELMAkG +A1UEBhMCUEwxHzAdBgNVBAoTFlRQIEludGVybmV0IFNwLiB6IG8uby4xJDAiBgNV +BAsTG0NlbnRydW0gQ2VydHlmaWthY2ppIFNpZ25ldDEhMB8GA1UEAxMYQ0MgU2ln +bmV0IC0gT0NTUCBLbGFzYSAyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCo +VCsaBStblXQYVNthe3dvaCrfvKpPXngh4almm988iIlEv9CVTaAdCfaJNihvA+Vs +Qw8++ix1VqteMQE474/MV/YaXigP0Zr0QB+g+/7PWVlv+5U9Gzp9+Xx4DJay8AoI +iB7Iy5Qf9iZiHm5BiPRIuUXT4ZRbZRYPh0/76vgRsQIDAQABo4IBkjCCAY4wDgYD +VR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMJMEEGA1UdHwQ6MDgwNqA0 +oDKGMGh0dHA6Ly93d3cuc2lnbmV0LnBsL3JlcG96eXRvcml1bS9jcmwva2xhc2Ey +LmNybDCB2AYDVR0gBIHQMIHNMIHKBg4rBgEEAb4/AoFICgwBADCBtzBsBggrBgEF +BQcCAjBgGl5DZXJ0eWZpa2F0IHd5ZGFueSB6Z29kbmllIHogZG9rdW1lbnRlbSAi +UG9saXR5a2EgQ2VydHlmaWthY2ppIC0gQ2VydHlmaWthdHkgcmVzcG9uZGVyb3cg +T0NTUCIuMEcGCCsGAQUFBwIBFjtodHRwOi8vd3d3LnNpZ25ldC5wbC9yZXBvenl0 +b3JpdW0vZG9rdW1lbnR5L3BjX29jc3BfMV8wLnBkZjAfBgNVHSMEGDAWgBS7RQZS +C8uBzSlUs7x8QUzNBw6MJTAdBgNVHQ4EFgQUKEVrOY7cEHvsVgvoyZdytlbtgwEw +CQYDVR0TBAIwADANBgkqhkiG9w0BAQUFAAOCAQEAQrRg5MV6dxr0HU2IsLInxhvt +iUVmSFkIUsBCjzLoewOXA16d2oDyHhI/eE+VgAsp+2ANjZu4xRteHIHoYMsN218M +eD2MLRsYS0U9xxAFK9gDj/KscPbrrdoqLvtPSMhUb4adJS9HLhvUe6BicvBf3A71 +iCNe431axGNDWKnpuj2KUpj4CFHYsWCXky847YtTXDjri9NIwJJauazsrSjK+oXp +ngRS506mdQ7vWrtApkh8zhhWp7duCkjcCo1O8JxqYr2qEW1fXmgOISe010v2mmuv +hHxPyVwoAU4KkOw0nbXZn53yak0is5+XmAjh0wWue44AssHrjC9nUh3mkLt6eQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEezCCA2OgAwIBAgIEP4vnLzANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJQ +TDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEfMB0GA1UEAxMWQ0Mg +U2lnbmV0IC0gQ0EgS2xhc2EgMzEXMBUGA1UEBRMOTnVtZXIgd3Bpc3U6IDQwHhcN +MDMxMDE0MTIwODAwWhcNMDgwNDI4MTA1MDU1WjB3MQswCQYDVQQGEwJQTDEfMB0G +A1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBD +ZXJ0eWZpa2FjamkgU2lnbmV0MSEwHwYDVQQDExhDQyBTaWduZXQgLSBPQ1NQIEts +YXNhIDMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM/9GwvARNuCVN+PqZmO +4FqH8vTqhenUyqRkmAVT4YhLu0a9AXeLAYVDu+NTkYzsAUMAfu55rIKHNLlm6WbF +KvLiKKz4p4pbUr+ToPcwl/TDotidloUdBAxDg0SL+PmQqACZDe3seJho2IYf2vDL +/G4TLMbKmNB0mlWFuN0f4fJNAgMBAAGjggGgMIIBnDAOBgNVHQ8BAf8EBAMCB4Aw +EwYDVR0lBAwwCgYIKwYBBQUHAwkwTwYDVR0fBEgwRjBEoEKgQIY+aHR0cDovL3d3 +dy5zaWduZXQucGwva3dhbGlmaWtvd2FuZS9yZXBvenl0b3JpdW0vY3JsL2tsYXNh +My5jcmwwgdgGA1UdIASB0DCBzTCBygYOKwYBBAG+PwKCLAoCAQAwgbcwbAYIKwYB +BQUHAgIwYBpeQ2VydHlmaWthdCB3eWRhbnkgemdvZG5pZSB6IGRva3VtZW50ZW0g +IlBvbGl0eWthIENlcnR5ZmlrYWNqaSAtIENlcnR5ZmlrYXR5IHJlc3BvbmRlcm93 +IE9DU1AiLjBHBggrBgEFBQcCARY7aHR0cDovL3d3dy5zaWduZXQucGwvcmVwb3p5 +dG9yaXVtL2Rva3VtZW50eS9wY19vY3NwXzFfMC5wZGYwHwYDVR0jBBgwFoAUe2PM +GZB6tM62O559bRUnUND5SbkwHQYDVR0OBBYEFG4jnCMvBALRQXtmDn9TyXQ/EKP+ +MAkGA1UdEwQCMAAwDQYJKoZIhvcNAQEFBQADggEBACXrKG5Def5lpRwmZom3UEDq +bl7y4U3qomG4B+ok2FVZGgPZti+ZgvrenPj7PtbYCUBPsCSTNrznKinoT3gD9lQQ +xkEHwdc6VD1GlFp+qI64u0+wS9Epatrdf7aBnizrOIB4LJd4E2TWQ6trspetjMIU +upyWls1BmYUxB91R7QkTiAUSNZ87s3auhZuG4f0V0JLVCcg2rn7AN1rfMkgxCbHk +GxiQbYWFljl6aatxR3odnnzVUe1I8uoY2JXpmmUcOG4dNGuQYziyKG3mtXCQWvug +5qi9Mf3KUh1oSTKx6HfLjjNl1+wMB5Mdb8LF0XyZLdJM9yIZh7SBRsYm9QiXevY= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFGjCCBAKgAwIBAgIEPL7eEDANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQTDEfMB0GA1UE +ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg +U2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBSb290Q0EwHhcNMDIwNDE4MTQ1NDA4WhcNMjYw +OTIxMTU0MjE5WjB2MQswCQYDVQQGEwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5v +LjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MSAwHgYDVQQDExdDQyBTaWdu +ZXQgLSBQQ0EgS2xhc2EgMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM7BrBlbN5ma +M5eg0BOTqoZ+9NBDvU8Lm5rTdrMswFTCathzpVVLK/JD4K3+4oCZ9SRAspEXE4gvwb08ASY6w5s+ +HpRkeJw8YzMFR5kDZD5adgnCAy4vDfIXYZgppXPaTQ8wnfUZ7BZ7Zfa7QBemUIcJIzJBB0UqgtxW +Ceol9IekpBRVmuuSA6QG0Jkm+pGDJ05yj2eQG8jTcBENM7sVA8rGRMyFA4skSZ+D0OG6FS2xC1i9 +JyN0ag1yII/LPx8HK5J4W9MaPRNjAEeaa2qI9EpchwrOxnyVbQfSedCG1VRJfAsE/9tT9CMUPZ3x +W20QjQcSZJqVcmGW9gVsXKQOVLsCAwEAAaOCAbMwggGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P +AQH/BAQDAgEGMIIBBAYDVR0gBIH8MIH5MIH2Bg0rBgEEAb4/AgEKAQEBMIHkMIGaBggrBgEFBQcC +AjCBjRqBikNlcnR5ZmlrYXQgd3lzdGF3aW9ueSB6Z29kbmllIHogZG9rdW1lbnRlbTogIlBvbGl0 +eWthIENlcnR5ZmlrYWNqaSBkbGEgUm9vdENBIi4gQ2VydHlmaWthdCB3eXN0YXdpb255IHByemV6 +IFJvb3RDQSB3IGhpZXJhcmNoaWkgQ0MgU2lnbmV0LjBFBggrBgEFBQcCARY5aHR0cDovL3d3dy5z +aWduZXQucGwvcmVwb3p5dG9yaXVtL2Rva3VtZW50eS9wY19yb290Y2EudHh0MEQGA1UdHwQ9MDsw +OaA3oDWGM2h0dHA6Ly93d3cuc2lnbmV0LnBsL3JlcG96eXRvcml1bS9yb290Y2Evcm9vdGNhLmNy +bDAfBgNVHSMEGDAWgBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAdBgNVHQ4EFgQUwGxGyl2CfpYHRonE +82AVXO08kMIwDQYJKoZIhvcNAQEFBQADggEBABp1TAUsa+BeVWg4cjowc8yTJ5XN3GvN96GObMkx +UGY7U9kVrLI71xBgoNVyzXTiMNDBvjh7vdPWjpl5SDiRpnnKiOFXA43HvNWzUaOkTu1mxjJsZsan +ot1Xt6j0ZDC+03FjLHdYMyM9kSWp6afb4980EPYZCcSzgM5TOGfJmNii5Tq468VFKrX+52Aou1G2 +2Ohu+EEOlOrG7ylKv1hHUJJCjwN0ZVEIn1nDbrU9FeGCz8J9ihVUvnENEBbBkU37PWqWuHitKQDV +tcwTwJJdR8cmKq3NmkwAm9fPacidQLpaw0WkuGrS+fEDhu1Nhy9xELP6NA9GRTCNxm/dXlcwnmY= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFGjCCBAKgAwIBAgIEPV0tNDANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQTDEfMB0GA1UE +ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg +U2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBSb290Q0EwHhcNMDIwODE2MTY0OTU2WhcNMjYw +OTIxMTU0MjE5WjB2MQswCQYDVQQGEwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5v +LjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MSAwHgYDVQQDExdDQyBTaWdu +ZXQgLSBQQ0EgS2xhc2EgMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALN3LanJtdue +Ne6geWUTFENa+lEuzqELcoqhYB+a/tJcPEkc6TX/bYPzalRRjqs+quMP6KZTU0DixOrV+K7iWaqA +iQ913HX5IBLmKDCrTVW/ZvSDpiBKbxlHfSNuJxAuVT6HdbzK7yAW38ssX+yS2tZYHZ5FhZcfqzPE +OpO94mAKcBUhk6T/ki0evXX/ZvvktwmF3hKattzwtM4JMLurAEl8SInyEYULw5JdlfcBez2Tg6Db +w34hA1A+ckTwhxzecrB8TUe2BnQKOs9vr2cCACpFFcOmPkM0Drtjctr1QHm1tYSqRFRf9VcV5tfC +3P8QqoK4ONjtLPHc9x5NE1uK/FMCAwEAAaOCAbMwggGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P +AQH/BAQDAgEGMIIBBAYDVR0gBIH8MIH5MIH2Bg0rBgEEAb4/AgEKAQECMIHkMIGaBggrBgEFBQcC +AjCBjRqBikNlcnR5ZmlrYXQgd3lzdGF3aW9ueSB6Z29kbmllIHogZG9rdW1lbnRlbTogIlBvbGl0 +eWthIENlcnR5ZmlrYWNqaSBkbGEgUm9vdENBIi4gQ2VydHlmaWthdCB3eXN0YXdpb255IHByemV6 +IFJvb3RDQSB3IGhpZXJhcmNoaWkgQ0MgU2lnbmV0LjBFBggrBgEFBQcCARY5aHR0cDovL3d3dy5z +aWduZXQucGwvcmVwb3p5dG9yaXVtL2Rva3VtZW50eS9wY19yb290Y2EudHh0MEQGA1UdHwQ9MDsw +OaA3oDWGM2h0dHA6Ly93d3cuc2lnbmV0LnBsL3JlcG96eXRvcml1bS9yb290Y2Evcm9vdGNhLmNy +bDAfBgNVHSMEGDAWgBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAdBgNVHQ4EFgQUXvthcPHlH5BgGhlM +ErJNXWlhlgAwDQYJKoZIhvcNAQEFBQADggEBACIce95Mvn710KCAISA0CuHD4aznTU6pLoCDShW4 +7OR+GTpJUm1coTcUqlBHV9mra4VFrBcBuOkHZoBLq/jmE0QJWnpSEULDcH9J3mF0nqO9SM+mWyJG +dsJF/XU/7smummgjMNQXwzQTtWORF+6v5KUbWX85anO2wR+M6YTBWC55zWpWi4RG3vkHFs5Ze2oF +JTlpuxw9ZgxTnWlwI9QR2MvEhYIUMKMOWxw1nt0kKj+5TCNQQGh/VJJ1dsiroGh/io1DOcePEhKz +1Ag52y6Wf0nJJB9yk0sFakqZH18F7eQecQImgZyyeRtsG95leNugB3BXWCW+KxwiBrtQTXv4dTE= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEzzCCA7egAwIBAgIEO6ocGTANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQTDEfMB0GA1UE +ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg +U2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBSb290Q0EwHhcNMDEwOTIwMTY0MjE5WhcNMjYw +OTIxMTU0MjE5WjBxMQswCQYDVQQGEwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5v +LjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MRswGQYDVQQDExJDQyBTaWdu +ZXQgLSBSb290Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrr2vydnNpELfGW3Ks +ARiDhJvwDtUe4AbWev+OfMc3+vA29nX8ZmIwno3gmItjo5DbUCCRiCMq5c9epcGu+kg4a3BJChVX +REl8gVh0ST15rr3RKrSc4VgsvQzl0ZUraeQLl8JoRT5PLsUj3qwF78jUCQVckiiLVcnGfZtFCm+D +CJXliQBDMB9XFAUEiO/DtEBs0B7wJGx7lgJeJpQUcGiaOPjcJDYOk7rNAYmmD2gWeSlepufO8luU +YG/YDxTC4mqhRqfa4MnVO5dqy+ICj2UvUpHbZDB0KfGRibgBYeQP1kuqgIzJN4UqknVAJb0aMBSP +l+9k2fAUdchx1njlbdcbAgMBAAGjggFtMIIBaTAPBgNVHRMBAf8EBTADAQH/MIIBBAYDVR0gBIH8 +MIH5MIH2Bg0rBgEEAb4/AgEKAQEAMIHkMIGaBggrBgEFBQcCAjCBjRqBikNlcnR5ZmlrYXQgd3lz +dGF3aW9ueSB6Z29kbmllIHogZG9rdW1lbnRlbTogIlBvbGl0eWthIENlcnR5ZmlrYWNqaSBkbGEg +Um9vdENBIi4gQ2VydHlmaWthdCB3eXN0YXdpb255IHByemV6IFJvb3RDQSB3IGhpZXJhcmNoaWkg +Q0MgU2lnbmV0LjBFBggrBgEFBQcCARY5aHR0cDovL3d3dy5zaWduZXQucGwvcmVwb3p5dG9yaXVt +L2Rva3VtZW50eS9wY19yb290Y2EudHh0MB0GA1UdDgQWBBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAf +BgNVHSMEGDAWgBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcN +AQEFBQADggEBAGnY5QmYqnnO9OqFOWZxxb25UHRnaRF6IV9aaGit5BZufZj2Tq3v8L3SgE34GOoI +cdRMMG5JEpEU4mN/Ef3oY6Eo+7HfqaPHI4KFmbDSPiK5s+wmf+bQSm0Yq5/h4ZOdcAESlLQeLSt1 +CQk2JoKQJ6pyAf6xJBgWEIlm4RXE4J3324PUiOp83kW6MDvaa1xY976WyInr4rwoLgxVl11LZeKW +ha0RJJxJgw/NyWpKG7LWCm1fglF8JH51vZNndGYq1iKtfnrIOvLZq6bzaCiZm1EurD8HE6P7pmAB +KK6o3C2OXlNfNIgwkDN/cDqk5TYsTkrpfriJPdxXBH8hQOkW89g= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID/TCCA2agAwIBAgIEP4/gkTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJQTDEfMB0GA1UE +ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg +U2lnbmV0MR8wHQYDVQQDExZDQyBTaWduZXQgLSBDQSBLbGFzYSAxMB4XDTAzMTAxNzEyMjkwMloX +DTExMDkyMzExMTgxN1owdjELMAkGA1UEBhMCUEwxHzAdBgNVBAoTFlRQIEludGVybmV0IFNwLiB6 +IG8uby4xJDAiBgNVBAsTG0NlbnRydW0gQ2VydHlmaWthY2ppIFNpZ25ldDEgMB4GA1UEAxMXQ0Mg +U2lnbmV0IC0gVFNBIEtsYXNhIDEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOJYrISEtSsd +uHajROh5/n7NGrkpYTT9NEaPe9+ucuQ37KxIbfJwXJjgUc1dw4wCkcQ12FJarD1X6mSQ4cfN/60v +LfKI5ZD4nhJTMKlAj1pX9ScQ/MuyvKStCbn5WTkjPhjRAM0tdwXSnzuTEunfw0Oup559y3Iqxg1c +ExflB6cfAgMBAAGjggGXMIIBkzBBBgNVHR8EOjA4MDagNKAyhjBodHRwOi8vd3d3LnNpZ25ldC5w +bC9yZXBvenl0b3JpdW0vY3JsL2tsYXNhMS5jcmwwDgYDVR0PAQH/BAQDAgeAMBYGA1UdJQEB/wQM +MAoGCCsGAQUFBwMIMIHaBgNVHSAEgdIwgc8wgcwGDSsGAQQBvj8CZAoRAgEwgbowbwYIKwYBBQUH +AgIwYxphQ2VydHlmaWthdCB3eXN0YXdpb255IHpnb2RuaWUgeiBkb2t1bWVudGVtICJQb2xpdHlr +YSBDZXJ0eWZpa2FjamkgQ0MgU2lnbmV0IC0gWm5ha293YW5pZSBjemFzZW0iLjBHBggrBgEFBQcC +ARY7aHR0cDovL3d3dy5zaWduZXQucGwvcmVwb3p5dG9yaXVtL2Rva3VtZW50eS9wY190c2ExXzJf +MS5wZGYwHwYDVR0jBBgwFoAUw4Me1Vl3VPtN+1dH+cQjXNHnieMwHQYDVR0OBBYEFJdDwEqtcavO +Yd9u9tej53vWXwNBMAkGA1UdEwQCMAAwDQYJKoZIhvcNAQEFBQADgYEAnpiQkqLCJQYXUrqMHUEz ++z3rOqS0XzSFnVVLhkVssvXc8S3FkJIiQTUrkScjI4CToCzujj3EyfNxH6yiLlMbskF8I31JxIeB +vueqV+s+o76CZm3ycu9hb0I4lswuxoT+q5ZzPR8Irrb51rZXlolR+7KtwMg4sFDJZ8RNgOf7tbA= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIGFTCCBX6gAwIBAgIBEDANBgkqhkiG9w0BAQUFADCBvjELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0luZGlhbmExFTATBgNVBAcTDEluZGlhbmFwb2xpczEoMCYGA1UE +ChMfU29mdHdhcmUgaW4gdGhlIFB1YmxpYyBJbnRlcmVzdDETMBEGA1UECxMKaG9z +dG1hc3RlcjEgMB4GA1UEAxMXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJTAjBgkq +hkiG9w0BCQEWFmhvc3RtYXN0ZXJAc3BpLWluYy5vcmcwHhcNMDYwODE2MjA0NjUy +WhcNMTYwODEzMjA0NjUyWjCBvDELMAkGA1UEBhMCVVMxEDAOBgNVBAgTB0luZGlh +bmExFTATBgNVBAcTDEluZGlhbmFwb2xpczEoMCYGA1UEChMfU29mdHdhcmUgaW4g +dGhlIFB1YmxpYyBJbnRlcmVzdDETMBEGA1UECxMKSG9zdG1hc3RlcjEeMBwGA1UE +AxMVQ2VydGlmaWNhdGUgQXV0aG9yaXR5MSUwIwYJKoZIhvcNAQkBFhZob3N0bWFz +dGVyQHNwaS1pbmMub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA +uTlCOrOYvCe0Qszlz90rVIQkS2UDa7R+qCTkRE5ipKC+3OZXGgv2EOYk/IOuCE3D +8+tlTAl8MwvmwOHgL0GWnjoluR95narhNiV9Px8xyL2Z8kctwrWXbEii0Ot48VcN +IQMDW5GK8Ww5puMKZr8+bXF2HFzkt8gwaCtrojcF4fLGcm3//bR13CKWbOzacANZ +gAi00pD70ppjJU/uNVOe5HX6x/Id+50G6jwasanEzhteYJdbbHaMqrL4J6XbTwgJ +ZciB0ifOZkwTBvQiRJpTkTWPyn/HptMbJGOwwiNbcgtWV7QVLW1GB3HYVum47Zwp +XcXVM4Fs4XLwfx1Ti87LGdAJJYDS5K1F2prHKW5MsmFLJg61Nd6dZPRDLJLaOPEq +0Jxa1NdfDjJ8rXOIcuLRAozjBui23vUhfOW9z4kpVIg+c+ylV2Oh/7f+fO731P7E +AqsTFmiU7svcvkm2OKslolpnQ+pqGFLM4laQE/Q0kjogm7LiOpRssBW/ZfZ7pPLZ +Ru0/AXrgKwQIM8mLazwlD3wHKPRElhIkxSv4qZ95zgJo6ky/7BpzZ/OAlz3BICbN +WQhW/MBQVFiC6ivhjDq3AzgyykLShB0eIMRN0SBfTy3/aNfIJbqLmTNookXPoSP7 ++mg5OVzVBvDv5ZskWSl8kJB1DzJbN+DOr/i8V3Ugl90CAwEAAaOCAZ0wggGZMB0G +A1UdDgQWBBTON+buqfoMXkWdtvObUS11tnY77DCB6wYDVR0jBIHjMIHggBQHrehB +HX+91r8bgXo/jEuI3gTS+qGBxKSBwTCBvjELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0luZGlhbmExFTATBgNVBAcTDEluZGlhbmFwb2xpczEoMCYGA1UEChMfU29mdHdh +cmUgaW4gdGhlIFB1YmxpYyBJbnRlcmVzdDETMBEGA1UECxMKaG9zdG1hc3RlcjEg +MB4GA1UEAxMXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJTAjBgkqhkiG9w0BCQEW +Fmhvc3RtYXN0ZXJAc3BpLWluYy5vcmeCAQAwDwYDVR0TAQH/BAUwAwEB/zARBglg +hkgBhvhCAQEEBAMCAQYwCQYDVR0SBAIwADArBglghkgBhvhCAQ0EHhYcVGlueUNB +IEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAhBgNVHREEGjAYgRZob3N0bWFzdGVyQHNw +aS1pbmMub3JnMAsGA1UdDwQEAwIBBjANBgkqhkiG9w0BAQUFAAOBgQA5HQcqwPE/ +RaN8cb8H1G34rkvSEsj4l8UIivMFEWIKnF3SQT8KVcD7j/eJuhMazwRlTs8Rnu6V +/uTC10w7SS6gELwDqAzR4PiXTzfkW8OJemyQn6JWXKfq2pR1n4fvwEn7htjeNS69 +iFKlFXyE9j2jhGaps1CKHfe1YX0MuwO4Jw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEFTCCA36gAwIBAgIBADANBgkqhkiG9w0BAQQFADCBvjELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0luZGlhbmExFTATBgNVBAcTDEluZGlhbmFwb2xpczEoMCYGA1UE +ChMfU29mdHdhcmUgaW4gdGhlIFB1YmxpYyBJbnRlcmVzdDETMBEGA1UECxMKaG9z +dG1hc3RlcjEgMB4GA1UEAxMXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJTAjBgkq +hkiG9w0BCQEWFmhvc3RtYXN0ZXJAc3BpLWluYy5vcmcwHhcNMDMwMTE1MTYyOTE3 +WhcNMDcwMTE0MTYyOTE3WjCBvjELMAkGA1UEBhMCVVMxEDAOBgNVBAgTB0luZGlh +bmExFTATBgNVBAcTDEluZGlhbmFwb2xpczEoMCYGA1UEChMfU29mdHdhcmUgaW4g +dGhlIFB1YmxpYyBJbnRlcmVzdDETMBEGA1UECxMKaG9zdG1hc3RlcjEgMB4GA1UE +AxMXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJTAjBgkqhkiG9w0BCQEWFmhvc3Rt +YXN0ZXJAc3BpLWluYy5vcmcwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPB6 +rdoiLR3RodtM22LMcfwfqb5OrJNl7fwmvskgF7yP6sdD2bOfDIXhg9852jhY8/kL +VOFe1ELAL2OyN4RAxk0rliZQVgeTgqvgkOVIBbNwgnjN6mqtuWzFiPL+NXQExq40 +I3whM+4lEiwSHaV+MYxWanMdhc+kImT50LKfkxcdAgMBAAGjggEfMIIBGzAdBgNV +HQ4EFgQUB63oQR1/vda/G4F6P4xLiN4E0vowgesGA1UdIwSB4zCB4IAUB63oQR1/ +vda/G4F6P4xLiN4E0vqhgcSkgcEwgb4xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdJ +bmRpYW5hMRUwEwYDVQQHEwxJbmRpYW5hcG9saXMxKDAmBgNVBAoTH1NvZnR3YXJl +IGluIHRoZSBQdWJsaWMgSW50ZXJlc3QxEzARBgNVBAsTCmhvc3RtYXN0ZXIxIDAe +BgNVBAMTF0NlcnRpZmljYXRpb24gQXV0aG9yaXR5MSUwIwYJKoZIhvcNAQkBFhZo +b3N0bWFzdGVyQHNwaS1pbmMub3JnggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcN +AQEEBQADgYEAm/Abn8c2y1nO3fgpAIslxvi9iNBZDhQtJ0VQZY6wgSfANyDOR4DW +iexO/AlorB49KnkFS7TjCAoLOZhcg5FaNiKnlstMI5krQmau1Qnb/vGSNsE/UGms +1ts+QYPUs0KmGEAFUri2XzLy+aQo9Kw74VBvqnxvaaMeY5yMcKNOieY= +-----END CERTIFICATE----- diff --git a/gcr/tests/test-data/cacert.org.pem b/gcr/tests/test-data/cacert.org.pem new file mode 100644 index 00000000..e7dfc829 --- /dev/null +++ b/gcr/tests/test-data/cacert.org.pem @@ -0,0 +1,41 @@ +-----BEGIN CERTIFICATE----- +MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290 +IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB +IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA +Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO +BgNVBAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEi +MCAGA1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJ +ARYSc3VwcG9ydEBjYWNlcnQub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC +CgKCAgEAziLA4kZ97DYoB1CW8qAzQIxL8TtmPzHlawI229Z89vGIj053NgVBlfkJ +8BLPRoZzYLdufujAWGSuzbCtRRcMY/pnCujW0r8+55jE8Ez64AO7NV1sId6eINm6 +zWYyN3L69wj1x81YyY7nDl7qPv4coRQKFWyGhFtkZip6qUtTefWIonvuLwphK42y +fk1WpRPs6tqSnqxEQR5YYGUFZvjARL3LlPdCfgv3ZWiYUQXw8wWRBB0bF4LsyFe7 +w2t6iPGwcswlWyCR7BYCEo8y6RcYSNDHBS4CMEK4JZwFaz+qOqfrU0j36NK2B5jc +G8Y0f3/JHIJ6BVgrCFvzOKKrF11myZjXnhCLotLddJr3cQxyYN/Nb5gznZY0dj4k +epKwDpUeb+agRThHqtdB7Uq3EvbXG4OKDy7YCbZZ16oE/9KTfWgu3YtLq1i6L43q +laegw1SJpfvbi1EinbLDvhG+LJGGi5Z4rSDTii8aP8bQUWWHIbEZAWV/RRyH9XzQ +QUxPKZgh/TMfdQwEUfoZd9vUFBzugcMd9Zi3aQaRIt0AUMyBMawSB3s42mhb5ivU +fslfrejrckzzAeVLIL+aplfKkQABi6F1ITe1Yw1nPkZPcCBnzsXWWdsC4PDSy826 +YreQQejdIOQpvGQpQsgi3Hia/0PsmBsJUUtaWsJx8cTLc6nloQsCAwEAAaOCAc4w +ggHKMB0GA1UdDgQWBBQWtTIb1Mfz4OaO873SsDrusjkY0TCBowYDVR0jBIGbMIGY +gBQWtTIb1Mfz4OaO873SsDrusjkY0aF9pHsweTEQMA4GA1UEChMHUm9vdCBDQTEe +MBwGA1UECxMVaHR0cDovL3d3dy5jYWNlcnQub3JnMSIwIAYDVQQDExlDQSBDZXJ0 +IFNpZ25pbmcgQXV0aG9yaXR5MSEwHwYJKoZIhvcNAQkBFhJzdXBwb3J0QGNhY2Vy +dC5vcmeCAQAwDwYDVR0TAQH/BAUwAwEB/zAyBgNVHR8EKzApMCegJaAjhiFodHRw +czovL3d3dy5jYWNlcnQub3JnL3Jldm9rZS5jcmwwMAYJYIZIAYb4QgEEBCMWIWh0 +dHBzOi8vd3d3LmNhY2VydC5vcmcvcmV2b2tlLmNybDA0BglghkgBhvhCAQgEJxYl +aHR0cDovL3d3dy5jYWNlcnQub3JnL2luZGV4LnBocD9pZD0xMDBWBglghkgBhvhC +AQ0ESRZHVG8gZ2V0IHlvdXIgb3duIGNlcnRpZmljYXRlIGZvciBGUkVFIGhlYWQg +b3ZlciB0byBodHRwOi8vd3d3LmNhY2VydC5vcmcwDQYJKoZIhvcNAQEEBQADggIB +ACjH7pyCArpcgBLKNQodgW+JapnM8mgPf6fhjViVPr3yBsOQWqy1YPaZQwGjiHCc +nWKdpIevZ1gNMDY75q1I08t0AoZxPuIrA2jxNGJARjtT6ij0rPtmlVOKTV39O9lg +18p5aTuxZZKmxoGCXJzN600BiqXfEVWqFcofN8CCmHBh22p8lqOOLlQ+TyGpkO/c +gr/c6EWtTZBzCDyUZbAEmXZ/4rzCahWqlwQ3JNgelE5tDlG+1sSPypZt90Pf6DBl +Jzt7u0NDY8RD97LsaMzhGY4i+5jhe1o+ATc7iwiwovOVThrLm82asduycPAtStvY +sONvRUgzEv/+PDIqVPfE94rwiCPCR/5kenHA0R6mY7AHfqQv0wGP3J8rtsYIqQ+T +SCX8Ev2fQtzzxD72V7DX3WnRBnc0CkvSyqD/HMaMyRa+xMwyN2hzXwj7UfdJUzYF +CpUCTPJ5GhD22Dp1nPMd8aINcGeGG7MW9S/lpOt5hvk9C8JzC6WZrG/8Z7jlLwum +GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk +zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW +omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD +-----END CERTIFICATE----- diff --git a/gcr/tests/test-data/der-certificate.crt b/gcr/tests/test-data/der-certificate.crt Binary files differnew file mode 100644 index 00000000..56fa8491 --- /dev/null +++ b/gcr/tests/test-data/der-certificate.crt diff --git a/gcr/tests/test-data/der-dsa-1024.key b/gcr/tests/test-data/der-dsa-1024.key Binary files differnew file mode 100644 index 00000000..61af5251 --- /dev/null +++ b/gcr/tests/test-data/der-dsa-1024.key diff --git a/gcr/tests/test-data/der-pkcs8-PBE-MD5-DES.key b/gcr/tests/test-data/der-pkcs8-PBE-MD5-DES.key Binary files differnew file mode 100644 index 00000000..71b7d61b --- /dev/null +++ b/gcr/tests/test-data/der-pkcs8-PBE-MD5-DES.key diff --git a/gcr/tests/test-data/der-pkcs8-PBE-SHA1-3DES.key b/gcr/tests/test-data/der-pkcs8-PBE-SHA1-3DES.key Binary files differnew file mode 100644 index 00000000..1c37fe10 --- /dev/null +++ b/gcr/tests/test-data/der-pkcs8-PBE-SHA1-3DES.key diff --git a/gcr/tests/test-data/der-pkcs8-PBE-SHA1-DES.key b/gcr/tests/test-data/der-pkcs8-PBE-SHA1-DES.key Binary files differnew file mode 100644 index 00000000..99896139 --- /dev/null +++ b/gcr/tests/test-data/der-pkcs8-PBE-SHA1-DES.key diff --git a/gcr/tests/test-data/der-pkcs8-PBE-SHA1-RC2-40.key b/gcr/tests/test-data/der-pkcs8-PBE-SHA1-RC2-40.key Binary files differnew file mode 100644 index 00000000..820926cc --- /dev/null +++ b/gcr/tests/test-data/der-pkcs8-PBE-SHA1-RC2-40.key diff --git a/gcr/tests/test-data/der-pkcs8-PBE-SHA1-RC4-128.key b/gcr/tests/test-data/der-pkcs8-PBE-SHA1-RC4-128.key Binary files differnew file mode 100644 index 00000000..2888450c --- /dev/null +++ b/gcr/tests/test-data/der-pkcs8-PBE-SHA1-RC4-128.key diff --git a/gcr/tests/test-data/der-pkcs8-dsa.key b/gcr/tests/test-data/der-pkcs8-dsa.key Binary files differnew file mode 100644 index 00000000..8b61684e --- /dev/null +++ b/gcr/tests/test-data/der-pkcs8-dsa.key diff --git a/gcr/tests/test-data/der-pkcs8-encrypted-pkcs5.key b/gcr/tests/test-data/der-pkcs8-encrypted-pkcs5.key Binary files differnew file mode 100644 index 00000000..68c6b4a5 --- /dev/null +++ b/gcr/tests/test-data/der-pkcs8-encrypted-pkcs5.key diff --git a/gcr/tests/test-data/der-pkcs8-v2-des.key b/gcr/tests/test-data/der-pkcs8-v2-des.key Binary files differnew file mode 100644 index 00000000..4cd80348 --- /dev/null +++ b/gcr/tests/test-data/der-pkcs8-v2-des.key diff --git a/gcr/tests/test-data/der-pkcs8-v2-des3.key b/gcr/tests/test-data/der-pkcs8-v2-des3.key Binary files differnew file mode 100644 index 00000000..9e2999c8 --- /dev/null +++ b/gcr/tests/test-data/der-pkcs8-v2-des3.key diff --git a/gcr/tests/test-data/der-pkcs8.key b/gcr/tests/test-data/der-pkcs8.key Binary files differnew file mode 100644 index 00000000..16505632 --- /dev/null +++ b/gcr/tests/test-data/der-pkcs8.key diff --git a/gcr/tests/test-data/der-rsa-1024.key b/gcr/tests/test-data/der-rsa-1024.key Binary files differnew file mode 100644 index 00000000..878fda5b --- /dev/null +++ b/gcr/tests/test-data/der-rsa-1024.key diff --git a/gcr/tests/test-data/email.p12 b/gcr/tests/test-data/email.p12 Binary files differnew file mode 100644 index 00000000..d45d0f8d --- /dev/null +++ b/gcr/tests/test-data/email.p12 diff --git a/gcr/tests/test-data/pem-dsa-1024.key b/gcr/tests/test-data/pem-dsa-1024.key new file mode 100644 index 00000000..ccb1e7b9 --- /dev/null +++ b/gcr/tests/test-data/pem-dsa-1024.key @@ -0,0 +1,12 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBuwIBAAKBgQCQ7Atgc1g5x1Tq+PZLsD/DU5jWl3K/rlQAed6i06Yfr/snYwoD +igGj0M1ioQdFpXSifstGL08IhbecYbvpVKYKKWaK1Uu6XAenL9ixEFJJZwsznfLF +nmSkcGTvzwtyNsXHLNVc6zKRdDC+yaAD1OSE+6qE15Vxs41rWslbtz4/ewIVAPoh +ShOFwhv+uq2rJAokMMYH1WJxAoGALeBXUfXa7pfz1DxUWVo+lKCAco8MZsmK6+1X +YvarFVgC2DWerR3h7DakWfvu6kjlm55qjLT1KVk2s8yIGl2VfHM5F14s/+DzDTcR +5DDbZkjC60dKoQpKMpdFBTH/LHxpUSIMnURra2sPACYuHr6zzIYUdqpRjMVVyav5 +5fOQI/wCgYBUc0RR23nU7t8LvOvUO7bLt7hYRgO5VwgAdd0xjrWwJm1LINxe/zdr +38TqKYOx9/AqOe1MYZ7WhxJyn/87fGlq3RttdI9WpLS+xcQ4XlKEI6O4iuZebVUA ++Xg556SGJVmCGJw7T6jZQzjHbw5cr8mjCh7XKLufIJHVlOMlCgnqAAIVAIdvhPcJ +1REI37DL+h8cVpwJxBPs +-----END DSA PRIVATE KEY----- diff --git a/gcr/tests/test-data/pem-pkcs8.key b/gcr/tests/test-data/pem-pkcs8.key new file mode 100644 index 00000000..1f0d5edb --- /dev/null +++ b/gcr/tests/test-data/pem-pkcs8.key @@ -0,0 +1,17 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIf4lXzcHXqAICAggA +MBQGCCqGSIb3DQMHBAhV8iKHmoUJDQSCAoDK4fY/dfIzOof1QlYV8mhr0OmhaIAe +aaDz4rER6+OGwq7WQ32ErmHBiJRI8oQRrxy4oHTXx8TR+JxQT1io9V9jjXZCS8HT +Ek0J69pgjPdIUnlZYV1GdJUJq7tWxTKJJFr1tsB0XzgugQLYcui4ikrZ6rHE9PVh +SXFIEbns42xHIvtQ/j3c6ScS63UNpSsKe5pWRNgHUHpjSGPAaZogOdMfStmj3tdN +nIH3mjIM8uisN9nyPV42aziZi5mO9F5JHlNp1H5pDAUWOKkKoXw27MgXnxvSkLAX +HSgpPuK5ejqXu4nkciwHnr4eULV0biwqpmYEWxC4aNuog/t3DoL1gkC74J07jjUU +3gZwxjKsAWfIKnNURsHlBAcYClug5ZWs9ru/4sc27bNV9qRKbHcgGD+nzfTXxZZ2 +BG5eSBVpYT2Jzdkpw8puSHwNW5mQcuY4E+ZEERFsW8q1raPSgYVk5rM8TiVdTD5x +UwQG7ADidVSVTR5KGV8wmonbuDu9b61GgU7VBslEK9Lsd92FO0/u09FF6DgCcICD +yRJ0nM0o9S9FI1lqKoxAdgWyFwrKkBVZ05IDHw+jS6r7D/2irYetPJmVO/dvi87r +aaLvyvzU3nz4LiWHmSl2AgDanjDcxtjGoWR2cc+J0v3r/+VEOctrc5EuAnlhl9Yj +kFcfZDfqthCNb49qNGDgQMGrKTt+Dvrka/ZZxXBN3v96L3K4O32j9c97sZ8LEFaI +RHl91Mx2okjrT9q2+Gef2UR9XEzuFEBRBqxktltlrIQIncn6Xx/TjEvIhf2Dgo4W +isaAwTazyZrzATTWR1JS6Hdm7Eb/nCEHAFmVUbQm0d5BDfKmnRsNaaZK +-----END ENCRYPTED PRIVATE KEY----- diff --git a/gcr/tests/test-data/pem-rsa-enc.key b/gcr/tests/test-data/pem-rsa-enc.key new file mode 100644 index 00000000..65439fe6 --- /dev/null +++ b/gcr/tests/test-data/pem-rsa-enc.key @@ -0,0 +1,18 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,24522D4CE5F5CD7B + +2H/8j0HYUya7LWEUxpgjp/LVcCX7yZB7SoREdoJdcqJEBUMWVxU/2OfVB8EZupmy +7YHcnn5v1JwwtmAXAtqM9JGlvNWaRr1m4zDrhJn1fY3tu8YGtMR49IOZmOUBK+X+ +IxWAwaFDqLntuGZZnAmRJtgFVYVABEs5yM9zgoCGDaU4WMK3caD7Jnw8jH5m0nqQ +XiQ1y1dHxFJmAgG0b5h2z7zjQTmmXd3IhXqSqsE/9ryruCCYa0Z7aAN5oAmO89I9 +gOyy3J4h76mTNFfF5btV4Jllwd4LkgGOmm69UxAyUTGzwYJ5gxgB3xFzGBwpVlcu +72PrQCrjZqZ6rj6cTPGUYzcyMtEw3Xd6mFhApqJpVRZwNWUAMMJwHl2oWwKcIxfV +y+OftRX6kc+cunrxCkl9aKuHDoJPEq+/Uh+AEXqir+942Vull0WPyuWUjaPKR1xJ +poYsNfHRWq+klKCggQQL6jwuVbDLhbaXfgaNBQO1XMracgfmnO1PQPw8JSQ5iOkm +Ybt2oHAEnrEWxZGn1PfRq6Z8HAbBlQpfmG7SMJZdQjlndKA6GR+tN5krKfpj6uak +0eklm0Nb0YcDzJ3qqHXxIimK3Kh/WRZ1hVTnX4mS9u3HNQMo5Ov6z8OQN+Q45ffi +ZDFkVwUTEJ+iwmCG7XnxX0v8Bv5LZmAnPu95KQTp4Ds0AZ6Sp+RqxvhnCO25cgWj ++N5jHGzsDk9/Jw7rAHz8pnl3sziNBWdAk5ASPA28HCQQo5peWnWajM3Pk98+/wHY +blTh7gw77gTake6hpiegnhNUXwGm6BXEqmyu7mPW0z5XFRb9W7bpog== +-----END RSA PRIVATE KEY----- diff --git a/gcr/tests/test-data/test-x509-swiss.p7b b/gcr/tests/test-data/test-x509-swiss.p7b Binary files differnew file mode 100755 index 00000000..d45b9e0e --- /dev/null +++ b/gcr/tests/test-data/test-x509-swiss.p7b diff --git a/gcr/tests/test-data/unclient.p12 b/gcr/tests/test-data/unclient.p12 Binary files differnew file mode 100644 index 00000000..321b4475 --- /dev/null +++ b/gcr/tests/test-data/unclient.p12 diff --git a/gcr/tests/unit-test-parser.c b/gcr/tests/unit-test-parser.c new file mode 100644 index 00000000..53af5c12 --- /dev/null +++ b/gcr/tests/unit-test-parser.c @@ -0,0 +1,136 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* unit-test-pkix-parser.c: Test PKIX parser + + Copyright (C) 2007 Stefan Walter + + The Gnome Keyring Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Gnome Keyring Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Gnome Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Stef Walter <stef@memberwebs.com> +*/ + +#include "config.h" + +#include "run-auto-test.h" + +#include "egg/egg-secure-memory.h" + +#include "gcr/gcr-parser.h" + +#include <glib.h> +#include <gcrypt.h> +#include <libtasn1.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +/* + * Each test looks like (on one line): + * void unit_test_xxxxx (CuTest* cu) + * + * Each setup looks like (on one line): + * void unit_setup_xxxxx (void); + * + * Each teardown looks like (on one line): + * void unit_teardown_xxxxx (void); + * + * Tests be run in the order specified here. + */ + +static GcrParser *parser = NULL; +static const gchar* filedesc = NULL; + +static void +parsed_item (GcrParser *par, gpointer user_data) +{ + GP11Attributes *attrs; + const gchar *description; + const gchar *label; + + g_assert (GCR_IS_PARSER (par)); + g_assert (par == parser); + g_assert (par == user_data); + + attrs = gcr_parser_get_parsed_attributes (parser); + description = gcr_parser_get_parsed_description (parser); + label = gcr_parser_get_parsed_label (parser); + + g_print ("parsed %s '%s' at: %s\n", description, label, filedesc); +} + +static gboolean +authenticate (GcrParser *par, gint state, gpointer user_data) +{ + g_assert (GCR_IS_PARSER (par)); + g_assert (par == parser); + g_assert (par == user_data); + + switch (state) { + case 0: + gcr_parser_add_password (parser, "booo"); + return TRUE; + default: + g_printerr ("decryption didn't work for: %s", filedesc); + g_assert (FALSE); + }; +} + +DEFINE_SETUP(parser) +{ + parser = gcr_parser_new (); + g_signal_connect (parser, "parsed", G_CALLBACK (parsed_item), parser); + g_signal_connect (parser, "authenticate", G_CALLBACK (authenticate), parser); +} + +DEFINE_TEARDOWN(parser) +{ + g_object_unref (parser); + parser = NULL; +} + +DEFINE_TEST(parse_all) +{ + guchar *contents; + GError *err = NULL; + gboolean result; + const gchar *filename; + gsize len; + GDir *dir; + + dir = g_dir_open ("test-data", 0, NULL); + g_assert (dir); + + for (;;) { + filename = g_dir_read_name (dir); + if (!filename) + break; + if (filename[0] == '.') + continue; + + filedesc = filename; + contents = test_read_testdata (filename, &len); + + result = gcr_parser_parse_data (parser, contents, len, &err); + if (!result) { + g_warning ("couldn't parse file data: %s: %s", + filename, err && err->message ? err->message : ""); + g_error_free (err); + g_assert (FALSE); + } + } + + g_dir_close (dir); +} diff --git a/gp11/gp11.h b/gp11/gp11.h index 65638ddd..eed9601c 100644 --- a/gp11/gp11.h +++ b/gp11/gp11.h @@ -21,8 +21,8 @@ Author: Stef Walter <nielsen@memberwebs.com> */ -#ifndef GP11_H_ -#define GP11_H_ +#ifndef GP11_H +#define GP11_H #include <glib.h> #include <glib-object.h> @@ -1431,4 +1431,4 @@ guchar* gp11_processor_close_finish (GP11Processor *proce G_END_DECLS -#endif /*GP11_H_*/ +#endif /*GP11_H*/ diff --git a/pkcs11/gck/Makefile.am b/pkcs11/gck/Makefile.am index 0fc9bc3c..8b1d8103 100644 --- a/pkcs11/gck/Makefile.am +++ b/pkcs11/gck/Makefile.am @@ -24,8 +24,6 @@ libgck_la_SOURCES = \ gck-data-asn1.c gck-data-asn1.h \ gck-data-der.c gck-data-der.h \ gck-data-file.c gck-data-file.h \ - gck-data-openssl.c gck-data-openssl.h \ - gck-data-pem.c gck-data-pem.h \ gck-data-types.h \ gck-factory.c gck-factory.h \ gck-file-tracker.c gck-file-tracker.h \ diff --git a/pkcs11/gck/gck-crypto.c b/pkcs11/gck/gck-crypto.c index 2e1af6ea..7a0d76e9 100644 --- a/pkcs11/gck/gck-crypto.c +++ b/pkcs11/gck/gck-crypto.c @@ -977,520 +977,6 @@ gck_crypto_rsa_unpad_two (guint bits, const guchar *padded, return unpad_rsa_pkcs1 (0x02, bits, padded, n_padded, n_raw); } -/* ----------------------------------------------------------------------------- - * PASSWORD TO KEY/IV - */ - -gboolean -gck_crypto_symkey_generate_simple (int cipher_algo, int hash_algo, - const gchar *password, gssize n_password, - const guchar *salt, gsize n_salt, int iterations, - guchar **key, guchar **iv) -{ - gcry_md_hd_t mdh; - gcry_error_t gcry; - guchar *digest; - guchar *digested; - guint n_digest; - gint pass, i; - gint needed_iv, needed_key; - guchar *at_iv, *at_key; - - g_assert (cipher_algo); - g_assert (hash_algo); - - g_return_val_if_fail (iterations >= 1, FALSE); - - if (!password) - n_password = 0; - if (n_password == -1) - n_password = strlen (password); - - /* - * If cipher algo needs more bytes than hash algo has available - * then the entire hashing process is done again (with the previous - * hash bytes as extra input), and so on until satisfied. - */ - - needed_key = gcry_cipher_get_algo_keylen (cipher_algo); - needed_iv = gcry_cipher_get_algo_blklen (cipher_algo); - - gcry = gcry_md_open (&mdh, hash_algo, 0); - if (gcry) { - g_warning ("couldn't create '%s' hash context: %s", - gcry_md_algo_name (hash_algo), gcry_strerror (gcry)); - return FALSE; - } - - n_digest = gcry_md_get_algo_dlen (hash_algo); - g_return_val_if_fail (n_digest > 0, FALSE); - - digest = gcry_calloc_secure (n_digest, 1); - g_return_val_if_fail (digest, FALSE); - if (key) { - *key = gcry_calloc_secure (needed_key, 1); - g_return_val_if_fail (*key, FALSE); - } - if (iv) - *iv = g_new0 (guchar, needed_iv); - - at_key = key ? *key : NULL; - at_iv = iv ? *iv : NULL; - - for (pass = 0; TRUE; ++pass) { - gcry_md_reset (mdh); - - /* Hash in the previous buffer on later passes */ - if (pass > 0) - gcry_md_write (mdh, digest, n_digest); - - if (password) - gcry_md_write (mdh, password, n_password); - if (salt && n_salt) - gcry_md_write (mdh, salt, n_salt); - gcry_md_final (mdh); - digested = gcry_md_read (mdh, 0); - g_return_val_if_fail (digested, FALSE); - memcpy (digest, digested, n_digest); - - for (i = 1; i < iterations; ++i) { - gcry_md_reset (mdh); - gcry_md_write (mdh, digest, n_digest); - gcry_md_final (mdh); - digested = gcry_md_read (mdh, 0); - g_return_val_if_fail (digested, FALSE); - memcpy (digest, digested, n_digest); - } - - /* Copy as much as possible into the destinations */ - i = 0; - while (needed_key && i < n_digest) { - if (at_key) - *(at_key++) = digest[i]; - needed_key--; - i++; - } - while (needed_iv && i < n_digest) { - if (at_iv) - *(at_iv++) = digest[i]; - needed_iv--; - i++; - } - - if (needed_key == 0 && needed_iv == 0) - break; - } - - gcry_free (digest); - gcry_md_close (mdh); - - return TRUE; -} - -gboolean -gck_crypto_symkey_generate_pbe (int cipher_algo, int hash_algo, const gchar *password, - gssize n_password, const guchar *salt, gsize n_salt, int iterations, - guchar **key, guchar **iv) -{ - gcry_md_hd_t mdh; - gcry_error_t gcry; - guchar *digest; - guchar *digested; - guint i, n_digest; - gint needed_iv, needed_key; - - g_assert (cipher_algo); - g_assert (hash_algo); - - g_return_val_if_fail (iterations >= 1, FALSE); - - if (!password) - n_password = 0; - if (n_password == -1) - n_password = strlen (password); - - /* - * We only do one pass here. - * - * The key ends up as the first needed_key bytes of the hash buffer. - * The iv ends up as the last needed_iv bytes of the hash buffer. - * - * The IV may overlap the key (which is stupid) if the wrong pair of - * hash/cipher algorithms are chosen. - */ - - n_digest = gcry_md_get_algo_dlen (hash_algo); - g_return_val_if_fail (n_digest > 0, FALSE); - - needed_key = gcry_cipher_get_algo_keylen (cipher_algo); - needed_iv = gcry_cipher_get_algo_blklen (cipher_algo); - if (needed_iv + needed_key > 16 || needed_iv + needed_key > n_digest) { - g_warning ("using PBE symkey generation with %s using an algorithm that needs " - "too many bytes of key and/or IV: %s", - gcry_cipher_algo_name (hash_algo), - gcry_cipher_algo_name (cipher_algo)); - return FALSE; - } - - gcry = gcry_md_open (&mdh, hash_algo, 0); - if (gcry) { - g_warning ("couldn't create '%s' hash context: %s", - gcry_md_algo_name (hash_algo), gcry_strerror (gcry)); - return FALSE; - } - - digest = gcry_calloc_secure (n_digest, 1); - g_return_val_if_fail (digest, FALSE); - if (key) { - *key = gcry_calloc_secure (needed_key, 1); - g_return_val_if_fail (*key, FALSE); - } - if (iv) - *iv = g_new0 (guchar, needed_iv); - - if (password) - gcry_md_write (mdh, password, n_password); - if (salt && n_salt) - gcry_md_write (mdh, salt, n_salt); - gcry_md_final (mdh); - digested = gcry_md_read (mdh, 0); - g_return_val_if_fail (digested, FALSE); - memcpy (digest, digested, n_digest); - - for (i = 1; i < iterations; ++i) - gcry_md_hash_buffer (hash_algo, digest, digest, n_digest); - - /* The first x bytes are the key */ - if (key) { - g_assert (needed_key <= n_digest); - memcpy (*key, digest, needed_key); - } - - /* The last 16 - x bytes are the iv */ - if (iv) { - g_assert (needed_iv <= n_digest && n_digest >= 16); - memcpy (*iv, digest + (16 - needed_iv), needed_iv); - } - - gcry_free (digest); - gcry_md_close (mdh); - - return TRUE; -} - -static gboolean -generate_pkcs12 (int hash_algo, int type, const gchar *utf8_password, - gssize n_password, const guchar *salt, gsize n_salt, - int iterations, guchar *output, gsize n_output) -{ - gcry_mpi_t num_b1, num_ij; - guchar *hash, *buf_i, *buf_b; - const gchar *end_password; - gcry_md_hd_t mdh; - const gchar *p2; - guchar *p; - gsize n_hash, i; - gunichar unich; - gcry_error_t gcry; - - num_b1 = num_ij = NULL; - - n_hash = gcry_md_get_algo_dlen (hash_algo); - g_return_val_if_fail (n_hash > 0, FALSE); - - if (!utf8_password) - n_password = 0; - if (n_password == -1) - end_password = utf8_password + strlen (utf8_password); - else - end_password = utf8_password + n_password; - - gcry = gcry_md_open (&mdh, hash_algo, 0); - if (gcry) { - g_warning ("couldn't create '%s' hash context: %s", - gcry_md_algo_name (hash_algo), gcry_strerror (gcry)); - return FALSE; - } - - /* Reqisition me a buffer */ - hash = gcry_calloc_secure (n_hash, 1); - buf_i = gcry_calloc_secure (1, 128); - buf_b = gcry_calloc_secure (1, 64); - g_return_val_if_fail (hash && buf_i && buf_b, FALSE); - - /* Bring in the salt */ - p = buf_i; - if (salt) { - for (i = 0; i < 64; ++i) - *(p++) = salt[i % n_salt]; - } else { - memset (p, 0, 64); - p += 64; - } - - /* Bring in the password, as 16bits per character BMP string, ie: UCS2 */ - if (utf8_password) { - p2 = utf8_password; - for (i = 0; i < 64; i += 2) { - - /* Get a character from the string */ - if (p2 < end_password) { - unich = g_utf8_get_char (p2); - p2 = g_utf8_next_char (p2); - - /* Get zero null terminator, and loop back to beginning */ - } else { - unich = 0; - p2 = utf8_password; - } - - /* Encode the bytes received */ - *(p++) = (unich & 0xFF00) >> 8; - *(p++) = (unich & 0xFF); - } - } else { - memset (p, 0, 64); - p += 64; - } - - /* Hash and bash */ - for (;;) { - gcry_md_reset (mdh); - - /* Put in the PKCS#12 type of key */ - for (i = 0; i < 64; ++i) - gcry_md_putc (mdh, type); - - /* Bring in the password */ - gcry_md_write (mdh, buf_i, utf8_password ? 128 : 64); - - /* First iteration done */ - memcpy (hash, gcry_md_read (mdh, hash_algo), n_hash); - - /* All the other iterations */ - for (i = 1; i < iterations; i++) - gcry_md_hash_buffer (hash_algo, hash, hash, n_hash); - - /* Take out as much as we need */ - for (i = 0; i < n_hash && n_output; ++i) { - *(output++) = hash[i]; - --n_output; - } - - /* Is that enough generated keying material? */ - if (!n_output) - break; - - /* Need more bytes, do some voodoo */ - for (i = 0; i < 64; ++i) - buf_b[i] = hash[i % n_hash]; - gcry = gcry_mpi_scan (&num_b1, GCRYMPI_FMT_USG, buf_b, 64, NULL); - g_return_val_if_fail (gcry == 0, FALSE); - gcry_mpi_add_ui (num_b1, num_b1, 1); - for (i = 0; i < 128; i += 64) { - gcry = gcry_mpi_scan (&num_ij, GCRYMPI_FMT_USG, buf_i + i, 64, NULL); - g_return_val_if_fail (gcry == 0, FALSE); - gcry_mpi_add (num_ij, num_ij, num_b1); - gcry_mpi_clear_highbit (num_ij, 64 * 8); - gcry = gcry_mpi_print (GCRYMPI_FMT_USG, buf_i + i, 64, NULL, num_ij); - g_return_val_if_fail (gcry == 0, FALSE); - gcry_mpi_release (num_ij); - } - } - - gcry_free (buf_i); - gcry_free (buf_b); - gcry_free (hash); - gcry_mpi_release (num_b1); - gcry_md_close (mdh); - - return TRUE; -} - -gboolean -gck_crypto_symkey_generate_pkcs12 (int cipher_algo, int hash_algo, const gchar *password, - gssize n_password, const guchar *salt, gsize n_salt, - int iterations, guchar **key, guchar **iv) -{ - gsize n_block, n_key; - gboolean ret = TRUE; - - g_return_val_if_fail (cipher_algo, FALSE); - g_return_val_if_fail (hash_algo, FALSE); - g_return_val_if_fail (iterations > 0, FALSE); - - n_key = gcry_cipher_get_algo_keylen (cipher_algo); - n_block = gcry_cipher_get_algo_blklen (cipher_algo); - - if (password && !g_utf8_validate (password, n_password, NULL)) { - g_warning ("invalid non-UTF8 password"); - g_return_val_if_reached (FALSE); - } - - if (key) - *key = NULL; - if (iv) - *iv = NULL; - - /* Generate us an key */ - if (key) { - *key = gcry_calloc_secure (n_key, 1); - g_return_val_if_fail (*key != NULL, FALSE); - ret = generate_pkcs12 (hash_algo, 1, password, n_password, salt, n_salt, - iterations, *key, n_key); - } - - /* Generate us an iv */ - if (ret && iv) { - if (n_block > 1) { - *iv = g_malloc (n_block); - ret = generate_pkcs12 (hash_algo, 2, password, n_password, salt, n_salt, - iterations, *iv, n_block); - } else { - *iv = NULL; - } - } - - /* Cleanup in case of failure */ - if (!ret) { - g_free (iv ? *iv : NULL); - gcry_free (key ? *key : NULL); - } - - return ret; -} - -static gboolean -generate_pbkdf2 (int hash_algo, const gchar *password, gsize n_password, - const guchar *salt, gsize n_salt, guint iterations, - guchar *output, gsize n_output) -{ - gcry_md_hd_t mdh; - guint u, l, r, i, k; - gcry_error_t gcry; - guchar *U, *T, *buf; - gsize n_buf, n_hash; - - g_return_val_if_fail (hash_algo > 0, FALSE); - g_return_val_if_fail (iterations > 0, FALSE); - g_return_val_if_fail (n_output > 0, FALSE); - g_return_val_if_fail (n_output < G_MAXUINT32, FALSE); - - n_hash = gcry_md_get_algo_dlen (hash_algo); - g_return_val_if_fail (n_hash > 0, FALSE); - - gcry = gcry_md_open (&mdh, hash_algo, GCRY_MD_FLAG_HMAC); - if (gcry != 0) { - g_warning ("couldn't create '%s' hash context: %s", - gcry_md_algo_name (hash_algo), gcry_strerror (gcry)); - return FALSE; - } - - /* Get us a temporary buffers */ - T = gcry_calloc_secure (n_hash, 1); - U = gcry_calloc_secure (n_hash, 1); - n_buf = n_salt + 4; - buf = gcry_calloc_secure (n_buf, 1); - g_return_val_if_fail (buf && T && U, FALSE); - - /* n_hash blocks in output, rounding up */ - l = ((n_output - 1) / n_hash) + 1; - - /* number of bytes in last, rounded up, n_hash block */ - r = n_output - (l - 1) * n_hash; - - memcpy (buf, salt, n_salt); - for (i = 1; i <= l; i++) { - memset (T, 0, n_hash); - for (u = 1; u <= iterations; u++) { - gcry_md_reset (mdh); - - gcry = gcry_md_setkey (mdh, password, n_password); - g_return_val_if_fail (gcry == 0, FALSE); - - /* For first iteration on each block add 4 extra bytes */ - if (u == 1) { - buf[n_salt + 0] = (i & 0xff000000) >> 24; - buf[n_salt + 1] = (i & 0x00ff0000) >> 16; - buf[n_salt + 2] = (i & 0x0000ff00) >> 8; - buf[n_salt + 3] = (i & 0x000000ff) >> 0; - - gcry_md_write (mdh, buf, n_buf); - - /* Other iterations, any block */ - } else { - gcry_md_write (mdh, U, n_hash); - } - - memcpy (U, gcry_md_read (mdh, hash_algo), n_hash); - - for (k = 0; k < n_hash; k++) - T[k] ^= U[k]; - } - - memcpy (output + (i - 1) * n_hash, T, i == l ? r : n_hash); - } - - gcry_free (T); - gcry_free (U); - gcry_free (buf); - gcry_md_close (mdh); - return TRUE; -} - -gboolean -gck_crypto_symkey_generate_pbkdf2 (int cipher_algo, int hash_algo, - const gchar *password, gssize n_password, - const guchar *salt, gsize n_salt, int iterations, - guchar **key, guchar **iv) -{ - gsize n_key, n_block; - gboolean ret = TRUE; - - g_return_val_if_fail (hash_algo, FALSE); - g_return_val_if_fail (cipher_algo, FALSE); - g_return_val_if_fail (iterations > 0, FALSE); - - n_key = gcry_cipher_get_algo_keylen (cipher_algo); - n_block = gcry_cipher_get_algo_blklen (cipher_algo); - - if (key) - *key = NULL; - if (iv) - *iv = NULL; - - if (!password) - n_password = 0; - if (n_password == -1) - n_password = strlen (password); - - /* Generate us an key */ - if (key) { - *key = gcry_calloc_secure (n_key, 1); - g_return_val_if_fail (*key != NULL, FALSE); - ret = generate_pbkdf2 (hash_algo, password, n_password, salt, n_salt, - iterations, *key, n_key); - } - - /* Generate us an iv */ - if (ret && iv) { - if (n_block > 1) { - *iv = g_malloc (n_block); - gcry_create_nonce (*iv, n_block); - } else { - *iv = NULL; - } - } - - /* Cleanup in case of failure */ - if (!ret) { - g_free (iv ? *iv : NULL); - gcry_free (key ? *key : NULL); - } - - return ret; -} - /* -------------------------------------------------------------------------- * INITIALIZATION */ diff --git a/pkcs11/gck/gck-crypto.h b/pkcs11/gck/gck-crypto.h index b7714b69..623b5448 100644 --- a/pkcs11/gck/gck-crypto.h +++ b/pkcs11/gck/gck-crypto.h @@ -159,44 +159,4 @@ guchar* gck_crypto_rsa_unpad_two (guint bi gsize n_padded, gsize *n_raw); -gboolean gck_crypto_symkey_generate_simple (int cipher_algo, - int hash_algo, - const gchar *password, - gssize n_password, - const guchar *salt, - gsize n_salt, - int iterations, - guchar **key, - guchar **iv); - -gboolean gck_crypto_symkey_generate_pbe (int cipher_algo, - int hash_algo, - const gchar *password, - gssize n_password, - const guchar *salt, - gsize n_salt, - int iterations, - guchar **key, - guchar **iv); - -gboolean gck_crypto_symkey_generate_pkcs12 (int cipher_algo, - int hash_algo, - const gchar *password, - gssize n_password, - const guchar *salt, - gsize n_salt, - int iterations, - guchar **key, - guchar **iv); - -gboolean gck_crypto_symkey_generate_pbkdf2 (int cipher_algo, - int hash_algo, - const gchar *password, - gssize n_password, - const guchar *salt, - gsize n_salt, - int iterations, - guchar **key, - guchar **iv); - #endif /* GCKCRYPTO_H_ */ diff --git a/pkcs11/gck/gck-data-der.c b/pkcs11/gck/gck-data-der.c index 3ba74197..48e6a940 100644 --- a/pkcs11/gck/gck-data-der.c +++ b/pkcs11/gck/gck-data-der.c @@ -29,6 +29,7 @@ #include "gck-data-types.h" #include "egg/egg-secure-memory.h" +#include "egg/egg-symkey.h" #include <glib.h> #include <gcrypt.h> @@ -40,27 +41,7 @@ static GQuark OID_PKIX1_RSA; static GQuark OID_PKIX1_DSA; - -static GQuark OID_PBE_MD2_DES_CBC; -static GQuark OID_PBE_MD5_DES_CBC; -static GQuark OID_PBE_MD2_RC2_CBC; -static GQuark OID_PBE_MD5_RC2_CBC; -static GQuark OID_PBE_SHA1_DES_CBC; -static GQuark OID_PBE_SHA1_RC2_CBC; -static GQuark OID_PBES2; -static GQuark OID_PBKDF2; - -static GQuark OID_DES_CBC; -static GQuark OID_DES_RC2_CBC; -static GQuark OID_DES_EDE3_CBC; -static GQuark OID_DES_RC5_CBC; - -static GQuark OID_PKCS12_PBE_ARCFOUR_SHA1; -static GQuark OID_PKCS12_PBE_RC4_40_SHA1; static GQuark OID_PKCS12_PBE_3DES_SHA1; -static GQuark OID_PKCS12_PBE_2DES_SHA1; -static GQuark OID_PKCS12_PBE_RC2_128_SHA1; -static GQuark OID_PKCS12_PBE_RC2_40_SHA1; static void init_quarks (void) @@ -74,29 +55,7 @@ init_quarks (void) QUARK (OID_PKIX1_RSA, "1.2.840.113549.1.1.1"); QUARK (OID_PKIX1_DSA, "1.2.840.10040.4.1"); - - QUARK (OID_PBE_MD2_DES_CBC, "1.2.840.113549.1.5.1"); - QUARK (OID_PBE_MD5_DES_CBC, "1.2.840.113549.1.5.3"); - QUARK (OID_PBE_MD2_RC2_CBC, "1.2.840.113549.1.5.4"); - QUARK (OID_PBE_MD5_RC2_CBC, "1.2.840.113549.1.5.6"); - QUARK (OID_PBE_SHA1_DES_CBC, "1.2.840.113549.1.5.10"); - QUARK (OID_PBE_SHA1_RC2_CBC, "1.2.840.113549.1.5.11"); - - QUARK (OID_PBES2, "1.2.840.113549.1.5.13"); - - QUARK (OID_PBKDF2, "1.2.840.113549.1.5.12"); - - QUARK (OID_DES_CBC, "1.3.14.3.2.7"); - QUARK (OID_DES_RC2_CBC, "1.2.840.113549.3.2"); - QUARK (OID_DES_EDE3_CBC, "1.2.840.113549.3.7"); - QUARK (OID_DES_RC5_CBC, "1.2.840.113549.3.9"); - - QUARK (OID_PKCS12_PBE_ARCFOUR_SHA1, "1.2.840.113549.1.12.1.1"); - QUARK (OID_PKCS12_PBE_RC4_40_SHA1, "1.2.840.113549.1.12.1.2"); QUARK (OID_PKCS12_PBE_3DES_SHA1, "1.2.840.113549.1.12.1.3"); - QUARK (OID_PKCS12_PBE_2DES_SHA1, "1.2.840.113549.1.12.1.4"); - QUARK (OID_PKCS12_PBE_RC2_128_SHA1, "1.2.840.113549.1.12.1.5"); - QUARK (OID_PKCS12_PBE_RC2_40_SHA1, "1.2.840.113549.1.12.1.6"); #undef QUARK @@ -638,7 +597,7 @@ gck_data_der_read_private_pkcs8_crypted (const guchar *data, gsize n_data, const /* * Parse the encryption stuff into a cipher. */ - r = gck_data_der_read_cipher (scheme, password, n_password, params, n_params, &cih); + r = egg_symkey_read_cipher (scheme, password, n_password, params, n_params, &cih); if (r == GCK_DATA_UNRECOGNIZED) { ret = GCK_DATA_FAILURE; goto done; @@ -1031,7 +990,7 @@ prepare_and_encode_pkcs8_cipher (ASN1_TYPE asn, const gchar *password, *n_block = gcry_cipher_get_algo_blklen (GCRY_MD_SHA1); g_return_val_if_fail (n_key && *n_block, NULL); - if (!gck_crypto_symkey_generate_pkcs12 (GCRY_CIPHER_3DES, GCRY_MD_SHA1, + if (!egg_symkey_generate_pkcs12 (GCRY_CIPHER_3DES, GCRY_MD_SHA1, password, n_password, salt, sizeof (salt), iterations, &key, &iv)) g_return_val_if_reached (NULL); @@ -1322,437 +1281,3 @@ gck_data_der_write_certificate (ASN1_TYPE asn1, gsize *n_data) return egg_asn1_encode (asn1, "", n_data, NULL); } - -/* ----------------------------------------------------------------------------- - * CIPHER/KEY DESCRIPTIONS - */ - -GckDataResult -gck_data_der_read_cipher (GQuark oid_scheme, const gchar *password, gsize n_password, - const guchar *data, gsize n_data, gcry_cipher_hd_t *cih) -{ - GckDataResult ret = GCK_DATA_UNRECOGNIZED; - - g_return_val_if_fail (oid_scheme != 0, GCK_DATA_FAILURE); - g_return_val_if_fail (cih != NULL, GCK_DATA_FAILURE); - g_return_val_if_fail (data != NULL && n_data != 0, GCK_DATA_FAILURE); - - init_quarks (); - - /* PKCS#5 PBE */ - if (oid_scheme == OID_PBE_MD2_DES_CBC) - ret = gck_data_der_read_cipher_pkcs5_pbe (GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CBC, - GCRY_MD_MD2, password, n_password, data, n_data, cih); - - else if (oid_scheme == OID_PBE_MD2_RC2_CBC) - /* RC2-64 has no implementation in libgcrypt */ - ret = GCK_DATA_UNRECOGNIZED; - else if (oid_scheme == OID_PBE_MD5_DES_CBC) - ret = gck_data_der_read_cipher_pkcs5_pbe (GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CBC, - GCRY_MD_MD5, password, n_password, data, n_data, cih); - else if (oid_scheme == OID_PBE_MD5_RC2_CBC) - /* RC2-64 has no implementation in libgcrypt */ - ret = GCK_DATA_UNRECOGNIZED; - else if (oid_scheme == OID_PBE_SHA1_DES_CBC) - ret = gck_data_der_read_cipher_pkcs5_pbe (GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CBC, - GCRY_MD_SHA1, password, n_password, data, n_data, cih); - else if (oid_scheme == OID_PBE_SHA1_RC2_CBC) - /* RC2-64 has no implementation in libgcrypt */ - ret = GCK_DATA_UNRECOGNIZED; - - - /* PKCS#5 PBES2 */ - else if (oid_scheme == OID_PBES2) - ret = gck_data_der_read_cipher_pkcs5_pbes2 (password, n_password, data, n_data, cih); - - - /* PKCS#12 PBE */ - else if (oid_scheme == OID_PKCS12_PBE_ARCFOUR_SHA1) - ret = gck_data_der_read_cipher_pkcs12_pbe (GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, - password, n_password, data, n_data, cih); - else if (oid_scheme == OID_PKCS12_PBE_RC4_40_SHA1) - /* RC4-40 has no implementation in libgcrypt */; - - else if (oid_scheme == OID_PKCS12_PBE_3DES_SHA1) - ret = gck_data_der_read_cipher_pkcs12_pbe (GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC, - password, n_password, data, n_data, cih); - else if (oid_scheme == OID_PKCS12_PBE_2DES_SHA1) - /* 2DES has no implementation in libgcrypt */; - - else if (oid_scheme == OID_PKCS12_PBE_RC2_128_SHA1) - ret = gck_data_der_read_cipher_pkcs12_pbe (GCRY_CIPHER_RFC2268_128, GCRY_CIPHER_MODE_CBC, - password, n_password, data, n_data, cih); - - else if (oid_scheme == OID_PKCS12_PBE_RC2_40_SHA1) - ret = gck_data_der_read_cipher_pkcs12_pbe (GCRY_CIPHER_RFC2268_40, GCRY_CIPHER_MODE_CBC, - password, n_password, data, n_data, cih); - - if (ret == GCK_DATA_UNRECOGNIZED) - g_message ("unsupported or unrecognized cipher oid: %s", g_quark_to_string (oid_scheme)); - return ret; -} - -GckDataResult -gck_data_der_read_cipher_pkcs5_pbe (int cipher_algo, int cipher_mode, int hash_algo, - const gchar *password, gsize n_password, const guchar *data, - gsize n_data, gcry_cipher_hd_t *cih) -{ - ASN1_TYPE asn = ASN1_TYPE_EMPTY; - gcry_error_t gcry; - GckDataResult ret; - const guchar *salt; - gsize n_salt; - gsize n_block, n_key; - guint iterations; - guchar *key = NULL; - guchar *iv = NULL; - - g_return_val_if_fail (cipher_algo != 0 && cipher_mode != 0, GCK_DATA_FAILURE); - g_return_val_if_fail (cih != NULL, GCK_DATA_FAILURE); - g_return_val_if_fail (data != NULL && n_data != 0, GCK_DATA_FAILURE); - - *cih = NULL; - ret = GCK_DATA_UNRECOGNIZED; - - /* Check if we can use this algorithm */ - if (gcry_cipher_algo_info (cipher_algo, GCRYCTL_TEST_ALGO, NULL, 0) != 0 || - gcry_md_test_algo (hash_algo) != 0) - goto done; - - asn = egg_asn1_decode ("PKIX1.pkcs-5-PBE-params", data, n_data); - if (!asn) - goto done; - - ret = GCK_DATA_FAILURE; - - salt = egg_asn1_read_content (asn, data, n_data, "salt", &n_salt); - if (!salt) - goto done; - if (!egg_asn1_read_uint (asn, "iterationCount", &iterations)) - iterations = 1; - - n_key = gcry_cipher_get_algo_keylen (cipher_algo); - g_return_val_if_fail (n_key > 0, GCK_DATA_FAILURE); - n_block = gcry_cipher_get_algo_blklen (cipher_algo); - - if (!gck_crypto_symkey_generate_pbe (cipher_algo, hash_algo, password, n_password, salt, - n_salt, iterations, &key, n_block > 1 ? &iv : NULL)) - goto done; - - gcry = gcry_cipher_open (cih, cipher_algo, cipher_mode, 0); - if (gcry != 0) { - g_warning ("couldn't create cipher: %s", gcry_strerror (gcry)); - goto done; - } - - if (iv) - gcry_cipher_setiv (*cih, iv, n_block); - gcry_cipher_setkey (*cih, key, n_key); - - ret = GCK_DATA_SUCCESS; - -done: - gcry_free (iv); - gcry_free (key); - - if (asn) - asn1_delete_structure (&asn); - - return ret; -} - -static gboolean -setup_pkcs5_rc2_params (const guchar *data, guchar n_data, gcry_cipher_hd_t cih) -{ - ASN1_TYPE asn = ASN1_TYPE_EMPTY; - gcry_error_t gcry; - const guchar *iv; - gsize n_iv; - guint version; - - g_assert (data); - - asn = egg_asn1_decode ("PKIX1.pkcs-5-rc2-CBC-params", data, n_data); - if (!asn) - return GCK_DATA_UNRECOGNIZED; - - if (!egg_asn1_read_uint (asn, "rc2ParameterVersion", &version)) - return GCK_DATA_FAILURE; - - iv = egg_asn1_read_content (asn, data, n_data, "iv", &n_iv); - asn1_delete_structure (&asn); - - if (!iv) - return GCK_DATA_FAILURE; - - gcry = gcry_cipher_setiv (cih, iv, n_iv); - - if (gcry != 0) { - g_message ("couldn't set %lu byte iv on cipher", (gulong)n_iv); - return GCK_DATA_FAILURE; - } - - return GCK_DATA_SUCCESS; -} - -static gboolean -setup_pkcs5_des_params (const guchar *data, guchar n_data, gcry_cipher_hd_t cih) -{ - ASN1_TYPE asn = ASN1_TYPE_EMPTY; - gcry_error_t gcry; - const guchar *iv; - gsize n_iv; - - g_assert (data); - - asn = egg_asn1_decode ("PKIX1.pkcs-5-des-EDE3-CBC-params", data, n_data); - if (!asn) - asn = egg_asn1_decode ("PKIX1.pkcs-5-des-CBC-params", data, n_data); - if (!asn) - return GCK_DATA_UNRECOGNIZED; - - iv = egg_asn1_read_content (asn, data, n_data, "", &n_iv); - asn1_delete_structure (&asn); - - if (!iv) - return GCK_DATA_FAILURE; - - gcry = gcry_cipher_setiv (cih, iv, n_iv); - - if (gcry != 0) { - g_message ("couldn't set %lu byte iv on cipher", (gulong)n_iv); - return GCK_DATA_FAILURE; - } - - return GCK_DATA_SUCCESS; -} - -static GckDataResult -setup_pkcs5_pbkdf2_params (const gchar *password, gsize n_password, const guchar *data, - gsize n_data, int cipher_algo, gcry_cipher_hd_t cih) -{ - ASN1_TYPE asn = ASN1_TYPE_EMPTY; - GckDataResult ret; - gcry_error_t gcry; - guchar *key = NULL; - const guchar *salt; - gsize n_salt, n_key; - guint iterations; - - g_assert (cipher_algo); - g_assert (data); - - ret = GCK_DATA_UNRECOGNIZED; - - asn = egg_asn1_decode ("PKIX1.pkcs-5-PBKDF2-params", data, n_data); - if (!asn) - goto done; - - ret = GCK_DATA_FAILURE; - - if (!egg_asn1_read_uint (asn, "iterationCount", &iterations)) - iterations = 1; - salt = egg_asn1_read_content (asn, data, n_data, "salt.specified", &n_salt); - if (!salt) - goto done; - - if (!gck_crypto_symkey_generate_pbkdf2 (cipher_algo, GCRY_MD_SHA1, password, n_password, - salt, n_salt, iterations, &key, NULL)) - goto done; - - n_key = gcry_cipher_get_algo_keylen (cipher_algo); - g_return_val_if_fail (n_key > 0, GCK_DATA_FAILURE); - - gcry = gcry_cipher_setkey (cih, key, n_key); - if (gcry != 0) { - g_message ("couldn't set %lu byte key on cipher", (gulong)n_key); - goto done; - } - - ret = GCK_DATA_SUCCESS; - -done: - gcry_free (key); - if (asn) - asn1_delete_structure (&asn); - return ret; -} - -GckDataResult -gck_data_der_read_cipher_pkcs5_pbes2 (const gchar *password, gsize n_password, const guchar *data, - gsize n_data, gcry_cipher_hd_t *cih) -{ - ASN1_TYPE asn = ASN1_TYPE_EMPTY; - GckDataResult r, ret; - GQuark key_deriv_algo, enc_oid; - gcry_error_t gcry; - int algo, mode; - int beg, end, res; - - g_return_val_if_fail (cih != NULL, GCK_DATA_FAILURE); - g_return_val_if_fail (data != NULL && n_data != 0, GCK_DATA_FAILURE); - - init_quarks (); - - *cih = NULL; - ret = GCK_DATA_UNRECOGNIZED; - - asn = egg_asn1_decode ("PKIX1.pkcs-5-PBES2-params", data, n_data); - if (!asn) - goto done; - - res = GCK_DATA_FAILURE; - algo = mode = 0; - - /* Read in all the encryption type */ - enc_oid = egg_asn1_read_oid (asn, "encryptionScheme.algorithm"); - if (!enc_oid) - goto done; - if (enc_oid == OID_DES_EDE3_CBC) - algo = GCRY_CIPHER_3DES; - else if (enc_oid == OID_DES_CBC) - algo = GCRY_CIPHER_DES; - else if (enc_oid == OID_DES_RC2_CBC) - algo = GCRY_CIPHER_RFC2268_128; - else if (enc_oid == OID_DES_RC5_CBC) - /* RC5 doesn't exist in libgcrypt */; - - /* Unsupported? */ - if (algo == 0 || gcry_cipher_algo_info (algo, GCRYCTL_TEST_ALGO, NULL, 0) != 0) { - ret = GCK_DATA_UNRECOGNIZED; - goto done; - } - - /* Instantiate our cipher */ - gcry = gcry_cipher_open (cih, algo, GCRY_CIPHER_MODE_CBC, 0); - if (gcry != 0) { - g_warning ("couldn't create cipher: %s", gcry_cipher_algo_name (algo)); - goto done; - } - - /* Read out the parameters */ - if (asn1_der_decoding_startEnd (asn, data, n_data, "encryptionScheme.parameters", - &beg, &end) != ASN1_SUCCESS) - goto done; - - switch (algo) { - case GCRY_CIPHER_3DES: - case GCRY_CIPHER_DES: - r = setup_pkcs5_des_params (data + beg, end - beg + 1, *cih); - break; - case GCRY_CIPHER_RFC2268_128: - r = setup_pkcs5_rc2_params (data + beg, end - beg + 1, *cih); - break; - default: - /* Should have been caught on the oid check above */ - g_assert_not_reached (); - r = GCK_DATA_UNRECOGNIZED; - break; - }; - - if (r != GCK_DATA_SUCCESS) { - ret = r; - goto done; - } - - /* Read out the key creation paramaters */ - key_deriv_algo = egg_asn1_read_oid (asn, "keyDerivationFunc.algorithm"); - if (!key_deriv_algo) - goto done; - if (key_deriv_algo != OID_PBKDF2) { - g_message ("unsupported key derivation algorithm: %s", g_quark_to_string (key_deriv_algo)); - ret = GCK_DATA_UNRECOGNIZED; - goto done; - } - - if (asn1_der_decoding_startEnd (asn, data, n_data, "keyDerivationFunc.parameters", - &beg, &end) != ASN1_SUCCESS) - goto done; - - ret = setup_pkcs5_pbkdf2_params (password, n_password, data + beg, end - beg + 1, algo, *cih); - -done: - if (ret != GCK_DATA_SUCCESS && *cih) { - gcry_cipher_close (*cih); - *cih = NULL; - } - - if (asn) - asn1_delete_structure (&asn); - - return ret; -} - -GckDataResult -gck_data_der_read_cipher_pkcs12_pbe (int cipher_algo, int cipher_mode, const gchar *password, - gsize n_password, const guchar *data, gsize n_data, - gcry_cipher_hd_t *cih) -{ - ASN1_TYPE asn = ASN1_TYPE_EMPTY; - gcry_error_t gcry; - GckDataResult ret; - const guchar *salt; - gsize n_salt; - gsize n_block, n_key; - guint iterations; - guchar *key = NULL; - guchar *iv = NULL; - - g_return_val_if_fail (cipher_algo != 0 && cipher_mode != 0, GCK_DATA_FAILURE); - g_return_val_if_fail (cih != NULL, GCK_DATA_FAILURE); - g_return_val_if_fail (data != NULL && n_data != 0, GCK_DATA_FAILURE); - - *cih = NULL; - ret = GCK_DATA_UNRECOGNIZED; - - /* Check if we can use this algorithm */ - if (gcry_cipher_algo_info (cipher_algo, GCRYCTL_TEST_ALGO, NULL, 0) != 0) - goto done; - - asn = egg_asn1_decode ("PKIX1.pkcs-12-PbeParams", data, n_data); - if (!asn) - goto done; - - ret = GCK_DATA_FAILURE; - - salt = egg_asn1_read_content (asn, data, n_data, "salt", &n_salt); - if (!salt) - goto done; - if (!egg_asn1_read_uint (asn, "iterations", &iterations)) - goto done; - - n_block = gcry_cipher_get_algo_blklen (cipher_algo); - n_key = gcry_cipher_get_algo_keylen (cipher_algo); - - /* Generate IV and key using salt read above */ - if (!gck_crypto_symkey_generate_pkcs12 (cipher_algo, GCRY_MD_SHA1, password, - n_password, salt, n_salt, iterations, &key, - n_block > 1 ? &iv : NULL)) - goto done; - - gcry = gcry_cipher_open (cih, cipher_algo, cipher_mode, 0); - if (gcry != 0) { - g_warning ("couldn't create encryption cipher: %s", gcry_strerror (gcry)); - goto done; - } - - if (iv) - gcry_cipher_setiv (*cih, iv, n_block); - gcry_cipher_setkey (*cih, key, n_key); - - ret = GCK_DATA_SUCCESS; - -done: - if (ret != GCK_DATA_SUCCESS && *cih) { - gcry_cipher_close (*cih); - *cih = NULL; - } - - gcry_free (iv); - gcry_free (key); - - if (asn) - asn1_delete_structure (&asn); - - return ret; -} diff --git a/pkcs11/gck/gck-data-der.h b/pkcs11/gck/gck-data-der.h index fe9e5004..26801e8f 100644 --- a/pkcs11/gck/gck-data-der.h +++ b/pkcs11/gck/gck-data-der.h @@ -118,24 +118,4 @@ GckDataResult gck_data_der_read_enhanced_usage (const guchar *data, guchar* gck_data_der_write_certificate (ASN1_TYPE asn1, gsize *n_data); -/* ----------------------------------------------------------------------------- - * CIPHERS - */ - -GckDataResult gck_data_der_read_cipher (GQuark oid_scheme, const gchar *password, - gsize n_password, const guchar *data, gsize n_data, - gcry_cipher_hd_t *cih); - -GckDataResult gck_data_der_read_cipher_pkcs5_pbe (int cipher_algo, int cipher_mode, - int hash_algo, const gchar *password, gsize n_password, - const guchar *data, gsize n_data, - gcry_cipher_hd_t *cih); - -GckDataResult gck_data_der_read_cipher_pkcs5_pbes2 (const gchar *password, gsize n_password, const guchar *data, - gsize n_data, gcry_cipher_hd_t *cih); - -GckDataResult gck_data_der_read_cipher_pkcs12_pbe (int cipher_algo, int cipher_mode, - const gchar *password, gsize n_password, const guchar *data, - gsize n_data, gcry_cipher_hd_t *cih); - #endif /*GKRPKIXDER_H_*/ diff --git a/pkcs11/gck/gck-data-file.c b/pkcs11/gck/gck-data-file.c index b08648a5..5616fd0d 100644 --- a/pkcs11/gck/gck-data-file.c +++ b/pkcs11/gck/gck-data-file.c @@ -30,6 +30,7 @@ #include "egg/egg-buffer.h" #include "egg/egg-secure-memory.h" +#include "egg/egg-symkey.h" #include <glib/gstdio.h> @@ -361,7 +362,7 @@ create_cipher (GckLogin *login, int calgo, int halgo, const guchar *salt, password = gck_login_get_password (login, &n_password); - if (!gck_crypto_symkey_generate_simple (calgo, halgo, password, n_password, + if (!egg_symkey_generate_simple (calgo, halgo, password, n_password, salt, n_salt, iterations, &key, &iv)) { gcry_free (key); g_free (iv); diff --git a/pkcs11/gck/gck-data-openssl.h b/pkcs11/gck/gck-data-openssl.h deleted file mode 100644 index 994f9cb7..00000000 --- a/pkcs11/gck/gck-data-openssl.h +++ /dev/null @@ -1,43 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* gck-data-openssl.h - OpenSSL compatibility functionality - - Copyright (C) 2007 Stefan Walter - - The Gnome Keyring Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Keyring Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Stef Walter <stef@memberwebs.com> -*/ - -#ifndef GCKDATAOPENSSL_H_ -#define GCKDATAOPENSSL_H_ - -#include "gck-data-types.h" - -int gck_data_openssl_parse_algo (const gchar *name, int *mode); - -gboolean gck_data_openssl_encrypt_block (const gchar *dekinfo, const gchar *password, - gssize n_password, const guchar *data, gsize n_data, - guchar **encrypted, gsize *n_encrypted); - -GckDataResult gck_data_openssl_decrypt_block (const gchar *dekinfo, const gchar *password, - gssize n_password, const guchar *data, gsize n_data, - guchar **decrypted, gsize *n_decrypted); - -const gchar* gck_data_openssl_get_dekinfo (GHashTable *headers); - -const gchar* gck_data_openssl_prep_dekinfo (GHashTable *headers); - -#endif /* GCKDATAOPENSSL_H_ */ diff --git a/pkcs11/gck/gck-data-pem.c b/pkcs11/gck/gck-data-pem.c deleted file mode 100644 index c2cfcf9b..00000000 --- a/pkcs11/gck/gck-data-pem.c +++ /dev/null @@ -1,345 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* gkr-pkix-pem.c - PEM base64 encoding helper routines - - Copyright (C) 2007 Stefan Walter - - The Gnome Keyring Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Keyring Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Stef Walter <stef@memberwebs.com> -*/ - -#include "config.h" - -#include "gck-data-pem.h" - -#include <glib.h> - -#include <gcrypt.h> - -#include <ctype.h> -#include <string.h> - -/* - * PEM looks like: - * - * -----BEGIN RSA PRIVATE KEY----- - * Proc-Type: 4,ENCRYPTED - * DEK-Info: DES-EDE3-CBC,704CFFD62FBA03E9 - * - * 4AV/g0BiTeb07hzo4/Ct47HGhHEshMhBPGJ843QzuAinpZBbg3OxwPsQsLgoPhJL - * Bg6Oxyz9M4UN1Xlx6Lyo2lRT908mBP6dl/OItLsVArqAzM+e29KHQVNjV1h7xN9F - * u84tOgZftKun+ZkQUOoRvMLLu4yV4CUraks9tgyXquugGba/tbeyj2MYsC8wwSJX - * .... - * -----END RSA PRIVATE KEY----- - */ - -#define PEM_SUFF "-----" -#define PEM_SUFF_L 5 -#define PEM_PREF_BEGIN "-----BEGIN " -#define PEM_PREF_BEGIN_L 11 -#define PEM_PREF_END "-----END " -#define PEM_PREF_END_L 9 - -static void -parse_header_lines (const gchar *hbeg, const gchar *hend, GHashTable **result) -{ - gchar **lines, **l; - gchar *line, *name, *value; - gchar *copy; - - copy = g_strndup (hbeg, hend - hbeg); - lines = g_strsplit (copy, "\n", 0); - g_free (copy); - - for (l = lines; l && *l; ++l) { - line = *l; - g_strstrip (line); - - /* Look for the break between name: value */ - value = strchr (line, ':'); - if (value == NULL) - continue; - - *value = 0; - value = g_strdup (value + 1); - g_strstrip (value); - - name = g_strdup (line); - g_strstrip (name); - - if (!*result) - *result = gck_data_pem_headers_new (); - g_hash_table_replace (*result, name, value); - } - - g_strfreev (lines); -} - -static const gchar* -pem_find_begin (const gchar *data, gsize n_data, GQuark *type) -{ - const gchar *pref, *suff; - gchar *stype; - - /* Look for a prefix */ - pref = g_strstr_len ((gchar*)data, n_data, PEM_PREF_BEGIN); - if (!pref) - return NULL; - - n_data -= (pref - data) + PEM_PREF_BEGIN_L; - data = pref + PEM_PREF_BEGIN_L; - - /* Look for the end of that begin */ - suff = g_strstr_len ((gchar*)data, n_data, PEM_SUFF); - if (!suff) - return NULL; - - /* Make sure on the same line */ - if (memchr (pref, '\n', suff - pref)) - return NULL; - - if (type) { - *type = 0; - pref += PEM_PREF_BEGIN_L; - g_assert (suff > pref); - stype = g_alloca (suff - pref + 1); - memcpy (stype, pref, suff - pref); - stype[suff - pref] = 0; - *type = g_quark_from_string (stype); - } - - /* The byte after this ---BEGIN--- */ - return suff + PEM_SUFF_L; -} - -static const gchar* -pem_find_end (const gchar *data, gsize n_data, GQuark type) -{ - const gchar *stype; - const gchar *pref; - gsize n_type; - - /* Look for a prefix */ - pref = g_strstr_len (data, n_data, PEM_PREF_END); - if (!pref) - return NULL; - - n_data -= (pref - data) + PEM_PREF_END_L; - data = pref + PEM_PREF_END_L; - - /* Next comes the type string */ - stype = g_quark_to_string (type); - n_type = strlen (stype); - if (strncmp ((gchar*)data, stype, n_type) != 0) - return NULL; - - n_data -= n_type; - data += n_type; - - /* Next comes the suffix */ - if (strncmp ((gchar*)data, PEM_SUFF, PEM_SUFF_L) != 0) - return NULL; - - /* The beginning of this ---END--- */ - return pref; -} - -static gboolean -pem_parse_block (const gchar *data, gsize n_data, guchar **decoded, gsize *n_decoded, - GHashTable **headers) -{ - const gchar *x, *hbeg, *hend; - const gchar *p, *end; - gint state = 0; - guint save = 0; - - g_assert (data); - g_assert (n_data); - - g_assert (decoded); - g_assert (n_decoded); - - p = data; - end = p + n_data; - - hbeg = hend = NULL; - - /* Try and find a pair of blank lines with only white space between */ - while (hend == NULL) { - x = memchr (p, '\n', end - p); - if (!x) - break; - ++x; - while (isspace (*x)) { - /* Found a second line, with only spaces between */ - if (*x == '\n') { - hbeg = data; - hend = x; - break; - /* Found a space between two lines */ - } else { - ++x; - } - } - - /* Try next line */ - p = x; - } - - /* Headers found? */ - if (hbeg && hend) { - data = hend; - n_data = end - data; - } - - *n_decoded = (n_data * 3) / 4 + 1; - if (gcry_is_secure (data)) - *decoded = gcry_calloc_secure (*n_decoded, 1); - else - *decoded = gcry_calloc (*n_decoded, 1); - g_return_val_if_fail (*decoded, FALSE); - - *n_decoded = g_base64_decode_step (data, n_data, *decoded, &state, &save); - if (!*n_decoded) { - gcry_free (*decoded); - return FALSE; - } - - if (headers && hbeg && hend) - parse_header_lines (hbeg, hend, headers); - - return TRUE; -} - -GHashTable* -gck_data_pem_headers_new (void) -{ - return g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); -} - -guint -gck_data_pem_parse (const guchar *data, gsize n_data, - GckDataPemCallback callback, gpointer user_data) -{ - const gchar *beg, *end; - guint nfound = 0; - guchar *decoded = NULL; - gsize n_decoded = 0; - GHashTable *headers = NULL; - GQuark type; - - g_return_val_if_fail (data, 0); - g_return_val_if_fail (n_data, 0); - g_return_val_if_fail (callback, 0); - - while (n_data > 0) { - - /* This returns the first character after the PEM BEGIN header */ - beg = pem_find_begin ((const gchar*)data, n_data, &type); - if (!beg) - break; - - g_assert (type); - - /* This returns the character position before the PEM END header */ - end = pem_find_end ((const gchar*)beg, n_data - ((const guchar*)beg - data), type); - if (!end) - break; - - if (beg != end) { - if (pem_parse_block (beg, end - beg, &decoded, &n_decoded, &headers)) { - (callback) (type, decoded, n_decoded, headers, user_data); - ++nfound; - gcry_free (decoded); - if (headers) - g_hash_table_remove_all (headers); - } - } - - /* Try for another block */ - end += PEM_SUFF_L; - n_data -= (const guchar*)end - data; - data = (const guchar*)end; - } - - if (headers) - g_hash_table_destroy (headers); - - return nfound; -} - -#ifdef UNTESTED_CODE - -static void -append_each_header (gpointer key, gpointer value, gpointer user_data) -{ - GString *string = (GString*)user_data; - - g_string_append (string, (gchar*)key); - g_string_append (string, ": "); - g_string_append (string, (gchar*)value); - g_string_append_c (string, '\n'); -} - -guchar* -gck_data_pem_write (const guchar *data, gsize n_data, GQuark type, - GHashTable *headers, gsize *n_result) -{ - GString *string; - gint state, save; - gsize length, n_prefix; - - g_return_val_if_fail (data || !n_data, NULL); - g_return_val_if_fail (type, NULL); - g_return_val_if_fail (n_result, NULL); - - string = g_string_sized_new (4096); - - /* The prefix */ - g_string_append_len (string, PEM_PREF_BEGIN, PEM_PREF_BEGIN_L); - g_string_append (string, g_quark_to_string (type)); - g_string_append_len (string, PEM_SUFF, PEM_SUFF_L); - g_string_append_c (string, '\n'); - - /* The headers */ - if (headers && g_hash_table_size (headers) > 0) { - g_hash_table_foreach (headers, append_each_header, string); - g_string_append_c (string, '\n'); - } - - /* Resize string to fit the base64 data. Algorithm from Glib reference */ - length = n_data * 4 / 3 + n_data * 4 / (3 * 72) + 7; - n_prefix = string->len; - g_string_set_size (string, n_prefix + length); - - /* The actual base64 data */ - state = save = 0; - length = g_base64_encode_step (data, n_data, TRUE, - string->str + string->len, &state, &save); - g_string_set_size (string, n_prefix + length); - - /* The suffix */ - g_string_append_c (string, '\n'); - g_string_append_len (string, PEM_PREF_END, PEM_PREF_END_L); - g_string_append (string, g_quark_to_string (type)); - g_string_append_len (string, PEM_SUFF, PEM_SUFF_L); - g_string_append_c (string, '\n'); - - *n_result = string->len; - return (guchar*)g_string_free (string, FALSE); -} - -#endif /* UNTESTED_CODE */ diff --git a/pkcs11/gck/gck-data-pem.h b/pkcs11/gck/gck-data-pem.h deleted file mode 100644 index 48268f3a..00000000 --- a/pkcs11/gck/gck-data-pem.h +++ /dev/null @@ -1,42 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* gkr-pkix-pem.h - PEM base64 helper routines - - Copyright (C) 2007 Stefan Walter - - The Gnome Keyring Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Keyring Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Stef Walter <stef@memberwebs.com> -*/ - -#ifndef GCK_DATA_PEM_H_ -#define GCK_DATA_PEM_H_ - -#include <glib.h> - -typedef void (*GckDataPemCallback) (GQuark type, const guchar *data, gsize n_data, - GHashTable *headers, gpointer user_data); - -GHashTable* gck_data_pem_headers_new (void); - -guint gck_data_pem_parse (const guchar *data, gsize n_data, - GckDataPemCallback callback, - gpointer user_data); - -guchar* gck_data_pem_write (const guchar *data, gsize n_data, - GQuark type, GHashTable *headers, - gsize *n_result); - -#endif /* GCK_DATA_PEM_H_ */ diff --git a/pkcs11/gck/gck-util.c b/pkcs11/gck/gck-util.c index 98c877ab..6e807fd2 100644 --- a/pkcs11/gck/gck-util.c +++ b/pkcs11/gck/gck-util.c @@ -29,8 +29,6 @@ /* Only access using atomic operations */ static gint next_handle = 0x00000010; -static const char HEXC[] = "0123456789ABCDEF"; - gulong* gck_util_ulong_alloc (gulong value) { @@ -89,79 +87,3 @@ gck_util_next_handle (void) { return (CK_ULONG)g_atomic_int_exchange_and_add (&next_handle, 1); } - -guchar* -gck_util_hex_decode (const gchar *data, gssize n_data, gsize *n_decoded) -{ - guchar *result; - guchar *decoded; - gushort j; - gint state = 0; - const gchar* pos; - - g_return_val_if_fail (data || !n_data, NULL); - g_return_val_if_fail (n_decoded, NULL); - - if (n_data == -1) - n_data = strlen (data); - - decoded = result = g_malloc0 ((n_data / 2) + 1); - *n_decoded = 0; - - while (n_data > 0) { - if (!g_ascii_isspace (*data)) { - - /* Find the position */ - pos = strchr (HEXC, g_ascii_toupper (*data)); - if (pos == 0) - break; - - j = pos - HEXC; - if(!state) { - *decoded = (j & 0xf) << 4; - state = 1; - } else { - *decoded |= (j & 0xf); - (*n_decoded)++; - decoded++; - state = 0; - } - } - - ++data; - --n_data; - } - - /* Parsing error */ - if (state != 0) { - g_free (result); - result = NULL; - } - - return result; -} - -gchar* -gck_util_hex_encode (const guchar *data, gsize n_data) -{ - gchar *result, *encoded; - guchar j; - - g_return_val_if_fail (data || !n_data, NULL); - - encoded = result = g_malloc0 (n_data * 2 + 1); - - while(n_data > 0) { - j = *(data) >> 4 & 0xf; - *(encoded++) = HEXC[j]; - - j = *(data++) & 0xf; - *(encoded++) = HEXC[j]; - - n_data--; - } - - /* Make sure still null terminated */ - g_assert (encoded[n_data * 2] == 0); - return result; -} diff --git a/pkcs11/gck/gck-util.h b/pkcs11/gck/gck-util.h index 3afb34fa..97e35560 100644 --- a/pkcs11/gck/gck-util.h +++ b/pkcs11/gck/gck-util.h @@ -47,11 +47,4 @@ CK_RV gck_attribute_set_mpi (CK_ATTRIBUTE_ CK_ULONG gck_util_next_handle (void); -guchar* gck_util_hex_decode (const gchar *data, - gssize n_data, - gsize *n_decoded); - -gchar* gck_util_hex_encode (const guchar *data, - gsize n_data); - #endif /* GCKUTIL_H_ */ diff --git a/pkcs11/gck/tests/Makefile.am b/pkcs11/gck/tests/Makefile.am index e75438fd..c0ed0df8 100644 --- a/pkcs11/gck/tests/Makefile.am +++ b/pkcs11/gck/tests/Makefile.am @@ -7,11 +7,9 @@ asn1-def-test.h: test.asn # Test files should be listed in order they need to run UNIT_AUTO = \ - unit-test-util.c \ unit-test-crypto.c \ unit-test-data-asn1.c \ unit-test-data-der.c \ - unit-test-data-openssl.c \ unit-test-transaction.c \ unit-test-store.c \ unit-test-memory-store.c \ diff --git a/pkcs11/gck/tests/unit-test-crypto.c b/pkcs11/gck/tests/unit-test-crypto.c index 737ad674..457306f4 100644 --- a/pkcs11/gck/tests/unit-test-crypto.c +++ b/pkcs11/gck/tests/unit-test-crypto.c @@ -72,190 +72,6 @@ DEFINE_TEARDOWN(crypto_setup) dsakey = NULL; } -const static struct { - const gchar *password; - int cipher_algo; - int hash_algo; - int iterations; - const gchar *salt; - - const gchar *result_simple; - const gchar *result_pkcs12; - const gchar *result_pbkdf2; - const gchar *result_pbe; -} all_generation_tests[] = { - - { /* 24 byte output */ - "booo", GCRY_CIPHER_3DES, GCRY_MD_MD5, 1, - "\x70\x4C\xFF\xD6\x2F\xBA\x03\xE9", - "\x84\x12\xBB\x34\x94\x8C\x40\xAD\x97\x57\x96\x74\x5B\x6A\xFB\xF8\xD6\x61\x33\x51\xEA\x8C\xCF\xD8", - NULL, - NULL, - NULL - }, - - { /* 5 byte output */ - "booo", GCRY_CIPHER_RFC2268_40, GCRY_MD_SHA1, 2048, - "\x8A\x58\xC2\xE8\x7C\x1D\x80\x11", - NULL, - "\xD6\xA6\xF0\x76\x66", - NULL, - NULL - }, - - { /* Null Password, 5 byte output */ - NULL, GCRY_CIPHER_RFC2268_40, GCRY_MD_SHA1, 2000, - "\x04\xE0\x1C\x3E\xF8\xF2\xE9\xFD", - NULL, - "\x98\x7F\x20\x97\x1E", - NULL, - NULL - }, - - { /* 24 byte output */ - "booo", GCRY_CIPHER_3DES, GCRY_MD_SHA1, 2048, - "\xBD\xEE\x0B\xC6\xCF\x43\xAC\x25", - NULL, - "\x3F\x38\x1B\x0E\x87\xEB\x19\xBE\xD1\x39\xDC\x5B\xC2\xD2\xB3\x3C\x35\xA8\xB8\xF9\xEE\x66\x48\x94", - "\x20\x25\x90\xD8\xD6\x98\x3E\x71\x10\x17\x1F\x51\x49\x87\x27\xCA\x97\x27\xD1\xC9\x72\xF8\x11\xBB", - NULL - }, - - { /* Empty password, 24 byte output */ - "", GCRY_CIPHER_3DES, GCRY_MD_SHA1, 2048, - "\xF7\xCF\xD9\xCF\x1F\xF3\xAD\xF6", - NULL, - NULL, - "\x53\xE3\x35\x9E\x5D\xC1\x85\x1A\x71\x3A\x67\x4E\x80\x56\x13\xD6\x4E\x3E\x89\x43\xB7\x1D\x5F\x7F", - NULL - }, - - { /* Empty password, 24 byte output */ - "", GCRY_CIPHER_3DES, GCRY_MD_SHA1, 2048, - "\xD9\xB3\x2E\xC7\xBA\x1A\x8E\x15", - NULL, - "\x39\x70\x75\x7C\xF5\xE2\x13\x0B\x5D\xC2\x9D\x96\x8B\x71\xC7\xFC\x5B\x97\x1F\x79\x9F\x06\xFC\xA2", - NULL, - NULL - }, - - { /* 8 byte output */ - "booo", GCRY_CIPHER_DES, GCRY_MD_MD5, 2048, - "\x93\x4C\x3D\x29\xA2\x42\xB0\xF5", - NULL, - NULL, - NULL, - "\x8C\x67\x19\x7F\xB9\x23\xE2\x8D" - } -}; - -#define N_GENERATION_TESTS (sizeof (all_generation_tests) / sizeof (all_generation_tests[0])) - -DEFINE_TEST(generate_key_simple) -{ - int i; - gboolean ret; - guchar *key; - - for (i = 0; i < N_GENERATION_TESTS; ++i) { - - if (!all_generation_tests[i].result_simple) - continue; - - ret = gck_crypto_symkey_generate_simple (all_generation_tests[i].cipher_algo, - all_generation_tests[i].hash_algo, - all_generation_tests[i].password, -1, - (guchar*)all_generation_tests[i].salt, 8, - all_generation_tests[i].iterations, - &key, NULL); - g_assert (ret && "key generation failed"); - - ret = (memcmp (key, all_generation_tests[i].result_simple, - gcry_cipher_get_algo_keylen (all_generation_tests[i].cipher_algo)) == 0); - - g_assert (ret && "invalid simple key generated"); - } -} - -DEFINE_TEST(generate_key_pkcs12) -{ - int i; - gboolean ret; - guchar *key; - - for (i = 0; i < N_GENERATION_TESTS; ++i) { - - if (!all_generation_tests[i].result_pkcs12) - continue; - - ret = gck_crypto_symkey_generate_pkcs12 (all_generation_tests[i].cipher_algo, - all_generation_tests[i].hash_algo, - all_generation_tests[i].password, -1, - (guchar*)all_generation_tests[i].salt, 8, - all_generation_tests[i].iterations, - &key, NULL); - g_assert ("failed to generate pkcs12 key" && ret); - - ret = (memcmp (key, all_generation_tests[i].result_pkcs12, - gcry_cipher_get_algo_keylen (all_generation_tests[i].cipher_algo)) == 0); - - g_assert ("invalid pkcs12 key generated" && ret); - } -} - -DEFINE_TEST(generate_key_pbkdf2) -{ - int i; - gboolean ret; - guchar *key; - - for (i = 0; i < N_GENERATION_TESTS; ++i) { - - if (!all_generation_tests[i].result_pbkdf2) - continue; - - ret = gck_crypto_symkey_generate_pbkdf2 (all_generation_tests[i].cipher_algo, - all_generation_tests[i].hash_algo, - all_generation_tests[i].password, -1, - (guchar*)all_generation_tests[i].salt, 8, - all_generation_tests[i].iterations, - &key, NULL); - g_assert ("failed to generate pbkdf2 key" && ret); - - ret = (memcmp (key, all_generation_tests[i].result_pbkdf2, - gcry_cipher_get_algo_keylen (all_generation_tests[i].cipher_algo)) == 0); - - g_assert ("invalid pbkdf2 key generated" && ret); - } -} - -DEFINE_TEST(generate_key_pbe) -{ - int i; - gboolean ret; - guchar *key; - - for (i = 0; i < N_GENERATION_TESTS; ++i) { - - if (!all_generation_tests[i].result_pbe) - continue; - - ret = gck_crypto_symkey_generate_pbe (all_generation_tests[i].cipher_algo, - all_generation_tests[i].hash_algo, - all_generation_tests[i].password, -1, - (guchar*)all_generation_tests[i].salt, 8, - all_generation_tests[i].iterations, - &key, NULL); - g_assert ("failed to generate pbe key" && ret); - - ret = (memcmp (key, all_generation_tests[i].result_pbe, - gcry_cipher_get_algo_keylen (all_generation_tests[i].cipher_algo)) == 0); - - g_assert ("invalid pbe key generated" && ret); - - } -} - DEFINE_TEST(parse_key) { gcry_sexp_t sexp = NULL; diff --git a/pkcs11/roots-store/gck-roots-module.c b/pkcs11/roots-store/gck-roots-module.c index 5deb246c..7d930d2d 100644 --- a/pkcs11/roots-store/gck-roots-module.c +++ b/pkcs11/roots-store/gck-roots-module.c @@ -25,10 +25,11 @@ #include "gck-roots-module.h" #include "gck-roots-certificate.h" -#include "gck/gck-data-pem.h" #include "gck/gck-file-tracker.h" #include "gck/gck-serializable.h" +#include "egg/egg-openssl.h" + #include <string.h> struct _GckRootsModule { @@ -204,7 +205,7 @@ file_load (GckFileTracker *tracker, const gchar *path, GckRootsModule *self) g_list_free (objects); /* Try and parse the PEM */ - num = gck_data_pem_parse (data, n_data, parsed_pem_block, &ctx); + num = egg_openssl_pem_parse (data, n_data, parsed_pem_block, &ctx); /* If no PEM data, try to parse directly as DER */ if (ctx.count == 0) { diff --git a/pkcs11/ssh-store/gck-ssh-openssh.c b/pkcs11/ssh-store/gck-ssh-openssh.c index 6e239280..b425061a 100644 --- a/pkcs11/ssh-store/gck-ssh-openssh.c +++ b/pkcs11/ssh-store/gck-ssh-openssh.c @@ -3,11 +3,10 @@ #include "gck/gck-data-asn1.h" #include "gck/gck-data-der.h" -#include "gck/gck-data-openssl.h" -#include "gck/gck-data-pem.h" #include "gck/gck-data-types.h" #include "egg/egg-buffer.h" +#include "egg/egg-openssl.h" typedef struct _ParsePrivate { gcry_sexp_t sexp; @@ -163,7 +162,7 @@ load_encrypted_key (const guchar *data, gsize n_data, const gchar *dekinfo, gint length; /* Decrypt, this will result in garble if invalid password */ - res = gck_data_openssl_decrypt_block (dekinfo, password, n_password, + res = egg_openssl_decrypt_block (dekinfo, password, n_password, data, n_data, &decrypted, &n_decrypted); if (!res) return FALSE; @@ -214,7 +213,7 @@ parsed_pem_block (GQuark type, const guchar *data, gsize n_data, return; /* If it's encrypted ... */ - dekinfo = gck_data_openssl_get_dekinfo (headers); + dekinfo = egg_openssl_get_dekinfo (headers); if (dekinfo) { ctx->result = load_encrypted_key (data, n_data, dekinfo, ctx->password, ctx->n_password, &ctx->sexp); @@ -346,7 +345,7 @@ gck_ssh_openssh_parse_private_key (const guchar *data, gsize n_data, ctx.password = password; ctx.n_password = n_password; - num = gck_data_pem_parse (data, n_data, parsed_pem_block, &ctx); + num = egg_openssl_pem_parse (data, n_data, parsed_pem_block, &ctx); /* Didn't find any private key there */ if (num == 0 || !ctx.seen) { diff --git a/pkcs11/user-store/gck-user-storage.c b/pkcs11/user-store/gck-user-storage.c index 318772fe..5c995f9e 100644 --- a/pkcs11/user-store/gck-user-storage.c +++ b/pkcs11/user-store/gck-user-storage.c @@ -33,6 +33,8 @@ #include "gck/gck-serializable.h" #include "gck/gck-util.h" +#include "egg/egg-hex.h" + #include <glib/gstdio.h> #include <libtasn1.h> @@ -175,7 +177,7 @@ identifier_for_object (GckObject *object) if (name == NULL) { data = gck_object_get_attribute_data (object, CKA_ID, &n_data); if (data && n_data) - name = gck_util_hex_encode (data, n_data); + name = egg_hex_encode (data, n_data); g_free (data); } |