The branch master has been updated via 616581aaac2dda1557586f7b43fc3a3d926899c4 (commit) via 6c4ecc655a1def370b4f5b43c455b0c6617938c8 (commit) via 24d5be7a2a9a6b992510f055a65462e372bd1085 (commit) via 6253cdcc8ea7b0116a43ee596ac03e0b04b8b762 (commit) via f23e4a17a2309793a0ac787725736f1c4474c804 (commit) via 6d9a54c6e661094c0668f0307213789c2d9be3ec (commit) from 3d46c81a7d6219fd51ccc3b16406f19b82d0176e (commit)
- Log ----------------------------------------------------------------- commit 616581aaac2dda1557586f7b43fc3a3d926899c4 Author: Tomas Mraz <tm...@fedoraproject.org> Date: Fri Jan 15 18:33:40 2021 +0100 dh_cms_set_shared_info: Use explicit fetch to be able to provide libctx Reviewed-by: Matt Caswell <m...@openssl.org> (Merged from https://github.com/openssl/openssl/pull/13869) commit 6c4ecc655a1def370b4f5b43c455b0c6617938c8 Author: Tomas Mraz <tm...@fedoraproject.org> Date: Fri Jan 15 17:13:00 2021 +0100 dh_cms_set_peerkey: The peer key is encoded as an ASN.1 integer It must be decoded from the ASN.1 integer before setting to the EVP_PKEY. Reviewed-by: Matt Caswell <m...@openssl.org> (Merged from https://github.com/openssl/openssl/pull/13869) commit 24d5be7a2a9a6b992510f055a65462e372bd1085 Author: Tomas Mraz <tm...@fedoraproject.org> Date: Fri Jan 15 11:12:09 2021 +0100 Make the smdh.pem test certificate usable with fips provider Reviewed-by: Matt Caswell <m...@openssl.org> (Merged from https://github.com/openssl/openssl/pull/13869) commit 6253cdcc8ea7b0116a43ee596ac03e0b04b8b762 Author: Tomas Mraz <tm...@fedoraproject.org> Date: Thu Jan 14 15:53:08 2021 +0100 kdf_exch.c (kdf_derive): Proper handling of NULL secret Reviewed-by: Matt Caswell <m...@openssl.org> (Merged from https://github.com/openssl/openssl/pull/13869) commit f23e4a17a2309793a0ac787725736f1c4474c804 Author: Tomas Mraz <tm...@fedoraproject.org> Date: Thu Jan 14 14:43:11 2021 +0100 Fixes related to broken DH support in CMS - DH support should work with both DH and DHX keys - UKM parameter is optional so it can have length 0 Fixes #13810 Reviewed-by: Matt Caswell <m...@openssl.org> (Merged from https://github.com/openssl/openssl/pull/13869) commit 6d9a54c6e661094c0668f0307213789c2d9be3ec Author: Tomas Mraz <tm...@fedoraproject.org> Date: Thu Jan 14 14:40:23 2021 +0100 Pass correct maximum output length to provider derive operation And improve error checking in EVP_PKEY_derive* calls. Reviewed-by: Matt Caswell <m...@openssl.org> (Merged from https://github.com/openssl/openssl/pull/13869) ----------------------------------------------------------------------- Summary of changes: crypto/cms/cms_dh.c | 28 +++++++++-- crypto/cms/cms_env.c | 4 +- crypto/evp/dh_ctrl.c | 2 +- crypto/evp/exchange.c | 16 +++--- crypto/evp/p_lib.c | 2 + providers/fips/self_test_kats.c | 2 +- providers/implementations/exchange/kdf_exch.c | 8 ++- test/recipes/80-test_cms.t | 22 ++++---- test/smime-certs/mksmime-certs.sh | 3 +- test/smime-certs/smdh.pem | 72 ++++++++++++++++----------- 10 files changed, 101 insertions(+), 58 deletions(-) diff --git a/crypto/cms/cms_dh.c b/crypto/cms/cms_dh.c index 9cba6364d1..538ef45174 100644 --- a/crypto/cms/cms_dh.c +++ b/crypto/cms/cms_dh.c @@ -13,6 +13,7 @@ #include <openssl/err.h> #include <openssl/core_names.h> #include "cms_local.h" +#include "crypto/evp.h" static int dh_cms_set_peerkey(EVP_PKEY_CTX *pctx, X509_ALGOR *alg, ASN1_BIT_STRING *pubkey) @@ -23,7 +24,9 @@ static int dh_cms_set_peerkey(EVP_PKEY_CTX *pctx, ASN1_INTEGER *public_key = NULL; int rv = 0; EVP_PKEY *pkpeer = NULL, *pk = NULL; + BIGNUM *bnpub = NULL; const unsigned char *p; + unsigned char *buf = NULL; int plen; X509_ALGOR_get0(&aoid, &atype, &aval, alg); @@ -43,16 +46,28 @@ static int dh_cms_set_peerkey(EVP_PKEY_CTX *pctx, if (p == NULL || plen == 0) goto err; + if ((public_key = d2i_ASN1_INTEGER(NULL, &p, plen)) == NULL) + goto err; + plen = ASN1_STRING_length((ASN1_STRING *)public_key); + if ((bnpub = ASN1_INTEGER_to_BN(public_key, NULL)) == NULL) + goto err; + if ((buf = OPENSSL_malloc(plen)) == NULL) + goto err; + if (BN_bn2binpad(bnpub, buf, plen) < 0) + goto err; + pkpeer = EVP_PKEY_new(); if (pkpeer == NULL || !EVP_PKEY_copy_parameters(pkpeer, pk) - || !EVP_PKEY_set1_encoded_public_key(pkpeer, p, plen)) + || !EVP_PKEY_set1_encoded_public_key(pkpeer, buf, plen)) goto err; if (EVP_PKEY_derive_set_peer(pctx, pkpeer) > 0) rv = 1; err: ASN1_INTEGER_free(public_key); + BN_free(bnpub); + OPENSSL_free(buf); EVP_PKEY_free(pkpeer); return rv; } @@ -66,8 +81,9 @@ static int dh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri) unsigned char *dukm = NULL; size_t dukmlen = 0; int keylen, plen; - const EVP_CIPHER *kekcipher; + EVP_CIPHER *kekcipher = NULL; EVP_CIPHER_CTX *kekctx; + const char *name; if (!CMS_RecipientInfo_kari_get0_alg(ri, &alg, &ukm)) goto err; @@ -96,7 +112,12 @@ static int dh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri) kekctx = CMS_RecipientInfo_kari_get0_ctx(ri); if (kekctx == NULL) goto err; - kekcipher = EVP_get_cipherbyobj(kekalg->algorithm); + + name = OBJ_nid2sn(OBJ_obj2nid(kekalg->algorithm)); + if (name == NULL) + goto err; + + kekcipher = EVP_CIPHER_fetch(pctx->libctx, name, pctx->propquery); if (kekcipher == NULL || EVP_CIPHER_mode(kekcipher) != EVP_CIPH_WRAP_MODE) goto err; if (!EVP_EncryptInit_ex(kekctx, kekcipher, NULL, NULL, NULL)) @@ -127,6 +148,7 @@ static int dh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri) rv = 1; err: X509_ALGOR_free(kekalg); + EVP_CIPHER_free(kekcipher); OPENSSL_free(dukm); return rv; } diff --git a/crypto/cms/cms_env.c b/crypto/cms/cms_env.c index d2f630146e..6f3ca020d8 100644 --- a/crypto/cms/cms_env.c +++ b/crypto/cms/cms_env.c @@ -115,7 +115,7 @@ int cms_env_asn1_ctrl(CMS_RecipientInfo *ri, int cmd) } else return 0; - if (EVP_PKEY_is_a(pkey, "DHX")) + if (EVP_PKEY_is_a(pkey, "DHX") || EVP_PKEY_is_a(pkey, "DH")) return cms_dh_envelope(ri, cmd); else if (EVP_PKEY_is_a(pkey, "EC")) return cms_ecdh_envelope(ri, cmd); @@ -1294,6 +1294,8 @@ int cms_pkey_get_ri_type(EVP_PKEY *pk) /* Check types that we know about */ if (EVP_PKEY_is_a(pk, "DH")) return CMS_RECIPINFO_AGREE; + else if (EVP_PKEY_is_a(pk, "DHX")) + return CMS_RECIPINFO_AGREE; else if (EVP_PKEY_is_a(pk, "DSA")) return CMS_RECIPINFO_NONE; else if (EVP_PKEY_is_a(pk, "EC")) diff --git a/crypto/evp/dh_ctrl.c b/crypto/evp/dh_ctrl.c index 64492389b7..7cf589f60b 100644 --- a/crypto/evp/dh_ctrl.c +++ b/crypto/evp/dh_ctrl.c @@ -514,7 +514,7 @@ int EVP_PKEY_CTX_set0_dh_kdf_ukm(EVP_PKEY_CTX *ctx, unsigned char *ukm, int len) int ret; OSSL_PARAM params[2], *p = params; - if (len <= 0) + if (len < 0) return -1; ret = dh_param_derive_check(ctx); diff --git a/crypto/evp/exchange.c b/crypto/evp/exchange.c index 501645fa0c..1721db94a7 100644 --- a/crypto/evp/exchange.c +++ b/crypto/evp/exchange.c @@ -183,7 +183,7 @@ int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx) const char *supported_exch = NULL; if (ctx == NULL) { - ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER); return -2; } @@ -318,8 +318,8 @@ int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer) void *provkey = NULL; if (ctx == NULL) { - ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); - return -2; + ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER); + return -1; } if (!EVP_PKEY_CTX_IS_DERIVE_OP(ctx) || ctx->op.kex.exchprovctx == NULL) @@ -413,9 +413,9 @@ int EVP_PKEY_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *pkeylen) { int ret; - if (ctx == NULL) { - ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); - return -2; + if (ctx == NULL || pkeylen == NULL) { + ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER); + return -1; } if (!EVP_PKEY_CTX_IS_DERIVE_OP(ctx)) { @@ -427,11 +427,11 @@ int EVP_PKEY_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *pkeylen) goto legacy; ret = ctx->op.kex.exchange->derive(ctx->op.kex.exchprovctx, key, pkeylen, - SIZE_MAX); + key != NULL ? *pkeylen : 0); return ret; legacy: - if (ctx == NULL || ctx->pmeth == NULL || ctx->pmeth->derive == NULL) { + if (ctx->pmeth == NULL || ctx->pmeth->derive == NULL) { ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); return -2; } diff --git a/crypto/evp/p_lib.c b/crypto/evp/p_lib.c index 93cdbb89bf..cc5a612748 100644 --- a/crypto/evp/p_lib.c +++ b/crypto/evp/p_lib.c @@ -972,6 +972,8 @@ int evp_pkey_name2type(const char *name) type = EVP_PKEY_DH; else if (strcasecmp(name, "X9.42 DH") == 0) type = EVP_PKEY_DHX; + else if (strcasecmp(name, "DHX") == 0) + type = EVP_PKEY_DHX; else if (strcasecmp(name, "DSA") == 0) type = EVP_PKEY_DSA; diff --git a/providers/fips/self_test_kats.c b/providers/fips/self_test_kats.c index 0d76778ab5..c80a2c0dbc 100644 --- a/providers/fips/self_test_kats.c +++ b/providers/fips/self_test_kats.c @@ -361,7 +361,7 @@ static int self_test_ka(const ST_KAT_KAS *t, OSSL_PARAM *params = NULL; OSSL_PARAM *params_peer = NULL; unsigned char secret[256]; - size_t secret_len; + size_t secret_len = sizeof(secret); OSSL_PARAM_BLD *bld = NULL; BN_CTX *bnctx = NULL; diff --git a/providers/implementations/exchange/kdf_exch.c b/providers/implementations/exchange/kdf_exch.c index c022a35107..43652faf50 100644 --- a/providers/implementations/exchange/kdf_exch.c +++ b/providers/implementations/exchange/kdf_exch.c @@ -95,7 +95,13 @@ static int kdf_derive(void *vpkdfctx, unsigned char *secret, size_t *secretlen, if (!ossl_prov_is_running()) return 0; - return EVP_KDF_derive(pkdfctx->kdfctx, secret, *secretlen); + + if (secret == NULL) { + *secretlen = EVP_KDF_CTX_get_kdf_size(pkdfctx->kdfctx); + return 1; + } + + return EVP_KDF_derive(pkdfctx->kdfctx, secret, outlen); } static void kdf_freectx(void *vpkdfctx) diff --git a/test/recipes/80-test_cms.t b/test/recipes/80-test_cms.t index 6783897139..1acc6980e0 100644 --- a/test/recipes/80-test_cms.t +++ b/test/recipes/80-test_cms.t @@ -598,7 +598,7 @@ my @smime_cms_param_tests = ( "-stream", "-out", "{output}.cms", "-recip", catfile($smdir, "smec1.pem"), "-aes-128-gcm", "-keyopt", "ecdh_kdf_md:sha256" ], [ "{cmd2}", "-decrypt", "-recip", catfile($smdir, "smec1.pem"), - "-in", "{output}.cms", "-out", "{output}.txt" ], + "-in", "{output}.cms", "-out", "{output}.txt" ], \&final_compare ], @@ -610,18 +610,16 @@ my @smime_cms_param_tests = ( [ "{cmd2}", @prov, "-decrypt", "-recip", catfile($smdir, "smec2.pem"), "-in", "{output}.cms", "-out", "{output}.txt" ], \&final_compare - ] + ], - # TODO(3.0) Add this test back in when "dhpublicnumber" is supported - # in the keymanger. - #[ "enveloped content test streaming S/MIME format, X9.42 DH", - # [ "{cmd1}", @prov, "-encrypt", "-in", $smcont, - # "-stream", "-out", "{output}.cms", - # "-recip", catfile($smdir, "smdh.pem"), "-aes128" ], - # [ "{cmd2}", "-decrypt", "-recip", catfile($smdir, "smdh.pem"), - # "-in", "{output}.cms", "-out", "{output}.txt" ], - # \&final_compare - #] + [ "enveloped content test streaming S/MIME format, X9.42 DH", + [ "{cmd1}", @prov, "-encrypt", "-in", $smcont, + "-stream", "-out", "{output}.cms", + "-recip", catfile($smdir, "smdh.pem"), "-aes128" ], + [ "{cmd2}", @prov, "-decrypt", "-recip", catfile($smdir, "smdh.pem"), + "-in", "{output}.cms", "-out", "{output}.txt" ], + \&final_compare + ] ); my @contenttype_cms_test = ( diff --git a/test/smime-certs/mksmime-certs.sh b/test/smime-certs/mksmime-certs.sh index b0603d4e86..d06edae98c 100644 --- a/test/smime-certs/mksmime-certs.sh +++ b/test/smime-certs/mksmime-certs.sh @@ -69,8 +69,7 @@ CN="Test S/MIME EE EC #3" $OPENSSL req -config ca.cnf -noenc \ $OPENSSL x509 -req -in req.pem -CA smroot.pem -days 3600 \ -extfile ca.cnf -extensions usr_cert -CAcreateserial >>smec3.pem # Create X9.42 DH parameters. -$OPENSSL genpkey -genparam -algorithm DH -pkeyopt dh_paramgen_type:2 \ - -out dhp.pem +$OPENSSL genpkey -genparam -algorithm DHX -out dhp.pem # Generate X9.42 DH key. $OPENSSL genpkey -paramfile dhp.pem -out smdh.pem $OPENSSL pkey -pubout -in smdh.pem -out dhpub.pem diff --git a/test/smime-certs/smdh.pem b/test/smime-certs/smdh.pem index f831b0713b..7d66a6b421 100644 --- a/test/smime-certs/smdh.pem +++ b/test/smime-certs/smdh.pem @@ -1,33 +1,47 @@ -----BEGIN PRIVATE KEY----- -MIIBSgIBADCCASsGByqGSM4+AgEwggEeAoGBANQMSgwEcnEZ31kZxa9Ef8qOK/AJ -9dMlsXMWVYnf/QevGdN/0Aei/j9a8QHG+CvvTm0DOEKhN9QUtABKsYZag865CA7B -mSdHjQuFqILtzA25sDJ+3+jk9vbss+56ETRll/wasJVLGbmmHNkBMvc1fC1d/sGF -cEn4zJnQvvFaeMgDAoGAaQD9ZvL8FYsJuNxN6qp5VfnfRqYvyi2PWSqtRKPGGC+V -thYg49PRjwPOcXzvOsdEOQ7iH9jTiSvnUdwSSEwYTZkSBuQXAgOMJAWOpoXyaRvh -atziBDoBnWS+/kX5RBhxvS0+em9yfRqAQleuGG+R1mEDihyJc8dWQQPT+O1l4oUC -FQCJlKsQZ0VBrWPGcUCNa54ZW6TH9QQWAhRR2NMZrQSfWthXDO8Lj5WZ34zQrA== +MIICXQIBADCCAjUGByqGSM4+AgEwggIoAoIBAQCCyx9ZhD6HY5xgusGDrJZJ+FdT +e9OxD/p9DQNKqoLyJ10TAUXuycozVqDAD4v1wsOAPH0TDOX9Ns87PXgTbd6DpSJt +F1ZLW+1pklZs2m0cLl4raOe8CZGHkSgia0wC40LAg/u/JZ6NAG2YSiFEtjbkf81l +pvL0946LiHfHklMtSOkK3H9PkGB/KrXMITRR2P1u78AzTvc2YL7iLlCu6mV2g6v4 +ieeWprywTaZ8gp3NBMjyuRJniGCQ52jPfOvT32w/sBTIfUO+95u/eEHrTP4K+vTk +VS3wLo5ypgrveRdALKvqkHe0qfNr5VQRk2Pt6ReH35kjiUPLZCccgJr9h80hAoIB +AE50cpgSJBYr9+5dj+fJJcXf/KX9rttlBXyveUP+vbSm/oW443/IksO3oLMy1Raq +tHTDBhtNrH7rSK6CDStKrMkgHsjTYkZOU85vCdrVi3UZBz0GiYO/8kQ8aLeTe3LB +7QB0kkkUgZ7etsnNxEkz9WQwohTvGBHBFNDKDqWadP9BpNrFoDCYojit7GOZPQgt +eEiCO8D9xu0sEXT8ZdRqWcmkTfeMRojrzxt0LpT/vUKHGsBFmUN7kH4Hy9z2LJxB +DrYYkV3LSAweuUQKBocNI7bbbOvPByUvHVMfJBrBmwIJI3vc3091njOH53zATNNv +ta+9S7L4zNsvbg8RtJyH8i4CHQCY12PTXj6Ipxbqq4d1Q+AoUqnN/H9lAS46teXv +BB8CHQCGE6pxpX5lWcH6+TGLDoLo3T5L2/5KTd0tRNdj -----END PRIVATE KEY----- -----BEGIN CERTIFICATE----- -MIID/zCCAuegAwIBAgIJANv1TSKgememMA0GCSqGSIb3DQEBBQUAMEQxCzAJBgNV -BAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMR0wGwYDVQQDDBRUZXN0IFMv -TUlNRSBSU0EgUm9vdDAeFw0xMzA4MDIxNDQ5MjlaFw0yMzA2MTExNDQ5MjlaMEQx -CzAJBgNVBAYTAlVLMRYwFAYDVQQKDA1PcGVuU1NMIEdyb3VwMR0wGwYDVQQDDBRU -ZXN0IFMvTUlNRSBFRSBESCAjMTCCAbYwggErBgcqhkjOPgIBMIIBHgKBgQDUDEoM -BHJxGd9ZGcWvRH/KjivwCfXTJbFzFlWJ3/0HrxnTf9AHov4/WvEBxvgr705tAzhC -oTfUFLQASrGGWoPOuQgOwZknR40LhaiC7cwNubAyft/o5Pb27LPuehE0ZZf8GrCV -Sxm5phzZATL3NXwtXf7BhXBJ+MyZ0L7xWnjIAwKBgGkA/Wby/BWLCbjcTeqqeVX5 -30amL8otj1kqrUSjxhgvlbYWIOPT0Y8DznF87zrHRDkO4h/Y04kr51HcEkhMGE2Z -EgbkFwIDjCQFjqaF8mkb4Wrc4gQ6AZ1kvv5F+UQYcb0tPnpvcn0agEJXrhhvkdZh -A4ociXPHVkED0/jtZeKFAhUAiZSrEGdFQa1jxnFAjWueGVukx/UDgYQAAoGAL1ve -cgI2awBeJH8ULBhSQpdL224VUDxFPiXzt8Vu5VLnxPv0pfA5En+8VByTuV7u6RSw -3/78NuTyr/sTyN8YlB1AuXHdTJynA1ICte1xgD4j2ijlq+dv8goOAFt9xkvXx7LD -umJ/cCignXETcNGfMi8+0s0bpMZyoHRdce8DQ26jYDBeMAwGA1UdEwEB/wQCMAAw -DgYDVR0PAQH/BAQDAgXgMB0GA1UdDgQWBBQLWk1ffSXH8p3Bqrdjgi/6jzLnwDAf -BgNVHSMEGDAWgBTffl6IBSQzCN0igQKXzJq3sTMnMDANBgkqhkiG9w0BAQUFAAOC -AQEAWvJj79MW1/Wq3RIANgAhonsI1jufYqxTH+1M0RU0ZXHulgem77Le2Ls1bizi -0SbvfpTiiFGkbKonKtO2wvfqwwuptSg3omMI5IjAGxYbyv2KBzIpp1O1LTDk9RbD -48JMMF01gByi2+NLUQ1MYF+5RqyoRqcyp5x2+Om1GeIM4Q/GRuI4p4dybWy8iC+d -LeXQfR7HXfh+tAum+WzjfLJwbnWbHmPhTbKB01U4lBp6+r8BGHAtNdPjEHqap4/z -vVZVXti9ThZ20EhM+VFU3y2wyapeQjhQvw/A2YRES0Ik7BSj3hHfWH/CTbLVQnhu -Uj6tw18ExOYxqoEGixNLPA5qsQ== +MIIFljCCBH6gAwIBAgIUYmx57362u3KsYCqtKby2mYi+pLMwDQYJKoZIhvcNAQEL +BQAwRDELMAkGA1UEBhMCVUsxFjAUBgNVBAoMDU9wZW5TU0wgR3JvdXAxHTAbBgNV +BAMMFFRlc3QgUy9NSU1FIFJTQSBSb290MB4XDTIxMDExNTEwMDk1MloXDTMwMTEy +NDEwMDk1MlowRDELMAkGA1UEBhMCVUsxFjAUBgNVBAoMDU9wZW5TU0wgR3JvdXAx +HTAbBgNVBAMMFFRlc3QgUy9NSU1FIEVFIERIICMxMIIDQjCCAjUGByqGSM4+AgEw +ggIoAoIBAQCCyx9ZhD6HY5xgusGDrJZJ+FdTe9OxD/p9DQNKqoLyJ10TAUXuycoz +VqDAD4v1wsOAPH0TDOX9Ns87PXgTbd6DpSJtF1ZLW+1pklZs2m0cLl4raOe8CZGH +kSgia0wC40LAg/u/JZ6NAG2YSiFEtjbkf81lpvL0946LiHfHklMtSOkK3H9PkGB/ +KrXMITRR2P1u78AzTvc2YL7iLlCu6mV2g6v4ieeWprywTaZ8gp3NBMjyuRJniGCQ +52jPfOvT32w/sBTIfUO+95u/eEHrTP4K+vTkVS3wLo5ypgrveRdALKvqkHe0qfNr +5VQRk2Pt6ReH35kjiUPLZCccgJr9h80hAoIBAE50cpgSJBYr9+5dj+fJJcXf/KX9 +rttlBXyveUP+vbSm/oW443/IksO3oLMy1RaqtHTDBhtNrH7rSK6CDStKrMkgHsjT +YkZOU85vCdrVi3UZBz0GiYO/8kQ8aLeTe3LB7QB0kkkUgZ7etsnNxEkz9WQwohTv +GBHBFNDKDqWadP9BpNrFoDCYojit7GOZPQgteEiCO8D9xu0sEXT8ZdRqWcmkTfeM +Rojrzxt0LpT/vUKHGsBFmUN7kH4Hy9z2LJxBDrYYkV3LSAweuUQKBocNI7bbbOvP +ByUvHVMfJBrBmwIJI3vc3091njOH53zATNNvta+9S7L4zNsvbg8RtJyH8i4CHQCY +12PTXj6Ipxbqq4d1Q+AoUqnN/H9lAS46teXvA4IBBQACggEAJP4Vy6vcIa7jLa93 +DWeT0pxe4zeYXxRWbvS7reLoZcBIhH253/QfXj+0UhcjtAa5A2X519anBuetUern +ecBmHO9vAj9F7J6feK+pUxE8cl793gmWzcGijMXCuRorW7GZ3XBTuQbWaJLtxB4a +rS54+CFMUfqR5coxGrraGPGjR9P6YCpJgWL74yxiQVzjEdwPLEz/0ehKeDkSvuj8 +Ixe06fY0eA9sfxx7+4lm2Jhw7XaIfguo8mgrfWjBzkkT2mcAHss/fdKcXNYrg+A+ +xgApPiyuy7S4YkQSsdV5Ns8UFttBCuojzEuWQ49fMZcv/rIHSHSxpbg2Sdka+d6h +wOQHK6NgMF4wDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCBeAwHQYDVR0OBBYE +FLG7SOccVVRWmPw87GRrYH/NCegTMB8GA1UdIwQYMBaAFMmRUwpjexZbi71E8HaI +qSTm5bZsMA0GCSqGSIb3DQEBCwUAA4IBAQA5r5k39ghJIgQKjOXSffhtAaBPT0Um +WtLjijp/iBUAowFpncDRIp+Ng7n/feJHDdnh59H0ZHGljWqZ3rgG3HjjArvG+iUm +6aaS4KdM6OwK60JTUXBQ/InISXzrZof2oZ5BjO6L6yV6cpaYOLlLo3QjU8HE54G9 +7UyR48NSvhwPw+vS1Abjib+K1En/ctnlm0CurHgP56LrJxguFZZP6+UjCnEy0wxm +VRr+y4+IgWikdOumMelJ+x9O9R7EPVfwQ9TYBtpo5hZQiGhSJ3Di9LZO5i0h2xjj +AhtR8zmzusFX2Ruh2dXQWeNx/dMEcYRJLU1P+IxUq2g1GUiCgq2Xc7ZY -----END CERTIFICATE-----