Adam Langley | c24c6d8 | 2011-04-19 09:57:58 -0400 | [diff] [blame] | 1 | // Copyright 2011 The Go Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style |
| 3 | // license that can be found in the LICENSE file. |
| 4 | |
| 5 | package x509 |
| 6 | |
| 7 | import ( |
Adam Langley | e74dcbe | 2011-10-14 15:06:54 -0400 | [diff] [blame] | 8 | "crypto/x509/pkix" |
Adam Langley | c24c6d8 | 2011-04-19 09:57:58 -0400 | [diff] [blame] | 9 | "encoding/pem" |
Russ Cox | c2049d2 | 2011-11-01 22:04:37 -0400 | [diff] [blame^] | 10 | "errors" |
Adam Langley | c24c6d8 | 2011-04-19 09:57:58 -0400 | [diff] [blame] | 11 | "strings" |
| 12 | "testing" |
| 13 | ) |
| 14 | |
| 15 | type verifyTest struct { |
| 16 | leaf string |
| 17 | intermediates []string |
| 18 | roots []string |
| 19 | currentTime int64 |
| 20 | dnsName string |
| 21 | |
Russ Cox | c2049d2 | 2011-11-01 22:04:37 -0400 | [diff] [blame^] | 22 | errorCallback func(*testing.T, int, error) bool |
Adam Langley | c24c6d8 | 2011-04-19 09:57:58 -0400 | [diff] [blame] | 23 | expectedChains [][]string |
| 24 | } |
| 25 | |
| 26 | var verifyTests = []verifyTest{ |
| 27 | { |
| 28 | leaf: googleLeaf, |
| 29 | intermediates: []string{thawteIntermediate}, |
| 30 | roots: []string{verisignRoot}, |
| 31 | currentTime: 1302726541, |
| 32 | dnsName: "www.google.com", |
| 33 | |
| 34 | expectedChains: [][]string{ |
Robert Griesemer | 61650b2 | 2011-09-06 16:04:55 -0700 | [diff] [blame] | 35 | {"Google", "Thawte", "VeriSign"}, |
Adam Langley | c24c6d8 | 2011-04-19 09:57:58 -0400 | [diff] [blame] | 36 | }, |
| 37 | }, |
| 38 | { |
| 39 | leaf: googleLeaf, |
| 40 | intermediates: []string{thawteIntermediate}, |
| 41 | roots: []string{verisignRoot}, |
| 42 | currentTime: 1302726541, |
| 43 | dnsName: "www.example.com", |
| 44 | |
| 45 | errorCallback: expectHostnameError, |
| 46 | }, |
| 47 | { |
| 48 | leaf: googleLeaf, |
| 49 | intermediates: []string{thawteIntermediate}, |
| 50 | roots: []string{verisignRoot}, |
| 51 | currentTime: 1, |
| 52 | dnsName: "www.example.com", |
| 53 | |
| 54 | errorCallback: expectExpired, |
| 55 | }, |
| 56 | { |
| 57 | leaf: googleLeaf, |
| 58 | roots: []string{verisignRoot}, |
| 59 | currentTime: 1302726541, |
| 60 | dnsName: "www.google.com", |
| 61 | |
| 62 | errorCallback: expectAuthorityUnknown, |
| 63 | }, |
| 64 | { |
| 65 | leaf: googleLeaf, |
| 66 | intermediates: []string{verisignRoot, thawteIntermediate}, |
| 67 | roots: []string{verisignRoot}, |
| 68 | currentTime: 1302726541, |
| 69 | dnsName: "www.google.com", |
| 70 | |
| 71 | expectedChains: [][]string{ |
Robert Griesemer | 61650b2 | 2011-09-06 16:04:55 -0700 | [diff] [blame] | 72 | {"Google", "Thawte", "VeriSign"}, |
Adam Langley | c24c6d8 | 2011-04-19 09:57:58 -0400 | [diff] [blame] | 73 | }, |
| 74 | }, |
| 75 | { |
Adam Langley | c24c6d8 | 2011-04-19 09:57:58 -0400 | [diff] [blame] | 76 | leaf: dnssecExpLeaf, |
| 77 | intermediates: []string{startComIntermediate}, |
| 78 | roots: []string{startComRoot}, |
| 79 | currentTime: 1302726541, |
| 80 | |
| 81 | expectedChains: [][]string{ |
Robert Griesemer | 61650b2 | 2011-09-06 16:04:55 -0700 | [diff] [blame] | 82 | {"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority"}, |
Adam Langley | c24c6d8 | 2011-04-19 09:57:58 -0400 | [diff] [blame] | 83 | }, |
| 84 | }, |
Adam Langley | d1d466f | 2011-07-07 18:06:50 -0400 | [diff] [blame] | 85 | { |
| 86 | leaf: dnssecExpLeaf, |
| 87 | intermediates: []string{startComIntermediate, startComRoot}, |
| 88 | roots: []string{startComRoot}, |
| 89 | currentTime: 1302726541, |
| 90 | |
| 91 | expectedChains: [][]string{ |
Robert Griesemer | 61650b2 | 2011-09-06 16:04:55 -0700 | [diff] [blame] | 92 | {"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority"}, |
| 93 | {"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority", "StartCom Certification Authority"}, |
Adam Langley | d1d466f | 2011-07-07 18:06:50 -0400 | [diff] [blame] | 94 | }, |
| 95 | }, |
Adam Langley | c24c6d8 | 2011-04-19 09:57:58 -0400 | [diff] [blame] | 96 | } |
| 97 | |
Russ Cox | c2049d2 | 2011-11-01 22:04:37 -0400 | [diff] [blame^] | 98 | func expectHostnameError(t *testing.T, i int, err error) (ok bool) { |
Adam Langley | c24c6d8 | 2011-04-19 09:57:58 -0400 | [diff] [blame] | 99 | if _, ok := err.(HostnameError); !ok { |
| 100 | t.Errorf("#%d: error was not a HostnameError: %s", i, err) |
| 101 | return false |
| 102 | } |
| 103 | return true |
| 104 | } |
| 105 | |
Russ Cox | c2049d2 | 2011-11-01 22:04:37 -0400 | [diff] [blame^] | 106 | func expectExpired(t *testing.T, i int, err error) (ok bool) { |
Adam Langley | c24c6d8 | 2011-04-19 09:57:58 -0400 | [diff] [blame] | 107 | if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != Expired { |
| 108 | t.Errorf("#%d: error was not Expired: %s", i, err) |
| 109 | return false |
| 110 | } |
| 111 | return true |
| 112 | } |
| 113 | |
Russ Cox | c2049d2 | 2011-11-01 22:04:37 -0400 | [diff] [blame^] | 114 | func expectAuthorityUnknown(t *testing.T, i int, err error) (ok bool) { |
Adam Langley | c24c6d8 | 2011-04-19 09:57:58 -0400 | [diff] [blame] | 115 | if _, ok := err.(UnknownAuthorityError); !ok { |
| 116 | t.Errorf("#%d: error was not UnknownAuthorityError: %s", i, err) |
| 117 | return false |
| 118 | } |
| 119 | return true |
| 120 | } |
| 121 | |
Russ Cox | c2049d2 | 2011-11-01 22:04:37 -0400 | [diff] [blame^] | 122 | func certificateFromPEM(pemBytes string) (*Certificate, error) { |
Adam Langley | c24c6d8 | 2011-04-19 09:57:58 -0400 | [diff] [blame] | 123 | block, _ := pem.Decode([]byte(pemBytes)) |
| 124 | if block == nil { |
Russ Cox | c2049d2 | 2011-11-01 22:04:37 -0400 | [diff] [blame^] | 125 | return nil, errors.New("failed to decode PEM") |
Adam Langley | c24c6d8 | 2011-04-19 09:57:58 -0400 | [diff] [blame] | 126 | } |
| 127 | return ParseCertificate(block.Bytes) |
| 128 | } |
| 129 | |
| 130 | func TestVerify(t *testing.T) { |
| 131 | for i, test := range verifyTests { |
| 132 | opts := VerifyOptions{ |
| 133 | Roots: NewCertPool(), |
| 134 | Intermediates: NewCertPool(), |
| 135 | DNSName: test.dnsName, |
| 136 | CurrentTime: test.currentTime, |
| 137 | } |
| 138 | |
| 139 | for j, root := range test.roots { |
| 140 | ok := opts.Roots.AppendCertsFromPEM([]byte(root)) |
| 141 | if !ok { |
Adam Langley | 8803d57 | 2011-04-26 10:26:22 -0400 | [diff] [blame] | 142 | t.Errorf("#%d: failed to parse root #%d", i, j) |
Adam Langley | c24c6d8 | 2011-04-19 09:57:58 -0400 | [diff] [blame] | 143 | return |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | for j, intermediate := range test.intermediates { |
| 148 | ok := opts.Intermediates.AppendCertsFromPEM([]byte(intermediate)) |
| 149 | if !ok { |
Adam Langley | 8803d57 | 2011-04-26 10:26:22 -0400 | [diff] [blame] | 150 | t.Errorf("#%d: failed to parse intermediate #%d", i, j) |
Adam Langley | c24c6d8 | 2011-04-19 09:57:58 -0400 | [diff] [blame] | 151 | return |
| 152 | } |
| 153 | } |
| 154 | |
| 155 | leaf, err := certificateFromPEM(test.leaf) |
| 156 | if err != nil { |
| 157 | t.Errorf("#%d: failed to parse leaf: %s", i, err) |
| 158 | return |
| 159 | } |
| 160 | |
| 161 | chains, err := leaf.Verify(opts) |
| 162 | |
| 163 | if test.errorCallback == nil && err != nil { |
| 164 | t.Errorf("#%d: unexpected error: %s", i, err) |
| 165 | } |
| 166 | if test.errorCallback != nil { |
| 167 | if !test.errorCallback(t, i, err) { |
| 168 | return |
| 169 | } |
| 170 | } |
| 171 | |
| 172 | if len(chains) != len(test.expectedChains) { |
| 173 | t.Errorf("#%d: wanted %d chains, got %d", i, len(test.expectedChains), len(chains)) |
| 174 | } |
| 175 | |
| 176 | // We check that each returned chain matches a chain from |
| 177 | // expectedChains but an entry in expectedChains can't match |
| 178 | // two chains. |
| 179 | seenChains := make([]bool, len(chains)) |
| 180 | NextOutputChain: |
| 181 | for _, chain := range chains { |
| 182 | TryNextExpected: |
| 183 | for j, expectedChain := range test.expectedChains { |
| 184 | if seenChains[j] { |
| 185 | continue |
| 186 | } |
| 187 | if len(chain) != len(expectedChain) { |
| 188 | continue |
| 189 | } |
| 190 | for k, cert := range chain { |
| 191 | if strings.Index(nameToKey(&cert.Subject), expectedChain[k]) == -1 { |
| 192 | continue TryNextExpected |
| 193 | } |
| 194 | } |
| 195 | // we matched |
| 196 | seenChains[j] = true |
| 197 | continue NextOutputChain |
| 198 | } |
| 199 | t.Errorf("#%d: No expected chain matched %s", i, chainToDebugString(chain)) |
| 200 | } |
| 201 | } |
| 202 | } |
| 203 | |
| 204 | func chainToDebugString(chain []*Certificate) string { |
| 205 | var chainStr string |
| 206 | for _, cert := range chain { |
| 207 | if len(chainStr) > 0 { |
| 208 | chainStr += " -> " |
| 209 | } |
| 210 | chainStr += nameToKey(&cert.Subject) |
| 211 | } |
| 212 | return chainStr |
| 213 | } |
| 214 | |
Adam Langley | e74dcbe | 2011-10-14 15:06:54 -0400 | [diff] [blame] | 215 | func nameToKey(name *pkix.Name) string { |
| 216 | return strings.Join(name.Country, ",") + "/" + strings.Join(name.Organization, ",") + "/" + strings.Join(name.OrganizationalUnit, ",") + "/" + name.CommonName |
| 217 | } |
| 218 | |
Adam Langley | c24c6d8 | 2011-04-19 09:57:58 -0400 | [diff] [blame] | 219 | const verisignRoot = `-----BEGIN CERTIFICATE----- |
| 220 | MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG |
| 221 | A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz |
| 222 | cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 |
| 223 | MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV |
| 224 | BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt |
| 225 | YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN |
| 226 | ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE |
| 227 | BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is |
| 228 | I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G |
| 229 | CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do |
| 230 | lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc |
| 231 | AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k |
| 232 | -----END CERTIFICATE----- |
| 233 | ` |
| 234 | |
| 235 | const thawteIntermediate = `-----BEGIN CERTIFICATE----- |
| 236 | MIIDIzCCAoygAwIBAgIEMAAAAjANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJV |
| 237 | UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDMgUHVi |
| 238 | bGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNTEzMDAw |
| 239 | MDAwWhcNMTQwNTEyMjM1OTU5WjBMMQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhh |
| 240 | d3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBD |
| 241 | QTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1NNn0I0Vf67NMf59HZGhPwtx |
| 242 | PKzMyGT7Y/wySweUvW+Aui/hBJPAM/wJMyPpC3QrccQDxtLN4i/1CWPN/0ilAL/g |
| 243 | 5/OIty0y3pg25gqtAHvEZEo7hHUD8nCSfQ5i9SGraTaEMXWQ+L/HbIgbBpV8yeWo |
| 244 | 3nWhLHpo39XKHIdYYBkCAwEAAaOB/jCB+zASBgNVHRMBAf8ECDAGAQH/AgEAMAsG |
| 245 | A1UdDwQEAwIBBjARBglghkgBhvhCAQEEBAMCAQYwKAYDVR0RBCEwH6QdMBsxGTAX |
| 246 | BgNVBAMTEFByaXZhdGVMYWJlbDMtMTUwMQYDVR0fBCowKDAmoCSgIoYgaHR0cDov |
| 247 | L2NybC52ZXJpc2lnbi5jb20vcGNhMy5jcmwwMgYIKwYBBQUHAQEEJjAkMCIGCCsG |
| 248 | AQUFBzABhhZodHRwOi8vb2NzcC50aGF3dGUuY29tMDQGA1UdJQQtMCsGCCsGAQUF |
| 249 | BwMBBggrBgEFBQcDAgYJYIZIAYb4QgQBBgpghkgBhvhFAQgBMA0GCSqGSIb3DQEB |
| 250 | BQUAA4GBAFWsY+reod3SkF+fC852vhNRj5PZBSvIG3dLrWlQoe7e3P3bB+noOZTc |
| 251 | q3J5Lwa/q4FwxKjt6lM07e8eU9kGx1Yr0Vz00YqOtCuxN5BICEIlxT6Ky3/rbwTR |
| 252 | bcV0oveifHtgPHfNDs5IAn8BL7abN+AqKjbc1YXWrOU/VG+WHgWv |
| 253 | -----END CERTIFICATE----- |
| 254 | ` |
| 255 | |
| 256 | const googleLeaf = `-----BEGIN CERTIFICATE----- |
| 257 | MIIDITCCAoqgAwIBAgIQL9+89q6RUm0PmqPfQDQ+mjANBgkqhkiG9w0BAQUFADBM |
| 258 | MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg |
| 259 | THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0wOTEyMTgwMDAwMDBaFw0x |
| 260 | MTEyMTgyMzU5NTlaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh |
| 261 | MRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApHb29nbGUgSW5jMRcw |
| 262 | FQYDVQQDFA53d3cuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC |
| 263 | gYEA6PmGD5D6htffvXImttdEAoN4c9kCKO+IRTn7EOh8rqk41XXGOOsKFQebg+jN |
| 264 | gtXj9xVoRaELGYW84u+E593y17iYwqG7tcFR39SDAqc9BkJb4SLD3muFXxzW2k6L |
| 265 | 05vuuWciKh0R73mkszeK9P4Y/bz5RiNQl/Os/CRGK1w7t0UCAwEAAaOB5zCB5DAM |
| 266 | BgNVHRMBAf8EAjAAMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwudGhhd3Rl |
| 267 | LmNvbS9UaGF3dGVTR0NDQS5jcmwwKAYDVR0lBCEwHwYIKwYBBQUHAwEGCCsGAQUF |
| 268 | BwMCBglghkgBhvhCBAEwcgYIKwYBBQUHAQEEZjBkMCIGCCsGAQUFBzABhhZodHRw |
| 269 | Oi8vb2NzcC50aGF3dGUuY29tMD4GCCsGAQUFBzAChjJodHRwOi8vd3d3LnRoYXd0 |
| 270 | ZS5jb20vcmVwb3NpdG9yeS9UaGF3dGVfU0dDX0NBLmNydDANBgkqhkiG9w0BAQUF |
| 271 | AAOBgQCfQ89bxFApsb/isJr/aiEdLRLDLE5a+RLizrmCUi3nHX4adpaQedEkUjh5 |
| 272 | u2ONgJd8IyAPkU0Wueru9G2Jysa9zCRo1kNbzipYvzwY4OA8Ys+WAi0oR1A04Se6 |
| 273 | z5nRUP8pJcA2NhUzUnC+MY+f6H/nEQyNv4SgQhqAibAxWEEHXw== |
| 274 | -----END CERTIFICATE-----` |
| 275 | |
| 276 | const dnssecExpLeaf = `-----BEGIN CERTIFICATE----- |
| 277 | MIIGzTCCBbWgAwIBAgIDAdD6MA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ |
| 278 | TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0 |
| 279 | YWwgQ2VydGlmaWNhdGUgU2lnbmluZzE4MDYGA1UEAxMvU3RhcnRDb20gQ2xhc3Mg |
| 280 | MSBQcmltYXJ5IEludGVybWVkaWF0ZSBTZXJ2ZXIgQ0EwHhcNMTAwNzA0MTQ1MjQ1 |
| 281 | WhcNMTEwNzA1MTA1NzA0WjCBwTEgMB4GA1UEDRMXMjIxMTM3LWxpOWE5dHhJRzZM |
| 282 | NnNyVFMxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVQZXJzb25hIE5vdCBWYWxpZGF0 |
| 283 | ZWQxKTAnBgNVBAsTIFN0YXJ0Q29tIEZyZWUgQ2VydGlmaWNhdGUgTWVtYmVyMRsw |
| 284 | GQYDVQQDExJ3d3cuZG5zc2VjLWV4cC5vcmcxKDAmBgkqhkiG9w0BCQEWGWhvc3Rt |
| 285 | YXN0ZXJAZG5zc2VjLWV4cC5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK |
| 286 | AoIBAQDEdF/22vaxrPbqpgVYMWi+alfpzBctpbfLBdPGuqOazJdCT0NbWcK8/+B4 |
| 287 | X6OlSOURNIlwLzhkmwVsWdVv6dVSaN7d4yI/fJkvgfDB9+au+iBJb6Pcz8ULBfe6 |
| 288 | D8HVvqKdORp6INzHz71z0sghxrQ0EAEkoWAZLh+kcn2ZHdcmZaBNUfjmGbyU6PRt |
| 289 | RjdqoP+owIaC1aktBN7zl4uO7cRjlYFdusINrh2kPP02KAx2W84xjxX1uyj6oS6e |
| 290 | 7eBfvcwe8czW/N1rbE0CoR7h9+HnIrjnVG9RhBiZEiw3mUmF++Up26+4KTdRKbu3 |
| 291 | +BL4yMpfd66z0+zzqu+HkvyLpFn5AgMBAAGjggL/MIIC+zAJBgNVHRMEAjAAMAsG |
| 292 | A1UdDwQEAwIDqDATBgNVHSUEDDAKBggrBgEFBQcDATAdBgNVHQ4EFgQUy04I5guM |
| 293 | drzfh2JQaXhgV86+4jUwHwYDVR0jBBgwFoAU60I00Jiwq5/0G2sI98xkLu8OLEUw |
| 294 | LQYDVR0RBCYwJIISd3d3LmRuc3NlYy1leHAub3Jngg5kbnNzZWMtZXhwLm9yZzCC |
| 295 | AUIGA1UdIASCATkwggE1MIIBMQYLKwYBBAGBtTcBAgIwggEgMC4GCCsGAQUFBwIB |
| 296 | FiJodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9wb2xpY3kucGRmMDQGCCsGAQUFBwIB |
| 297 | FihodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9pbnRlcm1lZGlhdGUucGRmMIG3Bggr |
| 298 | BgEFBQcCAjCBqjAUFg1TdGFydENvbSBMdGQuMAMCAQEagZFMaW1pdGVkIExpYWJp |
| 299 | bGl0eSwgc2VlIHNlY3Rpb24gKkxlZ2FsIExpbWl0YXRpb25zKiBvZiB0aGUgU3Rh |
| 300 | cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUG9saWN5IGF2YWlsYWJsZSBh |
| 301 | dCBodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9wb2xpY3kucGRmMGEGA1UdHwRaMFgw |
| 302 | KqAooCaGJGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL2NydDEtY3JsLmNybDAqoCig |
| 303 | JoYkaHR0cDovL2NybC5zdGFydHNzbC5jb20vY3J0MS1jcmwuY3JsMIGOBggrBgEF |
| 304 | BQcBAQSBgTB/MDkGCCsGAQUFBzABhi1odHRwOi8vb2NzcC5zdGFydHNzbC5jb20v |
| 305 | c3ViL2NsYXNzMS9zZXJ2ZXIvY2EwQgYIKwYBBQUHMAKGNmh0dHA6Ly93d3cuc3Rh |
| 306 | cnRzc2wuY29tL2NlcnRzL3N1Yi5jbGFzczEuc2VydmVyLmNhLmNydDAjBgNVHRIE |
| 307 | HDAahhhodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS8wDQYJKoZIhvcNAQEFBQADggEB |
| 308 | ACXj6SB59KRJPenn6gUdGEqcta97U769SATyiQ87i9er64qLwvIGLMa3o2Rcgl2Y |
| 309 | kghUeyLdN/EXyFBYA8L8uvZREPoc7EZukpT/ZDLXy9i2S0jkOxvF2fD/XLbcjGjM |
| 310 | iEYG1/6ASw0ri9C0k4oDDoJLCoeH9++yqF7SFCCMcDkJqiAGXNb4euDpa8vCCtEQ |
| 311 | CSS+ObZbfkreRt3cNCf5LfCXe9OsTnCfc8Cuq81c0oLaG+SmaLUQNBuToq8e9/Zm |
| 312 | +b+/a3RVjxmkV5OCcGVBxsXNDn54Q6wsdw0TBMcjwoEndzpLS7yWgFbbkq5ZiGpw |
| 313 | Qibb2+CfKuQ+WFV1GkVQmVA= |
| 314 | -----END CERTIFICATE-----` |
| 315 | |
| 316 | const startComIntermediate = `-----BEGIN CERTIFICATE----- |
| 317 | MIIGNDCCBBygAwIBAgIBGDANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW |
| 318 | MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg |
| 319 | Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh |
| 320 | dGlvbiBBdXRob3JpdHkwHhcNMDcxMDI0MjA1NDE3WhcNMTcxMDI0MjA1NDE3WjCB |
| 321 | jDELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4xKzApBgNVBAsT |
| 322 | IlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNpZ25pbmcxODA2BgNVBAMTL1N0 |
| 323 | YXJ0Q29tIENsYXNzIDEgUHJpbWFyeSBJbnRlcm1lZGlhdGUgU2VydmVyIENBMIIB |
| 324 | IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtonGrO8JUngHrJJj0PREGBiE |
| 325 | gFYfka7hh/oyULTTRwbw5gdfcA4Q9x3AzhA2NIVaD5Ksg8asWFI/ujjo/OenJOJA |
| 326 | pgh2wJJuniptTT9uYSAK21ne0n1jsz5G/vohURjXzTCm7QduO3CHtPn66+6CPAVv |
| 327 | kvek3AowHpNz/gfK11+AnSJYUq4G2ouHI2mw5CrY6oPSvfNx23BaKA+vWjhwRRI/ |
| 328 | ME3NO68X5Q/LoKldSKqxYVDLNM08XMML6BDAjJvwAwNi/rJsPnIO7hxDKslIDlc5 |
| 329 | xDEhyBDBLIf+VJVSH1I8MRKbf+fAoKVZ1eKPPvDVqOHXcDGpxLPPr21TLwb0pwID |
| 330 | AQABo4IBrTCCAakwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD |
| 331 | VR0OBBYEFOtCNNCYsKuf9BtrCPfMZC7vDixFMB8GA1UdIwQYMBaAFE4L7xqkQFul |
| 332 | F2mHMMo0aEPQQa7yMGYGCCsGAQUFBwEBBFowWDAnBggrBgEFBQcwAYYbaHR0cDov |
| 333 | L29jc3Auc3RhcnRzc2wuY29tL2NhMC0GCCsGAQUFBzAChiFodHRwOi8vd3d3LnN0 |
| 334 | YXJ0c3NsLmNvbS9zZnNjYS5jcnQwWwYDVR0fBFQwUjAnoCWgI4YhaHR0cDovL3d3 |
| 335 | dy5zdGFydHNzbC5jb20vc2ZzY2EuY3JsMCegJaAjhiFodHRwOi8vY3JsLnN0YXJ0 |
| 336 | c3NsLmNvbS9zZnNjYS5jcmwwgYAGA1UdIAR5MHcwdQYLKwYBBAGBtTcBAgEwZjAu |
| 337 | BggrBgEFBQcCARYiaHR0cDovL3d3dy5zdGFydHNzbC5jb20vcG9saWN5LnBkZjA0 |
| 338 | BggrBgEFBQcCARYoaHR0cDovL3d3dy5zdGFydHNzbC5jb20vaW50ZXJtZWRpYXRl |
| 339 | LnBkZjANBgkqhkiG9w0BAQUFAAOCAgEAIQlJPqWIbuALi0jaMU2P91ZXouHTYlfp |
| 340 | tVbzhUV1O+VQHwSL5qBaPucAroXQ+/8gA2TLrQLhxpFy+KNN1t7ozD+hiqLjfDen |
| 341 | xk+PNdb01m4Ge90h2c9W/8swIkn+iQTzheWq8ecf6HWQTd35RvdCNPdFWAwRDYSw |
| 342 | xtpdPvkBnufh2lWVvnQce/xNFE+sflVHfXv0pQ1JHpXo9xLBzP92piVH0PN1Nb6X |
| 343 | t1gW66pceG/sUzCv6gRNzKkC4/C2BBL2MLERPZBOVmTX3DxDX3M570uvh+v2/miI |
| 344 | RHLq0gfGabDBoYvvF0nXYbFFSF87ICHpW7LM9NfpMfULFWE7epTj69m8f5SuauNi |
| 345 | YpaoZHy4h/OZMn6SolK+u/hlz8nyMPyLwcKmltdfieFcNID1j0cHL7SRv7Gifl9L |
| 346 | WtBbnySGBVFaaQNlQ0lxxeBvlDRr9hvYqbBMflPrj0jfyjO1SPo2ShpTpjMM0InN |
| 347 | SRXNiTE8kMBy12VLUjWKRhFEuT2OKGWmPnmeXAhEKa2wNREuIU640ucQPl2Eg7PD |
| 348 | wuTSxv0JS3QJ3fGz0xk+gA2iCxnwOOfFwq/iI9th4p1cbiCJSS4jarJiwUW0n6+L |
| 349 | p/EiO/h94pDQehn7Skzj0n1fSoMD7SfWI55rjbRZotnvbIIp3XUZPD9MEI3vu3Un |
| 350 | 0q6Dp6jOW6c= |
| 351 | -----END CERTIFICATE-----` |
| 352 | |
| 353 | const startComRoot = `-----BEGIN CERTIFICATE----- |
| 354 | MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW |
| 355 | MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg |
| 356 | Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh |
| 357 | dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9 |
| 358 | MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi |
| 359 | U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh |
| 360 | cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA |
| 361 | A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk |
| 362 | pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf |
| 363 | OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C |
| 364 | Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT |
| 365 | Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi |
| 366 | HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM |
| 367 | Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w |
| 368 | +2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+ |
| 369 | Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3 |
| 370 | Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B |
| 371 | 26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID |
| 372 | AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE |
| 373 | FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j |
| 374 | ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js |
| 375 | LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM |
| 376 | BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0 |
| 377 | Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy |
| 378 | dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh |
| 379 | cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh |
| 380 | YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg |
| 381 | dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp |
| 382 | bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ |
| 383 | YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT |
| 384 | TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ |
| 385 | 9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8 |
| 386 | jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW |
| 387 | FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz |
| 388 | ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1 |
| 389 | ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L |
| 390 | EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu |
| 391 | L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq |
| 392 | yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC |
| 393 | O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V |
| 394 | um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh |
| 395 | NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14= |
| 396 | -----END CERTIFICATE-----` |