From d4acbba05c50b44ae34d60d9e1b0fd3b34a8619f Mon Sep 17 00:00:00 2001 From: sleevi Date: Fri, 12 Jun 2020 17:41:17 -0400 Subject: [PATCH] lints: cabf_br lint to verify .onion addresses are well-formed (#450) Adds a new lint, identified as `e_san_dns_name_onion_invalid`, that makes sure that the `.onion` addresses present within a certificate are well-formed v2 or v3 addresses, according to the v2 or v3 Rendezvous specifications. Closes #440 --- .../lint_san_dns_name_onion_invalid.go | 151 ++++++++++++++++++ .../lint_san_dns_name_onion_invalid_test.go | 69 ++++++++ v2/testdata/onionSANv2NameEV.pem | 66 ++++++++ v2/testdata/onionSANv2NameInvalidEV.pem | 66 ++++++++ v2/testdata/onionSANv2NameNonEV.pem | 62 +++++++ 5 files changed, 414 insertions(+) create mode 100644 v2/lints/cabf_br/lint_san_dns_name_onion_invalid.go create mode 100644 v2/lints/cabf_br/lint_san_dns_name_onion_invalid_test.go create mode 100644 v2/testdata/onionSANv2NameEV.pem create mode 100644 v2/testdata/onionSANv2NameInvalidEV.pem create mode 100644 v2/testdata/onionSANv2NameNonEV.pem diff --git a/v2/lints/cabf_br/lint_san_dns_name_onion_invalid.go b/v2/lints/cabf_br/lint_san_dns_name_onion_invalid.go new file mode 100644 index 000000000..4dcfe0973 --- /dev/null +++ b/v2/lints/cabf_br/lint_san_dns_name_onion_invalid.go @@ -0,0 +1,151 @@ +/* + * ZLint Copyright 2020 Regents of the University of Michigan + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +/******************************************************************* +https://tools.ietf.org/html/rfc7686#section-1 + + Note that .onion names are required to conform with DNS name syntax + (as defined in Section 3.5 of [RFC1034] and Section 2.1 of + [RFC1123]), as they will still be exposed to DNS implementations. + + See [tor-address] and [tor-rendezvous] for the details of the + creation and use of .onion names. + +Baseline Requirements, v1.6.9, Appendix C (Ballot SC27) + +The Domain Name MUST contain at least two labels, where the right-most label +is "onion", and the label immediately preceding the right-most "onion" label +is a valid Version 3 Onion Address, as defined in section 6 of the Tor +Rendezvous Specification - Version 3 located at +https://spec.torproject.org/rend-spec-v3. + +Explanation: +Since CA/Browser Forum Ballot 144, `.onion` names have been permitted, +predating the ratification of RFC 7686. RFC 7686 introduced a normative +dependency on the Tor address and rendezvous specifications, which describe +v2 addresses. As the EV Guidelines have, since v1.5.3, required that the CA +obtain a demonstration of control from the Applicant, which effectively +requires the `.onion` name to be well-formed, even prior to RFC 7686. + +See also https://github.com/cabforum/documents/issues/191 +*******************************************************************/ + +package cabf_br + +import ( + "fmt" + "regexp" + "strings" + + "github.com/zmap/zcrypto/x509" + "github.com/zmap/zlint/v2/lint" + "github.com/zmap/zlint/v2/util" +) + +var ( + // Per 2.4 of Rendezvous v2: + // Valid onion addresses contain 16 characters in a-z2-7 plus ".onion" + onionV2Len = 16 + + // Per 1.2 of Rendezvous v3: + // A hidden service's name is its long term master identity key. This is + // encoded as a hostname by encoding the entire key in Base 32, including + // a version byte and a checksum, and then appending the string ".onion" + // at the end. The result is a 56-character domain name. + onionV3Len = 56 + + // Per RFC 4648, Section 6, the Base-32 alphabet is A-Z, 2-7, and =. + // Because v2/v3 addresses are always aligned, they should never be padded, + // and so omit = from the character set, as it's also not permitted in a + // domain in the "preferred name syntax". Because `.onion` names appear in + // DNS, which is case insensitive, the alphabet is extended to include a-z, + // as the names are tested for well-formedness prior to normalization to + // uppercase. + base32SubsetRegex = regexp.MustCompile(`^[a-zA-Z2-7]+$`) +) + +type onionNotValid struct{} + +func (l *onionNotValid) Initialize() error { + return nil +} + +// CheckApplies returns true if the certificate contains one or more subject +// names ending in `.onion`. +func (l *onionNotValid) CheckApplies(c *x509.Certificate) bool { + // TODO(sleevi): This should also be extended to support nameConstraints + // in the future. + return util.CertificateSubjInTLD(c, util.OnionTLD) +} + +// Execute will lint the provided certificate. A lint.Error lint.LintResult will +// be returned if: +// +// 1) The certificate contains a Tor Rendezvous Spec v2 address and is not an +// EV certificate (BRs: Appendix C). +// 2) The certificate contains a `.onion` subject name/SAN that is neither a +// Rendezvous Spec v2 or v3 address. +func (l *onionNotValid) Execute(c *x509.Certificate) *lint.LintResult { + for _, subj := range append(c.DNSNames, c.Subject.CommonName) { + if !strings.HasSuffix(subj, util.OnionTLD) { + continue + } + labels := strings.Split(subj, ".") + if len(labels) < 2 { + return &lint.LintResult{ + Status: lint.Error, + Details: fmt.Sprintf("certificate contained a %s domain with too "+ + "few labels: %q", util.OnionTLD, subj), + } + } + onionDomain := labels[len(labels)-2] + if len(onionDomain) == onionV2Len { + // Onion v2 address. These are only permitted for EV, per BRs Appendix C. + if !util.IsEV(c.PolicyIdentifiers) { + return &lint.LintResult{ + Status: lint.Error, + Details: fmt.Sprintf("%q is a v2 address, but the certificate is not "+ + "EV", subj), + } + } + } else if len(onionDomain) == onionV3Len { + // Onion v3 address. Permitted for all certificates by CA/Browser Forum + // Ballot SC27. + } else { + return &lint.LintResult{ + Status: lint.Error, + Details: fmt.Sprintf("%q is not a v2 or v3 Tor address", subj), + } + } + if !base32SubsetRegex.MatchString(onionDomain) { + return &lint.LintResult{ + Status: lint.Error, + Details: fmt.Sprintf("%q contains invalid characters not permitted "+ + "within base-32", subj), + } + } + } + return &lint.LintResult{Status: lint.Pass} +} + +func init() { + lint.RegisterLint(&lint.Lint{ + Name: "e_san_dns_name_onion_invalid", + Description: "certificates with a .onion subject name must be issued in accordance with the Tor address/rendezvous specification", + Citation: "RFC 7686, EVGs v1.7.2: Appendix F, BRs v1.6.9: Appendix C", + Source: lint.CABFBaselineRequirements, + EffectiveDate: util.OnionOnlyEVDate, + Lint: &onionNotValid{}, + }) +} diff --git a/v2/lints/cabf_br/lint_san_dns_name_onion_invalid_test.go b/v2/lints/cabf_br/lint_san_dns_name_onion_invalid_test.go new file mode 100644 index 000000000..c3dabbadc --- /dev/null +++ b/v2/lints/cabf_br/lint_san_dns_name_onion_invalid_test.go @@ -0,0 +1,69 @@ +package cabf_br + +import ( + "testing" + + "github.com/zmap/zlint/v2/lint" + "github.com/zmap/zlint/v2/test" +) + +func TestOnionNotInvalid(t *testing.T) { + testCases := []struct { + Name string + InputFilename string + ExpectedResult lint.LintStatus + ExpectedDetails string + }{ + { + Name: "Onion subject, not EV cert, before util.OnionOnlyEVDate", + InputFilename: "dnsNameOnionTLD.pem", + ExpectedResult: lint.NE, + }, + { + Name: "non-V2/V3 onion subject, non-EV cert", + InputFilename: "onionSANNotEV.pem", + ExpectedResult: lint.Error, + ExpectedDetails: `"zmap.onion" is not a v2 or v3 Tor address`, + }, + { + Name: "non-V2/V3 onion subject, EV cert", + InputFilename: "onionSANEV.pem", + ExpectedResult: lint.Error, + ExpectedDetails: `"zmap.onion" is not a v2 or v3 Tor address`, + }, + { + Name: "v2 onion address, non-EV", + InputFilename: "onionSANv2NameNonEV.pem", + ExpectedResult: lint.Error, + ExpectedDetails: `"v2cbb2l4lsnpio4q.onion" is a v2 address, but the certificate is not EV`, + }, + { + Name: "v2 onion address, EV", + InputFilename: "onionSANv2NameEV.pem", + ExpectedResult: lint.Pass, + }, + { + Name: "misencoded v2 onion address, EV", + InputFilename: "onionSANv2NameInvalidEV.pem", + ExpectedResult: lint.Error, + ExpectedDetails: `"v2cbb2l-lsnpio4q.onion" contains invalid characters not permitted within base-32`, + }, + { + Name: "v3 onion address, non-EV", + InputFilename: "onionSANv3Name.pem", + ExpectedResult: lint.Pass, + }, + } + + for _, tc := range testCases { + t.Run(tc.Name, func(t *testing.T) { + result := test.TestLint("e_san_dns_name_onion_invalid", tc.InputFilename) + if result.Status != tc.ExpectedResult { + t.Errorf("expected result %v was %v", tc.ExpectedResult, result.Status) + } + if result.Details != tc.ExpectedDetails { + t.Errorf("expected result details %q was %q", tc.ExpectedDetails, result.Details) + } + }) + } +} diff --git a/v2/testdata/onionSANv2NameEV.pem b/v2/testdata/onionSANv2NameEV.pem new file mode 100644 index 000000000..1fd643793 --- /dev/null +++ b/v2/testdata/onionSANv2NameEV.pem @@ -0,0 +1,66 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 2050924719016117252 (0x1c76592a6a060404) + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN = zlint test 6fb5e2 + Validity + Not Before: Mar 28 00:00:00 2020 GMT + Not After : Mar 28 00:00:00 2021 GMT + Subject: CN = example.test + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:d3:cf:55:71:96:a8:51:60:82:3d:12:84:61:82: + 01:67:64:d8:38:07:b7:93:7b:d1:40:c3:67:cd:dd: + b0:bc:84:67:38:65:5c:69:91:33:30:84:6c:38:ae: + 65:c5:5f:02:39:7a:38:f1:55:9d:79:57:b8:75:47: + 07:55:63:9e:ff:21:a7:56:8b:be:9c:99:88:86:f9: + 36:64:2b:ac:a1:d8:7c:31:ad:c5:59:1e:c1:b3:06: + 53:d5:77:27:39:d6:68:a3:c6:5c:65:c3:d8:90:2d: + 2b:bd:9d:c4:39:9c:3f:53:53:af:1b:9c:6b:0f:3e: + 04:96:dd:40:7a:21:29:eb:76:e8:2c:95:7b:73:da: + 65:d0:cc:a4:51:cc:f7:6d:4c:d7:8c:e6:d8:bf:20: + d9:01:a6:a4:b3:35:60:ac:c2:04:d4:02:d7:1c:8d: + 71:62:76:a5:10:4c:36:bf:16:c2:be:1d:71:45:95: + 66:17:32:d0:06:94:67:36:90:db:20:53:36:c4:55: + 5c:bb:cb:9c:68:29:43:b6:76:11:da:6e:c2:6c:da: + ae:1c:57:c6:13:a9:2e:c0:cb:8d:de:2f:19:24:79: + d8:28:83:27:5d:29:e9:4a:f7:3b:04:5a:6c:db:c9: + bb:00:e1:30:e0:8e:a1:cf:92:1c:87:77:ab:82:29: + 66:f1 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Key Encipherment + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + X509v3 Basic Constraints: critical + CA:FALSE + X509v3 Subject Alternative Name: + DNS:v2cbb2l4lsnpio4q.onion, DNS:example.test + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.36305.2 + + Signature Algorithm: sha256WithRSAEncryption + 11:33:f2:c1:fc:a3:10:23:bd:36:d7:f0:74:44:b3:1c:3e:9c: + c3:c2:e8:c7:58:12:18:e8:e1:a0:5f:78:45:0e:9e:e5:b9:6b: + 4f:31:05:f3:2d:d6:f9:77:a0:b7:e4:81:5d:24:45:81:e8:00: + 28:0f:b9:6c:0f:b0:43:eb:8d:c4 +-----BEGIN CERTIFICATE----- +MIICfTCCAiegAwIBAgIIHHZZKmoGBAQwDQYJKoZIhvcNAQELBQAwHDEaMBgGA1UE +AxMRemxpbnQgdGVzdCA2ZmI1ZTIwHhcNMjAwMzI4MDAwMDAwWhcNMjEwMzI4MDAw +MDAwWjAXMRUwEwYDVQQDEwxleGFtcGxlLnRlc3QwggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQDTz1VxlqhRYII9EoRhggFnZNg4B7eTe9FAw2fN3bC8hGc4 +ZVxpkTMwhGw4rmXFXwI5ejjxVZ15V7h1RwdVY57/IadWi76cmYiG+TZkK6yh2Hwx +rcVZHsGzBlPVdyc51mijxlxlw9iQLSu9ncQ5nD9TU68bnGsPPgSW3UB6ISnrdugs +lXtz2mXQzKRRzPdtTNeM5ti/INkBpqSzNWCswgTUAtccjXFidqUQTDa/FsK+HXFF +lWYXMtAGlGc2kNsgUzbEVVy7y5xoKUO2dhHabsJs2q4cV8YTqS7Ay43eLxkkedgo +gyddKelK9zsEWmzbybsA4TDgjqHPkhyHd6uCKWbxAgMBAAGjgYkwgYYwDgYDVR0P +AQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMB +Af8EAjAAMC8GA1UdEQQoMCaCFnYyY2JiMmw0bHNucGlvNHEub25pb26CDGV4YW1w +bGUudGVzdDAWBgNVHSAEDzANMAsGCSsGAQQBgptRAjANBgkqhkiG9w0BAQsFAANB +ABEz8sH8oxAjvTbX8HREsxw+nMPC6MdYEhjo4aBfeEUOnuW5a08xBfMt1vl3oLfk +gV0kRYHoACgPuWwPsEPrjcQ= +-----END CERTIFICATE----- diff --git a/v2/testdata/onionSANv2NameInvalidEV.pem b/v2/testdata/onionSANv2NameInvalidEV.pem new file mode 100644 index 000000000..1bbdd66fb --- /dev/null +++ b/v2/testdata/onionSANv2NameInvalidEV.pem @@ -0,0 +1,66 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 2050924719016117509 (0x1c76592a6a060505) + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN = zlint test 6fb5e3 + Validity + Not Before: Mar 28 00:00:00 2020 GMT + Not After : Mar 28 00:00:00 2021 GMT + Subject: CN = example.test + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:d3:cf:55:71:96:a8:51:60:82:3d:12:84:61:82: + 01:67:64:d8:38:07:b7:93:7b:d1:40:c3:67:cd:dd: + b0:bc:84:67:38:65:5c:69:91:33:30:84:6c:38:ae: + 65:c5:5f:02:39:7a:38:f1:55:9d:79:57:b8:75:47: + 07:55:63:9e:ff:21:a7:56:8b:be:9c:99:88:86:f9: + 36:64:2b:ac:a1:d8:7c:31:ad:c5:59:1e:c1:b3:06: + 53:d5:77:27:39:d6:68:a3:c6:5c:65:c3:d8:90:2d: + 2b:bd:9d:c4:39:9c:3f:53:53:af:1b:9c:6b:0f:3e: + 04:96:dd:40:7a:21:29:eb:76:e8:2c:95:7b:73:da: + 65:d0:cc:a4:51:cc:f7:6d:4c:d7:8c:e6:d8:bf:20: + d9:01:a6:a4:b3:35:60:ac:c2:04:d4:02:d7:1c:8d: + 71:62:76:a5:10:4c:36:bf:16:c2:be:1d:71:45:95: + 66:17:32:d0:06:94:67:36:90:db:20:53:36:c4:55: + 5c:bb:cb:9c:68:29:43:b6:76:11:da:6e:c2:6c:da: + ae:1c:57:c6:13:a9:2e:c0:cb:8d:de:2f:19:24:79: + d8:28:83:27:5d:29:e9:4a:f7:3b:04:5a:6c:db:c9: + bb:00:e1:30:e0:8e:a1:cf:92:1c:87:77:ab:82:29: + 66:f1 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Key Encipherment + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + X509v3 Basic Constraints: critical + CA:FALSE + X509v3 Subject Alternative Name: + DNS:v2cbb2l-lsnpio4q.onion, DNS:example.test + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.36305.2 + + Signature Algorithm: sha256WithRSAEncryption + 75:00:96:f9:9f:96:d0:94:da:37:95:2e:b6:5a:a1:e6:2b:52: + 9a:d0:74:32:26:8a:5a:5c:38:23:3b:ef:c1:69:75:0f:c4:59: + ce:d5:ce:4c:6e:fc:30:8c:eb:1c:95:8a:45:69:0f:45:fb:72: + 3e:e0:8e:70:35:53:a0:17:ea:69 +-----BEGIN CERTIFICATE----- +MIICfTCCAiegAwIBAgIIHHZZKmoGBQUwDQYJKoZIhvcNAQELBQAwHDEaMBgGA1UE +AxMRemxpbnQgdGVzdCA2ZmI1ZTMwHhcNMjAwMzI4MDAwMDAwWhcNMjEwMzI4MDAw +MDAwWjAXMRUwEwYDVQQDEwxleGFtcGxlLnRlc3QwggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQDTz1VxlqhRYII9EoRhggFnZNg4B7eTe9FAw2fN3bC8hGc4 +ZVxpkTMwhGw4rmXFXwI5ejjxVZ15V7h1RwdVY57/IadWi76cmYiG+TZkK6yh2Hwx +rcVZHsGzBlPVdyc51mijxlxlw9iQLSu9ncQ5nD9TU68bnGsPPgSW3UB6ISnrdugs +lXtz2mXQzKRRzPdtTNeM5ti/INkBpqSzNWCswgTUAtccjXFidqUQTDa/FsK+HXFF +lWYXMtAGlGc2kNsgUzbEVVy7y5xoKUO2dhHabsJs2q4cV8YTqS7Ay43eLxkkedgo +gyddKelK9zsEWmzbybsA4TDgjqHPkhyHd6uCKWbxAgMBAAGjgYkwgYYwDgYDVR0P +AQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMB +Af8EAjAAMC8GA1UdEQQoMCaCFnYyY2JiMmwtbHNucGlvNHEub25pb26CDGV4YW1w +bGUudGVzdDAWBgNVHSAEDzANMAsGCSsGAQQBgptRAjANBgkqhkiG9w0BAQsFAANB +AHUAlvmfltCU2jeVLrZaoeYrUprQdDImilpcOCM778FpdQ/EWc7Vzkxu/DCM6xyV +ikVpD0X7cj7gjnA1U6AX6mk= +-----END CERTIFICATE----- diff --git a/v2/testdata/onionSANv2NameNonEV.pem b/v2/testdata/onionSANv2NameNonEV.pem new file mode 100644 index 000000000..04240bb42 --- /dev/null +++ b/v2/testdata/onionSANv2NameNonEV.pem @@ -0,0 +1,62 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 2050924719016116995 (0x1c76592a6a060303) + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN = zlint test 6fb5e1 + Validity + Not Before: Mar 28 00:00:00 2020 GMT + Not After : Mar 28 00:00:00 2021 GMT + Subject: CN = example.test + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:d3:cf:55:71:96:a8:51:60:82:3d:12:84:61:82: + 01:67:64:d8:38:07:b7:93:7b:d1:40:c3:67:cd:dd: + b0:bc:84:67:38:65:5c:69:91:33:30:84:6c:38:ae: + 65:c5:5f:02:39:7a:38:f1:55:9d:79:57:b8:75:47: + 07:55:63:9e:ff:21:a7:56:8b:be:9c:99:88:86:f9: + 36:64:2b:ac:a1:d8:7c:31:ad:c5:59:1e:c1:b3:06: + 53:d5:77:27:39:d6:68:a3:c6:5c:65:c3:d8:90:2d: + 2b:bd:9d:c4:39:9c:3f:53:53:af:1b:9c:6b:0f:3e: + 04:96:dd:40:7a:21:29:eb:76:e8:2c:95:7b:73:da: + 65:d0:cc:a4:51:cc:f7:6d:4c:d7:8c:e6:d8:bf:20: + d9:01:a6:a4:b3:35:60:ac:c2:04:d4:02:d7:1c:8d: + 71:62:76:a5:10:4c:36:bf:16:c2:be:1d:71:45:95: + 66:17:32:d0:06:94:67:36:90:db:20:53:36:c4:55: + 5c:bb:cb:9c:68:29:43:b6:76:11:da:6e:c2:6c:da: + ae:1c:57:c6:13:a9:2e:c0:cb:8d:de:2f:19:24:79: + d8:28:83:27:5d:29:e9:4a:f7:3b:04:5a:6c:db:c9: + bb:00:e1:30:e0:8e:a1:cf:92:1c:87:77:ab:82:29: + 66:f1 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Key Encipherment + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + X509v3 Basic Constraints: critical + CA:FALSE + X509v3 Subject Alternative Name: + DNS:v2cbb2l4lsnpio4q.onion, DNS:example.test + Signature Algorithm: sha256WithRSAEncryption + 83:0f:66:60:9c:25:29:06:60:c1:d4:c6:f8:53:57:e3:ea:94: + 9f:34:c3:18:f9:7a:19:bf:4c:ba:c0:96:f9:6d:a2:d2:7b:99: + 28:11:dd:e6:65:26:73:56:c0:e8:9d:fc:bb:d9:16:c4:4a:96: + 04:76:fa:d2:4b:17:41:cd:af:06 +-----BEGIN CERTIFICATE----- +MIICYzCCAg2gAwIBAgIIHHZZKmoGAwMwDQYJKoZIhvcNAQELBQAwHDEaMBgGA1UE +AxMRemxpbnQgdGVzdCA2ZmI1ZTEwHhcNMjAwMzI4MDAwMDAwWhcNMjEwMzI4MDAw +MDAwWjAXMRUwEwYDVQQDEwxleGFtcGxlLnRlc3QwggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQDTz1VxlqhRYII9EoRhggFnZNg4B7eTe9FAw2fN3bC8hGc4 +ZVxpkTMwhGw4rmXFXwI5ejjxVZ15V7h1RwdVY57/IadWi76cmYiG+TZkK6yh2Hwx +rcVZHsGzBlPVdyc51mijxlxlw9iQLSu9ncQ5nD9TU68bnGsPPgSW3UB6ISnrdugs +lXtz2mXQzKRRzPdtTNeM5ti/INkBpqSzNWCswgTUAtccjXFidqUQTDa/FsK+HXFF +lWYXMtAGlGc2kNsgUzbEVVy7y5xoKUO2dhHabsJs2q4cV8YTqS7Ay43eLxkkedgo +gyddKelK9zsEWmzbybsA4TDgjqHPkhyHd6uCKWbxAgMBAAGjcDBuMA4GA1UdDwEB +/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/ +BAIwADAvBgNVHREEKDAmghZ2MmNiYjJsNGxzbnBpbzRxLm9uaW9uggxleGFtcGxl +LnRlc3QwDQYJKoZIhvcNAQELBQADQQCDD2ZgnCUpBmDB1Mb4U1fj6pSfNMMY+XoZ +v0y6wJb5baLSe5koEd3mZSZzVsDonfy72RbESpYEdvrSSxdBza8G +-----END CERTIFICATE-----