Pārlūkot izejas kodu

Merge pull request #46184 from thaJeztah/bump_swarmkit

vendor: github.com/moby/swarmkit/v2 v2.0.0-20230808164555-1983e41a9fff
Bjorn Neergaard 1 gadu atpakaļ
vecāks
revīzija
fc5702b284
100 mainītis faili ar 22716 papildinājumiem un 316 dzēšanām
  1. 1 1
      integration-cli/docker_api_swarm_test.go
  2. 7 3
      vendor.mod
  3. 23 6
      vendor.sum
  4. 3 3
      vendor/github.com/cloudflare/cfssl/api/api.go
  5. 2 3
      vendor/github.com/cloudflare/cfssl/auth/auth.go
  6. 6 6
      vendor/github.com/cloudflare/cfssl/certdb/README.md
  7. 46 0
      vendor/github.com/cloudflare/cfssl/certdb/certdb.go
  8. 91 5
      vendor/github.com/cloudflare/cfssl/config/config.go
  9. 13 14
      vendor/github.com/cloudflare/cfssl/crypto/pkcs7/pkcs7.go
  10. 101 44
      vendor/github.com/cloudflare/cfssl/csr/csr.go
  11. 1 0
      vendor/github.com/cloudflare/cfssl/errors/doc.go
  12. 14 8
      vendor/github.com/cloudflare/cfssl/helpers/derhelpers/derhelpers.go
  13. 132 0
      vendor/github.com/cloudflare/cfssl/helpers/derhelpers/ed25519.go
  14. 41 12
      vendor/github.com/cloudflare/cfssl/helpers/helpers.go
  15. 4 0
      vendor/github.com/cloudflare/cfssl/initca/initca.go
  16. 159 35
      vendor/github.com/cloudflare/cfssl/signer/local/local.go
  17. 41 3
      vendor/github.com/cloudflare/cfssl/signer/signer.go
  18. 23 0
      vendor/github.com/jmoiron/sqlx/LICENSE
  19. 5 0
      vendor/github.com/jmoiron/sqlx/types/README.md
  20. 172 0
      vendor/github.com/jmoiron/sqlx/types/types.go
  21. 1 3
      vendor/github.com/moby/swarmkit/v2/agent/csi/volumes.go
  22. 2 4
      vendor/github.com/moby/swarmkit/v2/agent/exec/controller.go
  23. 7 8
      vendor/github.com/moby/swarmkit/v2/agent/session.go
  24. 11 12
      vendor/github.com/moby/swarmkit/v2/agent/worker.go
  25. 1 3
      vendor/github.com/moby/swarmkit/v2/ca/auth.go
  26. 2 2
      vendor/github.com/moby/swarmkit/v2/ca/certificates.go
  27. 6 7
      vendor/github.com/moby/swarmkit/v2/ca/config.go
  28. 1 2
      vendor/github.com/moby/swarmkit/v2/ca/external.go
  29. 10 11
      vendor/github.com/moby/swarmkit/v2/ca/renewer.go
  30. 15 16
      vendor/github.com/moby/swarmkit/v2/ca/server.go
  31. 5 2
      vendor/github.com/moby/swarmkit/v2/log/context.go
  32. 3 2
      vendor/github.com/moby/swarmkit/v2/manager/allocator/cnmallocator/drivers_ipam.go
  33. 1 2
      vendor/github.com/moby/swarmkit/v2/manager/allocator/cnmallocator/networkallocator.go
  34. 3 4
      vendor/github.com/moby/swarmkit/v2/manager/controlapi/config.go
  35. 2 3
      vendor/github.com/moby/swarmkit/v2/manager/controlapi/extension.go
  36. 1 2
      vendor/github.com/moby/swarmkit/v2/manager/controlapi/resource.go
  37. 3 4
      vendor/github.com/moby/swarmkit/v2/manager/controlapi/secret.go
  38. 2 4
      vendor/github.com/moby/swarmkit/v2/manager/csi/manager.go
  39. 3 2
      vendor/github.com/moby/swarmkit/v2/manager/dispatcher/assignments.go
  40. 30 31
      vendor/github.com/moby/swarmkit/v2/manager/dispatcher/dispatcher.go
  41. 8 9
      vendor/github.com/moby/swarmkit/v2/manager/logbroker/broker.go
  42. 5 7
      vendor/github.com/moby/swarmkit/v2/manager/manager.go
  43. 13 3
      vendor/github.com/moby/swarmkit/v2/manager/scheduler/scheduler.go
  44. 23 14
      vendor/github.com/moby/swarmkit/v2/manager/scheduler/volumes.go
  45. 11 11
      vendor/github.com/moby/swarmkit/v2/manager/state/raft/raft.go
  46. 3 3
      vendor/github.com/moby/swarmkit/v2/node/node.go
  47. 2 2
      vendor/github.com/moby/swarmkit/v2/watch/queue/queue.go
  48. 21 0
      vendor/github.com/weppos/publicsuffix-go/LICENSE.txt
  49. 544 0
      vendor/github.com/weppos/publicsuffix-go/publicsuffix/publicsuffix.go
  50. 9188 0
      vendor/github.com/weppos/publicsuffix-go/publicsuffix/rules.go
  51. 257 0
      vendor/github.com/zmap/zcrypto/LICENSE
  52. 309 0
      vendor/github.com/zmap/zcrypto/dsa/dsa.go
  53. 38 0
      vendor/github.com/zmap/zcrypto/internal/randutil/randutil.go
  54. 130 0
      vendor/github.com/zmap/zcrypto/json/dhe.go
  55. 107 0
      vendor/github.com/zmap/zcrypto/json/ecdhe.go
  56. 113 0
      vendor/github.com/zmap/zcrypto/json/names.go
  57. 67 0
      vendor/github.com/zmap/zcrypto/json/rsa.go
  58. 77 0
      vendor/github.com/zmap/zcrypto/util/isURL.go
  59. 8 0
      vendor/github.com/zmap/zcrypto/x509/README.md
  60. 171 0
      vendor/github.com/zmap/zcrypto/x509/cert_pool.go
  61. 64 0
      vendor/github.com/zmap/zcrypto/x509/certificate_type.go
  62. 70 0
      vendor/github.com/zmap/zcrypto/x509/chain.go
  63. 168 0
      vendor/github.com/zmap/zcrypto/x509/ct/serialization.go
  64. 229 0
      vendor/github.com/zmap/zcrypto/x509/ct/types.go
  65. 65 0
      vendor/github.com/zmap/zcrypto/x509/example.json
  66. 679 0
      vendor/github.com/zmap/zcrypto/x509/extended_key_usage.go
  67. 21 0
      vendor/github.com/zmap/zcrypto/x509/extended_key_usage_schema.sh
  68. 818 0
      vendor/github.com/zmap/zcrypto/x509/extensions.go
  69. 61 0
      vendor/github.com/zmap/zcrypto/x509/fingerprint.go
  70. 16 0
      vendor/github.com/zmap/zcrypto/x509/generated_certvalidationlevel_string.go
  71. 652 0
      vendor/github.com/zmap/zcrypto/x509/json.go
  72. 30 0
      vendor/github.com/zmap/zcrypto/x509/names.go
  73. 240 0
      vendor/github.com/zmap/zcrypto/x509/pem_decrypt.go
  74. 121 0
      vendor/github.com/zmap/zcrypto/x509/pkcs1.go
  75. 54 0
      vendor/github.com/zmap/zcrypto/x509/pkcs8.go
  76. 279 0
      vendor/github.com/zmap/zcrypto/x509/pkix/json.go
  77. 74 0
      vendor/github.com/zmap/zcrypto/x509/pkix/oid.go
  78. 1014 0
      vendor/github.com/zmap/zcrypto/x509/pkix/oid_names.go
  79. 299 0
      vendor/github.com/zmap/zcrypto/x509/pkix/pkix.go
  80. 173 0
      vendor/github.com/zmap/zcrypto/x509/qc_statements.go
  81. 105 0
      vendor/github.com/zmap/zcrypto/x509/sec1.go
  82. 158 0
      vendor/github.com/zmap/zcrypto/x509/tor_service_descriptor.go
  83. 60 0
      vendor/github.com/zmap/zcrypto/x509/validation.go
  84. 635 0
      vendor/github.com/zmap/zcrypto/x509/verify.go
  85. 3042 0
      vendor/github.com/zmap/zcrypto/x509/x509.go
  86. 30 0
      vendor/github.com/zmap/zlint/v3/.goreleaser.yml
  87. 202 0
      vendor/github.com/zmap/zlint/v3/LICENSE
  88. 96 0
      vendor/github.com/zmap/zlint/v3/lint/base.go
  89. 351 0
      vendor/github.com/zmap/zlint/v3/lint/registration.go
  90. 106 0
      vendor/github.com/zmap/zlint/v3/lint/result.go
  91. 129 0
      vendor/github.com/zmap/zlint/v3/lint/source.go
  92. 157 0
      vendor/github.com/zmap/zlint/v3/lints/apple/lint_ct_sct_policy_count_unsatisfied.go
  93. 61 0
      vendor/github.com/zmap/zlint/v3/lints/apple/lint_e_server_cert_valid_time_longer_than_398_days.go
  94. 67 0
      vendor/github.com/zmap/zlint/v3/lints/apple/lint_w_server_cert_valid_time_longer_than_397_days.go
  95. 13 0
      vendor/github.com/zmap/zlint/v3/lints/apple/time.go
  96. 50 0
      vendor/github.com/zmap/zlint/v3/lints/cabf_br/lint_ca_common_name_missing.go
  97. 63 0
      vendor/github.com/zmap/zlint/v3/lints/cabf_br/lint_ca_country_name_invalid.go
  98. 58 0
      vendor/github.com/zmap/zlint/v3/lints/cabf_br/lint_ca_country_name_missing.go
  99. 57 0
      vendor/github.com/zmap/zlint/v3/lints/cabf_br/lint_ca_crl_sign_not_set.go
  100. 60 0
      vendor/github.com/zmap/zlint/v3/lints/cabf_br/lint_ca_digital_signature_not_set.go

+ 1 - 1
integration-cli/docker_api_swarm_test.go

@@ -969,7 +969,7 @@ func (s *DockerSwarmSuite) TestSwarmRepeatedRootRotation(c *testing.T) {
 		if i%2 != 0 {
 			cert, _, key, err = initca.New(&csr.CertificateRequest{
 				CN:         "newRoot",
-				KeyRequest: csr.NewBasicKeyRequest(),
+				KeyRequest: csr.NewKeyRequest(),
 				CA:         &csr.CAConfig{Expiry: ca.RootCAExpiration},
 			})
 			assert.NilError(c, err)

+ 7 - 3
vendor.mod

@@ -23,7 +23,7 @@ require (
 	github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.15.17
 	github.com/aws/smithy-go v1.13.5
 	github.com/bsphere/le_go v0.0.0-20200109081728-fc06dab2caa8
-	github.com/cloudflare/cfssl v0.0.0-20180323000720-5d63dbd981b5
+	github.com/cloudflare/cfssl v1.6.4
 	github.com/container-orchestrated-devices/container-device-interface v0.6.0
 	github.com/containerd/cgroups/v3 v3.0.2
 	github.com/containerd/containerd v1.6.22
@@ -65,7 +65,7 @@ require (
 	github.com/moby/locker v1.0.1
 	github.com/moby/patternmatcher v0.5.0
 	github.com/moby/pubsub v1.0.0
-	github.com/moby/swarmkit/v2 v2.0.0-20230713153928-bc71908479e5
+	github.com/moby/swarmkit/v2 v2.0.0-20230814163642-60421a63a7f1
 	github.com/moby/sys/mount v0.3.3
 	github.com/moby/sys/mountinfo v0.6.2
 	github.com/moby/sys/sequential v0.5.0
@@ -158,6 +158,7 @@ require (
 	github.com/hashicorp/golang-lru v0.5.4 // indirect
 	github.com/in-toto/in-toto-golang v0.5.0 // indirect
 	github.com/inconshreveable/mousetrap v1.1.0 // indirect
+	github.com/jmoiron/sqlx v1.3.3 // indirect
 	github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
 	github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
 	github.com/mitchellh/reflectwalk v1.0.2 // indirect
@@ -176,6 +177,9 @@ require (
 	github.com/tonistiigi/fsutil v0.0.0-20230629203738-36ef4d8c0dbb // indirect
 	github.com/tonistiigi/go-actions-cache v0.0.0-20220404170428-0bdeb6e1eac7 // indirect
 	github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect
+	github.com/weppos/publicsuffix-go v0.15.1-0.20210511084619-b1f36a2d6c0b // indirect
+	github.com/zmap/zcrypto v0.0.0-20210511125630-18f1e0152cfc // indirect
+	github.com/zmap/zlint/v3 v3.1.0 // indirect
 	go.etcd.io/etcd/client/pkg/v3 v3.5.6 // indirect
 	go.etcd.io/etcd/pkg/v3 v3.5.6 // indirect
 	go.etcd.io/etcd/raft/v3 v3.5.6 // indirect
@@ -194,7 +198,7 @@ require (
 	go.uber.org/atomic v1.9.0 // indirect
 	go.uber.org/multierr v1.8.0 // indirect
 	go.uber.org/zap v1.21.0 // indirect
-	golang.org/x/crypto v0.2.0 // indirect
+	golang.org/x/crypto v0.3.0 // indirect
 	golang.org/x/oauth2 v0.6.0 // indirect
 	golang.org/x/tools v0.6.0 // indirect
 	google.golang.org/api v0.110.0 // indirect

+ 23 - 6
vendor.sum

@@ -293,8 +293,8 @@ github.com/cilium/ebpf v0.9.1/go.mod h1:+OhNOIXx/Fnu1IE8bJz2dzOA+VSfyTfdNUVdlQnx
 github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
 github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/cloudflare/cfssl v0.0.0-20180323000720-5d63dbd981b5 h1:PqZ3bA4yzwywivzk7PBQWngJp2/PAS0bWRZerKteicY=
-github.com/cloudflare/cfssl v0.0.0-20180323000720-5d63dbd981b5/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA=
+github.com/cloudflare/cfssl v1.6.4 h1:NMOvfrEjFfC63K3SGXgAnFdsgkmiq4kATme5BfcqrO8=
+github.com/cloudflare/cfssl v1.6.4/go.mod h1:8b3CQMxfWPAeom3zBnGJ6sd+G1NkL5TXqmDXacb+1J0=
 github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
 github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
 github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
@@ -895,6 +895,8 @@ github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeY
 github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
 github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
 github.com/jmoiron/sqlx v1.2.1-0.20190826204134-d7d95172beb5/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
+github.com/jmoiron/sqlx v1.3.3 h1:j82X0bf7oQ27XeqxicSZsTU5suPwKElg3oyxNn43iTk=
+github.com/jmoiron/sqlx v1.3.3/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ=
 github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8=
 github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
 github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
@@ -975,6 +977,7 @@ github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vq
 github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
 github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
 github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
+github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
 github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo=
 github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
@@ -1022,8 +1025,8 @@ github.com/moby/patternmatcher v0.5.0 h1:YCZgJOeULcxLw1Q+sVR636pmS7sPEn1Qo2iAN6M
 github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
 github.com/moby/pubsub v1.0.0 h1:jkp/imWsmJz2f6LyFsk7EkVeN2HxR/HTTOY8kHrsxfA=
 github.com/moby/pubsub v1.0.0/go.mod h1:bXSO+3h5MNXXCaEG+6/NlAIk7MMZbySZlnB+cUQhKKc=
-github.com/moby/swarmkit/v2 v2.0.0-20230713153928-bc71908479e5 h1:o6x+wIX1vKD0kJlEqe8M9TLIe0SK8lnGcA6XoJtaFqg=
-github.com/moby/swarmkit/v2 v2.0.0-20230713153928-bc71908479e5/go.mod h1:XUMlwIIC+wrwBDMUjxEvk5Z8FPoIPM8LdBw7w/Zu1rg=
+github.com/moby/swarmkit/v2 v2.0.0-20230814163642-60421a63a7f1 h1:B/mrXLRdSVXXJvwVNatNe+Yf+9WMS/TT7+mYKFMbgF0=
+github.com/moby/swarmkit/v2 v2.0.0-20230814163642-60421a63a7f1/go.mod h1:qYvjIScIddAio4DaXFZUyNuRxcHhm2Srm6GIrA/G/5c=
 github.com/moby/sys/mount v0.1.0/go.mod h1:FVQFLDRWwyBjDTBNQXDlWnSFREqOo3OKX9aqhmeoo74=
 github.com/moby/sys/mount v0.1.1/go.mod h1:FVQFLDRWwyBjDTBNQXDlWnSFREqOo3OKX9aqhmeoo74=
 github.com/moby/sys/mount v0.3.3 h1:fX1SVkXFJ47XWDoeFW4Sq7PdQJnV2QIDZAqjNqgEjUs=
@@ -1054,6 +1057,7 @@ github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
 github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
 github.com/mozilla/tls-observatory v0.0.0-20190404164649-a3c1b6cfecfd/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk=
 github.com/mozilla/tls-observatory v0.0.0-20200317151703-4fa42e1c2dee/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk=
+github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8=
 github.com/mrunalp/fileutils v0.0.0-20200520151820-abd8a0e76976/go.mod h1:x8F1gnqOkIEiO4rqoeEEEqQbo7HjGMTvyoq3gej4iT0=
 github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
 github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
@@ -1264,6 +1268,7 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV
 github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
 github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
 github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
@@ -1395,6 +1400,9 @@ github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1
 github.com/vishvananda/netns v0.0.2 h1:Cn05BRLm+iRP/DZxyVSsfVyrzgjDbwHwkVt38qvXnNI=
 github.com/vishvananda/netns v0.0.2/go.mod h1:yitZXdAVI+yPFSb4QUe+VW3vOVl4PZPNcBgbPxAtJxw=
 github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU=
+github.com/weppos/publicsuffix-go v0.13.1-0.20210123135404-5fd73613514e/go.mod h1:HYux0V0Zi04bHNwOHy4cXJVz/TQjYonnF6aoYhj+3QE=
+github.com/weppos/publicsuffix-go v0.15.1-0.20210511084619-b1f36a2d6c0b h1:FsyNrX12e5BkplJq7wKOLk0+C6LZ+KGXvuEcKUYm5ss=
+github.com/weppos/publicsuffix-go v0.15.1-0.20210511084619-b1f36a2d6c0b/go.mod h1:HYux0V0Zi04bHNwOHy4cXJVz/TQjYonnF6aoYhj+3QE=
 github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
 github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=
 github.com/xanzy/go-gitlab v0.31.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug=
@@ -1418,6 +1426,13 @@ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5t
 github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
 github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
 github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
+github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE=
+github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is=
+github.com/zmap/zcrypto v0.0.0-20210123152837-9cf5beac6d91/go.mod h1:R/deQh6+tSWlgI9tb4jNmXxn8nSCabl5ZQsBX9//I/E=
+github.com/zmap/zcrypto v0.0.0-20210511125630-18f1e0152cfc h1:zkGwegkOW709y0oiAraH/3D8njopUR/pARHv4tZZ6pw=
+github.com/zmap/zcrypto v0.0.0-20210511125630-18f1e0152cfc/go.mod h1:FM4U1E3NzlNMRnSUTU3P1UdukWhYGifqEsjk9fn7BCk=
+github.com/zmap/zlint/v3 v3.1.0 h1:WjVytZo79m/L1+/Mlphl09WBob6YTGljN5IGWZFpAv0=
+github.com/zmap/zlint/v3 v3.1.0/go.mod h1:L7t8s3sEKkb0A2BxGy1IWrxt1ZATa1R4QfJZaQOD3zU=
 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
 go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
 go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
@@ -1525,11 +1540,12 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
 golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
 golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.2.0 h1:BRXPfhNivWL5Yq0BGQ39a2sW6t44aODpfxkWjYdzewE=
-golang.org/x/crypto v0.2.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
+golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A=
+golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -1735,6 +1751,7 @@ golang.org/x/sys v0.0.0-20201013081832-0aaa2718063a/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201117170446-d9b008d0a637/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

+ 3 - 3
vendor/github.com/cloudflare/cfssl/api/api.go

@@ -3,7 +3,7 @@ package api
 
 import (
 	"encoding/json"
-	"io/ioutil"
+	"io"
 	"net/http"
 
 	"github.com/cloudflare/cfssl/errors"
@@ -92,7 +92,7 @@ func (h HTTPHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 func readRequestBlob(r *http.Request) (map[string]string, error) {
 	var blob map[string]string
 
-	body, err := ioutil.ReadAll(r.Body)
+	body, err := io.ReadAll(r.Body)
 	if err != nil {
 		return nil, err
 	}
@@ -176,7 +176,7 @@ type Response struct {
 	Messages []ResponseMessage `json:"messages"`
 }
 
-// NewSuccessResponse is a shortcut for creating new successul API
+// NewSuccessResponse is a shortcut for creating new successful API
 // responses.
 func NewSuccessResponse(result interface{}) Response {
 	return Response{

+ 2 - 3
vendor/github.com/cloudflare/cfssl/auth/auth.go

@@ -10,7 +10,6 @@ import (
 	"crypto/sha256"
 	"encoding/hex"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"strings"
 )
@@ -52,11 +51,11 @@ func New(key string, ad []byte) (*Standard, error) {
 		case "env":
 			key = os.Getenv(splitKey[1])
 		case "file":
-			data, err := ioutil.ReadFile(splitKey[1])
+			data, err := os.ReadFile(splitKey[1])
 			if err != nil {
 				return nil, err
 			}
-			key = string(data)
+			key = strings.TrimSpace(string(data))
 		default:
 			return nil, fmt.Errorf("unknown key prefix: %s", splitKey[0])
 		}

+ 6 - 6
vendor/github.com/cloudflare/cfssl/certdb/README.md

@@ -27,11 +27,11 @@ Currently supported:
 ### Use goose to start and terminate a MySQL DB
 To start a MySQL using goose:
 
-    goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/mysql up
+    goose -path certdb/mysql up
 
 To tear down a MySQL DB using goose
 
-    goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/mysql down
+    goose -path certdb/mysql down
 
 Note: the administration of MySQL DB is not included. We assume
 the databases being connected to are already created and access control
@@ -40,11 +40,11 @@ is properly handled.
 ### Use goose to start and terminate a PostgreSQL DB
 To start a PostgreSQL using goose:
 
-    goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/pg up
+    goose -path certdb/pg up
 
 To tear down a PostgreSQL DB using goose
 
-    goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/pg down
+    goose -path certdb/pg down
 
 Note: the administration of PostgreSQL DB is not included. We assume
 the databases being connected to are already created and access control
@@ -53,11 +53,11 @@ is properly handled.
 ### Use goose to start and terminate a SQLite DB
 To start a SQLite DB using goose:
 
-    goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/sqlite up
+    goose -path certdb/sqlite up
 
 To tear down a SQLite DB using goose
 
-    goose -path $GOPATH/src/github.com/cloudflare/cfssl/certdb/sqlite down
+    goose -path certdb/sqlite down
 
 ## CFSSL Configuration
 

+ 46 - 0
vendor/github.com/cloudflare/cfssl/certdb/certdb.go

@@ -1,7 +1,11 @@
 package certdb
 
 import (
+	"database/sql"
+	"encoding/json"
 	"time"
+
+	"github.com/jmoiron/sqlx/types"
 )
 
 // CertificateRecord encodes a certificate and its metadata
@@ -15,6 +19,46 @@ type CertificateRecord struct {
 	Expiry    time.Time `db:"expiry"`
 	RevokedAt time.Time `db:"revoked_at"`
 	PEM       string    `db:"pem"`
+	// the following fields will be empty for data inserted before migrate 002 has been run.
+	IssuedAt     *time.Time     `db:"issued_at"`
+	NotBefore    *time.Time     `db:"not_before"`
+	MetadataJSON types.JSONText `db:"metadata"`
+	SANsJSON     types.JSONText `db:"sans"`
+	CommonName   sql.NullString `db:"common_name"`
+}
+
+// SetMetadata sets the metadata json
+func (c *CertificateRecord) SetMetadata(meta map[string]interface{}) error {
+	marshaled, err := json.Marshal(meta)
+	if err != nil {
+		return err
+	}
+	c.MetadataJSON = types.JSONText(marshaled)
+	return nil
+}
+
+// GetMetadata returns the json metadata
+func (c *CertificateRecord) GetMetadata() (map[string]interface{}, error) {
+	var meta map[string]interface{}
+	err := c.MetadataJSON.Unmarshal(&meta)
+	return meta, err
+}
+
+// SetSANs sets the list of sans
+func (c *CertificateRecord) SetSANs(meta []string) error {
+	marshaled, err := json.Marshal(meta)
+	if err != nil {
+		return err
+	}
+	c.SANsJSON = types.JSONText(marshaled)
+	return nil
+}
+
+// GetSANs returns the json SANs
+func (c *CertificateRecord) GetSANs() ([]string, error) {
+	var sans []string
+	err := c.SANsJSON.Unmarshal(&sans)
+	return sans, err
 }
 
 // OCSPRecord encodes a OCSP response body and its metadata
@@ -32,7 +76,9 @@ type Accessor interface {
 	GetCertificate(serial, aki string) ([]CertificateRecord, error)
 	GetUnexpiredCertificates() ([]CertificateRecord, error)
 	GetRevokedAndUnexpiredCertificates() ([]CertificateRecord, error)
+	GetUnexpiredCertificatesByLabel(labels []string) (crs []CertificateRecord, err error)
 	GetRevokedAndUnexpiredCertificatesByLabel(label string) ([]CertificateRecord, error)
+	GetRevokedAndUnexpiredCertificatesByLabelSelectColumns(label string) ([]CertificateRecord, error)
 	RevokeCertificate(serial, aki string, reasonCode int) error
 	InsertOCSP(rr OCSPRecord) error
 	GetOCSP(serial, aki string) ([]OCSPRecord, error)

+ 91 - 5
vendor/github.com/cloudflare/cfssl/config/config.go

@@ -8,7 +8,7 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
-	"io/ioutil"
+	"os"
 	"regexp"
 	"strconv"
 	"strings"
@@ -19,6 +19,9 @@ import (
 	"github.com/cloudflare/cfssl/helpers"
 	"github.com/cloudflare/cfssl/log"
 	ocspConfig "github.com/cloudflare/cfssl/ocsp/config"
+	// empty import of zlint/v3 required to have lints registered.
+	_ "github.com/zmap/zlint/v3"
+	"github.com/zmap/zlint/v3/lint"
 )
 
 // A CSRWhitelist stores booleans for fields in the CSR. If a CSRWhitelist is
@@ -32,7 +35,7 @@ import (
 // mechanism.
 type CSRWhitelist struct {
 	Subject, PublicKeyAlgorithm, PublicKey, SignatureAlgorithm bool
-	DNSNames, IPAddresses, EmailAddresses                      bool
+	DNSNames, IPAddresses, EmailAddresses, URIs                bool
 }
 
 // OID is our own version of asn1's ObjectIdentifier, so we can define a custom
@@ -81,6 +84,8 @@ type SigningProfile struct {
 	ExpiryString        string       `json:"expiry"`
 	BackdateString      string       `json:"backdate"`
 	AuthKeyName         string       `json:"auth_key"`
+	CopyExtensions      bool         `json:"copy_extensions"`
+	PrevAuthKeyName     string       `json:"prev_auth_key"` // to support key rotation
 	RemoteName          string       `json:"remote"`
 	NotBefore           time.Time    `json:"not_before"`
 	NotAfter            time.Time    `json:"not_after"`
@@ -89,11 +94,26 @@ type SigningProfile struct {
 	CTLogServers        []string     `json:"ct_log_servers"`
 	AllowedExtensions   []OID        `json:"allowed_extensions"`
 	CertStore           string       `json:"cert_store"`
+	// LintErrLevel controls preissuance linting for the signing profile.
+	// 0 = no linting is performed [default]
+	// 2..3 = reserved
+	// 3 = all lint results except pass are considered errors
+	// 4 = all lint results except pass and notice are considered errors
+	// 5 = all lint results except pass, notice and warn are considered errors
+	// 6 = all lint results except pass, notice, warn and error are considered errors.
+	// 7 = lint is performed, no lint results are treated as errors.
+	LintErrLevel lint.LintStatus `json:"lint_error_level"`
+	// ExcludeLints lists ZLint lint names to exclude from preissuance linting.
+	ExcludeLints []string `json:"ignored_lints"`
+	// ExcludeLintSources lists ZLint lint sources to exclude from preissuance
+	// linting.
+	ExcludeLintSources []string `json:"ignored_lint_sources"`
 
 	Policies                    []CertificatePolicy
 	Expiry                      time.Duration
 	Backdate                    time.Duration
 	Provider                    auth.Provider
+	PrevProvider                auth.Provider // to suppport key rotation
 	RemoteProvider              auth.Provider
 	RemoteServer                string
 	RemoteCAs                   *x509.CertPool
@@ -102,6 +122,11 @@ type SigningProfile struct {
 	NameWhitelist               *regexp.Regexp
 	ExtensionWhitelist          map[string]bool
 	ClientProvidesSerialNumbers bool
+	// LintRegistry is the collection of lints that should be used if
+	// LintErrLevel is configured. By default all ZLint lints are used. If
+	// ExcludeLints or ExcludeLintSources are set then this registry will be
+	// filtered in populate() to exclude the named lints and lint sources.
+	LintRegistry lint.Registry
 }
 
 // UnmarshalJSON unmarshals a JSON string into an OID.
@@ -229,7 +254,7 @@ func (p *SigningProfile) populate(cfg *Config) error {
 
 	if p.AuthKeyName != "" {
 		log.Debug("match auth key in profile to auth_keys section")
-		if key, ok := cfg.AuthKeys[p.AuthKeyName]; ok == true {
+		if key, ok := cfg.AuthKeys[p.AuthKeyName]; ok {
 			if key.Type == "standard" {
 				p.Provider, err = auth.New(key.Key, nil)
 				if err != nil {
@@ -248,6 +273,27 @@ func (p *SigningProfile) populate(cfg *Config) error {
 		}
 	}
 
+	if p.PrevAuthKeyName != "" {
+		log.Debug("match previous auth key in profile to auth_keys section")
+		if key, ok := cfg.AuthKeys[p.PrevAuthKeyName]; ok {
+			if key.Type == "standard" {
+				p.PrevProvider, err = auth.New(key.Key, nil)
+				if err != nil {
+					log.Debugf("failed to create new standard auth provider: %v", err)
+					return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
+						errors.New("failed to create new standard auth provider"))
+				}
+			} else {
+				log.Debugf("unknown authentication type %v", key.Type)
+				return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
+					errors.New("unknown authentication type"))
+			}
+		} else {
+			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
+				errors.New("failed to find prev_auth_key in auth_keys section"))
+		}
+	}
+
 	if p.AuthRemote.AuthKeyName != "" {
 		log.Debug("match auth remote key in profile to auth_keys section")
 		if key, ok := cfg.AuthKeys[p.AuthRemote.AuthKeyName]; ok == true {
@@ -284,6 +330,40 @@ func (p *SigningProfile) populate(cfg *Config) error {
 		p.ExtensionWhitelist[asn1.ObjectIdentifier(oid).String()] = true
 	}
 
+	// By default perform any required preissuance linting with all ZLint lints.
+	p.LintRegistry = lint.GlobalRegistry()
+
+	// If ExcludeLintSources are present in config build a lint.SourceList while
+	// validating that no unknown sources were specified.
+	var excludedSources lint.SourceList
+	if len(p.ExcludeLintSources) > 0 {
+		for _, sourceName := range p.ExcludeLintSources {
+			var lintSource lint.LintSource
+			lintSource.FromString(sourceName)
+			if lintSource == lint.UnknownLintSource {
+				return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
+					fmt.Errorf("failed to build excluded lint source list: unknown source %q",
+						sourceName))
+			}
+			excludedSources = append(excludedSources, lintSource)
+		}
+	}
+
+	opts := lint.FilterOptions{
+		ExcludeNames:   p.ExcludeLints,
+		ExcludeSources: excludedSources,
+	}
+	if !opts.Empty() {
+		// If ExcludeLints or ExcludeLintSources were not empty then filter out the
+		// lints we don't want to use for preissuance linting with this profile.
+		filteredRegistry, err := p.LintRegistry.Filter(opts)
+		if err != nil {
+			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
+				fmt.Errorf("failed to build filtered lint registry: %v", err))
+		}
+		p.LintRegistry = filteredRegistry
+	}
+
 	return nil
 }
 
@@ -404,7 +484,8 @@ func (p *SigningProfile) Usages() (ku x509.KeyUsage, eku []x509.ExtKeyUsage, unk
 // valid local default profile has defined at least a default expiration.
 // A valid remote profile (default or not) has remote signer initialized.
 // In addition, a remote profile must has a valid auth provider if auth
-// key defined.
+// key defined. A valid profile must not include a lint_error_level outside of
+// [0,8).
 func (p *SigningProfile) validProfile(isDefault bool) bool {
 	if p == nil {
 		return false
@@ -461,6 +542,11 @@ func (p *SigningProfile) validProfile(isDefault bool) bool {
 		}
 	}
 
+	if p.LintErrLevel < 0 || p.LintErrLevel >= 8 {
+		log.Debugf("invalid profile: lint_error_level outside of range [0,8)")
+		return false
+	}
+
 	log.Debugf("profile is valid")
 	return true
 }
@@ -613,7 +699,7 @@ func LoadFile(path string) (*Config, error) {
 		return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("invalid path"))
 	}
 
-	body, err := ioutil.ReadFile(path)
+	body, err := os.ReadFile(path)
 	if err != nil {
 		return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("could not read configuration file"))
 	}

+ 13 - 14
vendor/github.com/cloudflare/cfssl/crypto/pkcs7/pkcs7.go

@@ -3,17 +3,17 @@
 // to PKCS #7 format from another encoding such as PEM conforms to this implementation.
 // reference: https://www.openssl.org/docs/man1.1.0/apps/crl2pkcs7.html
 //
-//			PKCS #7 Data type, reference: https://tools.ietf.org/html/rfc2315
+// PKCS #7 Data type, reference: https://tools.ietf.org/html/rfc2315
 //
 // The full pkcs#7 cryptographic message syntax allows for cryptographic enhancements,
 // for example data can be encrypted and signed and then packaged through pkcs#7 to be
 // sent over a network and then verified and decrypted.  It is asn1, and the type of
 // PKCS #7 ContentInfo, which comprises the PKCS #7 structure, is:
 //
-//			ContentInfo ::= SEQUENCE {
-//				contentType ContentType,
-//				content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL
-//			}
+//	ContentInfo ::= SEQUENCE {
+//		contentType ContentType,
+//		content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL
+//	}
 //
 // There are 6 possible ContentTypes, data, signedData, envelopedData,
 // signedAndEnvelopedData, digestedData, and encryptedData.  Here signedData, Data, and encrypted
@@ -22,15 +22,14 @@
 // formats.
 // The ContentType signedData has the form:
 //
-//
-//			signedData ::= SEQUENCE {
-//				version Version,
-//				digestAlgorithms DigestAlgorithmIdentifiers,
-//				contentInfo ContentInfo,
-//				certificates [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL
-//				crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
-//				signerInfos SignerInfos
-//			}
+//	signedData ::= SEQUENCE {
+//		version Version,
+//		digestAlgorithms DigestAlgorithmIdentifiers,
+//		contentInfo ContentInfo,
+//		certificates [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL
+//		crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+//		signerInfos SignerInfos
+//	}
 //
 // As of yet signerInfos and digestAlgorithms are not parsed, as they are not relevant to
 // this system's use of PKCS #7 data.  Version is an integer type, note that PKCS #7 is

+ 101 - 44
vendor/github.com/cloudflare/cfssl/csr/csr.go

@@ -12,8 +12,11 @@ import (
 	"encoding/asn1"
 	"encoding/pem"
 	"errors"
+	"fmt"
 	"net"
 	"net/mail"
+	"net/url"
+	"strconv"
 	"strings"
 
 	cferr "github.com/cloudflare/cfssl/errors"
@@ -29,46 +32,40 @@ const (
 
 // A Name contains the SubjectInfo fields.
 type Name struct {
-	C            string // Country
-	ST           string // State
-	L            string // Locality
-	O            string // OrganisationName
-	OU           string // OrganisationalUnitName
-	SerialNumber string
+	C            string            `json:"C,omitempty" yaml:"C,omitempty"`   // Country
+	ST           string            `json:"ST,omitempty" yaml:"ST,omitempty"` // State
+	L            string            `json:"L,omitempty" yaml:"L,omitempty"`   // Locality
+	O            string            `json:"O,omitempty" yaml:"O,omitempty"`   // OrganisationName
+	OU           string            `json:"OU,omitempty" yaml:"OU,omitempty"` // OrganisationalUnitName
+	E            string            `json:"E,omitempty" yaml:"E,omitempty"`
+	SerialNumber string            `json:"SerialNumber,omitempty" yaml:"SerialNumber,omitempty"`
+	OID          map[string]string `json:"OID,omitempty", yaml:"OID,omitempty"`
 }
 
-// A KeyRequest is a generic request for a new key.
-type KeyRequest interface {
-	Algo() string
-	Size() int
-	Generate() (crypto.PrivateKey, error)
-	SigAlgo() x509.SignatureAlgorithm
-}
-
-// A BasicKeyRequest contains the algorithm and key size for a new private key.
-type BasicKeyRequest struct {
+// A KeyRequest contains the algorithm and key size for a new private key.
+type KeyRequest struct {
 	A string `json:"algo" yaml:"algo"`
 	S int    `json:"size" yaml:"size"`
 }
 
-// NewBasicKeyRequest returns a default BasicKeyRequest.
-func NewBasicKeyRequest() *BasicKeyRequest {
-	return &BasicKeyRequest{"ecdsa", curveP256}
+// NewKeyRequest returns a default KeyRequest.
+func NewKeyRequest() *KeyRequest {
+	return &KeyRequest{"ecdsa", curveP256}
 }
 
 // Algo returns the requested key algorithm represented as a string.
-func (kr *BasicKeyRequest) Algo() string {
+func (kr *KeyRequest) Algo() string {
 	return kr.A
 }
 
 // Size returns the requested key size.
-func (kr *BasicKeyRequest) Size() int {
+func (kr *KeyRequest) Size() int {
 	return kr.S
 }
 
 // Generate generates a key as specified in the request. Currently,
 // only ECDSA and RSA are supported.
-func (kr *BasicKeyRequest) Generate() (crypto.PrivateKey, error) {
+func (kr *KeyRequest) Generate() (crypto.PrivateKey, error) {
 	log.Debugf("generate key from request: algo=%s, size=%d", kr.Algo(), kr.Size())
 	switch kr.Algo() {
 	case "rsa":
@@ -99,7 +96,7 @@ func (kr *BasicKeyRequest) Generate() (crypto.PrivateKey, error) {
 
 // SigAlgo returns an appropriate X.509 signature algorithm given the
 // key request's type and size.
-func (kr *BasicKeyRequest) SigAlgo() x509.SignatureAlgorithm {
+func (kr *KeyRequest) SigAlgo() x509.SignatureAlgorithm {
 	switch kr.Algo() {
 	case "rsa":
 		switch {
@@ -139,19 +136,22 @@ type CAConfig struct {
 // A CertificateRequest encapsulates the API interface to the
 // certificate request functionality.
 type CertificateRequest struct {
-	CN           string
-	Names        []Name     `json:"names" yaml:"names"`
-	Hosts        []string   `json:"hosts" yaml:"hosts"`
-	KeyRequest   KeyRequest `json:"key,omitempty" yaml:"key,omitempty"`
-	CA           *CAConfig  `json:"ca,omitempty" yaml:"ca,omitempty"`
-	SerialNumber string     `json:"serialnumber,omitempty" yaml:"serialnumber,omitempty"`
+	CN                string           `json:"CN" yaml:"CN"`
+	Names             []Name           `json:"names" yaml:"names"`
+	Hosts             []string         `json:"hosts" yaml:"hosts"`
+	KeyRequest        *KeyRequest      `json:"key,omitempty" yaml:"key,omitempty"`
+	CA                *CAConfig        `json:"ca,omitempty" yaml:"ca,omitempty"`
+	SerialNumber      string           `json:"serialnumber,omitempty" yaml:"serialnumber,omitempty"`
+	DelegationEnabled bool             `json:"delegation_enabled,omitempty" yaml:"delegation_enabled,omitempty"`
+	Extensions        []pkix.Extension `json:"extensions,omitempty" yaml:"extensions,omitempty"`
+	CRL               string           `json:"crl_url,omitempty" yaml:"crl_url,omitempty"`
 }
 
 // New returns a new, empty CertificateRequest with a
-// BasicKeyRequest.
+// KeyRequest.
 func New() *CertificateRequest {
 	return &CertificateRequest{
-		KeyRequest: NewBasicKeyRequest(),
+		KeyRequest: NewKeyRequest(),
 	}
 }
 
@@ -162,8 +162,25 @@ func appendIf(s string, a *[]string) {
 	}
 }
 
+// OIDFromString creates an ASN1 ObjectIdentifier from its string representation
+func OIDFromString(s string) (asn1.ObjectIdentifier, error) {
+	var oid []int
+	parts := strings.Split(s, ".")
+	if len(parts) < 1 {
+		return oid, fmt.Errorf("invalid OID string: %s", s)
+	}
+	for _, p := range parts {
+		i, err := strconv.Atoi(p)
+		if err != nil {
+			return nil, fmt.Errorf("invalid OID part %s", p)
+		}
+		oid = append(oid, i)
+	}
+	return oid, nil
+}
+
 // Name returns the PKIX name for the request.
-func (cr *CertificateRequest) Name() pkix.Name {
+func (cr *CertificateRequest) Name() (pkix.Name, error) {
 	var name pkix.Name
 	name.CommonName = cr.CN
 
@@ -173,9 +190,19 @@ func (cr *CertificateRequest) Name() pkix.Name {
 		appendIf(n.L, &name.Locality)
 		appendIf(n.O, &name.Organization)
 		appendIf(n.OU, &name.OrganizationalUnit)
+		for k, v := range n.OID {
+			oid, err := OIDFromString(k)
+			if err != nil {
+				return name, err
+			}
+			name.ExtraNames = append(name.ExtraNames, pkix.AttributeTypeAndValue{Type: oid, Value: v})
+		}
+		if n.E != "" {
+			name.ExtraNames = append(name.ExtraNames, pkix.AttributeTypeAndValue{Type: asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: n.E})
+		}
 	}
 	name.SerialNumber = cr.SerialNumber
-	return name
+	return name, nil
 }
 
 // BasicConstraints CSR information RFC 5280, 4.2.1.9
@@ -193,7 +220,7 @@ type BasicConstraints struct {
 func ParseRequest(req *CertificateRequest) (csr, key []byte, err error) {
 	log.Info("received CSR")
 	if req.KeyRequest == nil {
-		req.KeyRequest = NewBasicKeyRequest()
+		req.KeyRequest = NewKeyRequest()
 	}
 
 	log.Infof("generating key: %s-%d", req.KeyRequest.Algo(), req.KeyRequest.Size())
@@ -268,14 +295,17 @@ func getHosts(cert *x509.Certificate) []string {
 	for _, email := range cert.EmailAddresses {
 		hosts = append(hosts, email)
 	}
+	for _, uri := range cert.URIs {
+		hosts = append(hosts, uri.String())
+	}
 
 	return hosts
 }
 
 // getNames returns an array of Names from the certificate
-// It onnly cares about Country, Organization, OrganizationalUnit, Locality, Province
+// It only cares about Country, Organization, OrganizationalUnit, Locality, Province
 func getNames(sub pkix.Name) []Name {
-	// anonymous func for finding the max of a list of interger
+	// anonymous func for finding the max of a list of integer
 	max := func(v1 int, vn ...int) (max int) {
 		max = v1
 		for i := 0; i < len(vn); i++ {
@@ -369,8 +399,13 @@ func Generate(priv crypto.Signer, req *CertificateRequest) (csr []byte, err erro
 		return nil, cferr.New(cferr.PrivateKeyError, cferr.Unavailable)
 	}
 
+	subj, err := req.Name()
+	if err != nil {
+		return nil, err
+	}
+
 	var tpl = x509.CertificateRequest{
-		Subject:            req.Name(),
+		Subject:            subj,
 		SignatureAlgorithm: sigAlgo,
 	}
 
@@ -379,11 +414,15 @@ func Generate(priv crypto.Signer, req *CertificateRequest) (csr []byte, err erro
 			tpl.IPAddresses = append(tpl.IPAddresses, ip)
 		} else if email, err := mail.ParseAddress(req.Hosts[i]); err == nil && email != nil {
 			tpl.EmailAddresses = append(tpl.EmailAddresses, email.Address)
+		} else if uri, err := url.ParseRequestURI(req.Hosts[i]); err == nil && uri != nil {
+			tpl.URIs = append(tpl.URIs, uri)
 		} else {
 			tpl.DNSNames = append(tpl.DNSNames, req.Hosts[i])
 		}
 	}
 
+	tpl.ExtraExtensions = []pkix.Extension{}
+
 	if req.CA != nil {
 		err = appendCAInfoToCSR(req.CA, &tpl)
 		if err != nil {
@@ -392,6 +431,18 @@ func Generate(priv crypto.Signer, req *CertificateRequest) (csr []byte, err erro
 		}
 	}
 
+	if req.DelegationEnabled {
+		tpl.ExtraExtensions = append(tpl.Extensions, helpers.DelegationExtension)
+	}
+
+	if req.Extensions != nil {
+		err = appendExtensionsToCSR(req.Extensions, &tpl)
+		if err != nil {
+			err = cferr.Wrap(cferr.CSRError, cferr.GenerationFailed, err)
+			return
+		}
+	}
+
 	csr, err = x509.CreateCertificateRequest(rand.Reader, &tpl, priv)
 	if err != nil {
 		log.Errorf("failed to generate a CSR: %v", err)
@@ -420,13 +471,19 @@ func appendCAInfoToCSR(reqConf *CAConfig, csr *x509.CertificateRequest) error {
 		return err
 	}
 
-	csr.ExtraExtensions = []pkix.Extension{
-		{
-			Id:       asn1.ObjectIdentifier{2, 5, 29, 19},
-			Value:    val,
-			Critical: true,
-		},
-	}
+	csr.ExtraExtensions = append(csr.ExtraExtensions, pkix.Extension{
+		Id:       asn1.ObjectIdentifier{2, 5, 29, 19},
+		Value:    val,
+		Critical: true,
+	})
 
 	return nil
 }
+
+// appendCAInfoToCSR appends user-defined extension to a CSR
+func appendExtensionsToCSR(extensions []pkix.Extension, csr *x509.CertificateRequest) error {
+	for _, extension := range extensions {
+		csr.ExtraExtensions = append(csr.ExtraExtensions, extension)
+	}
+	return nil
+}

+ 1 - 0
vendor/github.com/cloudflare/cfssl/errors/doc.go

@@ -7,6 +7,7 @@ It formats to a json object that consists of an error message and a 4-digit code
 Example: {"code":1002, "message": "Failed to decode certificate"}
 
 The index of codes are listed below:
+
 	1XXX: CertificateError
 	    1000: Unknown
 	    1001: ReadFailed

+ 14 - 8
vendor/github.com/cloudflare/cfssl/helpers/derhelpers/derhelpers.go

@@ -5,14 +5,15 @@ package derhelpers
 import (
 	"crypto"
 	"crypto/ecdsa"
+	"crypto/ed25519"
 	"crypto/rsa"
 	"crypto/x509"
 
 	cferr "github.com/cloudflare/cfssl/errors"
 )
 
-// ParsePrivateKeyDER parses a PKCS #1, PKCS #8, or elliptic curve
-// DER-encoded private key. The key must not be in PEM format.
+// ParsePrivateKeyDER parses a PKCS #1, PKCS #8, ECDSA, or Ed25519 DER-encoded
+// private key. The key must not be in PEM format.
 func ParsePrivateKeyDER(keyDER []byte) (key crypto.Signer, err error) {
 	generalKey, err := x509.ParsePKCS8PrivateKey(keyDER)
 	if err != nil {
@@ -20,12 +21,15 @@ func ParsePrivateKeyDER(keyDER []byte) (key crypto.Signer, err error) {
 		if err != nil {
 			generalKey, err = x509.ParseECPrivateKey(keyDER)
 			if err != nil {
-				// We don't include the actual error into
-				// the final error. The reason might be
-				// we don't want to leak any info about
-				// the private key.
-				return nil, cferr.New(cferr.PrivateKeyError,
-					cferr.ParseFailed)
+				generalKey, err = ParseEd25519PrivateKey(keyDER)
+				if err != nil {
+					// We don't include the actual error into
+					// the final error. The reason might be
+					// we don't want to leak any info about
+					// the private key.
+					return nil, cferr.New(cferr.PrivateKeyError,
+						cferr.ParseFailed)
+				}
 			}
 		}
 	}
@@ -35,6 +39,8 @@ func ParsePrivateKeyDER(keyDER []byte) (key crypto.Signer, err error) {
 		return generalKey.(*rsa.PrivateKey), nil
 	case *ecdsa.PrivateKey:
 		return generalKey.(*ecdsa.PrivateKey), nil
+	case ed25519.PrivateKey:
+		return generalKey.(ed25519.PrivateKey), nil
 	}
 
 	// should never reach here

+ 132 - 0
vendor/github.com/cloudflare/cfssl/helpers/derhelpers/ed25519.go

@@ -0,0 +1,132 @@
+package derhelpers
+
+import (
+	"crypto"
+	"crypto/ed25519"
+	"crypto/x509/pkix"
+	"encoding/asn1"
+	"errors"
+)
+
+var errEd25519WrongID = errors.New("incorrect object identifier")
+var errEd25519WrongKeyType = errors.New("incorrect key type")
+
+// ed25519OID is the OID for the Ed25519 signature scheme: see
+// https://datatracker.ietf.org/doc/draft-ietf-curdle-pkix-04.
+var ed25519OID = asn1.ObjectIdentifier{1, 3, 101, 112}
+
+// subjectPublicKeyInfo reflects the ASN.1 object defined in the X.509 standard.
+//
+// This is defined in crypto/x509 as "publicKeyInfo".
+type subjectPublicKeyInfo struct {
+	Algorithm pkix.AlgorithmIdentifier
+	PublicKey asn1.BitString
+}
+
+// MarshalEd25519PublicKey creates a DER-encoded SubjectPublicKeyInfo for an
+// ed25519 public key, as defined in
+// https://tools.ietf.org/html/draft-ietf-curdle-pkix-04. This is analogous to
+// MarshalPKIXPublicKey in crypto/x509, which doesn't currently support Ed25519.
+func MarshalEd25519PublicKey(pk crypto.PublicKey) ([]byte, error) {
+	pub, ok := pk.(ed25519.PublicKey)
+	if !ok {
+		return nil, errEd25519WrongKeyType
+	}
+
+	spki := subjectPublicKeyInfo{
+		Algorithm: pkix.AlgorithmIdentifier{
+			Algorithm: ed25519OID,
+		},
+		PublicKey: asn1.BitString{
+			BitLength: len(pub) * 8,
+			Bytes:     pub,
+		},
+	}
+
+	return asn1.Marshal(spki)
+}
+
+// ParseEd25519PublicKey returns the Ed25519 public key encoded by the input.
+func ParseEd25519PublicKey(der []byte) (crypto.PublicKey, error) {
+	var spki subjectPublicKeyInfo
+	if rest, err := asn1.Unmarshal(der, &spki); err != nil {
+		return nil, err
+	} else if len(rest) > 0 {
+		return nil, errors.New("SubjectPublicKeyInfo too long")
+	}
+
+	if !spki.Algorithm.Algorithm.Equal(ed25519OID) {
+		return nil, errEd25519WrongID
+	}
+
+	if spki.PublicKey.BitLength != ed25519.PublicKeySize*8 {
+		return nil, errors.New("SubjectPublicKeyInfo PublicKey length mismatch")
+	}
+
+	return ed25519.PublicKey(spki.PublicKey.Bytes), nil
+}
+
+// oneAsymmetricKey reflects the ASN.1 structure for storing private keys in
+// https://tools.ietf.org/html/draft-ietf-curdle-pkix-04, excluding the optional
+// fields, which we don't use here.
+//
+// This is identical to pkcs8 in crypto/x509.
+type oneAsymmetricKey struct {
+	Version    int
+	Algorithm  pkix.AlgorithmIdentifier
+	PrivateKey []byte
+}
+
+// curvePrivateKey is the innter type of the PrivateKey field of
+// oneAsymmetricKey.
+type curvePrivateKey []byte
+
+// MarshalEd25519PrivateKey returns a DER encoding of the input private key as
+// specified in https://tools.ietf.org/html/draft-ietf-curdle-pkix-04.
+func MarshalEd25519PrivateKey(sk crypto.PrivateKey) ([]byte, error) {
+	priv, ok := sk.(ed25519.PrivateKey)
+	if !ok {
+		return nil, errEd25519WrongKeyType
+	}
+
+	// Marshal the innter CurvePrivateKey.
+	curvePrivateKey, err := asn1.Marshal(priv.Seed())
+	if err != nil {
+		return nil, err
+	}
+
+	// Marshal the OneAsymmetricKey.
+	asym := oneAsymmetricKey{
+		Version: 0,
+		Algorithm: pkix.AlgorithmIdentifier{
+			Algorithm: ed25519OID,
+		},
+		PrivateKey: curvePrivateKey,
+	}
+	return asn1.Marshal(asym)
+}
+
+// ParseEd25519PrivateKey returns the Ed25519 private key encoded by the input.
+func ParseEd25519PrivateKey(der []byte) (crypto.PrivateKey, error) {
+	asym := new(oneAsymmetricKey)
+	if rest, err := asn1.Unmarshal(der, asym); err != nil {
+		return nil, err
+	} else if len(rest) > 0 {
+		return nil, errors.New("OneAsymmetricKey too long")
+	}
+
+	// Check that the key type is correct.
+	if !asym.Algorithm.Algorithm.Equal(ed25519OID) {
+		return nil, errEd25519WrongID
+	}
+
+	// Unmarshal the inner CurvePrivateKey.
+	seed := new(curvePrivateKey)
+	if rest, err := asn1.Unmarshal(asym.PrivateKey, seed); err != nil {
+		return nil, err
+	} else if len(rest) > 0 {
+		return nil, errors.New("CurvePrivateKey too long")
+	}
+
+	return ed25519.NewKeyFromSeed(*seed), nil
+}

+ 41 - 12
vendor/github.com/cloudflare/cfssl/helpers/helpers.go

@@ -15,14 +15,7 @@ import (
 	"encoding/pem"
 	"errors"
 	"fmt"
-	"io/ioutil"
 	"os"
-
-	"github.com/google/certificate-transparency-go"
-	cttls "github.com/google/certificate-transparency-go/tls"
-	ctx509 "github.com/google/certificate-transparency-go/x509"
-	"golang.org/x/crypto/ocsp"
-
 	"strings"
 	"time"
 
@@ -30,6 +23,11 @@ import (
 	cferr "github.com/cloudflare/cfssl/errors"
 	"github.com/cloudflare/cfssl/helpers/derhelpers"
 	"github.com/cloudflare/cfssl/log"
+
+	ct "github.com/google/certificate-transparency-go"
+	cttls "github.com/google/certificate-transparency-go/tls"
+	ctx509 "github.com/google/certificate-transparency-go/x509"
+	"golang.org/x/crypto/ocsp"
 	"golang.org/x/crypto/pkcs12"
 )
 
@@ -39,6 +37,16 @@ const OneYear = 8760 * time.Hour
 // OneDay is a time.Duration representing a day's worth of seconds.
 const OneDay = 24 * time.Hour
 
+// DelegationUsage  is the OID for the DelegationUseage extensions
+var DelegationUsage = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 44363, 44}
+
+// DelegationExtension
+var DelegationExtension = pkix.Extension{
+	Id:       DelegationUsage,
+	Critical: false,
+	Value:    []byte{0x05, 0x00}, // ASN.1 NULL
+}
+
 // InclusiveDate returns the time.Time representation of a date - 1
 // nanosecond. This allows time.After to be used inclusively.
 func InclusiveDate(year int, month time.Month, day int) time.Time {
@@ -184,6 +192,19 @@ func HashAlgoString(alg x509.SignatureAlgorithm) string {
 	}
 }
 
+// StringTLSVersion returns underlying enum values from human names for TLS
+// versions, defaults to current golang default of TLS 1.0
+func StringTLSVersion(version string) uint16 {
+	switch version {
+	case "1.2":
+		return tls.VersionTLS12
+	case "1.1":
+		return tls.VersionTLS11
+	default:
+		return tls.VersionTLS10
+	}
+}
+
 // EncodeCertificatesPEM encodes a number of x509 certificates to PEM
 func EncodeCertificatesPEM(certs []*x509.Certificate) []byte {
 	var buffer bytes.Buffer
@@ -322,7 +343,7 @@ func LoadPEMCertPool(certsFile string) (*x509.CertPool, error) {
 	if certsFile == "" {
 		return nil, nil
 	}
-	pemCerts, err := ioutil.ReadFile(certsFile)
+	pemCerts, err := os.ReadFile(certsFile)
 	if err != nil {
 		return nil, err
 	}
@@ -365,7 +386,15 @@ func ParsePrivateKeyPEMWithPassword(keyPEM []byte, password []byte) (key crypto.
 
 // GetKeyDERFromPEM parses a PEM-encoded private key and returns DER-format key bytes.
 func GetKeyDERFromPEM(in []byte, password []byte) ([]byte, error) {
-	keyDER, _ := pem.Decode(in)
+	// Ignore any EC PARAMETERS blocks when looking for a key (openssl includes
+	// them by default).
+	var keyDER *pem.Block
+	for {
+		keyDER, in = pem.Decode(in)
+		if keyDER == nil || keyDER.Type != "EC PARAMETERS" {
+			break
+		}
+	}
 	if keyDER != nil {
 		if procType, ok := keyDER.Headers["Proc-Type"]; ok {
 			if strings.Contains(procType, "ENCRYPTED") {
@@ -460,7 +489,7 @@ func LoadClientCertificate(certFile string, keyFile string) (*tls.Certificate, e
 	if certFile != "" && keyFile != "" {
 		cert, err := tls.LoadX509KeyPair(certFile, keyFile)
 		if err != nil {
-			log.Critical("Unable to read client certificate from file: %s or key from file: %s", certFile, keyFile)
+			log.Criticalf("Unable to read client certificate from file: %s or key from file: %s", certFile, keyFile)
 			return nil, err
 		}
 		log.Debug("Client certificate loaded ")
@@ -560,13 +589,13 @@ func SCTListFromOCSPResponse(response *ocsp.Response) ([]ct.SignedCertificateTim
 func ReadBytes(valFile string) ([]byte, error) {
 	switch splitVal := strings.SplitN(valFile, ":", 2); len(splitVal) {
 	case 1:
-		return ioutil.ReadFile(valFile)
+		return os.ReadFile(valFile)
 	case 2:
 		switch splitVal[0] {
 		case "env":
 			return []byte(os.Getenv(splitVal[1])), nil
 		case "file":
-			return ioutil.ReadFile(splitVal[1])
+			return os.ReadFile(splitVal[1])
 		default:
 			return nil, fmt.Errorf("unknown prefix: %s", splitVal[0])
 		}

+ 4 - 0
vendor/github.com/cloudflare/cfssl/initca/initca.go

@@ -69,6 +69,10 @@ func New(req *csr.CertificateRequest) (cert, csrPEM, key []byte, err error) {
 		}
 	}
 
+	if req.CRL != "" {
+		policy.Default.CRL = req.CRL
+	}
+
 	g := &csr.Generator{Validator: validator}
 	csrPEM, key, err = g.ProcessRequest(req)
 	if err != nil {

+ 159 - 35
vendor/github.com/cloudflare/cfssl/signer/local/local.go

@@ -3,20 +3,27 @@ package local
 
 import (
 	"bytes"
+	"context"
 	"crypto"
+	"crypto/ecdsa"
+	"crypto/elliptic"
 	"crypto/rand"
 	"crypto/x509"
 	"crypto/x509/pkix"
+	"database/sql"
 	"encoding/asn1"
 	"encoding/hex"
 	"encoding/pem"
 	"errors"
+	"fmt"
 	"io"
 	"math/big"
 	"net"
 	"net/http"
 	"net/mail"
+	"net/url"
 	"os"
+	"time"
 
 	"github.com/cloudflare/cfssl/certdb"
 	"github.com/cloudflare/cfssl/config"
@@ -25,17 +32,23 @@ import (
 	"github.com/cloudflare/cfssl/info"
 	"github.com/cloudflare/cfssl/log"
 	"github.com/cloudflare/cfssl/signer"
-	"github.com/google/certificate-transparency-go"
+	ct "github.com/google/certificate-transparency-go"
 	"github.com/google/certificate-transparency-go/client"
 	"github.com/google/certificate-transparency-go/jsonclient"
-	"golang.org/x/net/context"
+
+	zx509 "github.com/zmap/zcrypto/x509"
+	"github.com/zmap/zlint/v3"
+	"github.com/zmap/zlint/v3/lint"
 )
 
 // Signer contains a signer that uses the standard library to
 // support both ECDSA and RSA CA keys.
 type Signer struct {
-	ca         *x509.Certificate
-	priv       crypto.Signer
+	ca   *x509.Certificate
+	priv crypto.Signer
+	// lintPriv is generated randomly when pre-issuance linting is configured and
+	// used to sign TBSCertificates for linting.
+	lintPriv   crypto.Signer
 	policy     *config.Signing
 	sigAlgo    x509.SignatureAlgorithm
 	dbAccessor certdb.Accessor
@@ -54,11 +67,30 @@ func NewSigner(priv crypto.Signer, cert *x509.Certificate, sigAlgo x509.Signatur
 		return nil, cferr.New(cferr.PolicyError, cferr.InvalidPolicy)
 	}
 
+	var lintPriv crypto.Signer
+	// If there is at least one profile (including the default) that configures
+	// pre-issuance linting then generate the one-off lintPriv key.
+	for _, profile := range policy.Profiles {
+		if profile.LintErrLevel > 0 || policy.Default.LintErrLevel > 0 {
+			// In the future there may be demand for specifying the type of signer used
+			// for pre-issuance linting in configuration. For now we assume that signing
+			// with a randomly generated P-256 ECDSA private key is acceptable for all cases
+			// where linting is requested.
+			k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+			if err != nil {
+				return nil, cferr.New(cferr.PrivateKeyError, cferr.GenerationFailed)
+			}
+			lintPriv = k
+			break
+		}
+	}
+
 	return &Signer{
-		ca:      cert,
-		priv:    priv,
-		sigAlgo: sigAlgo,
-		policy:  policy,
+		ca:       cert,
+		priv:     priv,
+		lintPriv: lintPriv,
+		sigAlgo:  sigAlgo,
+		policy:   policy,
 	}, nil
 }
 
@@ -89,14 +121,75 @@ func NewSignerFromFile(caFile, caKeyFile string, policy *config.Signing) (*Signe
 
 	priv, err := helpers.ParsePrivateKeyPEMWithPassword(cakey, password)
 	if err != nil {
-		log.Debug("Malformed private key %v", err)
+		log.Debugf("Malformed private key %v", err)
 		return nil, err
 	}
 
 	return NewSigner(priv, parsedCa, signer.DefaultSigAlgo(priv), policy)
 }
 
-func (s *Signer) sign(template *x509.Certificate) (cert []byte, err error) {
+// LintError is an error type returned when pre-issuance linting is configured
+// in a signing profile and a TBS Certificate fails linting. It wraps the
+// concrete zlint LintResults so that callers can further inspect the cause of
+// the failing lints.
+type LintError struct {
+	ErrorResults map[string]lint.LintResult
+}
+
+func (e *LintError) Error() string {
+	return fmt.Sprintf("pre-issuance linting found %d error results",
+		len(e.ErrorResults))
+}
+
+// lint performs pre-issuance linting of a given TBS certificate template when
+// the provided errLevel is > 0. Note that the template is provided by-value and
+// not by-reference. This is important as the lint function needs to mutate the
+// template's signature algorithm to match the lintPriv.
+func (s *Signer) lint(template x509.Certificate, errLevel lint.LintStatus, lintRegistry lint.Registry) error {
+	// Always return nil when linting is disabled (lint.Reserved == 0).
+	if errLevel == lint.Reserved {
+		return nil
+	}
+	// without a lintPriv key to use to sign the tbsCertificate we can't lint it.
+	if s.lintPriv == nil {
+		return cferr.New(cferr.PrivateKeyError, cferr.Unavailable)
+	}
+
+	// The template's SignatureAlgorithm must be mutated to match the lintPriv or
+	// x509.CreateCertificate will error because of the mismatch. At the time of
+	// writing s.lintPriv is always an ECDSA private key. This switch will need to
+	// be expanded if the lint key type is made configurable.
+	switch s.lintPriv.(type) {
+	case *ecdsa.PrivateKey:
+		template.SignatureAlgorithm = x509.ECDSAWithSHA256
+	default:
+		return cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch)
+	}
+
+	prelintBytes, err := x509.CreateCertificate(rand.Reader, &template, s.ca, template.PublicKey, s.lintPriv)
+	if err != nil {
+		return cferr.Wrap(cferr.CertificateError, cferr.Unknown, err)
+	}
+	prelintCert, err := zx509.ParseCertificate(prelintBytes)
+	if err != nil {
+		return cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err)
+	}
+	errorResults := map[string]lint.LintResult{}
+	results := zlint.LintCertificateEx(prelintCert, lintRegistry)
+	for name, res := range results.Results {
+		if res.Status > errLevel {
+			errorResults[name] = *res
+		}
+	}
+	if len(errorResults) > 0 {
+		return &LintError{
+			ErrorResults: errorResults,
+		}
+	}
+	return nil
+}
+
+func (s *Signer) sign(template *x509.Certificate, lintErrLevel lint.LintStatus, lintRegistry lint.Registry) (cert []byte, err error) {
 	var initRoot bool
 	if s.ca == nil {
 		if !template.IsCA {
@@ -105,10 +198,15 @@ func (s *Signer) sign(template *x509.Certificate) (cert []byte, err error) {
 		}
 		template.DNSNames = nil
 		template.EmailAddresses = nil
+		template.URIs = nil
 		s.ca = template
 		initRoot = true
 	}
 
+	if err := s.lint(*template, lintErrLevel, lintRegistry); err != nil {
+		return nil, err
+	}
+
 	derBytes, err := x509.CreateCertificate(rand.Reader, template, s.ca, template.PublicKey, s.priv)
 	if err != nil {
 		return nil, cferr.Wrap(cferr.CertificateError, cferr.Unknown, err)
@@ -159,13 +257,14 @@ func PopulateSubjectFromCSR(s *signer.Subject, req pkix.Name) pkix.Name {
 	return name
 }
 
-// OverrideHosts fills template's IPAddresses, EmailAddresses, and DNSNames with the
+// OverrideHosts fills template's IPAddresses, EmailAddresses, DNSNames, and URIs with the
 // content of hosts, if it is not nil.
 func OverrideHosts(template *x509.Certificate, hosts []string) {
 	if hosts != nil {
 		template.IPAddresses = []net.IP{}
 		template.EmailAddresses = []string{}
 		template.DNSNames = []string{}
+		template.URIs = []*url.URL{}
 	}
 
 	for i := range hosts {
@@ -173,6 +272,8 @@ func OverrideHosts(template *x509.Certificate, hosts []string) {
 			template.IPAddresses = append(template.IPAddresses, ip)
 		} else if email, err := mail.ParseAddress(hosts[i]); err == nil && email != nil {
 			template.EmailAddresses = append(template.EmailAddresses, email.Address)
+		} else if uri, err := url.ParseRequestURI(hosts[i]); err == nil && uri != nil {
+			template.URIs = append(template.URIs, uri)
 		} else {
 			template.DNSNames = append(template.DNSNames, hosts[i])
 		}
@@ -199,7 +300,7 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
 			cferr.BadRequest, errors.New("not a csr"))
 	}
 
-	csrTemplate, err := signer.ParseCertificateRequest(s, block.Bytes)
+	csrTemplate, err := signer.ParseCertificateRequest(s, profile, block.Bytes)
 	if err != nil {
 		return nil, err
 	}
@@ -232,6 +333,9 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
 		if profile.CSRWhitelist.EmailAddresses {
 			safeTemplate.EmailAddresses = csrTemplate.EmailAddresses
 		}
+		if profile.CSRWhitelist.URIs {
+			safeTemplate.URIs = csrTemplate.URIs
+		}
 	}
 
 	if req.CRLOverride != "" {
@@ -277,6 +381,11 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
 				return nil, cferr.New(cferr.PolicyError, cferr.UnmatchedWhitelist)
 			}
 		}
+		for _, name := range safeTemplate.URIs {
+			if profile.NameWhitelist.Find([]byte(name.String())) == nil {
+				return nil, cferr.New(cferr.PolicyError, cferr.UnmatchedWhitelist)
+			}
+		}
 	}
 
 	if profile.ClientProvidesSerialNumbers {
@@ -342,7 +451,7 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
 		var poisonExtension = pkix.Extension{Id: signer.CTPoisonOID, Critical: true, Value: []byte{0x05, 0x00}}
 		var poisonedPreCert = certTBS
 		poisonedPreCert.ExtraExtensions = append(safeTemplate.ExtraExtensions, poisonExtension)
-		cert, err = s.sign(&poisonedPreCert)
+		cert, err = s.sign(&poisonedPreCert, profile.LintErrLevel, profile.LintRegistry)
 		if err != nil {
 			return
 		}
@@ -385,8 +494,9 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
 		var SCTListExtension = pkix.Extension{Id: signer.SCTListOID, Critical: false, Value: serializedSCTList}
 		certTBS.ExtraExtensions = append(certTBS.ExtraExtensions, SCTListExtension)
 	}
+
 	var signedCert []byte
-	signedCert, err = s.sign(&certTBS)
+	signedCert, err = s.sign(&certTBS, profile.LintErrLevel, profile.LintRegistry)
 	if err != nil {
 		return nil, err
 	}
@@ -397,19 +507,29 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
 	parsedCert, _ := helpers.ParseCertificatePEM(signedCert)
 
 	if s.dbAccessor != nil {
+		now := time.Now()
 		var certRecord = certdb.CertificateRecord{
 			Serial: certTBS.SerialNumber.String(),
 			// this relies on the specific behavior of x509.CreateCertificate
 			// which sets the AuthorityKeyId from the signer's SubjectKeyId
-			AKI:     hex.EncodeToString(parsedCert.AuthorityKeyId),
-			CALabel: req.Label,
-			Status:  "good",
-			Expiry:  certTBS.NotAfter,
-			PEM:     string(signedCert),
+			AKI:        hex.EncodeToString(parsedCert.AuthorityKeyId),
+			CALabel:    req.Label,
+			Status:     "good",
+			Expiry:     certTBS.NotAfter,
+			PEM:        string(signedCert),
+			IssuedAt:   &now,
+			NotBefore:  &certTBS.NotBefore,
+			CommonName: sql.NullString{String: certTBS.Subject.CommonName, Valid: true},
 		}
 
-		err = s.dbAccessor.InsertCertificate(certRecord)
-		if err != nil {
+		if err := certRecord.SetMetadata(req.Metadata); err != nil {
+			return nil, err
+		}
+		if err := certRecord.SetSANs(certTBS.DNSNames); err != nil {
+			return nil, err
+		}
+
+		if err := s.dbAccessor.InsertCertificate(certRecord); err != nil {
 			return nil, err
 		}
 		log.Debug("saved certificate with serial number ", certTBS.SerialNumber)
@@ -424,7 +544,9 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
 // except for the removal of the poison extension and the addition of the SCT list
 // extension. SignFromPrecert does not verify that the contents of the certificate
 // still match the signing profile of the signer, it only requires that the precert
-// was previously signed by the Signers CA.
+// was previously signed by the Signers CA. Similarly, any linting configured
+// by the profile used to sign the precert will not be re-applied to the final
+// cert and must be done separately by the caller.
 func (s *Signer) SignFromPrecert(precert *x509.Certificate, scts []ct.SignedCertificateTimestamp) ([]byte, error) {
 	// Verify certificate was signed by s.ca
 	if err := precert.CheckSignatureFrom(s.ca); err != nil {
@@ -467,17 +589,17 @@ func (s *Signer) SignFromPrecert(precert *x509.Certificate, scts []ct.SignedCert
 	// Create the new tbsCert from precert. Do explicit copies of any slices so that we don't
 	// use memory that may be altered by us or the caller at a later stage.
 	tbsCert := x509.Certificate{
-		SignatureAlgorithm:    precert.SignatureAlgorithm,
-		PublicKeyAlgorithm:    precert.PublicKeyAlgorithm,
-		PublicKey:             precert.PublicKey,
-		Version:               precert.Version,
-		SerialNumber:          precert.SerialNumber,
-		Issuer:                precert.Issuer,
-		Subject:               precert.Subject,
-		NotBefore:             precert.NotBefore,
-		NotAfter:              precert.NotAfter,
-		KeyUsage:              precert.KeyUsage,
-		BasicConstraintsValid: precert.BasicConstraintsValid,
+		SignatureAlgorithm:          precert.SignatureAlgorithm,
+		PublicKeyAlgorithm:          precert.PublicKeyAlgorithm,
+		PublicKey:                   precert.PublicKey,
+		Version:                     precert.Version,
+		SerialNumber:                precert.SerialNumber,
+		Issuer:                      precert.Issuer,
+		Subject:                     precert.Subject,
+		NotBefore:                   precert.NotBefore,
+		NotAfter:                    precert.NotAfter,
+		KeyUsage:                    precert.KeyUsage,
+		BasicConstraintsValid:       precert.BasicConstraintsValid,
 		IsCA:                        precert.IsCA,
 		MaxPathLen:                  precert.MaxPathLen,
 		MaxPathLenZero:              precert.MaxPathLenZero,
@@ -493,8 +615,10 @@ func (s *Signer) SignFromPrecert(precert *x509.Certificate, scts []ct.SignedCert
 	// Insert the SCT list extension
 	tbsCert.ExtraExtensions = append(tbsCert.ExtraExtensions, sctExt)
 
-	// Sign the tbsCert
-	return s.sign(&tbsCert)
+	// Sign the tbsCert. Linting is always disabled because there is no way for
+	// this API to know the correct lint settings to use because there is no
+	// reference to the signing profile of the precert available.
+	return s.sign(&tbsCert, 0, nil)
 }
 
 // Info return a populated info.Resp struct or an error.

+ 41 - 3
vendor/github.com/cloudflare/cfssl/signer/signer.go

@@ -20,6 +20,7 @@ import (
 	"github.com/cloudflare/cfssl/config"
 	"github.com/cloudflare/cfssl/csr"
 	cferr "github.com/cloudflare/cfssl/errors"
+	"github.com/cloudflare/cfssl/helpers"
 	"github.com/cloudflare/cfssl/info"
 )
 
@@ -45,7 +46,7 @@ type Extension struct {
 // Extensions provided in the signRequest are copied into the certificate, as
 // long as they are in the ExtensionWhitelist for the signer's policy.
 // Extensions requested in the CSR are ignored, except for those processed by
-// ParseCertificateRequest (mainly subjectAltName).
+// ParseCertificateRequest (mainly subjectAltName) and DelegationUsage.
 type SignRequest struct {
 	Hosts       []string    `json:"hosts"`
 	Request     string      `json:"certificate_request"`
@@ -70,6 +71,9 @@ type SignRequest struct {
 	// be passed to SignFromPrecert with the SCTs in order to create a
 	// valid certificate.
 	ReturnPrecert bool
+
+	// Arbitrary metadata to be stored in certdb.
+	Metadata map[string]interface{} `json:"metadata"`
 }
 
 // appendIf appends to a if s is not an empty string.
@@ -169,15 +173,38 @@ func DefaultSigAlgo(priv crypto.Signer) x509.SignatureAlgorithm {
 	}
 }
 
+func isCommonAttr(t []int) bool {
+	return (len(t) == 4 && t[0] == 2 && t[1] == 5 && t[2] == 4 && (t[3] == 3 || (t[3] >= 5 && t[3] <= 11) || t[3] == 17))
+}
+
 // ParseCertificateRequest takes an incoming certificate request and
 // builds a certificate template from it.
-func ParseCertificateRequest(s Signer, csrBytes []byte) (template *x509.Certificate, err error) {
+func ParseCertificateRequest(s Signer, p *config.SigningProfile, csrBytes []byte) (template *x509.Certificate, err error) {
 	csrv, err := x509.ParseCertificateRequest(csrBytes)
 	if err != nil {
 		err = cferr.Wrap(cferr.CSRError, cferr.ParseFailed, err)
 		return
 	}
 
+	var r pkix.RDNSequence
+	_, err = asn1.Unmarshal(csrv.RawSubject, &r)
+
+	if err != nil {
+		err = cferr.Wrap(cferr.CSRError, cferr.ParseFailed, err)
+		return
+	}
+
+	var subject pkix.Name
+	subject.FillFromRDNSequence(&r)
+
+	for _, v := range r {
+		for _, vv := range v {
+			if !isCommonAttr(vv.Type) {
+				subject.ExtraNames = append(subject.ExtraNames, vv)
+			}
+		}
+	}
+
 	err = csrv.CheckSignature()
 	if err != nil {
 		err = cferr.Wrap(cferr.CSRError, cferr.KeyMismatch, err)
@@ -185,13 +212,16 @@ func ParseCertificateRequest(s Signer, csrBytes []byte) (template *x509.Certific
 	}
 
 	template = &x509.Certificate{
-		Subject:            csrv.Subject,
+		Subject:            subject,
 		PublicKeyAlgorithm: csrv.PublicKeyAlgorithm,
 		PublicKey:          csrv.PublicKey,
 		SignatureAlgorithm: s.SigAlgo(),
 		DNSNames:           csrv.DNSNames,
 		IPAddresses:        csrv.IPAddresses,
 		EmailAddresses:     csrv.EmailAddresses,
+		URIs:               csrv.URIs,
+		Extensions:         csrv.Extensions,
+		ExtraExtensions:    []pkix.Extension{},
 	}
 
 	for _, val := range csrv.Extensions {
@@ -211,6 +241,13 @@ func ParseCertificateRequest(s Signer, csrBytes []byte) (template *x509.Certific
 			template.IsCA = constraints.IsCA
 			template.MaxPathLen = constraints.MaxPathLen
 			template.MaxPathLenZero = template.MaxPathLen == 0
+		} else if val.Id.Equal(helpers.DelegationUsage) {
+			template.ExtraExtensions = append(template.ExtraExtensions, val)
+		} else {
+			// If the profile has 'copy_extensions' to true then lets add it
+			if p.CopyExtensions {
+				template.ExtraExtensions = append(template.ExtraExtensions, val)
+			}
 		}
 	}
 
@@ -320,6 +357,7 @@ func FillTemplate(template *x509.Certificate, defaultProfile, profile *config.Si
 		}
 		template.DNSNames = nil
 		template.EmailAddresses = nil
+		template.URIs = nil
 	}
 	template.SubjectKeyId = ski
 

+ 23 - 0
vendor/github.com/jmoiron/sqlx/LICENSE

@@ -0,0 +1,23 @@
+ Copyright (c) 2013, Jason Moiron
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without
+ restriction, including without limitation the rights to use,
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following
+ conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+

+ 5 - 0
vendor/github.com/jmoiron/sqlx/types/README.md

@@ -0,0 +1,5 @@
+# types
+
+The types package provides some useful types which implement the `sql.Scanner`
+and `driver.Valuer` interfaces, suitable for use as scan and value targets with
+database/sql.

+ 172 - 0
vendor/github.com/jmoiron/sqlx/types/types.go

@@ -0,0 +1,172 @@
+package types
+
+import (
+	"bytes"
+	"compress/gzip"
+	"database/sql/driver"
+	"encoding/json"
+	"errors"
+
+	"io/ioutil"
+)
+
+// GzippedText is a []byte which transparently gzips data being submitted to
+// a database and ungzips data being Scanned from a database.
+type GzippedText []byte
+
+// Value implements the driver.Valuer interface, gzipping the raw value of
+// this GzippedText.
+func (g GzippedText) Value() (driver.Value, error) {
+	b := make([]byte, 0, len(g))
+	buf := bytes.NewBuffer(b)
+	w := gzip.NewWriter(buf)
+	w.Write(g)
+	w.Close()
+	return buf.Bytes(), nil
+
+}
+
+// Scan implements the sql.Scanner interface, ungzipping the value coming off
+// the wire and storing the raw result in the GzippedText.
+func (g *GzippedText) Scan(src interface{}) error {
+	var source []byte
+	switch src := src.(type) {
+	case string:
+		source = []byte(src)
+	case []byte:
+		source = src
+	default:
+		return errors.New("Incompatible type for GzippedText")
+	}
+	reader, err := gzip.NewReader(bytes.NewReader(source))
+	if err != nil {
+		return err
+	}
+	defer reader.Close()
+	b, err := ioutil.ReadAll(reader)
+	if err != nil {
+		return err
+	}
+	*g = GzippedText(b)
+	return nil
+}
+
+// JSONText is a json.RawMessage, which is a []byte underneath.
+// Value() validates the json format in the source, and returns an error if
+// the json is not valid.  Scan does no validation.  JSONText additionally
+// implements `Unmarshal`, which unmarshals the json within to an interface{}
+type JSONText json.RawMessage
+
+var emptyJSON = JSONText("{}")
+
+// MarshalJSON returns the *j as the JSON encoding of j.
+func (j JSONText) MarshalJSON() ([]byte, error) {
+	if len(j) == 0 {
+		return emptyJSON, nil
+	}
+	return j, nil
+}
+
+// UnmarshalJSON sets *j to a copy of data
+func (j *JSONText) UnmarshalJSON(data []byte) error {
+	if j == nil {
+		return errors.New("JSONText: UnmarshalJSON on nil pointer")
+	}
+	*j = append((*j)[0:0], data...)
+	return nil
+}
+
+// Value returns j as a value.  This does a validating unmarshal into another
+// RawMessage.  If j is invalid json, it returns an error.
+func (j JSONText) Value() (driver.Value, error) {
+	var m json.RawMessage
+	var err = j.Unmarshal(&m)
+	if err != nil {
+		return []byte{}, err
+	}
+	return []byte(j), nil
+}
+
+// Scan stores the src in *j.  No validation is done.
+func (j *JSONText) Scan(src interface{}) error {
+	var source []byte
+	switch t := src.(type) {
+	case string:
+		source = []byte(t)
+	case []byte:
+		if len(t) == 0 {
+			source = emptyJSON
+		} else {
+			source = t
+		}
+	case nil:
+		*j = emptyJSON
+	default:
+		return errors.New("Incompatible type for JSONText")
+	}
+	*j = append((*j)[0:0], source...)
+	return nil
+}
+
+// Unmarshal unmarshal's the json in j to v, as in json.Unmarshal.
+func (j *JSONText) Unmarshal(v interface{}) error {
+	if len(*j) == 0 {
+		*j = emptyJSON
+	}
+	return json.Unmarshal([]byte(*j), v)
+}
+
+// String supports pretty printing for JSONText types.
+func (j JSONText) String() string {
+	return string(j)
+}
+
+// NullJSONText represents a JSONText that may be null.
+// NullJSONText implements the scanner interface so
+// it can be used as a scan destination, similar to NullString.
+type NullJSONText struct {
+	JSONText
+	Valid bool // Valid is true if JSONText is not NULL
+}
+
+// Scan implements the Scanner interface.
+func (n *NullJSONText) Scan(value interface{}) error {
+	if value == nil {
+		n.JSONText, n.Valid = emptyJSON, false
+		return nil
+	}
+	n.Valid = true
+	return n.JSONText.Scan(value)
+}
+
+// Value implements the driver Valuer interface.
+func (n NullJSONText) Value() (driver.Value, error) {
+	if !n.Valid {
+		return nil, nil
+	}
+	return n.JSONText.Value()
+}
+
+// BitBool is an implementation of a bool for the MySQL type BIT(1).
+// This type allows you to avoid wasting an entire byte for MySQL's boolean type TINYINT.
+type BitBool bool
+
+// Value implements the driver.Valuer interface,
+// and turns the BitBool into a bitfield (BIT(1)) for MySQL storage.
+func (b BitBool) Value() (driver.Value, error) {
+	if b {
+		return []byte{1}, nil
+	}
+	return []byte{0}, nil
+}
+
+// Scan implements the sql.Scanner interface,
+// and turns the bitfield incoming from MySQL into a BitBool
+func (b *BitBool) Scan(src interface{}) error {
+	v, ok := src.([]byte)
+	if !ok {
+		return errors.New("bad []byte type assertion")
+	}
+	*b = v[0] == 1
+	return nil
+}

+ 1 - 3
vendor/github.com/moby/swarmkit/v2/agent/csi/volumes.go

@@ -6,8 +6,6 @@ import (
 	"sync"
 	"time"
 
-	"github.com/sirupsen/logrus"
-
 	"github.com/docker/docker/pkg/plugingetter"
 
 	"github.com/moby/swarmkit/v2/agent/csi/plugin"
@@ -65,7 +63,7 @@ func (r *volumes) retryVolumes() {
 	for {
 		vid, attempt := r.pendingVolumes.Wait()
 
-		dctx := log.WithFields(ctx, logrus.Fields{
+		dctx := log.WithFields(ctx, log.Fields{
 			"volume.id": vid,
 			"attempt":   fmt.Sprintf("%d", attempt),
 		})

+ 2 - 4
vendor/github.com/moby/swarmkit/v2/agent/exec/controller.go

@@ -10,7 +10,6 @@ import (
 	"github.com/moby/swarmkit/v2/log"
 	"github.com/moby/swarmkit/v2/protobuf/ptypes"
 	"github.com/pkg/errors"
-	"github.com/sirupsen/logrus"
 )
 
 // Controller controls execution of a task.
@@ -348,11 +347,10 @@ func Do(ctx context.Context, task *api.Task, ctlr Controller) (*api.TaskStatus,
 
 func logStateChange(ctx context.Context, desired, previous, next api.TaskState) {
 	if previous != next {
-		fields := logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"state.transition": fmt.Sprintf("%v->%v", previous, next),
 			"state.desired":    desired,
-		}
-		log.G(ctx).WithFields(fields).Debug("state changed")
+		}).Debug("state changed")
 	}
 }
 

+ 7 - 8
vendor/github.com/moby/swarmkit/v2/agent/session.go

@@ -10,7 +10,6 @@ import (
 	"github.com/moby/swarmkit/v2/api"
 	"github.com/moby/swarmkit/v2/connectionbroker"
 	"github.com/moby/swarmkit/v2/log"
-	"github.com/sirupsen/logrus"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
@@ -180,7 +179,7 @@ func (s *session) heartbeat(ctx context.Context) error {
 	heartbeat := time.NewTimer(1) // send out a heartbeat right away
 	defer heartbeat.Stop()
 
-	fields := logrus.Fields{
+	fields := log.Fields{
 		"sessionID": s.sessionID,
 		"method":    "(*session).heartbeat",
 	}
@@ -243,8 +242,8 @@ func (s *session) handleSessionMessage(ctx context.Context, msg *api.SessionMess
 }
 
 func (s *session) logSubscriptions(ctx context.Context) error {
-	log := log.G(ctx).WithFields(logrus.Fields{"method": "(*session).logSubscriptions"})
-	log.Debugf("")
+	logger := log.G(ctx).WithFields(log.Fields{"method": "(*session).logSubscriptions"})
+	logger.Debugf("")
 
 	client := api.NewLogBrokerClient(s.conn.ClientConn)
 	subscriptions, err := client.ListenSubscriptions(ctx, &api.ListenSubscriptionsRequest{})
@@ -257,7 +256,7 @@ func (s *session) logSubscriptions(ctx context.Context) error {
 		resp, err := subscriptions.Recv()
 		st, _ := status.FromError(err)
 		if st.Code() == codes.Unimplemented {
-			log.Warning("manager does not support log subscriptions")
+			logger.Warning("manager does not support log subscriptions")
 			// Don't return, because returning would bounce the session
 			select {
 			case <-s.closed:
@@ -281,8 +280,8 @@ func (s *session) logSubscriptions(ctx context.Context) error {
 }
 
 func (s *session) watch(ctx context.Context) error {
-	log := log.G(ctx).WithFields(logrus.Fields{"method": "(*session).watch"})
-	log.Debugf("")
+	logger := log.G(ctx).WithFields(log.Fields{"method": "(*session).watch"})
+	logger.Debugf("")
 	var (
 		resp            *api.AssignmentsMessage
 		assignmentWatch api.Dispatcher_AssignmentsClient
@@ -313,7 +312,7 @@ func (s *session) watch(ctx context.Context) error {
 				}
 				tasksFallback = true
 				assignmentWatch = nil
-				log.WithError(err).Infof("falling back to Tasks")
+				logger.WithError(err).Infof("falling back to Tasks")
 			}
 		}
 

+ 11 - 12
vendor/github.com/moby/swarmkit/v2/agent/worker.go

@@ -8,7 +8,6 @@ import (
 	"github.com/moby/swarmkit/v2/api"
 	"github.com/moby/swarmkit/v2/log"
 	"github.com/moby/swarmkit/v2/watch"
-	"github.com/sirupsen/logrus"
 	bolt "go.etcd.io/bbolt"
 )
 
@@ -135,7 +134,7 @@ func (w *worker) Assign(ctx context.Context, assignments []*api.AssignmentChange
 		return ErrClosed
 	}
 
-	log.G(ctx).WithFields(logrus.Fields{
+	log.G(ctx).WithFields(log.Fields{
 		"len(assignments)": len(assignments),
 	}).Debug("(*worker).Assign")
 
@@ -174,7 +173,7 @@ func (w *worker) Update(ctx context.Context, assignments []*api.AssignmentChange
 		return ErrClosed
 	}
 
-	log.G(ctx).WithFields(logrus.Fields{
+	log.G(ctx).WithFields(log.Fields{
 		"len(assignments)": len(assignments),
 	}).Debug("(*worker).Update")
 
@@ -212,7 +211,7 @@ func reconcileTaskState(ctx context.Context, w *worker, assignments []*api.Assig
 		}
 	}
 
-	log.G(ctx).WithFields(logrus.Fields{
+	log.G(ctx).WithFields(log.Fields{
 		"len(updatedTasks)": len(updatedTasks),
 		"len(removedTasks)": len(removedTasks),
 	}).Debug("(*worker).reconcileTaskState")
@@ -227,10 +226,10 @@ func reconcileTaskState(ctx context.Context, w *worker, assignments []*api.Assig
 	assigned := map[string]struct{}{}
 
 	for _, task := range updatedTasks {
-		log.G(ctx).WithFields(
-			logrus.Fields{
-				"task.id":           task.ID,
-				"task.desiredstate": task.DesiredState}).Debug("assigned")
+		log.G(ctx).WithFields(log.Fields{
+			"task.id":           task.ID,
+			"task.desiredstate": task.DesiredState,
+		}).Debug("assigned")
 		if err := PutTask(tx, task); err != nil {
 			return err
 		}
@@ -359,7 +358,7 @@ func reconcileSecrets(ctx context.Context, w *worker, assignments []*api.Assignm
 
 	secrets := secretsProvider.Secrets()
 
-	log.G(ctx).WithFields(logrus.Fields{
+	log.G(ctx).WithFields(log.Fields{
 		"len(updatedSecrets)": len(updatedSecrets),
 		"len(removedSecrets)": len(removedSecrets),
 	}).Debug("(*worker).reconcileSecrets")
@@ -402,7 +401,7 @@ func reconcileConfigs(ctx context.Context, w *worker, assignments []*api.Assignm
 
 	configs := configsProvider.Configs()
 
-	log.G(ctx).WithFields(logrus.Fields{
+	log.G(ctx).WithFields(log.Fields{
 		"len(updatedConfigs)": len(updatedConfigs),
 		"len(removedConfigs)": len(removedConfigs),
 	}).Debug("(*worker).reconcileConfigs")
@@ -448,7 +447,7 @@ func reconcileVolumes(ctx context.Context, w *worker, assignments []*api.Assignm
 
 	volumes := volumesProvider.Volumes()
 
-	log.G(ctx).WithFields(logrus.Fields{
+	log.G(ctx).WithFields(log.Fields{
 		"len(updatedVolumes)": len(updatedVolumes),
 		"len(removedVolumes)": len(removedVolumes),
 	}).Debug("(*worker).reconcileVolumes")
@@ -536,7 +535,7 @@ func (w *worker) taskManager(ctx context.Context, tx *bolt.Tx, task *api.Task) (
 }
 
 func (w *worker) newTaskManager(ctx context.Context, tx *bolt.Tx, task *api.Task) (*taskManager, error) {
-	ctx = log.WithLogger(ctx, log.G(ctx).WithFields(logrus.Fields{
+	ctx = log.WithLogger(ctx, log.G(ctx).WithFields(log.Fields{
 		"task.id":    task.ID,
 		"service.id": task.ServiceID,
 	}))

+ 1 - 3
vendor/github.com/moby/swarmkit/v2/ca/auth.go

@@ -6,8 +6,6 @@ import (
 	"crypto/x509/pkix"
 	"strings"
 
-	"github.com/sirupsen/logrus"
-
 	"github.com/moby/swarmkit/v2/api"
 	"github.com/moby/swarmkit/v2/log"
 	"google.golang.org/grpc/codes"
@@ -43,7 +41,7 @@ func LogTLSState(ctx context.Context, tlsState *tls.ConnectionState) {
 		verifiedChain = append(verifiedChain, strings.Join(subjects, ","))
 	}
 
-	log.G(ctx).WithFields(logrus.Fields{
+	log.G(ctx).WithFields(log.Fields{
 		"peer.peerCert": peerCerts,
 		// "peer.verifiedChain": verifiedChain},
 	}).Debugf("")

+ 2 - 2
vendor/github.com/moby/swarmkit/v2/ca/certificates.go

@@ -769,7 +769,7 @@ func CreateRootCA(rootCN string) (RootCA, error) {
 	// Create a simple CSR for the CA using the default CA validator and policy
 	req := cfcsr.CertificateRequest{
 		CN:         rootCN,
-		KeyRequest: &cfcsr.BasicKeyRequest{A: RootKeyAlgo, S: RootKeySize},
+		KeyRequest: &cfcsr.KeyRequest{A: RootKeyAlgo, S: RootKeySize},
 		CA:         &cfcsr.CAConfig{Expiry: RootCAExpiration},
 	}
 
@@ -919,7 +919,7 @@ func SaveRootCA(rootCA RootCA, paths CertPaths) error {
 // GenerateNewCSR returns a newly generated key and CSR signed with said key
 func GenerateNewCSR() ([]byte, []byte, error) {
 	req := &cfcsr.CertificateRequest{
-		KeyRequest: cfcsr.NewBasicKeyRequest(),
+		KeyRequest: cfcsr.NewKeyRequest(),
 	}
 
 	csr, key, err := cfcsr.ParseRequest(req)

+ 6 - 7
vendor/github.com/moby/swarmkit/v2/ca/config.go

@@ -22,7 +22,6 @@ import (
 	"github.com/moby/swarmkit/v2/watch"
 	"github.com/opencontainers/go-digest"
 	"github.com/pkg/errors"
-	"github.com/sirupsen/logrus"
 	"google.golang.org/grpc/credentials"
 )
 
@@ -463,7 +462,7 @@ func LoadSecurityConfig(ctx context.Context, rootCA RootCA, krw *KeyReadWriter,
 		PublicKey: issuer.RawSubjectPublicKeyInfo,
 	})
 	if err == nil {
-		log.G(ctx).WithFields(logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"node.id":   secConfig.ClientTLSCreds.NodeID(),
 			"node.role": secConfig.ClientTLSCreds.Role(),
 		}).Debug("loaded node credentials")
@@ -524,12 +523,12 @@ func (rootCA RootCA) CreateSecurityConfig(ctx context.Context, krw *KeyReadWrite
 			return nil, nil, err
 		}
 	case nil:
-		log.G(ctx).WithFields(logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"node.id":   cn,
 			"node.role": proposedRole,
 		}).Debug("issued new TLS certificate")
 	default:
-		log.G(ctx).WithFields(logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"node.id":   cn,
 			"node.role": proposedRole,
 		}).WithError(err).Errorf("failed to issue and save new certificate")
@@ -538,7 +537,7 @@ func (rootCA RootCA) CreateSecurityConfig(ctx context.Context, krw *KeyReadWrite
 
 	secConfig, cleanup, err := NewSecurityConfig(&rootCA, krw, tlsKeyPair, issuerInfo)
 	if err == nil {
-		log.G(ctx).WithFields(logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"node.id":   secConfig.ClientTLSCreds.NodeID(),
 			"node.role": secConfig.ClientTLSCreds.Role(),
 		}).Debugf("new node credentials generated: %s", krw.Target())
@@ -579,7 +578,7 @@ func RenewTLSConfigNow(ctx context.Context, s *SecurityConfig, connBroker *conne
 	defer s.renewalMu.Unlock()
 
 	ctx = log.WithModule(ctx, "tls")
-	log := log.G(ctx).WithFields(logrus.Fields{
+	logger := log.G(ctx).WithFields(log.Fields{
 		"node.id":   s.ClientTLSCreds.NodeID(),
 		"node.role": s.ClientTLSCreds.Role(),
 	})
@@ -602,7 +601,7 @@ func RenewTLSConfigNow(ctx context.Context, s *SecurityConfig, connBroker *conne
 		}
 	}
 	if err != nil {
-		log.WithError(err).Errorf("failed to renew the certificate")
+		logger.WithError(err).Errorf("failed to renew the certificate")
 		return err
 	}
 

+ 1 - 2
vendor/github.com/moby/swarmkit/v2/ca/external.go

@@ -20,7 +20,6 @@ import (
 	"github.com/cloudflare/cfssl/signer"
 	"github.com/moby/swarmkit/v2/log"
 	"github.com/pkg/errors"
-	"github.com/sirupsen/logrus"
 	"golang.org/x/net/context/ctxhttp"
 )
 
@@ -203,7 +202,7 @@ func makeExternalSignRequest(ctx context.Context, client *http.Client, url strin
 
 	var apiResponse api.Response
 	if err := json.Unmarshal(body, &apiResponse); err != nil {
-		logrus.Debugf("unable to JSON-parse CFSSL API response body: %s", string(body))
+		log.G(ctx).Debugf("unable to JSON-parse CFSSL API response body: %s", string(body))
 		return nil, recoverableErr{err: errors.Wrap(err, "unable to parse JSON response")}
 	}
 

+ 10 - 11
vendor/github.com/moby/swarmkit/v2/ca/renewer.go

@@ -9,7 +9,6 @@ import (
 	"github.com/moby/swarmkit/v2/connectionbroker"
 	"github.com/moby/swarmkit/v2/log"
 	"github.com/pkg/errors"
-	"github.com/sirupsen/logrus"
 )
 
 // RenewTLSExponentialBackoff sets the exponential backoff when trying to renew TLS certificates that have expired
@@ -72,7 +71,7 @@ func (t *TLSRenewer) Start(ctx context.Context) <-chan CertificateUpdate {
 		defer close(updates)
 		for {
 			ctx = log.WithModule(ctx, "tls")
-			log := log.G(ctx).WithFields(logrus.Fields{
+			logger := log.G(ctx).WithFields(log.Fields{
 				"node.id":   t.s.ClientTLSCreds.NodeID(),
 				"node.role": t.s.ClientTLSCreds.Role(),
 			})
@@ -85,19 +84,19 @@ func (t *TLSRenewer) Start(ctx context.Context) <-chan CertificateUpdate {
 			validFrom, validUntil, err := readCertValidity(t.s.KeyReader())
 			if err != nil {
 				// We failed to read the expiration, let's stick with the starting default
-				log.Errorf("failed to read the expiration of the TLS certificate in: %s", t.s.KeyReader().Target())
+				logger.Errorf("failed to read the expiration of the TLS certificate in: %s", t.s.KeyReader().Target())
 
 				select {
 				case updates <- CertificateUpdate{Err: errors.New("failed to read certificate expiration")}:
 				case <-ctx.Done():
-					log.Info("shutting down certificate renewal routine")
+					logger.Info("shutting down certificate renewal routine")
 					return
 				}
 			} else {
 				// If we have an expired certificate, try to renew immediately: the hope that this is a temporary clock skew, or
 				// we can issue our own TLS certs.
 				if validUntil.Before(time.Now()) {
-					log.Warn("the current TLS certificate is expired, so an attempt to renew it will be made immediately")
+					logger.Warn("the current TLS certificate is expired, so an attempt to renew it will be made immediately")
 					// retry immediately(ish) with exponential backoff
 					retry = expBackoff.Proceed(nil)
 				} else if forceRetry {
@@ -110,16 +109,16 @@ func (t *TLSRenewer) Start(ctx context.Context) <-chan CertificateUpdate {
 				}
 			}
 
-			log.WithFields(logrus.Fields{
+			logger.WithFields(log.Fields{
 				"time": time.Now().Add(retry),
 			}).Debugf("next certificate renewal scheduled for %v from now", retry)
 
 			select {
 			case <-time.After(retry):
-				log.Info("renewing certificate")
+				logger.Info("renewing certificate")
 			case <-t.renew:
 				forceRetry = true
-				log.Info("forced certificate renewal")
+				logger.Info("forced certificate renewal")
 
 				// Pause briefly before attempting the renewal,
 				// to give the CA a chance to reconcile the
@@ -127,11 +126,11 @@ func (t *TLSRenewer) Start(ctx context.Context) <-chan CertificateUpdate {
 				select {
 				case <-time.After(500 * time.Millisecond):
 				case <-ctx.Done():
-					log.Info("shutting down certificate renewal routine")
+					logger.Info("shutting down certificate renewal routine")
 					return
 				}
 			case <-ctx.Done():
-				log.Info("shutting down certificate renewal routine")
+				logger.Info("shutting down certificate renewal routine")
 				return
 			}
 
@@ -158,7 +157,7 @@ func (t *TLSRenewer) Start(ctx context.Context) <-chan CertificateUpdate {
 			select {
 			case updates <- certUpdate:
 			case <-ctx.Done():
-				log.Info("shutting down certificate renewal routine")
+				logger.Info("shutting down certificate renewal routine")
 				return
 			}
 		}

+ 15 - 16
vendor/github.com/moby/swarmkit/v2/ca/server.go

@@ -15,7 +15,6 @@ import (
 	"github.com/moby/swarmkit/v2/log"
 	"github.com/moby/swarmkit/v2/manager/state/store"
 	"github.com/pkg/errors"
-	"github.com/sirupsen/logrus"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 )
@@ -182,7 +181,7 @@ func (s *Server) NodeCertificateStatus(ctx context.Context, request *api.NodeCer
 		return nil, status.Errorf(codes.NotFound, codes.NotFound.String())
 	}
 
-	log.G(ctx).WithFields(logrus.Fields{
+	log.G(ctx).WithFields(log.Fields{
 		"node.id": node.ID,
 		"status":  node.Certificate.Status,
 		"method":  "NodeCertificateStatus",
@@ -196,7 +195,7 @@ func (s *Server) NodeCertificateStatus(ctx context.Context, request *api.NodeCer
 		}, nil
 	}
 
-	log.G(ctx).WithFields(logrus.Fields{
+	log.G(ctx).WithFields(log.Fields{
 		"node.id": node.ID,
 		"status":  node.Certificate.Status,
 		"method":  "NodeCertificateStatus",
@@ -326,7 +325,7 @@ func (s *Server) IssueNodeCertificate(ctx context.Context, request *api.IssueNod
 			return store.CreateNode(tx, node)
 		})
 		if err == nil {
-			log.G(ctx).WithFields(logrus.Fields{
+			log.G(ctx).WithFields(log.Fields{
 				"node.id":   nodeID,
 				"node.role": role,
 				"method":    "IssueNodeCertificate",
@@ -339,7 +338,7 @@ func (s *Server) IssueNodeCertificate(ctx context.Context, request *api.IssueNod
 		if i == maxRetries {
 			return nil, err
 		}
-		log.G(ctx).WithFields(logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"node.id":   nodeID,
 			"node.role": role,
 			"method":    "IssueNodeCertificate",
@@ -363,7 +362,7 @@ func (s *Server) issueRenewCertificate(ctx context.Context, nodeID string, csr [
 		// Attempt to retrieve the node with nodeID
 		node = store.GetNode(tx, nodeID)
 		if node == nil {
-			log.G(ctx).WithFields(logrus.Fields{
+			log.G(ctx).WithFields(log.Fields{
 				"node.id": nodeID,
 				"method":  "issueRenewCertificate",
 			}).Warnf("node does not exist")
@@ -388,7 +387,7 @@ func (s *Server) issueRenewCertificate(ctx context.Context, nodeID string, csr [
 		return nil, err
 	}
 
-	log.G(ctx).WithFields(logrus.Fields{
+	log.G(ctx).WithFields(log.Fields{
 		"cert.cn":   cert.CN,
 		"cert.role": cert.Role,
 		"method":    "issueRenewCertificate",
@@ -404,7 +403,7 @@ func (s *Server) issueRenewCertificate(ctx context.Context, nodeID string, csr [
 // the root of trust for the swarm. Clients should be using the CA hash to verify if they weren't target to
 // a MiTM. If they fail to do so, node bootstrap works with TOFU semantics.
 func (s *Server) GetRootCACertificate(ctx context.Context, request *api.GetRootCACertificateRequest) (*api.GetRootCACertificateResponse, error) {
-	log.G(ctx).WithFields(logrus.Fields{
+	log.G(ctx).WithFields(log.Fields{
 		"method": "GetRootCACertificate",
 	})
 
@@ -477,7 +476,7 @@ func (s *Server) Run(ctx context.Context) error {
 	s.mu.Unlock()
 
 	if err != nil {
-		log.G(ctx).WithFields(logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"method": "(*Server).Run",
 		}).WithError(err).Errorf("snapshot store view failed")
 		return err
@@ -489,7 +488,7 @@ func (s *Server) Run(ctx context.Context) error {
 	if err := s.reconcileNodeCertificates(ctx, nodes); err != nil {
 		// We don't return here because that means the Run loop would
 		// never run. Log an error instead.
-		log.G(ctx).WithFields(logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"method": "(*Server).Run",
 		}).WithError(err).Errorf("error attempting to reconcile certificates")
 	}
@@ -668,7 +667,7 @@ func (s *Server) UpdateRootCA(ctx context.Context, cluster *api.Cluster, reconci
 	firstSeenCluster := s.lastSeenClusterRootCA == nil && s.lastSeenExternalCAs == nil
 	rootCAChanged := len(rCA.CACert) != 0 && !equality.RootCAEqualStable(s.lastSeenClusterRootCA, rCA)
 	externalCAChanged := !equality.ExternalCAsEqualStable(s.lastSeenExternalCAs, cluster.Spec.CAConfig.ExternalCAs)
-	ctx = log.WithLogger(ctx, log.G(ctx).WithFields(logrus.Fields{
+	ctx = log.WithLogger(ctx, log.G(ctx).WithFields(log.Fields{
 		"cluster.id": cluster.ID,
 		"method":     "(*Server).UpdateRootCA",
 	}))
@@ -773,7 +772,7 @@ func (s *Server) signNodeCert(ctx context.Context, node *api.Node) error {
 	// Convert the role from proto format
 	role, err := ParseRole(node.Certificate.Role)
 	if err != nil {
-		log.G(ctx).WithFields(logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"node.id": node.ID,
 			"method":  "(*Server).signNodeCert",
 		}).WithError(err).Errorf("failed to parse role")
@@ -798,7 +797,7 @@ func (s *Server) signNodeCert(ctx context.Context, node *api.Node) error {
 	}
 
 	if err != nil {
-		log.G(ctx).WithFields(logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"node.id": node.ID,
 			"method":  "(*Server).signNodeCert",
 		}).WithError(err).Errorf("failed to sign CSR")
@@ -830,7 +829,7 @@ func (s *Server) signNodeCert(ctx context.Context, node *api.Node) error {
 			return store.UpdateNode(tx, node)
 		})
 		if err != nil {
-			log.G(ctx).WithFields(logrus.Fields{
+			log.G(ctx).WithFields(log.Fields{
 				"node.id": nodeID,
 				"method":  "(*Server).signNodeCert",
 			}).WithError(err).Errorf("transaction failed when setting state to FAILED")
@@ -858,7 +857,7 @@ func (s *Server) signNodeCert(ctx context.Context, node *api.Node) error {
 			return err
 		})
 		if err == nil {
-			log.G(ctx).WithFields(logrus.Fields{
+			log.G(ctx).WithFields(log.Fields{
 				"node.id":   node.ID,
 				"node.role": node.Certificate.Role,
 				"method":    "(*Server).signNodeCert",
@@ -870,7 +869,7 @@ func (s *Server) signNodeCert(ctx context.Context, node *api.Node) error {
 			continue
 		}
 
-		log.G(ctx).WithFields(logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"node.id": nodeID,
 			"method":  "(*Server).signNodeCert",
 		}).WithError(err).Errorf("transaction failed")

+ 5 - 2
vendor/github.com/moby/swarmkit/v2/log/context.go

@@ -23,6 +23,9 @@ type (
 	moduleKey struct{}
 )
 
+// Fields type to pass to "WithFields".
+type Fields = map[string]any
+
 // WithLogger returns a new context with the provided logger. Use in
 // combination with logger.WithField(s) for great effect.
 func WithLogger(ctx context.Context, logger *logrus.Entry) context.Context {
@@ -30,7 +33,7 @@ func WithLogger(ctx context.Context, logger *logrus.Entry) context.Context {
 }
 
 // WithFields returns a new context with added fields to logger.
-func WithFields(ctx context.Context, fields logrus.Fields) context.Context {
+func WithFields(ctx context.Context, fields Fields) context.Context {
 	logger := ctx.Value(loggerKey{})
 
 	if logger == nil {
@@ -41,7 +44,7 @@ func WithFields(ctx context.Context, fields logrus.Fields) context.Context {
 
 // WithField is convenience wrapper around WithFields.
 func WithField(ctx context.Context, key, value string) context.Context {
-	return WithFields(ctx, logrus.Fields{key: value})
+	return WithFields(ctx, Fields{key: value})
 }
 
 // GetLogger retrieves the current logger from the context. If no logger is

+ 3 - 2
vendor/github.com/moby/swarmkit/v2/manager/allocator/cnmallocator/drivers_ipam.go

@@ -1,6 +1,7 @@
 package cnmallocator
 
 import (
+	"context"
 	"strconv"
 	"strings"
 
@@ -8,7 +9,7 @@ import (
 	builtinIpam "github.com/docker/docker/libnetwork/ipams/builtin"
 	nullIpam "github.com/docker/docker/libnetwork/ipams/null"
 	"github.com/docker/docker/libnetwork/ipamutils"
-	"github.com/sirupsen/logrus"
+	"github.com/moby/swarmkit/v2/log"
 )
 
 func initIPAMDrivers(r ipamapi.Registerer, netConfig *NetworkConfig) error {
@@ -35,7 +36,7 @@ func initIPAMDrivers(r ipamapi.Registerer, netConfig *NetworkConfig) error {
 		return err
 	}
 	if addressPool != nil {
-		logrus.Infof("Swarm initialized global default address pool to: " + str.String())
+		log.G(context.TODO()).Infof("Swarm initialized global default address pool to: " + str.String())
 	}
 
 	for _, fn := range [](func(ipamapi.Registerer) error){

+ 1 - 2
vendor/github.com/moby/swarmkit/v2/manager/allocator/cnmallocator/networkallocator.go

@@ -18,7 +18,6 @@ import (
 	"github.com/moby/swarmkit/v2/log"
 	"github.com/moby/swarmkit/v2/manager/allocator/networkallocator"
 	"github.com/pkg/errors"
-	"github.com/sirupsen/logrus"
 )
 
 const (
@@ -261,7 +260,7 @@ vipLoop:
 		}
 		for _, nAttach := range specNetworks {
 			if nAttach.Target == eAttach.NetworkID {
-				log.L.WithFields(logrus.Fields{"service_id": s.ID, "vip": eAttach.Addr}).Debug("allocate vip")
+				log.L.WithFields(log.Fields{"service_id": s.ID, "vip": eAttach.Addr}).Debug("allocate vip")
 				if err = na.allocateVIP(eAttach); err != nil {
 					return err
 				}

+ 3 - 4
vendor/github.com/moby/swarmkit/v2/manager/controlapi/config.go

@@ -9,7 +9,6 @@ import (
 	"github.com/moby/swarmkit/v2/identity"
 	"github.com/moby/swarmkit/v2/log"
 	"github.com/moby/swarmkit/v2/manager/state/store"
-	"github.com/sirupsen/logrus"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 )
@@ -80,7 +79,7 @@ func (s *Server) UpdateConfig(ctx context.Context, request *api.UpdateConfigRequ
 		return nil, err
 	}
 
-	log.G(ctx).WithFields(logrus.Fields{
+	log.G(ctx).WithFields(log.Fields{
 		"config.ID":   request.ConfigID,
 		"config.Name": request.Spec.Annotations.Name,
 		"method":      "UpdateConfig",
@@ -166,7 +165,7 @@ func (s *Server) CreateConfig(ctx context.Context, request *api.CreateConfigRequ
 	case store.ErrNameConflict:
 		return nil, status.Errorf(codes.AlreadyExists, "config %s already exists", request.Spec.Annotations.Name)
 	case nil:
-		log.G(ctx).WithFields(logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"config.Name": request.Spec.Annotations.Name,
 			"method":      "CreateConfig",
 		}).Debugf("config created")
@@ -222,7 +221,7 @@ func (s *Server) RemoveConfig(ctx context.Context, request *api.RemoveConfigRequ
 	case store.ErrNotExist:
 		return nil, status.Errorf(codes.NotFound, "config %s not found", request.ConfigID)
 	case nil:
-		log.G(ctx).WithFields(logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"config.ID": request.ConfigID,
 			"method":    "RemoveConfig",
 		}).Debugf("config removed")

+ 2 - 3
vendor/github.com/moby/swarmkit/v2/manager/controlapi/extension.go

@@ -8,7 +8,6 @@ import (
 	"github.com/moby/swarmkit/v2/identity"
 	"github.com/moby/swarmkit/v2/log"
 	"github.com/moby/swarmkit/v2/manager/state/store"
-	"github.com/sirupsen/logrus"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 )
@@ -37,7 +36,7 @@ func (s *Server) CreateExtension(ctx context.Context, request *api.CreateExtensi
 	case store.ErrNameConflict:
 		return nil, status.Errorf(codes.AlreadyExists, "extension %s already exists", request.Annotations.Name)
 	case nil:
-		log.G(ctx).WithFields(logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"extension.Name": request.Annotations.Name,
 			"method":         "CreateExtension",
 		}).Debugf("extension created")
@@ -121,7 +120,7 @@ func (s *Server) RemoveExtension(ctx context.Context, request *api.RemoveExtensi
 	case store.ErrNotExist:
 		return nil, status.Errorf(codes.NotFound, "extension %s not found", request.ExtensionID)
 	case nil:
-		log.G(ctx).WithFields(logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"extension.ID": request.ExtensionID,
 			"method":       "RemoveExtension",
 		}).Debugf("extension removed")

+ 1 - 2
vendor/github.com/moby/swarmkit/v2/manager/controlapi/resource.go

@@ -3,7 +3,6 @@ package controlapi
 import (
 	"context"
 
-	"github.com/sirupsen/logrus"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 
@@ -50,7 +49,7 @@ func (s *Server) CreateResource(ctx context.Context, request *api.CreateResource
 			r.Annotations.Name,
 		)
 	case nil:
-		log.G(ctx).WithFields(logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"resource.Name": r.Annotations.Name,
 			"method":        "CreateResource",
 		}).Debugf("resource created")

+ 3 - 4
vendor/github.com/moby/swarmkit/v2/manager/controlapi/secret.go

@@ -10,7 +10,6 @@ import (
 	"github.com/moby/swarmkit/v2/identity"
 	"github.com/moby/swarmkit/v2/log"
 	"github.com/moby/swarmkit/v2/manager/state/store"
-	"github.com/sirupsen/logrus"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 )
@@ -78,7 +77,7 @@ func (s *Server) UpdateSecret(ctx context.Context, request *api.UpdateSecretRequ
 		return nil, err
 	}
 
-	log.G(ctx).WithFields(logrus.Fields{
+	log.G(ctx).WithFields(log.Fields{
 		"secret.ID":   request.SecretID,
 		"secret.Name": request.Spec.Annotations.Name,
 		"method":      "UpdateSecret",
@@ -174,7 +173,7 @@ func (s *Server) CreateSecret(ctx context.Context, request *api.CreateSecretRequ
 		return nil, status.Errorf(codes.AlreadyExists, "secret %s already exists", request.Spec.Annotations.Name)
 	case nil:
 		secret.Spec.Data = nil // clean the actual secret data so it's never returned
-		log.G(ctx).WithFields(logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"secret.Name": request.Spec.Annotations.Name,
 			"method":      "CreateSecret",
 		}).Debugf("secret created")
@@ -230,7 +229,7 @@ func (s *Server) RemoveSecret(ctx context.Context, request *api.RemoveSecretRequ
 	case store.ErrNotExist:
 		return nil, status.Errorf(codes.NotFound, "secret %s not found", request.SecretID)
 	case nil:
-		log.G(ctx).WithFields(logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"secret.ID": request.SecretID,
 			"method":    "RemoveSecret",
 		}).Debugf("secret removed")

+ 2 - 4
vendor/github.com/moby/swarmkit/v2/manager/csi/manager.go

@@ -7,10 +7,8 @@ import (
 	"sync"
 	"time"
 
-	"github.com/docker/go-events"
-	"github.com/sirupsen/logrus"
-
 	"github.com/docker/docker/pkg/plugingetter"
+	"github.com/docker/go-events"
 
 	"github.com/moby/swarmkit/v2/api"
 	"github.com/moby/swarmkit/v2/log"
@@ -154,7 +152,7 @@ func (vm *Manager) run(pctx context.Context) {
 // processVolumes encapuslates the logic for processing pending Volumes.
 func (vm *Manager) processVolume(ctx context.Context, id string, attempt uint) {
 	// set up log fields for a derrived context to pass to handleVolume.
-	logCtx := log.WithFields(ctx, logrus.Fields{
+	logCtx := log.WithFields(ctx, log.Fields{
 		"volume.id": id,
 		"attempt":   attempt,
 	})

+ 3 - 2
vendor/github.com/moby/swarmkit/v2/manager/dispatcher/assignments.go

@@ -7,6 +7,7 @@ import (
 	"github.com/moby/swarmkit/v2/api/equality"
 	"github.com/moby/swarmkit/v2/api/validation"
 	"github.com/moby/swarmkit/v2/identity"
+	"github.com/moby/swarmkit/v2/log"
 	"github.com/moby/swarmkit/v2/manager/drivers"
 	"github.com/moby/swarmkit/v2/manager/state/store"
 	"github.com/sirupsen/logrus"
@@ -53,7 +54,7 @@ func assignSecret(a *assignmentSet, readTx store.ReadTx, mapKey typeAndID, t *ap
 	}
 	secret, doNotReuse, err := a.secret(readTx, t, mapKey.id)
 	if err != nil {
-		a.log.WithFields(logrus.Fields{
+		a.log.WithFields(log.Fields{
 			"resource.type": "secret",
 			"secret.id":     mapKey.id,
 			"error":         err,
@@ -89,7 +90,7 @@ func assignConfig(a *assignmentSet, readTx store.ReadTx, mapKey typeAndID) {
 	a.tasksUsingDependency[mapKey] = make(map[string]struct{})
 	config := store.GetConfig(readTx, mapKey.id)
 	if config == nil {
-		a.log.WithFields(logrus.Fields{
+		a.log.WithFields(log.Fields{
 			"resource.type": "config",
 			"config.id":     mapKey.id,
 		}).Debug("config not found")

+ 30 - 31
vendor/github.com/moby/swarmkit/v2/manager/dispatcher/dispatcher.go

@@ -21,7 +21,6 @@ import (
 	"github.com/moby/swarmkit/v2/remotes"
 	"github.com/moby/swarmkit/v2/watch"
 	"github.com/pkg/errors"
-	"github.com/sirupsen/logrus"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 )
@@ -619,7 +618,7 @@ func (d *Dispatcher) UpdateTaskStatus(ctx context.Context, r *api.UpdateTaskStat
 		return nil, err
 	}
 	nodeID := nodeInfo.NodeID
-	fields := logrus.Fields{
+	fields := log.Fields{
 		"node.id":      nodeID,
 		"node.session": r.SessionID,
 		"method":       "(*Dispatcher).UpdateTaskStatus",
@@ -695,7 +694,7 @@ func (d *Dispatcher) UpdateVolumeStatus(ctx context.Context, r *api.UpdateVolume
 	}
 
 	nodeID := nodeInfo.NodeID
-	fields := logrus.Fields{
+	fields := log.Fields{
 		"node.id":      nodeID,
 		"node.session": r.SessionID,
 		"method":       "(*Dispatcher).UpdateVolumeStatus",
@@ -703,19 +702,19 @@ func (d *Dispatcher) UpdateVolumeStatus(ctx context.Context, r *api.UpdateVolume
 	if nodeInfo.ForwardedBy != nil {
 		fields["forwarder.id"] = nodeInfo.ForwardedBy.NodeID
 	}
-	log := log.G(ctx).WithFields(fields)
+	logger := log.G(ctx).WithFields(fields)
 
 	if _, err := d.nodes.GetWithSession(nodeID, r.SessionID); err != nil {
 		return nil, err
 	}
 
 	d.unpublishedVolumesLock.Lock()
-	for _, status := range r.Updates {
-		if status.Unpublished {
+	for _, volumeStatus := range r.Updates {
+		if volumeStatus.Unpublished {
 			// it's ok if nodes is nil, because append works on a nil slice.
-			nodes := append(d.unpublishedVolumes[status.ID], nodeID)
-			d.unpublishedVolumes[status.ID] = nodes
-			log.Debugf("volume %s unpublished on node %s", status.ID, nodeID)
+			nodes := append(d.unpublishedVolumes[volumeStatus.ID], nodeID)
+			d.unpublishedVolumes[volumeStatus.ID] = nodes
+			logger.Debugf("volume %s unpublished on node %s", volumeStatus.ID, nodeID)
 		}
 	}
 	d.unpublishedVolumesLock.Unlock()
@@ -756,14 +755,14 @@ func (d *Dispatcher) processUpdates(ctx context.Context) {
 		return
 	}
 
-	log := log.G(ctx).WithFields(logrus.Fields{
+	logr := log.G(ctx).WithFields(log.Fields{
 		"method": "(*Dispatcher).processUpdates",
 	})
 
 	err := d.store.Batch(func(batch *store.Batch) error {
-		for taskID, status := range taskUpdates {
+		for taskID, taskStatus := range taskUpdates {
 			err := batch.Update(func(tx store.Tx) error {
-				logger := log.WithField("task.id", taskID)
+				logger := logr.WithField("task.id", taskID)
 				task := store.GetTask(tx, taskID)
 				if task == nil {
 					// Task may have been deleted
@@ -771,14 +770,14 @@ func (d *Dispatcher) processUpdates(ctx context.Context) {
 					return nil
 				}
 
-				logger = logger.WithField("state.transition", fmt.Sprintf("%v->%v", task.Status.State, status.State))
+				logger = logger.WithField("state.transition", fmt.Sprintf("%v->%v", task.Status.State, taskStatus.State))
 
-				if task.Status == *status {
+				if task.Status == *taskStatus {
 					logger.Debug("task status identical, ignoring")
 					return nil
 				}
 
-				if task.Status.State > status.State {
+				if task.Status.State > taskStatus.State {
 					logger.Debug("task status invalid transition")
 					return nil
 				}
@@ -789,12 +788,12 @@ func (d *Dispatcher) processUpdates(ctx context.Context) {
 				// the network delay between the worker and the leader.
 				// This is not ideal, but its a known overestimation, rather than using the status update time
 				// from the worker node, which may cause unknown incorrect results due to possible clock skew.
-				if status.State == api.TaskStateRunning {
-					start := time.Unix(status.AppliedAt.GetSeconds(), int64(status.AppliedAt.GetNanos()))
+				if taskStatus.State == api.TaskStateRunning {
+					start := time.Unix(taskStatus.AppliedAt.GetSeconds(), int64(taskStatus.AppliedAt.GetNanos()))
 					schedulingDelayTimer.UpdateSince(start)
 				}
 
-				task.Status = *status
+				task.Status = *taskStatus
 				task.Status.AppliedBy = d.securityConfig.ClientTLSCreds.NodeID()
 				task.Status.AppliedAt = ptypes.MustTimestampProto(time.Now())
 				logger.Debugf("state for task %v updated to %v", task.GetID(), task.Status.State)
@@ -806,13 +805,13 @@ func (d *Dispatcher) processUpdates(ctx context.Context) {
 				return nil
 			})
 			if err != nil {
-				log.WithError(err).Error("dispatcher task update transaction failed")
+				logr.WithError(err).Error("dispatcher task update transaction failed")
 			}
 		}
 
 		for nodeID, nodeUpdate := range nodeUpdates {
 			err := batch.Update(func(tx store.Tx) error {
-				logger := log.WithField("node.id", nodeID)
+				logger := logr.WithField("node.id", nodeID)
 				node := store.GetNode(tx, nodeID)
 				if node == nil {
 					logger.Error("node unavailable")
@@ -838,13 +837,13 @@ func (d *Dispatcher) processUpdates(ctx context.Context) {
 				return nil
 			})
 			if err != nil {
-				log.WithError(err).Error("dispatcher node update transaction failed")
+				logr.WithError(err).Error("dispatcher node update transaction failed")
 			}
 		}
 
 		for volumeID, nodes := range unpublishedVolumes {
 			err := batch.Update(func(tx store.Tx) error {
-				logger := log.WithField("volume.id", volumeID)
+				logger := logr.WithField("volume.id", volumeID)
 				volume := store.GetVolume(tx, volumeID)
 				if volume == nil {
 					logger.Error("volume unavailable")
@@ -869,14 +868,14 @@ func (d *Dispatcher) processUpdates(ctx context.Context) {
 			})
 
 			if err != nil {
-				log.WithError(err).Error("dispatcher volume update transaction failed")
+				logr.WithError(err).Error("dispatcher volume update transaction failed")
 			}
 		}
 
 		return nil
 	})
 	if err != nil {
-		log.WithError(err).Error("dispatcher batch failed")
+		logr.WithError(err).Error("dispatcher batch failed")
 	}
 
 	d.processUpdatesCond.Broadcast()
@@ -900,7 +899,7 @@ func (d *Dispatcher) Tasks(r *api.TasksRequest, stream api.Dispatcher_TasksServe
 	}
 	nodeID := nodeInfo.NodeID
 
-	fields := logrus.Fields{
+	fields := log.Fields{
 		"node.id":      nodeID,
 		"node.session": r.SessionID,
 		"method":       "(*Dispatcher).Tasks",
@@ -1026,7 +1025,7 @@ func (d *Dispatcher) Assignments(r *api.AssignmentsRequest, stream api.Dispatche
 	}
 	nodeID := nodeInfo.NodeID
 
-	fields := logrus.Fields{
+	fields := log.Fields{
 		"node.id":      nodeID,
 		"node.session": r.SessionID,
 		"method":       "(*Dispatcher).Assignments",
@@ -1394,7 +1393,7 @@ func (d *Dispatcher) Session(r *api.SessionRequest, stream api.Dispatcher_Sessio
 		}
 	}
 
-	fields := logrus.Fields{
+	fields := log.Fields{
 		"node.id":      nodeID,
 		"node.session": sessionID,
 		"method":       "(*Dispatcher).Session",
@@ -1402,7 +1401,7 @@ func (d *Dispatcher) Session(r *api.SessionRequest, stream api.Dispatcher_Sessio
 	if nodeInfo.ForwardedBy != nil {
 		fields["forwarder.id"] = nodeInfo.ForwardedBy.NodeID
 	}
-	log := log.G(ctx).WithFields(fields)
+	logger := log.G(ctx).WithFields(fields)
 
 	var nodeObj *api.Node
 	nodeUpdates, cancel, err := store.ViewAndWatch(d.store, func(readTx store.ReadTx) error {
@@ -1416,7 +1415,7 @@ func (d *Dispatcher) Session(r *api.SessionRequest, stream api.Dispatcher_Sessio
 	}
 
 	if err != nil {
-		log.WithError(err).Error("ViewAndWatch Node failed")
+		logger.WithError(err).Error("ViewAndWatch Node failed")
 	}
 
 	if _, err = d.nodes.GetWithSession(nodeID, sessionID); err != nil {
@@ -1438,9 +1437,9 @@ func (d *Dispatcher) Session(r *api.SessionRequest, stream api.Dispatcher_Sessio
 
 	// disconnectNode is a helper forcibly shutdown connection
 	disconnectNode := func() error {
-		log.Infof("dispatcher session dropped, marking node %s down", nodeID)
+		logger.Infof("dispatcher session dropped, marking node %s down", nodeID)
 		if err := d.markNodeNotReady(nodeID, api.NodeStatus_DISCONNECTED, "node is currently trying to find new manager"); err != nil {
-			log.WithError(err).Error("failed to remove node")
+			logger.WithError(err).Error("failed to remove node")
 		}
 		// still return an abort if the transport closure was ineffective.
 		return status.Errorf(codes.Aborted, "node must disconnect")

+ 8 - 9
vendor/github.com/moby/swarmkit/v2/manager/logbroker/broker.go

@@ -14,7 +14,6 @@ import (
 	"github.com/moby/swarmkit/v2/log"
 	"github.com/moby/swarmkit/v2/manager/state/store"
 	"github.com/moby/swarmkit/v2/watch"
-	"github.com/sirupsen/logrus"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 )
@@ -239,13 +238,13 @@ func (lb *LogBroker) SubscribeLogs(request *api.SubscribeLogsRequest, stream api
 	subscription.Run(pctx)
 	defer subscription.Stop()
 
-	log := log.G(ctx).WithFields(
-		logrus.Fields{
+	logger := log.G(ctx).WithFields(
+		log.Fields{
 			"method":          "(*LogBroker).SubscribeLogs",
 			"subscription.id": subscription.message.ID,
 		},
 	)
-	log.Debug("subscribed")
+	logger.Debug("subscribed")
 
 	publishCh, publishCancel := lb.subscribe(subscription.message.ID)
 	defer publishCancel()
@@ -319,8 +318,8 @@ func (lb *LogBroker) ListenSubscriptions(request *api.ListenSubscriptionsRequest
 	lb.nodeConnected(remote.NodeID)
 	defer lb.nodeDisconnected(remote.NodeID)
 
-	log := log.G(stream.Context()).WithFields(
-		logrus.Fields{
+	logger := log.G(stream.Context()).WithFields(
+		log.Fields{
 			"method": "(*LogBroker).ListenSubscriptions",
 			"node":   remote.NodeID,
 		},
@@ -328,7 +327,7 @@ func (lb *LogBroker) ListenSubscriptions(request *api.ListenSubscriptionsRequest
 	subscriptions, subscriptionCh, subscriptionCancel := lb.watchSubscriptions(remote.NodeID)
 	defer subscriptionCancel()
 
-	log.Debug("node registered")
+	logger.Debug("node registered")
 
 	activeSubscriptions := make(map[string]*subscription)
 
@@ -343,7 +342,7 @@ func (lb *LogBroker) ListenSubscriptions(request *api.ListenSubscriptionsRequest
 		}
 
 		if err := stream.Send(subscription.message); err != nil {
-			log.Error(err)
+			logger.Error(err)
 			return err
 		}
 		activeSubscriptions[subscription.message.ID] = subscription
@@ -365,7 +364,7 @@ func (lb *LogBroker) ListenSubscriptions(request *api.ListenSubscriptionsRequest
 				activeSubscriptions[subscription.message.ID] = subscription
 			}
 			if err := stream.Send(subscription.message); err != nil {
-				log.Error(err)
+				logger.Error(err)
 				return err
 			}
 		case <-stream.Context().Done():

+ 5 - 7
vendor/github.com/moby/swarmkit/v2/manager/manager.go

@@ -49,7 +49,6 @@ import (
 	"github.com/moby/swarmkit/v2/remotes"
 	"github.com/moby/swarmkit/v2/xnet"
 	"github.com/pkg/errors"
-	"github.com/sirupsen/logrus"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/credentials"
 )
@@ -736,7 +735,7 @@ func (m *Manager) Stop(ctx context.Context, clearData bool) {
 func (m *Manager) updateKEK(ctx context.Context, cluster *api.Cluster) error {
 	securityConfig := m.config.SecurityConfig
 	nodeID := m.config.SecurityConfig.ClientTLSCreds.NodeID()
-	logger := log.G(ctx).WithFields(logrus.Fields{
+	logger := log.G(ctx).WithFields(log.Fields{
 		"node.id":   nodeID,
 		"node.role": ca.ManagerRole,
 	})
@@ -899,11 +898,10 @@ func (m *Manager) serveListener(ctx context.Context, lCh <-chan net.Listener) {
 	case <-ctx.Done():
 		return
 	}
-	ctx = log.WithLogger(ctx, log.G(ctx).WithFields(
-		logrus.Fields{
-			"proto": l.Addr().Network(),
-			"addr":  l.Addr().String(),
-		}))
+	ctx = log.WithLogger(ctx, log.G(ctx).WithFields(log.Fields{
+		"proto": l.Addr().Network(),
+		"addr":  l.Addr().String(),
+	}))
 	if _, ok := l.(*net.TCPListener); !ok {
 		log.G(ctx).Info("Listening for local connections")
 		// we need to disallow double closes because UnixListener.Close

+ 13 - 3
vendor/github.com/moby/swarmkit/v2/manager/scheduler/scheduler.go

@@ -488,6 +488,18 @@ func (s *Scheduler) tick(ctx context.Context) {
 }
 
 func (s *Scheduler) applySchedulingDecisions(ctx context.Context, schedulingDecisions map[string]schedulingDecision) (successful, failed []schedulingDecision) {
+	// applySchedulingDecisions is the only place where we make store
+	// transactions in the scheduler. the scheduler is responsible for freeing
+	// volumes that are no longer in use. this means that volumes should be
+	// freed in this function. sometimes, there are no scheduling decisions to
+	// be made, so we return early in the if statement below.
+	//
+	// however, in all cases, any activity that results in a tick could result
+	// in needing volumes to be freed, even if nothing new is scheduled. this
+	// freeing of volumes should always happen *after* all of the scheduling
+	// decisions have been committed, hence the defer.
+	defer s.store.Batch(s.volumes.freeVolumes)
+
 	if len(schedulingDecisions) == 0 {
 		return
 	}
@@ -619,9 +631,7 @@ func (s *Scheduler) applySchedulingDecisions(ctx context.Context, schedulingDeci
 		}
 		// finally, every time we make new scheduling decisions, take the
 		// opportunity to release volumes.
-		return batch.Update(func(tx store.Tx) error {
-			return s.volumes.freeVolumes(tx)
-		})
+		return nil
 	})
 
 	if err != nil {

+ 23 - 14
vendor/github.com/moby/swarmkit/v2/manager/scheduler/volumes.go

@@ -183,24 +183,33 @@ func (vs *volumeSet) releaseVolume(volumeID, taskID string) {
 //
 // TODO(dperny): this is messy and has a lot of overhead. it should be reworked
 // to something more streamlined.
-func (vs *volumeSet) freeVolumes(tx store.Tx) error {
+func (vs *volumeSet) freeVolumes(batch *store.Batch) error {
 	for volumeID, info := range vs.volumes {
-		v := store.GetVolume(tx, volumeID)
-		if v == nil {
-			continue
-		}
+		if err := batch.Update(func(tx store.Tx) error {
+			v := store.GetVolume(tx, volumeID)
+			if v == nil {
+				return nil
+			}
 
-		changed := false
-		for _, status := range v.PublishStatus {
-			if info.nodes[status.NodeID] == 0 && status.State == api.VolumePublishStatus_PUBLISHED {
-				status.State = api.VolumePublishStatus_PENDING_NODE_UNPUBLISH
-				changed = true
+			// when we are freeing a volume, we may update more than one of the
+			// volume's PublishStatuses. this means we can't simply put the
+			// Update call inside of the if statement; we need to know if we've
+			// changed anything once we've checked *all* of the statuses.
+			changed := false
+			for _, status := range v.PublishStatus {
+				if info.nodes[status.NodeID] == 0 && status.State == api.VolumePublishStatus_PUBLISHED {
+					status.State = api.VolumePublishStatus_PENDING_NODE_UNPUBLISH
+					changed = true
+				}
 			}
-		}
-		if changed {
-			if err := store.UpdateVolume(tx, v); err != nil {
-				return err
+			if changed {
+				if err := store.UpdateVolume(tx, v); err != nil {
+					return err
+				}
 			}
+			return nil
+		}); err != nil {
+			return err
 		}
 	}
 	return nil

+ 11 - 11
vendor/github.com/moby/swarmkit/v2/manager/state/raft/raft.go

@@ -929,7 +929,7 @@ func (n *Node) Join(ctx context.Context, req *api.JoinRequest) (*api.JoinRespons
 		return nil, err
 	}
 
-	fields := logrus.Fields{
+	fields := log.Fields{
 		"node.id": nodeInfo.NodeID,
 		"method":  "(*Node).Join",
 		"raft_id": fmt.Sprintf("%x", n.Config.ID),
@@ -937,8 +937,8 @@ func (n *Node) Join(ctx context.Context, req *api.JoinRequest) (*api.JoinRespons
 	if nodeInfo.ForwardedBy != nil {
 		fields["forwarder.id"] = nodeInfo.ForwardedBy.NodeID
 	}
-	log := log.G(ctx).WithFields(fields)
-	log.Debug("")
+	logger := log.G(ctx).WithFields(fields)
+	logger.Debug("")
 
 	// can't stop the raft node while an async RPC is in progress
 	n.stopMu.RLock()
@@ -999,11 +999,11 @@ func (n *Node) Join(ctx context.Context, req *api.JoinRequest) (*api.JoinRespons
 			}
 
 			if err := n.updateNodeBlocking(ctx, m.RaftID, remoteAddr); err != nil {
-				log.WithError(err).Error("failed to update node address")
+				logger.WithError(err).Error("failed to update node address")
 				return nil, err
 			}
 
-			log.Info("updated node address")
+			logger.Info("updated node address")
 			return n.joinResponse(m.RaftID), nil
 		}
 	}
@@ -1019,11 +1019,11 @@ func (n *Node) Join(ctx context.Context, req *api.JoinRequest) (*api.JoinRespons
 
 	err = n.addMember(ctx, remoteAddr, raftID, nodeInfo.NodeID)
 	if err != nil {
-		log.WithError(err).Errorf("failed to add member %x", raftID)
+		logger.WithError(err).Errorf("failed to add member %x", raftID)
 		return nil, err
 	}
 
-	log.Debug("node joined")
+	logger.Debug("node joined")
 
 	return n.joinResponse(raftID), nil
 }
@@ -1126,7 +1126,7 @@ func (n *Node) UpdateNode(id uint64, addr string) {
 	// spawn updating info in raft in background to unblock transport
 	go func() {
 		if err := n.updateNodeBlocking(ctx, id, addr); err != nil {
-			log.G(ctx).WithFields(logrus.Fields{"raft_id": n.Config.ID, "update_id": id}).WithError(err).Error("failed to update member address in cluster")
+			log.G(ctx).WithFields(log.Fields{"raft_id": n.Config.ID, "update_id": id}).WithError(err).Error("failed to update member address in cluster")
 		}
 	}()
 }
@@ -1148,7 +1148,7 @@ func (n *Node) Leave(ctx context.Context, req *api.LeaveRequest) (*api.LeaveResp
 	ctx, cancel := n.WithContext(ctx)
 	defer cancel()
 
-	fields := logrus.Fields{
+	fields := log.Fields{
 		"node.id": nodeInfo.NodeID,
 		"method":  "(*Node).Leave",
 		"raft_id": fmt.Sprintf("%x", n.Config.ID),
@@ -1273,7 +1273,7 @@ func (n *Node) RemoveMember(ctx context.Context, id uint64) error {
 // ProcessRaftMessage. Usually nothing will be logged, so it is useful to avoid
 // formatting strings and allocating a logger when it won't be used.
 func (n *Node) processRaftMessageLogger(ctx context.Context, msg *api.ProcessRaftMessageRequest) *logrus.Entry {
-	fields := logrus.Fields{
+	fields := log.Fields{
 		"method": "(*Node).ProcessRaftMessage",
 	}
 
@@ -1474,7 +1474,7 @@ func (n *Node) ResolveAddress(ctx context.Context, msg *api.ResolveAddressReques
 		return nil, err
 	}
 
-	fields := logrus.Fields{
+	fields := log.Fields{
 		"node.id": nodeInfo.NodeID,
 		"method":  "(*Node).ResolveAddress",
 		"raft_id": fmt.Sprintf("%x", n.Config.ID),

+ 3 - 3
vendor/github.com/moby/swarmkit/v2/node/node.go

@@ -276,7 +276,7 @@ func configVXLANUDPPort(ctx context.Context, vxlanUDPPort uint32) {
 		log.G(ctx).WithError(err).Error("failed to configure VXLAN UDP port")
 		return
 	}
-	logrus.Infof("initialized VXLAN UDP port to %d ", vxlanUDPPort)
+	log.G(ctx).Infof("initialized VXLAN UDP port to %d ", vxlanUDPPort)
 }
 
 func (n *Node) run(ctx context.Context) (err error) {
@@ -444,7 +444,7 @@ func (n *Node) run(ctx context.Context) (err error) {
 	go func() {
 		for certUpdate := range updates {
 			if certUpdate.Err != nil {
-				logrus.Warnf("error renewing TLS certificate: %v", certUpdate.Err)
+				log.G(ctx).Warnf("error renewing TLS certificate: %v", certUpdate.Err)
 				continue
 			}
 			// Set the new role, and notify our waiting role changing logic
@@ -862,7 +862,7 @@ func (n *Node) loadSecurityConfig(ctx context.Context, paths *ca.SecurityConfigP
 		// Attempt to load certificate from disk
 		securityConfig, cancel, err = ca.LoadSecurityConfig(ctx, rootCA, krw, n.config.ForceNewCluster)
 		if err == nil {
-			log.G(ctx).WithFields(logrus.Fields{
+			log.G(ctx).WithFields(log.Fields{
 				"node.id": securityConfig.ClientTLSCreds.NodeID(),
 			}).Debugf("loaded TLS certificate")
 		} else {

+ 2 - 2
vendor/github.com/moby/swarmkit/v2/watch/queue/queue.go

@@ -6,7 +6,7 @@ import (
 	"sync"
 
 	"github.com/docker/go-events"
-	"github.com/sirupsen/logrus"
+	"github.com/moby/swarmkit/v2/log"
 )
 
 // ErrQueueFull is returned by a Write operation when that Write causes the
@@ -112,7 +112,7 @@ func (eq *LimitQueue) run() {
 			// Eventually, go-events should not use logrus at all,
 			// and should bubble up conditions like this through
 			// error values.
-			logrus.WithFields(logrus.Fields{
+			log.L.WithFields(log.Fields{
 				"event": event,
 				"sink":  eq.dst,
 			}).WithError(err).Debug("eventqueue: dropped event")

+ 21 - 0
vendor/github.com/weppos/publicsuffix-go/LICENSE.txt

@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016-2020 Simone Carletti
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 544 - 0
vendor/github.com/weppos/publicsuffix-go/publicsuffix/publicsuffix.go

@@ -0,0 +1,544 @@
+//go:generate go run ../cmd/gen/gen.go
+
+// Package publicsuffix provides a domain name parser
+// based on data from the public suffix list http://publicsuffix.org/.
+// A public suffix is one under which Internet users can directly register names.
+package publicsuffix
+
+import (
+	"bufio"
+	"fmt"
+	"io"
+	"net/http/cookiejar"
+	"os"
+	"strings"
+
+	"golang.org/x/net/idna"
+)
+
+const (
+	// Version identifies the current library version.
+	// This is a pro forma convention given that Go dependencies
+	// tends to be fetched directly from the repo.
+	Version = "0.15.0"
+
+	// NormalType represents a normal rule such as "com"
+	NormalType = 1
+	// WildcardType represents a wildcard rule such as "*.com"
+	WildcardType = 2
+	// ExceptionType represents an exception to a wildard rule
+	ExceptionType = 3
+
+	listTokenPrivateDomains = "===BEGIN PRIVATE DOMAINS==="
+	listTokenComment        = "//"
+)
+
+// DefaultList is the default List and it is used by Parse and Domain.
+var DefaultList = NewList()
+
+// DefaultRule is the default Rule that represents "*".
+var DefaultRule = MustNewRule("*")
+
+// DefaultParserOptions are the default options used to parse a Public Suffix list.
+var DefaultParserOptions = &ParserOption{PrivateDomains: true, ASCIIEncoded: false}
+
+// DefaultFindOptions are the default options used to perform the lookup of rules in the list.
+var DefaultFindOptions = &FindOptions{IgnorePrivate: false, DefaultRule: DefaultRule}
+
+// Rule represents a single rule in a Public Suffix List.
+type Rule struct {
+	Type    int
+	Value   string
+	Length  int
+	Private bool
+}
+
+// ParserOption are the options you can use to customize the way a List
+// is parsed from a file or a string.
+type ParserOption struct {
+	// Set to false to skip the private domains when parsing.
+	// Default to true, which means the private domains are included.
+	PrivateDomains bool
+
+	// Set to false if the input is encoded in U-labels (Unicode)
+	// as opposite to A-labels.
+	// Default to false, which means the list is containing Unicode domains.
+	// This is the default because the original PSL currently contains Unicode.
+	ASCIIEncoded bool
+}
+
+// FindOptions are the options you can use to customize the way a Rule
+// is searched within the list.
+type FindOptions struct {
+	// Set to true to ignore the rules within the "Private" section of the Public Suffix List.
+	IgnorePrivate bool
+
+	// The default rule to use when no rule matches the input.
+	// The format Public Suffix algorithm states that the rule "*" should be used when no other rule matches,
+	// but some consumers may have different needs.
+	DefaultRule *Rule
+}
+
+// List represents a Public Suffix List.
+type List struct {
+	// rules is kept private because you should not access rules directly
+	rules map[string]*Rule
+}
+
+// NewList creates a new empty list.
+func NewList() *List {
+	return &List{
+		rules: map[string]*Rule{},
+	}
+}
+
+// NewListFromString parses a string that represents a Public Suffix source
+// and returns a List initialized with the rules in the source.
+func NewListFromString(src string, options *ParserOption) (*List, error) {
+	l := NewList()
+	_, err := l.LoadString(src, options)
+	return l, err
+}
+
+// NewListFromFile parses a string that represents a Public Suffix source
+// and returns a List initialized with the rules in the source.
+func NewListFromFile(path string, options *ParserOption) (*List, error) {
+	l := NewList()
+	_, err := l.LoadFile(path, options)
+	return l, err
+}
+
+// Load parses and loads a set of rules from an io.Reader into the current list.
+func (l *List) Load(r io.Reader, options *ParserOption) ([]Rule, error) {
+	return l.parse(r, options)
+}
+
+// LoadString parses and loads a set of rules from a String into the current list.
+func (l *List) LoadString(src string, options *ParserOption) ([]Rule, error) {
+	r := strings.NewReader(src)
+	return l.parse(r, options)
+}
+
+// LoadFile parses and loads a set of rules from a File into the current list.
+func (l *List) LoadFile(path string, options *ParserOption) ([]Rule, error) {
+	f, err := os.Open(path)
+	if err != nil {
+		return nil, err
+	}
+	defer f.Close()
+	return l.parse(f, options)
+}
+
+// AddRule adds a new rule to the list.
+//
+// The exact position of the rule into the list is unpredictable.
+// The list may be optimized internally for lookups, therefore the algorithm
+// will decide the best position for the new rule.
+func (l *List) AddRule(r *Rule) error {
+	l.rules[r.Value] = r
+	return nil
+}
+
+// Size returns the size of the list, which is the number of rules.
+func (l *List) Size() int {
+	return len(l.rules)
+}
+
+func (l *List) parse(r io.Reader, options *ParserOption) ([]Rule, error) {
+	if options == nil {
+		options = DefaultParserOptions
+	}
+	var rules []Rule
+
+	scanner := bufio.NewScanner(r)
+	var section int // 1 == ICANN, 2 == PRIVATE
+
+Scanning:
+	for scanner.Scan() {
+		line := strings.TrimSpace(scanner.Text())
+		switch {
+
+		// skip blank lines
+		case line == "":
+			break
+
+		// include private domains or stop scanner
+		case strings.Contains(line, listTokenPrivateDomains):
+			if !options.PrivateDomains {
+				break Scanning
+			}
+			section = 2
+
+		// skip comments
+		case strings.HasPrefix(line, listTokenComment):
+			break
+
+		default:
+			var rule *Rule
+			var err error
+
+			if options.ASCIIEncoded {
+				rule, err = NewRule(line)
+			} else {
+				rule, err = NewRuleUnicode(line)
+			}
+			if err != nil {
+				return []Rule{}, err
+			}
+
+			rule.Private = (section == 2)
+			l.AddRule(rule)
+			rules = append(rules, *rule)
+		}
+
+	}
+
+	return rules, scanner.Err()
+}
+
+// Find and returns the most appropriate rule for the domain name.
+func (l *List) Find(name string, options *FindOptions) *Rule {
+	if options == nil {
+		options = DefaultFindOptions
+	}
+
+	part := name
+	for {
+		rule, ok := l.rules[part]
+
+		if ok && rule.Match(name) && !(options.IgnorePrivate && rule.Private) {
+			return rule
+		}
+
+		i := strings.IndexRune(part, '.')
+		if i < 0 {
+			return options.DefaultRule
+		}
+
+		part = part[i+1:]
+	}
+
+}
+
+// NewRule parses the rule content, creates and returns a Rule.
+//
+// The content of the rule MUST be encoded in ASCII (A-labels).
+func NewRule(content string) (*Rule, error) {
+	var rule *Rule
+	var value string
+
+	switch content[0] {
+	case '*': // wildcard
+		if content == "*" {
+			value = ""
+		} else {
+			value = content[2:]
+		}
+		rule = &Rule{Type: WildcardType, Value: value, Length: len(Labels(value)) + 1}
+	case '!': // exception
+		value = content[1:]
+		rule = &Rule{Type: ExceptionType, Value: value, Length: len(Labels(value))}
+	default: // normal
+		value = content
+		rule = &Rule{Type: NormalType, Value: value, Length: len(Labels(value))}
+	}
+
+	return rule, nil
+}
+
+// NewRuleUnicode is like NewRule, but expects the content to be encoded in Unicode (U-labels).
+func NewRuleUnicode(content string) (*Rule, error) {
+	var err error
+
+	content, err = ToASCII(content)
+	if err != nil {
+		return nil, err
+	}
+
+	return NewRule(content)
+}
+
+// MustNewRule is like NewRule, but panics if the content cannot be parsed.
+func MustNewRule(content string) *Rule {
+	rule, err := NewRule(content)
+	if err != nil {
+		panic(err)
+	}
+	return rule
+}
+
+// Match checks if the rule matches the name.
+//
+// A domain name is said to match a rule if and only if all of the following conditions are met:
+// - When the domain and rule are split into corresponding labels,
+//   that the domain contains as many or more labels than the rule.
+// - Beginning with the right-most labels of both the domain and the rule,
+//   and continuing for all labels in the rule, one finds that for every pair,
+//   either they are identical, or that the label from the rule is "*".
+//
+// See https://publicsuffix.org/list/
+func (r *Rule) Match(name string) bool {
+	left := strings.TrimSuffix(name, r.Value)
+
+	// the name contains as many labels than the rule
+	// this is a match, unless it's a wildcard
+	// because the wildcard requires one more label
+	if left == "" {
+		return r.Type != WildcardType
+	}
+
+	// if there is one more label, the rule match
+	// because either the rule is shorter than the domain
+	// or the rule is a wildcard and there is one more label
+	return left[len(left)-1:] == "."
+}
+
+// Decompose takes a name as input and decomposes it into a tuple of <TRD+SLD, TLD>,
+// according to the rule definition and type.
+func (r *Rule) Decompose(name string) (result [2]string) {
+	if r == DefaultRule {
+		i := strings.LastIndexByte(name, '.')
+		if i < 0 {
+			return
+		}
+		result[0], result[1] = name[:i], name[i+1:]
+		return
+	}
+	switch r.Type {
+	case NormalType:
+		name = strings.TrimSuffix(name, r.Value)
+		if len(name) == 0 {
+			return
+		}
+		result[0], result[1] = name[:len(name)-1], r.Value
+	case WildcardType:
+		name := strings.TrimSuffix(name, r.Value)
+		if len(name) == 0 {
+			return
+		}
+		name = name[:len(name)-1]
+		i := strings.LastIndexByte(name, '.')
+		if i < 0 {
+			return
+		}
+		result[0], result[1] = name[:i], name[i+1:]+"."+r.Value
+	case ExceptionType:
+		i := strings.IndexRune(r.Value, '.')
+		if i < 0 {
+			return
+		}
+		suffix := r.Value[i+1:]
+		name = strings.TrimSuffix(name, suffix)
+		if len(name) == 0 {
+			return
+		}
+		result[0], result[1] = name[:len(name)-1], suffix
+	}
+	return
+}
+
+// Labels decomposes given domain name into labels,
+// corresponding to the dot-separated tokens.
+func Labels(name string) []string {
+	return strings.Split(name, ".")
+}
+
+// DomainName represents a domain name.
+type DomainName struct {
+	TLD  string
+	SLD  string
+	TRD  string
+	Rule *Rule
+}
+
+// String joins the components of the domain name into a single string.
+// Empty labels are skipped.
+//
+// Examples:
+//
+// 	DomainName{"com", "example"}.String()
+//	// example.com
+// 	DomainName{"com", "example", "www"}.String()
+//	// www.example.com
+//
+func (d *DomainName) String() string {
+	switch {
+	case d.TLD == "":
+		return ""
+	case d.SLD == "":
+		return d.TLD
+	case d.TRD == "":
+		return d.SLD + "." + d.TLD
+	default:
+		return d.TRD + "." + d.SLD + "." + d.TLD
+	}
+}
+
+// Domain extract and return the domain name from the input
+// using the default (Public Suffix) List.
+//
+// Examples:
+//
+// 	publicsuffix.Domain("example.com")
+//	// example.com
+// 	publicsuffix.Domain("www.example.com")
+//	// example.com
+// 	publicsuffix.Domain("www.example.co.uk")
+//	// example.co.uk
+//
+func Domain(name string) (string, error) {
+	return DomainFromListWithOptions(DefaultList, name, DefaultFindOptions)
+}
+
+// Parse decomposes the name into TLD, SLD, TRD
+// using the default (Public Suffix) List,
+// and returns the result as a DomainName
+//
+// Examples:
+//
+//	list := NewList()
+//
+// 	publicsuffix.Parse("example.com")
+//	// &DomainName{"com", "example"}
+// 	publicsuffix.Parse("www.example.com")
+//	// &DomainName{"com", "example", "www"}
+// 	publicsuffix.Parse("www.example.co.uk")
+//	// &DomainName{"co.uk", "example"}
+//
+func Parse(name string) (*DomainName, error) {
+	return ParseFromListWithOptions(DefaultList, name, DefaultFindOptions)
+}
+
+// DomainFromListWithOptions extract and return the domain name from the input
+// using the (Public Suffix) list passed as argument.
+//
+// Examples:
+//
+//	list := NewList()
+//
+// 	publicsuffix.DomainFromListWithOptions(list, "example.com")
+//	// example.com
+// 	publicsuffix.DomainFromListWithOptions(list, "www.example.com")
+//	// example.com
+// 	publicsuffix.DomainFromListWithOptions(list, "www.example.co.uk")
+//	// example.co.uk
+//
+func DomainFromListWithOptions(l *List, name string, options *FindOptions) (string, error) {
+	dn, err := ParseFromListWithOptions(l, name, options)
+	if err != nil {
+		return "", err
+	}
+	return dn.SLD + "." + dn.TLD, nil
+}
+
+// ParseFromListWithOptions decomposes the name into TLD, SLD, TRD
+// using the (Public Suffix) list passed as argument,
+// and returns the result as a DomainName
+//
+// Examples:
+//
+//	list := NewList()
+//
+// 	publicsuffix.ParseFromListWithOptions(list, "example.com")
+//	// &DomainName{"com", "example"}
+// 	publicsuffix.ParseFromListWithOptions(list, "www.example.com")
+//	// &DomainName{"com", "example", "www"}
+// 	publicsuffix.ParseFromListWithOptions(list, "www.example.co.uk")
+//	// &DomainName{"co.uk", "example"}
+//
+func ParseFromListWithOptions(l *List, name string, options *FindOptions) (*DomainName, error) {
+	n, err := normalize(name)
+	if err != nil {
+		return nil, err
+	}
+
+	r := l.Find(n, options)
+	if r == nil {
+		return nil, fmt.Errorf("no rule matching name %s", name)
+	}
+
+	parts := r.Decompose(n)
+	left, tld := parts[0], parts[1]
+	if tld == "" {
+		return nil, fmt.Errorf("%s is a suffix", n)
+	}
+
+	dn := &DomainName{
+		Rule: r,
+		TLD:  tld,
+	}
+	if i := strings.LastIndexByte(left, '.'); i < 0 {
+		dn.SLD = left
+	} else {
+		dn.TRD = left[:i]
+		dn.SLD = left[i+1:]
+	}
+	return dn, nil
+}
+
+func normalize(name string) (string, error) {
+	ret := strings.ToLower(name)
+
+	if ret == "" {
+		return "", fmt.Errorf("name is blank")
+	}
+	if ret[0] == '.' {
+		return "", fmt.Errorf("name %s starts with a dot", ret)
+	}
+
+	return ret, nil
+}
+
+// ToASCII is a wrapper for idna.ToASCII.
+//
+// This wrapper exists because idna.ToASCII backward-compatibility was broken twice in few months
+// and I can't call this package directly anymore. The wrapper performs some terrible-but-necessary
+// before-after replacements to make sure an already ASCII input always results in the same output
+// even if passed through ToASCII.
+//
+// See golang/net@67957fd0b1, golang/net@f2499483f9, golang/net@78ebe5c8b6,
+// and weppos/publicsuffix-go#66.
+func ToASCII(s string) (string, error) {
+	// .example.com should be .example.com
+	// ..example.com should be ..example.com
+	if strings.HasPrefix(s, ".") {
+		dotIndex := 0
+		for i := 0; i < len(s); i++ {
+			if s[i] == '.' {
+				dotIndex = i
+			} else {
+				break
+			}
+		}
+		out, err := idna.ToASCII(s[dotIndex+1:])
+		out = s[:dotIndex+1] + out
+		return out, err
+	}
+
+	return idna.ToASCII(s)
+}
+
+// ToUnicode is a wrapper for idna.ToUnicode.
+//
+// See ToASCII for more details about why this wrapper exists.
+func ToUnicode(s string) (string, error) {
+	return idna.ToUnicode(s)
+}
+
+// CookieJarList implements the cookiejar.PublicSuffixList interface.
+var CookieJarList cookiejar.PublicSuffixList = cookiejarList{DefaultList}
+
+type cookiejarList struct {
+	List *List
+}
+
+// PublicSuffix implements cookiejar.PublicSuffixList.
+func (l cookiejarList) PublicSuffix(domain string) string {
+	rule := l.List.Find(domain, nil)
+	return rule.Decompose(domain)[1]
+}
+
+// PublicSuffix implements cookiejar.String.
+func (cookiejarList) String() string {
+	return defaultListVersion
+}

+ 9188 - 0
vendor/github.com/weppos/publicsuffix-go/publicsuffix/rules.go

@@ -0,0 +1,9188 @@
+// This file is automatically generated
+// Run "go run cmd/gen/gen.go" to update the list.
+
+package publicsuffix
+
+const defaultListVersion = "PSL version 598c63 (Thu May  6 04:03:10 2021)"
+
+func DefaultRules() [9169]Rule {
+	return r
+}
+
+var r = [9169]Rule{
+	{1, "ac", 1, false},
+	{1, "com.ac", 2, false},
+	{1, "edu.ac", 2, false},
+	{1, "gov.ac", 2, false},
+	{1, "net.ac", 2, false},
+	{1, "mil.ac", 2, false},
+	{1, "org.ac", 2, false},
+	{1, "ad", 1, false},
+	{1, "nom.ad", 2, false},
+	{1, "ae", 1, false},
+	{1, "co.ae", 2, false},
+	{1, "net.ae", 2, false},
+	{1, "org.ae", 2, false},
+	{1, "sch.ae", 2, false},
+	{1, "ac.ae", 2, false},
+	{1, "gov.ae", 2, false},
+	{1, "mil.ae", 2, false},
+	{1, "aero", 1, false},
+	{1, "accident-investigation.aero", 2, false},
+	{1, "accident-prevention.aero", 2, false},
+	{1, "aerobatic.aero", 2, false},
+	{1, "aeroclub.aero", 2, false},
+	{1, "aerodrome.aero", 2, false},
+	{1, "agents.aero", 2, false},
+	{1, "aircraft.aero", 2, false},
+	{1, "airline.aero", 2, false},
+	{1, "airport.aero", 2, false},
+	{1, "air-surveillance.aero", 2, false},
+	{1, "airtraffic.aero", 2, false},
+	{1, "air-traffic-control.aero", 2, false},
+	{1, "ambulance.aero", 2, false},
+	{1, "amusement.aero", 2, false},
+	{1, "association.aero", 2, false},
+	{1, "author.aero", 2, false},
+	{1, "ballooning.aero", 2, false},
+	{1, "broker.aero", 2, false},
+	{1, "caa.aero", 2, false},
+	{1, "cargo.aero", 2, false},
+	{1, "catering.aero", 2, false},
+	{1, "certification.aero", 2, false},
+	{1, "championship.aero", 2, false},
+	{1, "charter.aero", 2, false},
+	{1, "civilaviation.aero", 2, false},
+	{1, "club.aero", 2, false},
+	{1, "conference.aero", 2, false},
+	{1, "consultant.aero", 2, false},
+	{1, "consulting.aero", 2, false},
+	{1, "control.aero", 2, false},
+	{1, "council.aero", 2, false},
+	{1, "crew.aero", 2, false},
+	{1, "design.aero", 2, false},
+	{1, "dgca.aero", 2, false},
+	{1, "educator.aero", 2, false},
+	{1, "emergency.aero", 2, false},
+	{1, "engine.aero", 2, false},
+	{1, "engineer.aero", 2, false},
+	{1, "entertainment.aero", 2, false},
+	{1, "equipment.aero", 2, false},
+	{1, "exchange.aero", 2, false},
+	{1, "express.aero", 2, false},
+	{1, "federation.aero", 2, false},
+	{1, "flight.aero", 2, false},
+	{1, "fuel.aero", 2, false},
+	{1, "gliding.aero", 2, false},
+	{1, "government.aero", 2, false},
+	{1, "groundhandling.aero", 2, false},
+	{1, "group.aero", 2, false},
+	{1, "hanggliding.aero", 2, false},
+	{1, "homebuilt.aero", 2, false},
+	{1, "insurance.aero", 2, false},
+	{1, "journal.aero", 2, false},
+	{1, "journalist.aero", 2, false},
+	{1, "leasing.aero", 2, false},
+	{1, "logistics.aero", 2, false},
+	{1, "magazine.aero", 2, false},
+	{1, "maintenance.aero", 2, false},
+	{1, "media.aero", 2, false},
+	{1, "microlight.aero", 2, false},
+	{1, "modelling.aero", 2, false},
+	{1, "navigation.aero", 2, false},
+	{1, "parachuting.aero", 2, false},
+	{1, "paragliding.aero", 2, false},
+	{1, "passenger-association.aero", 2, false},
+	{1, "pilot.aero", 2, false},
+	{1, "press.aero", 2, false},
+	{1, "production.aero", 2, false},
+	{1, "recreation.aero", 2, false},
+	{1, "repbody.aero", 2, false},
+	{1, "res.aero", 2, false},
+	{1, "research.aero", 2, false},
+	{1, "rotorcraft.aero", 2, false},
+	{1, "safety.aero", 2, false},
+	{1, "scientist.aero", 2, false},
+	{1, "services.aero", 2, false},
+	{1, "show.aero", 2, false},
+	{1, "skydiving.aero", 2, false},
+	{1, "software.aero", 2, false},
+	{1, "student.aero", 2, false},
+	{1, "trader.aero", 2, false},
+	{1, "trading.aero", 2, false},
+	{1, "trainer.aero", 2, false},
+	{1, "union.aero", 2, false},
+	{1, "workinggroup.aero", 2, false},
+	{1, "works.aero", 2, false},
+	{1, "af", 1, false},
+	{1, "gov.af", 2, false},
+	{1, "com.af", 2, false},
+	{1, "org.af", 2, false},
+	{1, "net.af", 2, false},
+	{1, "edu.af", 2, false},
+	{1, "ag", 1, false},
+	{1, "com.ag", 2, false},
+	{1, "org.ag", 2, false},
+	{1, "net.ag", 2, false},
+	{1, "co.ag", 2, false},
+	{1, "nom.ag", 2, false},
+	{1, "ai", 1, false},
+	{1, "off.ai", 2, false},
+	{1, "com.ai", 2, false},
+	{1, "net.ai", 2, false},
+	{1, "org.ai", 2, false},
+	{1, "al", 1, false},
+	{1, "com.al", 2, false},
+	{1, "edu.al", 2, false},
+	{1, "gov.al", 2, false},
+	{1, "mil.al", 2, false},
+	{1, "net.al", 2, false},
+	{1, "org.al", 2, false},
+	{1, "am", 1, false},
+	{1, "co.am", 2, false},
+	{1, "com.am", 2, false},
+	{1, "commune.am", 2, false},
+	{1, "net.am", 2, false},
+	{1, "org.am", 2, false},
+	{1, "ao", 1, false},
+	{1, "ed.ao", 2, false},
+	{1, "gv.ao", 2, false},
+	{1, "og.ao", 2, false},
+	{1, "co.ao", 2, false},
+	{1, "pb.ao", 2, false},
+	{1, "it.ao", 2, false},
+	{1, "aq", 1, false},
+	{1, "ar", 1, false},
+	{1, "com.ar", 2, false},
+	{1, "edu.ar", 2, false},
+	{1, "gob.ar", 2, false},
+	{1, "gov.ar", 2, false},
+	{1, "int.ar", 2, false},
+	{1, "mil.ar", 2, false},
+	{1, "musica.ar", 2, false},
+	{1, "net.ar", 2, false},
+	{1, "org.ar", 2, false},
+	{1, "tur.ar", 2, false},
+	{1, "arpa", 1, false},
+	{1, "e164.arpa", 2, false},
+	{1, "in-addr.arpa", 2, false},
+	{1, "ip6.arpa", 2, false},
+	{1, "iris.arpa", 2, false},
+	{1, "uri.arpa", 2, false},
+	{1, "urn.arpa", 2, false},
+	{1, "as", 1, false},
+	{1, "gov.as", 2, false},
+	{1, "asia", 1, false},
+	{1, "at", 1, false},
+	{1, "ac.at", 2, false},
+	{1, "co.at", 2, false},
+	{1, "gv.at", 2, false},
+	{1, "or.at", 2, false},
+	{1, "sth.ac.at", 3, false},
+	{1, "au", 1, false},
+	{1, "com.au", 2, false},
+	{1, "net.au", 2, false},
+	{1, "org.au", 2, false},
+	{1, "edu.au", 2, false},
+	{1, "gov.au", 2, false},
+	{1, "asn.au", 2, false},
+	{1, "id.au", 2, false},
+	{1, "info.au", 2, false},
+	{1, "conf.au", 2, false},
+	{1, "oz.au", 2, false},
+	{1, "act.au", 2, false},
+	{1, "nsw.au", 2, false},
+	{1, "nt.au", 2, false},
+	{1, "qld.au", 2, false},
+	{1, "sa.au", 2, false},
+	{1, "tas.au", 2, false},
+	{1, "vic.au", 2, false},
+	{1, "wa.au", 2, false},
+	{1, "act.edu.au", 3, false},
+	{1, "catholic.edu.au", 3, false},
+	{1, "nsw.edu.au", 3, false},
+	{1, "nt.edu.au", 3, false},
+	{1, "qld.edu.au", 3, false},
+	{1, "sa.edu.au", 3, false},
+	{1, "tas.edu.au", 3, false},
+	{1, "vic.edu.au", 3, false},
+	{1, "wa.edu.au", 3, false},
+	{1, "qld.gov.au", 3, false},
+	{1, "sa.gov.au", 3, false},
+	{1, "tas.gov.au", 3, false},
+	{1, "vic.gov.au", 3, false},
+	{1, "wa.gov.au", 3, false},
+	{1, "schools.nsw.edu.au", 4, false},
+	{1, "aw", 1, false},
+	{1, "com.aw", 2, false},
+	{1, "ax", 1, false},
+	{1, "az", 1, false},
+	{1, "com.az", 2, false},
+	{1, "net.az", 2, false},
+	{1, "int.az", 2, false},
+	{1, "gov.az", 2, false},
+	{1, "org.az", 2, false},
+	{1, "edu.az", 2, false},
+	{1, "info.az", 2, false},
+	{1, "pp.az", 2, false},
+	{1, "mil.az", 2, false},
+	{1, "name.az", 2, false},
+	{1, "pro.az", 2, false},
+	{1, "biz.az", 2, false},
+	{1, "ba", 1, false},
+	{1, "com.ba", 2, false},
+	{1, "edu.ba", 2, false},
+	{1, "gov.ba", 2, false},
+	{1, "mil.ba", 2, false},
+	{1, "net.ba", 2, false},
+	{1, "org.ba", 2, false},
+	{1, "bb", 1, false},
+	{1, "biz.bb", 2, false},
+	{1, "co.bb", 2, false},
+	{1, "com.bb", 2, false},
+	{1, "edu.bb", 2, false},
+	{1, "gov.bb", 2, false},
+	{1, "info.bb", 2, false},
+	{1, "net.bb", 2, false},
+	{1, "org.bb", 2, false},
+	{1, "store.bb", 2, false},
+	{1, "tv.bb", 2, false},
+	{2, "bd", 2, false},
+	{1, "be", 1, false},
+	{1, "ac.be", 2, false},
+	{1, "bf", 1, false},
+	{1, "gov.bf", 2, false},
+	{1, "bg", 1, false},
+	{1, "a.bg", 2, false},
+	{1, "b.bg", 2, false},
+	{1, "c.bg", 2, false},
+	{1, "d.bg", 2, false},
+	{1, "e.bg", 2, false},
+	{1, "f.bg", 2, false},
+	{1, "g.bg", 2, false},
+	{1, "h.bg", 2, false},
+	{1, "i.bg", 2, false},
+	{1, "j.bg", 2, false},
+	{1, "k.bg", 2, false},
+	{1, "l.bg", 2, false},
+	{1, "m.bg", 2, false},
+	{1, "n.bg", 2, false},
+	{1, "o.bg", 2, false},
+	{1, "p.bg", 2, false},
+	{1, "q.bg", 2, false},
+	{1, "r.bg", 2, false},
+	{1, "s.bg", 2, false},
+	{1, "t.bg", 2, false},
+	{1, "u.bg", 2, false},
+	{1, "v.bg", 2, false},
+	{1, "w.bg", 2, false},
+	{1, "x.bg", 2, false},
+	{1, "y.bg", 2, false},
+	{1, "z.bg", 2, false},
+	{1, "0.bg", 2, false},
+	{1, "1.bg", 2, false},
+	{1, "2.bg", 2, false},
+	{1, "3.bg", 2, false},
+	{1, "4.bg", 2, false},
+	{1, "5.bg", 2, false},
+	{1, "6.bg", 2, false},
+	{1, "7.bg", 2, false},
+	{1, "8.bg", 2, false},
+	{1, "9.bg", 2, false},
+	{1, "bh", 1, false},
+	{1, "com.bh", 2, false},
+	{1, "edu.bh", 2, false},
+	{1, "net.bh", 2, false},
+	{1, "org.bh", 2, false},
+	{1, "gov.bh", 2, false},
+	{1, "bi", 1, false},
+	{1, "co.bi", 2, false},
+	{1, "com.bi", 2, false},
+	{1, "edu.bi", 2, false},
+	{1, "or.bi", 2, false},
+	{1, "org.bi", 2, false},
+	{1, "biz", 1, false},
+	{1, "bj", 1, false},
+	{1, "asso.bj", 2, false},
+	{1, "barreau.bj", 2, false},
+	{1, "gouv.bj", 2, false},
+	{1, "bm", 1, false},
+	{1, "com.bm", 2, false},
+	{1, "edu.bm", 2, false},
+	{1, "gov.bm", 2, false},
+	{1, "net.bm", 2, false},
+	{1, "org.bm", 2, false},
+	{1, "bn", 1, false},
+	{1, "com.bn", 2, false},
+	{1, "edu.bn", 2, false},
+	{1, "gov.bn", 2, false},
+	{1, "net.bn", 2, false},
+	{1, "org.bn", 2, false},
+	{1, "bo", 1, false},
+	{1, "com.bo", 2, false},
+	{1, "edu.bo", 2, false},
+	{1, "gob.bo", 2, false},
+	{1, "int.bo", 2, false},
+	{1, "org.bo", 2, false},
+	{1, "net.bo", 2, false},
+	{1, "mil.bo", 2, false},
+	{1, "tv.bo", 2, false},
+	{1, "web.bo", 2, false},
+	{1, "academia.bo", 2, false},
+	{1, "agro.bo", 2, false},
+	{1, "arte.bo", 2, false},
+	{1, "blog.bo", 2, false},
+	{1, "bolivia.bo", 2, false},
+	{1, "ciencia.bo", 2, false},
+	{1, "cooperativa.bo", 2, false},
+	{1, "democracia.bo", 2, false},
+	{1, "deporte.bo", 2, false},
+	{1, "ecologia.bo", 2, false},
+	{1, "economia.bo", 2, false},
+	{1, "empresa.bo", 2, false},
+	{1, "indigena.bo", 2, false},
+	{1, "industria.bo", 2, false},
+	{1, "info.bo", 2, false},
+	{1, "medicina.bo", 2, false},
+	{1, "movimiento.bo", 2, false},
+	{1, "musica.bo", 2, false},
+	{1, "natural.bo", 2, false},
+	{1, "nombre.bo", 2, false},
+	{1, "noticias.bo", 2, false},
+	{1, "patria.bo", 2, false},
+	{1, "politica.bo", 2, false},
+	{1, "profesional.bo", 2, false},
+	{1, "plurinacional.bo", 2, false},
+	{1, "pueblo.bo", 2, false},
+	{1, "revista.bo", 2, false},
+	{1, "salud.bo", 2, false},
+	{1, "tecnologia.bo", 2, false},
+	{1, "tksat.bo", 2, false},
+	{1, "transporte.bo", 2, false},
+	{1, "wiki.bo", 2, false},
+	{1, "br", 1, false},
+	{1, "9guacu.br", 2, false},
+	{1, "abc.br", 2, false},
+	{1, "adm.br", 2, false},
+	{1, "adv.br", 2, false},
+	{1, "agr.br", 2, false},
+	{1, "aju.br", 2, false},
+	{1, "am.br", 2, false},
+	{1, "anani.br", 2, false},
+	{1, "aparecida.br", 2, false},
+	{1, "app.br", 2, false},
+	{1, "arq.br", 2, false},
+	{1, "art.br", 2, false},
+	{1, "ato.br", 2, false},
+	{1, "b.br", 2, false},
+	{1, "barueri.br", 2, false},
+	{1, "belem.br", 2, false},
+	{1, "bhz.br", 2, false},
+	{1, "bib.br", 2, false},
+	{1, "bio.br", 2, false},
+	{1, "blog.br", 2, false},
+	{1, "bmd.br", 2, false},
+	{1, "boavista.br", 2, false},
+	{1, "bsb.br", 2, false},
+	{1, "campinagrande.br", 2, false},
+	{1, "campinas.br", 2, false},
+	{1, "caxias.br", 2, false},
+	{1, "cim.br", 2, false},
+	{1, "cng.br", 2, false},
+	{1, "cnt.br", 2, false},
+	{1, "com.br", 2, false},
+	{1, "contagem.br", 2, false},
+	{1, "coop.br", 2, false},
+	{1, "coz.br", 2, false},
+	{1, "cri.br", 2, false},
+	{1, "cuiaba.br", 2, false},
+	{1, "curitiba.br", 2, false},
+	{1, "def.br", 2, false},
+	{1, "des.br", 2, false},
+	{1, "det.br", 2, false},
+	{1, "dev.br", 2, false},
+	{1, "ecn.br", 2, false},
+	{1, "eco.br", 2, false},
+	{1, "edu.br", 2, false},
+	{1, "emp.br", 2, false},
+	{1, "enf.br", 2, false},
+	{1, "eng.br", 2, false},
+	{1, "esp.br", 2, false},
+	{1, "etc.br", 2, false},
+	{1, "eti.br", 2, false},
+	{1, "far.br", 2, false},
+	{1, "feira.br", 2, false},
+	{1, "flog.br", 2, false},
+	{1, "floripa.br", 2, false},
+	{1, "fm.br", 2, false},
+	{1, "fnd.br", 2, false},
+	{1, "fortal.br", 2, false},
+	{1, "fot.br", 2, false},
+	{1, "foz.br", 2, false},
+	{1, "fst.br", 2, false},
+	{1, "g12.br", 2, false},
+	{1, "geo.br", 2, false},
+	{1, "ggf.br", 2, false},
+	{1, "goiania.br", 2, false},
+	{1, "gov.br", 2, false},
+	{1, "ac.gov.br", 3, false},
+	{1, "al.gov.br", 3, false},
+	{1, "am.gov.br", 3, false},
+	{1, "ap.gov.br", 3, false},
+	{1, "ba.gov.br", 3, false},
+	{1, "ce.gov.br", 3, false},
+	{1, "df.gov.br", 3, false},
+	{1, "es.gov.br", 3, false},
+	{1, "go.gov.br", 3, false},
+	{1, "ma.gov.br", 3, false},
+	{1, "mg.gov.br", 3, false},
+	{1, "ms.gov.br", 3, false},
+	{1, "mt.gov.br", 3, false},
+	{1, "pa.gov.br", 3, false},
+	{1, "pb.gov.br", 3, false},
+	{1, "pe.gov.br", 3, false},
+	{1, "pi.gov.br", 3, false},
+	{1, "pr.gov.br", 3, false},
+	{1, "rj.gov.br", 3, false},
+	{1, "rn.gov.br", 3, false},
+	{1, "ro.gov.br", 3, false},
+	{1, "rr.gov.br", 3, false},
+	{1, "rs.gov.br", 3, false},
+	{1, "sc.gov.br", 3, false},
+	{1, "se.gov.br", 3, false},
+	{1, "sp.gov.br", 3, false},
+	{1, "to.gov.br", 3, false},
+	{1, "gru.br", 2, false},
+	{1, "imb.br", 2, false},
+	{1, "ind.br", 2, false},
+	{1, "inf.br", 2, false},
+	{1, "jab.br", 2, false},
+	{1, "jampa.br", 2, false},
+	{1, "jdf.br", 2, false},
+	{1, "joinville.br", 2, false},
+	{1, "jor.br", 2, false},
+	{1, "jus.br", 2, false},
+	{1, "leg.br", 2, false},
+	{1, "lel.br", 2, false},
+	{1, "log.br", 2, false},
+	{1, "londrina.br", 2, false},
+	{1, "macapa.br", 2, false},
+	{1, "maceio.br", 2, false},
+	{1, "manaus.br", 2, false},
+	{1, "maringa.br", 2, false},
+	{1, "mat.br", 2, false},
+	{1, "med.br", 2, false},
+	{1, "mil.br", 2, false},
+	{1, "morena.br", 2, false},
+	{1, "mp.br", 2, false},
+	{1, "mus.br", 2, false},
+	{1, "natal.br", 2, false},
+	{1, "net.br", 2, false},
+	{1, "niteroi.br", 2, false},
+	{2, "nom.br", 3, false},
+	{1, "not.br", 2, false},
+	{1, "ntr.br", 2, false},
+	{1, "odo.br", 2, false},
+	{1, "ong.br", 2, false},
+	{1, "org.br", 2, false},
+	{1, "osasco.br", 2, false},
+	{1, "palmas.br", 2, false},
+	{1, "poa.br", 2, false},
+	{1, "ppg.br", 2, false},
+	{1, "pro.br", 2, false},
+	{1, "psc.br", 2, false},
+	{1, "psi.br", 2, false},
+	{1, "pvh.br", 2, false},
+	{1, "qsl.br", 2, false},
+	{1, "radio.br", 2, false},
+	{1, "rec.br", 2, false},
+	{1, "recife.br", 2, false},
+	{1, "rep.br", 2, false},
+	{1, "ribeirao.br", 2, false},
+	{1, "rio.br", 2, false},
+	{1, "riobranco.br", 2, false},
+	{1, "riopreto.br", 2, false},
+	{1, "salvador.br", 2, false},
+	{1, "sampa.br", 2, false},
+	{1, "santamaria.br", 2, false},
+	{1, "santoandre.br", 2, false},
+	{1, "saobernardo.br", 2, false},
+	{1, "saogonca.br", 2, false},
+	{1, "seg.br", 2, false},
+	{1, "sjc.br", 2, false},
+	{1, "slg.br", 2, false},
+	{1, "slz.br", 2, false},
+	{1, "sorocaba.br", 2, false},
+	{1, "srv.br", 2, false},
+	{1, "taxi.br", 2, false},
+	{1, "tc.br", 2, false},
+	{1, "tec.br", 2, false},
+	{1, "teo.br", 2, false},
+	{1, "the.br", 2, false},
+	{1, "tmp.br", 2, false},
+	{1, "trd.br", 2, false},
+	{1, "tur.br", 2, false},
+	{1, "tv.br", 2, false},
+	{1, "udi.br", 2, false},
+	{1, "vet.br", 2, false},
+	{1, "vix.br", 2, false},
+	{1, "vlog.br", 2, false},
+	{1, "wiki.br", 2, false},
+	{1, "zlg.br", 2, false},
+	{1, "bs", 1, false},
+	{1, "com.bs", 2, false},
+	{1, "net.bs", 2, false},
+	{1, "org.bs", 2, false},
+	{1, "edu.bs", 2, false},
+	{1, "gov.bs", 2, false},
+	{1, "bt", 1, false},
+	{1, "com.bt", 2, false},
+	{1, "edu.bt", 2, false},
+	{1, "gov.bt", 2, false},
+	{1, "net.bt", 2, false},
+	{1, "org.bt", 2, false},
+	{1, "bv", 1, false},
+	{1, "bw", 1, false},
+	{1, "co.bw", 2, false},
+	{1, "org.bw", 2, false},
+	{1, "by", 1, false},
+	{1, "gov.by", 2, false},
+	{1, "mil.by", 2, false},
+	{1, "com.by", 2, false},
+	{1, "of.by", 2, false},
+	{1, "bz", 1, false},
+	{1, "com.bz", 2, false},
+	{1, "net.bz", 2, false},
+	{1, "org.bz", 2, false},
+	{1, "edu.bz", 2, false},
+	{1, "gov.bz", 2, false},
+	{1, "ca", 1, false},
+	{1, "ab.ca", 2, false},
+	{1, "bc.ca", 2, false},
+	{1, "mb.ca", 2, false},
+	{1, "nb.ca", 2, false},
+	{1, "nf.ca", 2, false},
+	{1, "nl.ca", 2, false},
+	{1, "ns.ca", 2, false},
+	{1, "nt.ca", 2, false},
+	{1, "nu.ca", 2, false},
+	{1, "on.ca", 2, false},
+	{1, "pe.ca", 2, false},
+	{1, "qc.ca", 2, false},
+	{1, "sk.ca", 2, false},
+	{1, "yk.ca", 2, false},
+	{1, "gc.ca", 2, false},
+	{1, "cat", 1, false},
+	{1, "cc", 1, false},
+	{1, "cd", 1, false},
+	{1, "gov.cd", 2, false},
+	{1, "cf", 1, false},
+	{1, "cg", 1, false},
+	{1, "ch", 1, false},
+	{1, "ci", 1, false},
+	{1, "org.ci", 2, false},
+	{1, "or.ci", 2, false},
+	{1, "com.ci", 2, false},
+	{1, "co.ci", 2, false},
+	{1, "edu.ci", 2, false},
+	{1, "ed.ci", 2, false},
+	{1, "ac.ci", 2, false},
+	{1, "net.ci", 2, false},
+	{1, "go.ci", 2, false},
+	{1, "asso.ci", 2, false},
+	{1, "xn--aroport-bya.ci", 2, false},
+	{1, "int.ci", 2, false},
+	{1, "presse.ci", 2, false},
+	{1, "md.ci", 2, false},
+	{1, "gouv.ci", 2, false},
+	{2, "ck", 2, false},
+	{3, "www.ck", 2, false},
+	{1, "cl", 1, false},
+	{1, "aprendemas.cl", 2, false},
+	{1, "co.cl", 2, false},
+	{1, "gob.cl", 2, false},
+	{1, "gov.cl", 2, false},
+	{1, "mil.cl", 2, false},
+	{1, "cm", 1, false},
+	{1, "co.cm", 2, false},
+	{1, "com.cm", 2, false},
+	{1, "gov.cm", 2, false},
+	{1, "net.cm", 2, false},
+	{1, "cn", 1, false},
+	{1, "ac.cn", 2, false},
+	{1, "com.cn", 2, false},
+	{1, "edu.cn", 2, false},
+	{1, "gov.cn", 2, false},
+	{1, "net.cn", 2, false},
+	{1, "org.cn", 2, false},
+	{1, "mil.cn", 2, false},
+	{1, "xn--55qx5d.cn", 2, false},
+	{1, "xn--io0a7i.cn", 2, false},
+	{1, "xn--od0alg.cn", 2, false},
+	{1, "ah.cn", 2, false},
+	{1, "bj.cn", 2, false},
+	{1, "cq.cn", 2, false},
+	{1, "fj.cn", 2, false},
+	{1, "gd.cn", 2, false},
+	{1, "gs.cn", 2, false},
+	{1, "gz.cn", 2, false},
+	{1, "gx.cn", 2, false},
+	{1, "ha.cn", 2, false},
+	{1, "hb.cn", 2, false},
+	{1, "he.cn", 2, false},
+	{1, "hi.cn", 2, false},
+	{1, "hl.cn", 2, false},
+	{1, "hn.cn", 2, false},
+	{1, "jl.cn", 2, false},
+	{1, "js.cn", 2, false},
+	{1, "jx.cn", 2, false},
+	{1, "ln.cn", 2, false},
+	{1, "nm.cn", 2, false},
+	{1, "nx.cn", 2, false},
+	{1, "qh.cn", 2, false},
+	{1, "sc.cn", 2, false},
+	{1, "sd.cn", 2, false},
+	{1, "sh.cn", 2, false},
+	{1, "sn.cn", 2, false},
+	{1, "sx.cn", 2, false},
+	{1, "tj.cn", 2, false},
+	{1, "xj.cn", 2, false},
+	{1, "xz.cn", 2, false},
+	{1, "yn.cn", 2, false},
+	{1, "zj.cn", 2, false},
+	{1, "hk.cn", 2, false},
+	{1, "mo.cn", 2, false},
+	{1, "tw.cn", 2, false},
+	{1, "co", 1, false},
+	{1, "arts.co", 2, false},
+	{1, "com.co", 2, false},
+	{1, "edu.co", 2, false},
+	{1, "firm.co", 2, false},
+	{1, "gov.co", 2, false},
+	{1, "info.co", 2, false},
+	{1, "int.co", 2, false},
+	{1, "mil.co", 2, false},
+	{1, "net.co", 2, false},
+	{1, "nom.co", 2, false},
+	{1, "org.co", 2, false},
+	{1, "rec.co", 2, false},
+	{1, "web.co", 2, false},
+	{1, "com", 1, false},
+	{1, "coop", 1, false},
+	{1, "cr", 1, false},
+	{1, "ac.cr", 2, false},
+	{1, "co.cr", 2, false},
+	{1, "ed.cr", 2, false},
+	{1, "fi.cr", 2, false},
+	{1, "go.cr", 2, false},
+	{1, "or.cr", 2, false},
+	{1, "sa.cr", 2, false},
+	{1, "cu", 1, false},
+	{1, "com.cu", 2, false},
+	{1, "edu.cu", 2, false},
+	{1, "org.cu", 2, false},
+	{1, "net.cu", 2, false},
+	{1, "gov.cu", 2, false},
+	{1, "inf.cu", 2, false},
+	{1, "cv", 1, false},
+	{1, "cw", 1, false},
+	{1, "com.cw", 2, false},
+	{1, "edu.cw", 2, false},
+	{1, "net.cw", 2, false},
+	{1, "org.cw", 2, false},
+	{1, "cx", 1, false},
+	{1, "gov.cx", 2, false},
+	{1, "cy", 1, false},
+	{1, "ac.cy", 2, false},
+	{1, "biz.cy", 2, false},
+	{1, "com.cy", 2, false},
+	{1, "ekloges.cy", 2, false},
+	{1, "gov.cy", 2, false},
+	{1, "ltd.cy", 2, false},
+	{1, "name.cy", 2, false},
+	{1, "net.cy", 2, false},
+	{1, "org.cy", 2, false},
+	{1, "parliament.cy", 2, false},
+	{1, "press.cy", 2, false},
+	{1, "pro.cy", 2, false},
+	{1, "tm.cy", 2, false},
+	{1, "cz", 1, false},
+	{1, "de", 1, false},
+	{1, "dj", 1, false},
+	{1, "dk", 1, false},
+	{1, "dm", 1, false},
+	{1, "com.dm", 2, false},
+	{1, "net.dm", 2, false},
+	{1, "org.dm", 2, false},
+	{1, "edu.dm", 2, false},
+	{1, "gov.dm", 2, false},
+	{1, "do", 1, false},
+	{1, "art.do", 2, false},
+	{1, "com.do", 2, false},
+	{1, "edu.do", 2, false},
+	{1, "gob.do", 2, false},
+	{1, "gov.do", 2, false},
+	{1, "mil.do", 2, false},
+	{1, "net.do", 2, false},
+	{1, "org.do", 2, false},
+	{1, "sld.do", 2, false},
+	{1, "web.do", 2, false},
+	{1, "dz", 1, false},
+	{1, "art.dz", 2, false},
+	{1, "asso.dz", 2, false},
+	{1, "com.dz", 2, false},
+	{1, "edu.dz", 2, false},
+	{1, "gov.dz", 2, false},
+	{1, "org.dz", 2, false},
+	{1, "net.dz", 2, false},
+	{1, "pol.dz", 2, false},
+	{1, "soc.dz", 2, false},
+	{1, "tm.dz", 2, false},
+	{1, "ec", 1, false},
+	{1, "com.ec", 2, false},
+	{1, "info.ec", 2, false},
+	{1, "net.ec", 2, false},
+	{1, "fin.ec", 2, false},
+	{1, "k12.ec", 2, false},
+	{1, "med.ec", 2, false},
+	{1, "pro.ec", 2, false},
+	{1, "org.ec", 2, false},
+	{1, "edu.ec", 2, false},
+	{1, "gov.ec", 2, false},
+	{1, "gob.ec", 2, false},
+	{1, "mil.ec", 2, false},
+	{1, "edu", 1, false},
+	{1, "ee", 1, false},
+	{1, "edu.ee", 2, false},
+	{1, "gov.ee", 2, false},
+	{1, "riik.ee", 2, false},
+	{1, "lib.ee", 2, false},
+	{1, "med.ee", 2, false},
+	{1, "com.ee", 2, false},
+	{1, "pri.ee", 2, false},
+	{1, "aip.ee", 2, false},
+	{1, "org.ee", 2, false},
+	{1, "fie.ee", 2, false},
+	{1, "eg", 1, false},
+	{1, "com.eg", 2, false},
+	{1, "edu.eg", 2, false},
+	{1, "eun.eg", 2, false},
+	{1, "gov.eg", 2, false},
+	{1, "mil.eg", 2, false},
+	{1, "name.eg", 2, false},
+	{1, "net.eg", 2, false},
+	{1, "org.eg", 2, false},
+	{1, "sci.eg", 2, false},
+	{2, "er", 2, false},
+	{1, "es", 1, false},
+	{1, "com.es", 2, false},
+	{1, "nom.es", 2, false},
+	{1, "org.es", 2, false},
+	{1, "gob.es", 2, false},
+	{1, "edu.es", 2, false},
+	{1, "et", 1, false},
+	{1, "com.et", 2, false},
+	{1, "gov.et", 2, false},
+	{1, "org.et", 2, false},
+	{1, "edu.et", 2, false},
+	{1, "biz.et", 2, false},
+	{1, "name.et", 2, false},
+	{1, "info.et", 2, false},
+	{1, "net.et", 2, false},
+	{1, "eu", 1, false},
+	{1, "fi", 1, false},
+	{1, "aland.fi", 2, false},
+	{1, "fj", 1, false},
+	{1, "ac.fj", 2, false},
+	{1, "biz.fj", 2, false},
+	{1, "com.fj", 2, false},
+	{1, "gov.fj", 2, false},
+	{1, "info.fj", 2, false},
+	{1, "mil.fj", 2, false},
+	{1, "name.fj", 2, false},
+	{1, "net.fj", 2, false},
+	{1, "org.fj", 2, false},
+	{1, "pro.fj", 2, false},
+	{2, "fk", 2, false},
+	{1, "com.fm", 2, false},
+	{1, "edu.fm", 2, false},
+	{1, "net.fm", 2, false},
+	{1, "org.fm", 2, false},
+	{1, "fm", 1, false},
+	{1, "fo", 1, false},
+	{1, "fr", 1, false},
+	{1, "asso.fr", 2, false},
+	{1, "com.fr", 2, false},
+	{1, "gouv.fr", 2, false},
+	{1, "nom.fr", 2, false},
+	{1, "prd.fr", 2, false},
+	{1, "tm.fr", 2, false},
+	{1, "aeroport.fr", 2, false},
+	{1, "avocat.fr", 2, false},
+	{1, "avoues.fr", 2, false},
+	{1, "cci.fr", 2, false},
+	{1, "chambagri.fr", 2, false},
+	{1, "chirurgiens-dentistes.fr", 2, false},
+	{1, "experts-comptables.fr", 2, false},
+	{1, "geometre-expert.fr", 2, false},
+	{1, "greta.fr", 2, false},
+	{1, "huissier-justice.fr", 2, false},
+	{1, "medecin.fr", 2, false},
+	{1, "notaires.fr", 2, false},
+	{1, "pharmacien.fr", 2, false},
+	{1, "port.fr", 2, false},
+	{1, "veterinaire.fr", 2, false},
+	{1, "ga", 1, false},
+	{1, "gb", 1, false},
+	{1, "edu.gd", 2, false},
+	{1, "gov.gd", 2, false},
+	{1, "gd", 1, false},
+	{1, "ge", 1, false},
+	{1, "com.ge", 2, false},
+	{1, "edu.ge", 2, false},
+	{1, "gov.ge", 2, false},
+	{1, "org.ge", 2, false},
+	{1, "mil.ge", 2, false},
+	{1, "net.ge", 2, false},
+	{1, "pvt.ge", 2, false},
+	{1, "gf", 1, false},
+	{1, "gg", 1, false},
+	{1, "co.gg", 2, false},
+	{1, "net.gg", 2, false},
+	{1, "org.gg", 2, false},
+	{1, "gh", 1, false},
+	{1, "com.gh", 2, false},
+	{1, "edu.gh", 2, false},
+	{1, "gov.gh", 2, false},
+	{1, "org.gh", 2, false},
+	{1, "mil.gh", 2, false},
+	{1, "gi", 1, false},
+	{1, "com.gi", 2, false},
+	{1, "ltd.gi", 2, false},
+	{1, "gov.gi", 2, false},
+	{1, "mod.gi", 2, false},
+	{1, "edu.gi", 2, false},
+	{1, "org.gi", 2, false},
+	{1, "gl", 1, false},
+	{1, "co.gl", 2, false},
+	{1, "com.gl", 2, false},
+	{1, "edu.gl", 2, false},
+	{1, "net.gl", 2, false},
+	{1, "org.gl", 2, false},
+	{1, "gm", 1, false},
+	{1, "gn", 1, false},
+	{1, "ac.gn", 2, false},
+	{1, "com.gn", 2, false},
+	{1, "edu.gn", 2, false},
+	{1, "gov.gn", 2, false},
+	{1, "org.gn", 2, false},
+	{1, "net.gn", 2, false},
+	{1, "gov", 1, false},
+	{1, "gp", 1, false},
+	{1, "com.gp", 2, false},
+	{1, "net.gp", 2, false},
+	{1, "mobi.gp", 2, false},
+	{1, "edu.gp", 2, false},
+	{1, "org.gp", 2, false},
+	{1, "asso.gp", 2, false},
+	{1, "gq", 1, false},
+	{1, "gr", 1, false},
+	{1, "com.gr", 2, false},
+	{1, "edu.gr", 2, false},
+	{1, "net.gr", 2, false},
+	{1, "org.gr", 2, false},
+	{1, "gov.gr", 2, false},
+	{1, "gs", 1, false},
+	{1, "gt", 1, false},
+	{1, "com.gt", 2, false},
+	{1, "edu.gt", 2, false},
+	{1, "gob.gt", 2, false},
+	{1, "ind.gt", 2, false},
+	{1, "mil.gt", 2, false},
+	{1, "net.gt", 2, false},
+	{1, "org.gt", 2, false},
+	{1, "gu", 1, false},
+	{1, "com.gu", 2, false},
+	{1, "edu.gu", 2, false},
+	{1, "gov.gu", 2, false},
+	{1, "guam.gu", 2, false},
+	{1, "info.gu", 2, false},
+	{1, "net.gu", 2, false},
+	{1, "org.gu", 2, false},
+	{1, "web.gu", 2, false},
+	{1, "gw", 1, false},
+	{1, "gy", 1, false},
+	{1, "co.gy", 2, false},
+	{1, "com.gy", 2, false},
+	{1, "edu.gy", 2, false},
+	{1, "gov.gy", 2, false},
+	{1, "net.gy", 2, false},
+	{1, "org.gy", 2, false},
+	{1, "hk", 1, false},
+	{1, "com.hk", 2, false},
+	{1, "edu.hk", 2, false},
+	{1, "gov.hk", 2, false},
+	{1, "idv.hk", 2, false},
+	{1, "net.hk", 2, false},
+	{1, "org.hk", 2, false},
+	{1, "xn--55qx5d.hk", 2, false},
+	{1, "xn--wcvs22d.hk", 2, false},
+	{1, "xn--lcvr32d.hk", 2, false},
+	{1, "xn--mxtq1m.hk", 2, false},
+	{1, "xn--gmqw5a.hk", 2, false},
+	{1, "xn--ciqpn.hk", 2, false},
+	{1, "xn--gmq050i.hk", 2, false},
+	{1, "xn--zf0avx.hk", 2, false},
+	{1, "xn--io0a7i.hk", 2, false},
+	{1, "xn--mk0axi.hk", 2, false},
+	{1, "xn--od0alg.hk", 2, false},
+	{1, "xn--od0aq3b.hk", 2, false},
+	{1, "xn--tn0ag.hk", 2, false},
+	{1, "xn--uc0atv.hk", 2, false},
+	{1, "xn--uc0ay4a.hk", 2, false},
+	{1, "hm", 1, false},
+	{1, "hn", 1, false},
+	{1, "com.hn", 2, false},
+	{1, "edu.hn", 2, false},
+	{1, "org.hn", 2, false},
+	{1, "net.hn", 2, false},
+	{1, "mil.hn", 2, false},
+	{1, "gob.hn", 2, false},
+	{1, "hr", 1, false},
+	{1, "iz.hr", 2, false},
+	{1, "from.hr", 2, false},
+	{1, "name.hr", 2, false},
+	{1, "com.hr", 2, false},
+	{1, "ht", 1, false},
+	{1, "com.ht", 2, false},
+	{1, "shop.ht", 2, false},
+	{1, "firm.ht", 2, false},
+	{1, "info.ht", 2, false},
+	{1, "adult.ht", 2, false},
+	{1, "net.ht", 2, false},
+	{1, "pro.ht", 2, false},
+	{1, "org.ht", 2, false},
+	{1, "med.ht", 2, false},
+	{1, "art.ht", 2, false},
+	{1, "coop.ht", 2, false},
+	{1, "pol.ht", 2, false},
+	{1, "asso.ht", 2, false},
+	{1, "edu.ht", 2, false},
+	{1, "rel.ht", 2, false},
+	{1, "gouv.ht", 2, false},
+	{1, "perso.ht", 2, false},
+	{1, "hu", 1, false},
+	{1, "co.hu", 2, false},
+	{1, "info.hu", 2, false},
+	{1, "org.hu", 2, false},
+	{1, "priv.hu", 2, false},
+	{1, "sport.hu", 2, false},
+	{1, "tm.hu", 2, false},
+	{1, "2000.hu", 2, false},
+	{1, "agrar.hu", 2, false},
+	{1, "bolt.hu", 2, false},
+	{1, "casino.hu", 2, false},
+	{1, "city.hu", 2, false},
+	{1, "erotica.hu", 2, false},
+	{1, "erotika.hu", 2, false},
+	{1, "film.hu", 2, false},
+	{1, "forum.hu", 2, false},
+	{1, "games.hu", 2, false},
+	{1, "hotel.hu", 2, false},
+	{1, "ingatlan.hu", 2, false},
+	{1, "jogasz.hu", 2, false},
+	{1, "konyvelo.hu", 2, false},
+	{1, "lakas.hu", 2, false},
+	{1, "media.hu", 2, false},
+	{1, "news.hu", 2, false},
+	{1, "reklam.hu", 2, false},
+	{1, "sex.hu", 2, false},
+	{1, "shop.hu", 2, false},
+	{1, "suli.hu", 2, false},
+	{1, "szex.hu", 2, false},
+	{1, "tozsde.hu", 2, false},
+	{1, "utazas.hu", 2, false},
+	{1, "video.hu", 2, false},
+	{1, "id", 1, false},
+	{1, "ac.id", 2, false},
+	{1, "biz.id", 2, false},
+	{1, "co.id", 2, false},
+	{1, "desa.id", 2, false},
+	{1, "go.id", 2, false},
+	{1, "mil.id", 2, false},
+	{1, "my.id", 2, false},
+	{1, "net.id", 2, false},
+	{1, "or.id", 2, false},
+	{1, "ponpes.id", 2, false},
+	{1, "sch.id", 2, false},
+	{1, "web.id", 2, false},
+	{1, "ie", 1, false},
+	{1, "gov.ie", 2, false},
+	{1, "il", 1, false},
+	{1, "ac.il", 2, false},
+	{1, "co.il", 2, false},
+	{1, "gov.il", 2, false},
+	{1, "idf.il", 2, false},
+	{1, "k12.il", 2, false},
+	{1, "muni.il", 2, false},
+	{1, "net.il", 2, false},
+	{1, "org.il", 2, false},
+	{1, "im", 1, false},
+	{1, "ac.im", 2, false},
+	{1, "co.im", 2, false},
+	{1, "com.im", 2, false},
+	{1, "ltd.co.im", 3, false},
+	{1, "net.im", 2, false},
+	{1, "org.im", 2, false},
+	{1, "plc.co.im", 3, false},
+	{1, "tt.im", 2, false},
+	{1, "tv.im", 2, false},
+	{1, "in", 1, false},
+	{1, "co.in", 2, false},
+	{1, "firm.in", 2, false},
+	{1, "net.in", 2, false},
+	{1, "org.in", 2, false},
+	{1, "gen.in", 2, false},
+	{1, "ind.in", 2, false},
+	{1, "nic.in", 2, false},
+	{1, "ac.in", 2, false},
+	{1, "edu.in", 2, false},
+	{1, "res.in", 2, false},
+	{1, "gov.in", 2, false},
+	{1, "mil.in", 2, false},
+	{1, "info", 1, false},
+	{1, "int", 1, false},
+	{1, "eu.int", 2, false},
+	{1, "io", 1, false},
+	{1, "com.io", 2, false},
+	{1, "iq", 1, false},
+	{1, "gov.iq", 2, false},
+	{1, "edu.iq", 2, false},
+	{1, "mil.iq", 2, false},
+	{1, "com.iq", 2, false},
+	{1, "org.iq", 2, false},
+	{1, "net.iq", 2, false},
+	{1, "ir", 1, false},
+	{1, "ac.ir", 2, false},
+	{1, "co.ir", 2, false},
+	{1, "gov.ir", 2, false},
+	{1, "id.ir", 2, false},
+	{1, "net.ir", 2, false},
+	{1, "org.ir", 2, false},
+	{1, "sch.ir", 2, false},
+	{1, "xn--mgba3a4f16a.ir", 2, false},
+	{1, "xn--mgba3a4fra.ir", 2, false},
+	{1, "is", 1, false},
+	{1, "net.is", 2, false},
+	{1, "com.is", 2, false},
+	{1, "edu.is", 2, false},
+	{1, "gov.is", 2, false},
+	{1, "org.is", 2, false},
+	{1, "int.is", 2, false},
+	{1, "it", 1, false},
+	{1, "gov.it", 2, false},
+	{1, "edu.it", 2, false},
+	{1, "abr.it", 2, false},
+	{1, "abruzzo.it", 2, false},
+	{1, "aosta-valley.it", 2, false},
+	{1, "aostavalley.it", 2, false},
+	{1, "bas.it", 2, false},
+	{1, "basilicata.it", 2, false},
+	{1, "cal.it", 2, false},
+	{1, "calabria.it", 2, false},
+	{1, "cam.it", 2, false},
+	{1, "campania.it", 2, false},
+	{1, "emilia-romagna.it", 2, false},
+	{1, "emiliaromagna.it", 2, false},
+	{1, "emr.it", 2, false},
+	{1, "friuli-v-giulia.it", 2, false},
+	{1, "friuli-ve-giulia.it", 2, false},
+	{1, "friuli-vegiulia.it", 2, false},
+	{1, "friuli-venezia-giulia.it", 2, false},
+	{1, "friuli-veneziagiulia.it", 2, false},
+	{1, "friuli-vgiulia.it", 2, false},
+	{1, "friuliv-giulia.it", 2, false},
+	{1, "friulive-giulia.it", 2, false},
+	{1, "friulivegiulia.it", 2, false},
+	{1, "friulivenezia-giulia.it", 2, false},
+	{1, "friuliveneziagiulia.it", 2, false},
+	{1, "friulivgiulia.it", 2, false},
+	{1, "fvg.it", 2, false},
+	{1, "laz.it", 2, false},
+	{1, "lazio.it", 2, false},
+	{1, "lig.it", 2, false},
+	{1, "liguria.it", 2, false},
+	{1, "lom.it", 2, false},
+	{1, "lombardia.it", 2, false},
+	{1, "lombardy.it", 2, false},
+	{1, "lucania.it", 2, false},
+	{1, "mar.it", 2, false},
+	{1, "marche.it", 2, false},
+	{1, "mol.it", 2, false},
+	{1, "molise.it", 2, false},
+	{1, "piedmont.it", 2, false},
+	{1, "piemonte.it", 2, false},
+	{1, "pmn.it", 2, false},
+	{1, "pug.it", 2, false},
+	{1, "puglia.it", 2, false},
+	{1, "sar.it", 2, false},
+	{1, "sardegna.it", 2, false},
+	{1, "sardinia.it", 2, false},
+	{1, "sic.it", 2, false},
+	{1, "sicilia.it", 2, false},
+	{1, "sicily.it", 2, false},
+	{1, "taa.it", 2, false},
+	{1, "tos.it", 2, false},
+	{1, "toscana.it", 2, false},
+	{1, "trentin-sud-tirol.it", 2, false},
+	{1, "xn--trentin-sd-tirol-rzb.it", 2, false},
+	{1, "trentin-sudtirol.it", 2, false},
+	{1, "xn--trentin-sdtirol-7vb.it", 2, false},
+	{1, "trentin-sued-tirol.it", 2, false},
+	{1, "trentin-suedtirol.it", 2, false},
+	{1, "trentino-a-adige.it", 2, false},
+	{1, "trentino-aadige.it", 2, false},
+	{1, "trentino-alto-adige.it", 2, false},
+	{1, "trentino-altoadige.it", 2, false},
+	{1, "trentino-s-tirol.it", 2, false},
+	{1, "trentino-stirol.it", 2, false},
+	{1, "trentino-sud-tirol.it", 2, false},
+	{1, "xn--trentino-sd-tirol-c3b.it", 2, false},
+	{1, "trentino-sudtirol.it", 2, false},
+	{1, "xn--trentino-sdtirol-szb.it", 2, false},
+	{1, "trentino-sued-tirol.it", 2, false},
+	{1, "trentino-suedtirol.it", 2, false},
+	{1, "trentino.it", 2, false},
+	{1, "trentinoa-adige.it", 2, false},
+	{1, "trentinoaadige.it", 2, false},
+	{1, "trentinoalto-adige.it", 2, false},
+	{1, "trentinoaltoadige.it", 2, false},
+	{1, "trentinos-tirol.it", 2, false},
+	{1, "trentinostirol.it", 2, false},
+	{1, "trentinosud-tirol.it", 2, false},
+	{1, "xn--trentinosd-tirol-rzb.it", 2, false},
+	{1, "trentinosudtirol.it", 2, false},
+	{1, "xn--trentinosdtirol-7vb.it", 2, false},
+	{1, "trentinosued-tirol.it", 2, false},
+	{1, "trentinosuedtirol.it", 2, false},
+	{1, "trentinsud-tirol.it", 2, false},
+	{1, "xn--trentinsd-tirol-6vb.it", 2, false},
+	{1, "trentinsudtirol.it", 2, false},
+	{1, "xn--trentinsdtirol-nsb.it", 2, false},
+	{1, "trentinsued-tirol.it", 2, false},
+	{1, "trentinsuedtirol.it", 2, false},
+	{1, "tuscany.it", 2, false},
+	{1, "umb.it", 2, false},
+	{1, "umbria.it", 2, false},
+	{1, "val-d-aosta.it", 2, false},
+	{1, "val-daosta.it", 2, false},
+	{1, "vald-aosta.it", 2, false},
+	{1, "valdaosta.it", 2, false},
+	{1, "valle-aosta.it", 2, false},
+	{1, "valle-d-aosta.it", 2, false},
+	{1, "valle-daosta.it", 2, false},
+	{1, "valleaosta.it", 2, false},
+	{1, "valled-aosta.it", 2, false},
+	{1, "valledaosta.it", 2, false},
+	{1, "vallee-aoste.it", 2, false},
+	{1, "xn--valle-aoste-ebb.it", 2, false},
+	{1, "vallee-d-aoste.it", 2, false},
+	{1, "xn--valle-d-aoste-ehb.it", 2, false},
+	{1, "valleeaoste.it", 2, false},
+	{1, "xn--valleaoste-e7a.it", 2, false},
+	{1, "valleedaoste.it", 2, false},
+	{1, "xn--valledaoste-ebb.it", 2, false},
+	{1, "vao.it", 2, false},
+	{1, "vda.it", 2, false},
+	{1, "ven.it", 2, false},
+	{1, "veneto.it", 2, false},
+	{1, "ag.it", 2, false},
+	{1, "agrigento.it", 2, false},
+	{1, "al.it", 2, false},
+	{1, "alessandria.it", 2, false},
+	{1, "alto-adige.it", 2, false},
+	{1, "altoadige.it", 2, false},
+	{1, "an.it", 2, false},
+	{1, "ancona.it", 2, false},
+	{1, "andria-barletta-trani.it", 2, false},
+	{1, "andria-trani-barletta.it", 2, false},
+	{1, "andriabarlettatrani.it", 2, false},
+	{1, "andriatranibarletta.it", 2, false},
+	{1, "ao.it", 2, false},
+	{1, "aosta.it", 2, false},
+	{1, "aoste.it", 2, false},
+	{1, "ap.it", 2, false},
+	{1, "aq.it", 2, false},
+	{1, "aquila.it", 2, false},
+	{1, "ar.it", 2, false},
+	{1, "arezzo.it", 2, false},
+	{1, "ascoli-piceno.it", 2, false},
+	{1, "ascolipiceno.it", 2, false},
+	{1, "asti.it", 2, false},
+	{1, "at.it", 2, false},
+	{1, "av.it", 2, false},
+	{1, "avellino.it", 2, false},
+	{1, "ba.it", 2, false},
+	{1, "balsan-sudtirol.it", 2, false},
+	{1, "xn--balsan-sdtirol-nsb.it", 2, false},
+	{1, "balsan-suedtirol.it", 2, false},
+	{1, "balsan.it", 2, false},
+	{1, "bari.it", 2, false},
+	{1, "barletta-trani-andria.it", 2, false},
+	{1, "barlettatraniandria.it", 2, false},
+	{1, "belluno.it", 2, false},
+	{1, "benevento.it", 2, false},
+	{1, "bergamo.it", 2, false},
+	{1, "bg.it", 2, false},
+	{1, "bi.it", 2, false},
+	{1, "biella.it", 2, false},
+	{1, "bl.it", 2, false},
+	{1, "bn.it", 2, false},
+	{1, "bo.it", 2, false},
+	{1, "bologna.it", 2, false},
+	{1, "bolzano-altoadige.it", 2, false},
+	{1, "bolzano.it", 2, false},
+	{1, "bozen-sudtirol.it", 2, false},
+	{1, "xn--bozen-sdtirol-2ob.it", 2, false},
+	{1, "bozen-suedtirol.it", 2, false},
+	{1, "bozen.it", 2, false},
+	{1, "br.it", 2, false},
+	{1, "brescia.it", 2, false},
+	{1, "brindisi.it", 2, false},
+	{1, "bs.it", 2, false},
+	{1, "bt.it", 2, false},
+	{1, "bulsan-sudtirol.it", 2, false},
+	{1, "xn--bulsan-sdtirol-nsb.it", 2, false},
+	{1, "bulsan-suedtirol.it", 2, false},
+	{1, "bulsan.it", 2, false},
+	{1, "bz.it", 2, false},
+	{1, "ca.it", 2, false},
+	{1, "cagliari.it", 2, false},
+	{1, "caltanissetta.it", 2, false},
+	{1, "campidano-medio.it", 2, false},
+	{1, "campidanomedio.it", 2, false},
+	{1, "campobasso.it", 2, false},
+	{1, "carbonia-iglesias.it", 2, false},
+	{1, "carboniaiglesias.it", 2, false},
+	{1, "carrara-massa.it", 2, false},
+	{1, "carraramassa.it", 2, false},
+	{1, "caserta.it", 2, false},
+	{1, "catania.it", 2, false},
+	{1, "catanzaro.it", 2, false},
+	{1, "cb.it", 2, false},
+	{1, "ce.it", 2, false},
+	{1, "cesena-forli.it", 2, false},
+	{1, "xn--cesena-forl-mcb.it", 2, false},
+	{1, "cesenaforli.it", 2, false},
+	{1, "xn--cesenaforl-i8a.it", 2, false},
+	{1, "ch.it", 2, false},
+	{1, "chieti.it", 2, false},
+	{1, "ci.it", 2, false},
+	{1, "cl.it", 2, false},
+	{1, "cn.it", 2, false},
+	{1, "co.it", 2, false},
+	{1, "como.it", 2, false},
+	{1, "cosenza.it", 2, false},
+	{1, "cr.it", 2, false},
+	{1, "cremona.it", 2, false},
+	{1, "crotone.it", 2, false},
+	{1, "cs.it", 2, false},
+	{1, "ct.it", 2, false},
+	{1, "cuneo.it", 2, false},
+	{1, "cz.it", 2, false},
+	{1, "dell-ogliastra.it", 2, false},
+	{1, "dellogliastra.it", 2, false},
+	{1, "en.it", 2, false},
+	{1, "enna.it", 2, false},
+	{1, "fc.it", 2, false},
+	{1, "fe.it", 2, false},
+	{1, "fermo.it", 2, false},
+	{1, "ferrara.it", 2, false},
+	{1, "fg.it", 2, false},
+	{1, "fi.it", 2, false},
+	{1, "firenze.it", 2, false},
+	{1, "florence.it", 2, false},
+	{1, "fm.it", 2, false},
+	{1, "foggia.it", 2, false},
+	{1, "forli-cesena.it", 2, false},
+	{1, "xn--forl-cesena-fcb.it", 2, false},
+	{1, "forlicesena.it", 2, false},
+	{1, "xn--forlcesena-c8a.it", 2, false},
+	{1, "fr.it", 2, false},
+	{1, "frosinone.it", 2, false},
+	{1, "ge.it", 2, false},
+	{1, "genoa.it", 2, false},
+	{1, "genova.it", 2, false},
+	{1, "go.it", 2, false},
+	{1, "gorizia.it", 2, false},
+	{1, "gr.it", 2, false},
+	{1, "grosseto.it", 2, false},
+	{1, "iglesias-carbonia.it", 2, false},
+	{1, "iglesiascarbonia.it", 2, false},
+	{1, "im.it", 2, false},
+	{1, "imperia.it", 2, false},
+	{1, "is.it", 2, false},
+	{1, "isernia.it", 2, false},
+	{1, "kr.it", 2, false},
+	{1, "la-spezia.it", 2, false},
+	{1, "laquila.it", 2, false},
+	{1, "laspezia.it", 2, false},
+	{1, "latina.it", 2, false},
+	{1, "lc.it", 2, false},
+	{1, "le.it", 2, false},
+	{1, "lecce.it", 2, false},
+	{1, "lecco.it", 2, false},
+	{1, "li.it", 2, false},
+	{1, "livorno.it", 2, false},
+	{1, "lo.it", 2, false},
+	{1, "lodi.it", 2, false},
+	{1, "lt.it", 2, false},
+	{1, "lu.it", 2, false},
+	{1, "lucca.it", 2, false},
+	{1, "macerata.it", 2, false},
+	{1, "mantova.it", 2, false},
+	{1, "massa-carrara.it", 2, false},
+	{1, "massacarrara.it", 2, false},
+	{1, "matera.it", 2, false},
+	{1, "mb.it", 2, false},
+	{1, "mc.it", 2, false},
+	{1, "me.it", 2, false},
+	{1, "medio-campidano.it", 2, false},
+	{1, "mediocampidano.it", 2, false},
+	{1, "messina.it", 2, false},
+	{1, "mi.it", 2, false},
+	{1, "milan.it", 2, false},
+	{1, "milano.it", 2, false},
+	{1, "mn.it", 2, false},
+	{1, "mo.it", 2, false},
+	{1, "modena.it", 2, false},
+	{1, "monza-brianza.it", 2, false},
+	{1, "monza-e-della-brianza.it", 2, false},
+	{1, "monza.it", 2, false},
+	{1, "monzabrianza.it", 2, false},
+	{1, "monzaebrianza.it", 2, false},
+	{1, "monzaedellabrianza.it", 2, false},
+	{1, "ms.it", 2, false},
+	{1, "mt.it", 2, false},
+	{1, "na.it", 2, false},
+	{1, "naples.it", 2, false},
+	{1, "napoli.it", 2, false},
+	{1, "no.it", 2, false},
+	{1, "novara.it", 2, false},
+	{1, "nu.it", 2, false},
+	{1, "nuoro.it", 2, false},
+	{1, "og.it", 2, false},
+	{1, "ogliastra.it", 2, false},
+	{1, "olbia-tempio.it", 2, false},
+	{1, "olbiatempio.it", 2, false},
+	{1, "or.it", 2, false},
+	{1, "oristano.it", 2, false},
+	{1, "ot.it", 2, false},
+	{1, "pa.it", 2, false},
+	{1, "padova.it", 2, false},
+	{1, "padua.it", 2, false},
+	{1, "palermo.it", 2, false},
+	{1, "parma.it", 2, false},
+	{1, "pavia.it", 2, false},
+	{1, "pc.it", 2, false},
+	{1, "pd.it", 2, false},
+	{1, "pe.it", 2, false},
+	{1, "perugia.it", 2, false},
+	{1, "pesaro-urbino.it", 2, false},
+	{1, "pesarourbino.it", 2, false},
+	{1, "pescara.it", 2, false},
+	{1, "pg.it", 2, false},
+	{1, "pi.it", 2, false},
+	{1, "piacenza.it", 2, false},
+	{1, "pisa.it", 2, false},
+	{1, "pistoia.it", 2, false},
+	{1, "pn.it", 2, false},
+	{1, "po.it", 2, false},
+	{1, "pordenone.it", 2, false},
+	{1, "potenza.it", 2, false},
+	{1, "pr.it", 2, false},
+	{1, "prato.it", 2, false},
+	{1, "pt.it", 2, false},
+	{1, "pu.it", 2, false},
+	{1, "pv.it", 2, false},
+	{1, "pz.it", 2, false},
+	{1, "ra.it", 2, false},
+	{1, "ragusa.it", 2, false},
+	{1, "ravenna.it", 2, false},
+	{1, "rc.it", 2, false},
+	{1, "re.it", 2, false},
+	{1, "reggio-calabria.it", 2, false},
+	{1, "reggio-emilia.it", 2, false},
+	{1, "reggiocalabria.it", 2, false},
+	{1, "reggioemilia.it", 2, false},
+	{1, "rg.it", 2, false},
+	{1, "ri.it", 2, false},
+	{1, "rieti.it", 2, false},
+	{1, "rimini.it", 2, false},
+	{1, "rm.it", 2, false},
+	{1, "rn.it", 2, false},
+	{1, "ro.it", 2, false},
+	{1, "roma.it", 2, false},
+	{1, "rome.it", 2, false},
+	{1, "rovigo.it", 2, false},
+	{1, "sa.it", 2, false},
+	{1, "salerno.it", 2, false},
+	{1, "sassari.it", 2, false},
+	{1, "savona.it", 2, false},
+	{1, "si.it", 2, false},
+	{1, "siena.it", 2, false},
+	{1, "siracusa.it", 2, false},
+	{1, "so.it", 2, false},
+	{1, "sondrio.it", 2, false},
+	{1, "sp.it", 2, false},
+	{1, "sr.it", 2, false},
+	{1, "ss.it", 2, false},
+	{1, "suedtirol.it", 2, false},
+	{1, "xn--sdtirol-n2a.it", 2, false},
+	{1, "sv.it", 2, false},
+	{1, "ta.it", 2, false},
+	{1, "taranto.it", 2, false},
+	{1, "te.it", 2, false},
+	{1, "tempio-olbia.it", 2, false},
+	{1, "tempioolbia.it", 2, false},
+	{1, "teramo.it", 2, false},
+	{1, "terni.it", 2, false},
+	{1, "tn.it", 2, false},
+	{1, "to.it", 2, false},
+	{1, "torino.it", 2, false},
+	{1, "tp.it", 2, false},
+	{1, "tr.it", 2, false},
+	{1, "trani-andria-barletta.it", 2, false},
+	{1, "trani-barletta-andria.it", 2, false},
+	{1, "traniandriabarletta.it", 2, false},
+	{1, "tranibarlettaandria.it", 2, false},
+	{1, "trapani.it", 2, false},
+	{1, "trento.it", 2, false},
+	{1, "treviso.it", 2, false},
+	{1, "trieste.it", 2, false},
+	{1, "ts.it", 2, false},
+	{1, "turin.it", 2, false},
+	{1, "tv.it", 2, false},
+	{1, "ud.it", 2, false},
+	{1, "udine.it", 2, false},
+	{1, "urbino-pesaro.it", 2, false},
+	{1, "urbinopesaro.it", 2, false},
+	{1, "va.it", 2, false},
+	{1, "varese.it", 2, false},
+	{1, "vb.it", 2, false},
+	{1, "vc.it", 2, false},
+	{1, "ve.it", 2, false},
+	{1, "venezia.it", 2, false},
+	{1, "venice.it", 2, false},
+	{1, "verbania.it", 2, false},
+	{1, "vercelli.it", 2, false},
+	{1, "verona.it", 2, false},
+	{1, "vi.it", 2, false},
+	{1, "vibo-valentia.it", 2, false},
+	{1, "vibovalentia.it", 2, false},
+	{1, "vicenza.it", 2, false},
+	{1, "viterbo.it", 2, false},
+	{1, "vr.it", 2, false},
+	{1, "vs.it", 2, false},
+	{1, "vt.it", 2, false},
+	{1, "vv.it", 2, false},
+	{1, "je", 1, false},
+	{1, "co.je", 2, false},
+	{1, "net.je", 2, false},
+	{1, "org.je", 2, false},
+	{2, "jm", 2, false},
+	{1, "jo", 1, false},
+	{1, "com.jo", 2, false},
+	{1, "org.jo", 2, false},
+	{1, "net.jo", 2, false},
+	{1, "edu.jo", 2, false},
+	{1, "sch.jo", 2, false},
+	{1, "gov.jo", 2, false},
+	{1, "mil.jo", 2, false},
+	{1, "name.jo", 2, false},
+	{1, "jobs", 1, false},
+	{1, "jp", 1, false},
+	{1, "ac.jp", 2, false},
+	{1, "ad.jp", 2, false},
+	{1, "co.jp", 2, false},
+	{1, "ed.jp", 2, false},
+	{1, "go.jp", 2, false},
+	{1, "gr.jp", 2, false},
+	{1, "lg.jp", 2, false},
+	{1, "ne.jp", 2, false},
+	{1, "or.jp", 2, false},
+	{1, "aichi.jp", 2, false},
+	{1, "akita.jp", 2, false},
+	{1, "aomori.jp", 2, false},
+	{1, "chiba.jp", 2, false},
+	{1, "ehime.jp", 2, false},
+	{1, "fukui.jp", 2, false},
+	{1, "fukuoka.jp", 2, false},
+	{1, "fukushima.jp", 2, false},
+	{1, "gifu.jp", 2, false},
+	{1, "gunma.jp", 2, false},
+	{1, "hiroshima.jp", 2, false},
+	{1, "hokkaido.jp", 2, false},
+	{1, "hyogo.jp", 2, false},
+	{1, "ibaraki.jp", 2, false},
+	{1, "ishikawa.jp", 2, false},
+	{1, "iwate.jp", 2, false},
+	{1, "kagawa.jp", 2, false},
+	{1, "kagoshima.jp", 2, false},
+	{1, "kanagawa.jp", 2, false},
+	{1, "kochi.jp", 2, false},
+	{1, "kumamoto.jp", 2, false},
+	{1, "kyoto.jp", 2, false},
+	{1, "mie.jp", 2, false},
+	{1, "miyagi.jp", 2, false},
+	{1, "miyazaki.jp", 2, false},
+	{1, "nagano.jp", 2, false},
+	{1, "nagasaki.jp", 2, false},
+	{1, "nara.jp", 2, false},
+	{1, "niigata.jp", 2, false},
+	{1, "oita.jp", 2, false},
+	{1, "okayama.jp", 2, false},
+	{1, "okinawa.jp", 2, false},
+	{1, "osaka.jp", 2, false},
+	{1, "saga.jp", 2, false},
+	{1, "saitama.jp", 2, false},
+	{1, "shiga.jp", 2, false},
+	{1, "shimane.jp", 2, false},
+	{1, "shizuoka.jp", 2, false},
+	{1, "tochigi.jp", 2, false},
+	{1, "tokushima.jp", 2, false},
+	{1, "tokyo.jp", 2, false},
+	{1, "tottori.jp", 2, false},
+	{1, "toyama.jp", 2, false},
+	{1, "wakayama.jp", 2, false},
+	{1, "yamagata.jp", 2, false},
+	{1, "yamaguchi.jp", 2, false},
+	{1, "yamanashi.jp", 2, false},
+	{1, "xn--4pvxs.jp", 2, false},
+	{1, "xn--vgu402c.jp", 2, false},
+	{1, "xn--c3s14m.jp", 2, false},
+	{1, "xn--f6qx53a.jp", 2, false},
+	{1, "xn--8pvr4u.jp", 2, false},
+	{1, "xn--uist22h.jp", 2, false},
+	{1, "xn--djrs72d6uy.jp", 2, false},
+	{1, "xn--mkru45i.jp", 2, false},
+	{1, "xn--0trq7p7nn.jp", 2, false},
+	{1, "xn--8ltr62k.jp", 2, false},
+	{1, "xn--2m4a15e.jp", 2, false},
+	{1, "xn--efvn9s.jp", 2, false},
+	{1, "xn--32vp30h.jp", 2, false},
+	{1, "xn--4it797k.jp", 2, false},
+	{1, "xn--1lqs71d.jp", 2, false},
+	{1, "xn--5rtp49c.jp", 2, false},
+	{1, "xn--5js045d.jp", 2, false},
+	{1, "xn--ehqz56n.jp", 2, false},
+	{1, "xn--1lqs03n.jp", 2, false},
+	{1, "xn--qqqt11m.jp", 2, false},
+	{1, "xn--kbrq7o.jp", 2, false},
+	{1, "xn--pssu33l.jp", 2, false},
+	{1, "xn--ntsq17g.jp", 2, false},
+	{1, "xn--uisz3g.jp", 2, false},
+	{1, "xn--6btw5a.jp", 2, false},
+	{1, "xn--1ctwo.jp", 2, false},
+	{1, "xn--6orx2r.jp", 2, false},
+	{1, "xn--rht61e.jp", 2, false},
+	{1, "xn--rht27z.jp", 2, false},
+	{1, "xn--djty4k.jp", 2, false},
+	{1, "xn--nit225k.jp", 2, false},
+	{1, "xn--rht3d.jp", 2, false},
+	{1, "xn--klty5x.jp", 2, false},
+	{1, "xn--kltx9a.jp", 2, false},
+	{1, "xn--kltp7d.jp", 2, false},
+	{1, "xn--uuwu58a.jp", 2, false},
+	{1, "xn--zbx025d.jp", 2, false},
+	{1, "xn--ntso0iqx3a.jp", 2, false},
+	{1, "xn--elqq16h.jp", 2, false},
+	{1, "xn--4it168d.jp", 2, false},
+	{1, "xn--klt787d.jp", 2, false},
+	{1, "xn--rny31h.jp", 2, false},
+	{1, "xn--7t0a264c.jp", 2, false},
+	{1, "xn--5rtq34k.jp", 2, false},
+	{1, "xn--k7yn95e.jp", 2, false},
+	{1, "xn--tor131o.jp", 2, false},
+	{1, "xn--d5qv7z876c.jp", 2, false},
+	{2, "kawasaki.jp", 3, false},
+	{2, "kitakyushu.jp", 3, false},
+	{2, "kobe.jp", 3, false},
+	{2, "nagoya.jp", 3, false},
+	{2, "sapporo.jp", 3, false},
+	{2, "sendai.jp", 3, false},
+	{2, "yokohama.jp", 3, false},
+	{3, "city.kawasaki.jp", 3, false},
+	{3, "city.kitakyushu.jp", 3, false},
+	{3, "city.kobe.jp", 3, false},
+	{3, "city.nagoya.jp", 3, false},
+	{3, "city.sapporo.jp", 3, false},
+	{3, "city.sendai.jp", 3, false},
+	{3, "city.yokohama.jp", 3, false},
+	{1, "aisai.aichi.jp", 3, false},
+	{1, "ama.aichi.jp", 3, false},
+	{1, "anjo.aichi.jp", 3, false},
+	{1, "asuke.aichi.jp", 3, false},
+	{1, "chiryu.aichi.jp", 3, false},
+	{1, "chita.aichi.jp", 3, false},
+	{1, "fuso.aichi.jp", 3, false},
+	{1, "gamagori.aichi.jp", 3, false},
+	{1, "handa.aichi.jp", 3, false},
+	{1, "hazu.aichi.jp", 3, false},
+	{1, "hekinan.aichi.jp", 3, false},
+	{1, "higashiura.aichi.jp", 3, false},
+	{1, "ichinomiya.aichi.jp", 3, false},
+	{1, "inazawa.aichi.jp", 3, false},
+	{1, "inuyama.aichi.jp", 3, false},
+	{1, "isshiki.aichi.jp", 3, false},
+	{1, "iwakura.aichi.jp", 3, false},
+	{1, "kanie.aichi.jp", 3, false},
+	{1, "kariya.aichi.jp", 3, false},
+	{1, "kasugai.aichi.jp", 3, false},
+	{1, "kira.aichi.jp", 3, false},
+	{1, "kiyosu.aichi.jp", 3, false},
+	{1, "komaki.aichi.jp", 3, false},
+	{1, "konan.aichi.jp", 3, false},
+	{1, "kota.aichi.jp", 3, false},
+	{1, "mihama.aichi.jp", 3, false},
+	{1, "miyoshi.aichi.jp", 3, false},
+	{1, "nishio.aichi.jp", 3, false},
+	{1, "nisshin.aichi.jp", 3, false},
+	{1, "obu.aichi.jp", 3, false},
+	{1, "oguchi.aichi.jp", 3, false},
+	{1, "oharu.aichi.jp", 3, false},
+	{1, "okazaki.aichi.jp", 3, false},
+	{1, "owariasahi.aichi.jp", 3, false},
+	{1, "seto.aichi.jp", 3, false},
+	{1, "shikatsu.aichi.jp", 3, false},
+	{1, "shinshiro.aichi.jp", 3, false},
+	{1, "shitara.aichi.jp", 3, false},
+	{1, "tahara.aichi.jp", 3, false},
+	{1, "takahama.aichi.jp", 3, false},
+	{1, "tobishima.aichi.jp", 3, false},
+	{1, "toei.aichi.jp", 3, false},
+	{1, "togo.aichi.jp", 3, false},
+	{1, "tokai.aichi.jp", 3, false},
+	{1, "tokoname.aichi.jp", 3, false},
+	{1, "toyoake.aichi.jp", 3, false},
+	{1, "toyohashi.aichi.jp", 3, false},
+	{1, "toyokawa.aichi.jp", 3, false},
+	{1, "toyone.aichi.jp", 3, false},
+	{1, "toyota.aichi.jp", 3, false},
+	{1, "tsushima.aichi.jp", 3, false},
+	{1, "yatomi.aichi.jp", 3, false},
+	{1, "akita.akita.jp", 3, false},
+	{1, "daisen.akita.jp", 3, false},
+	{1, "fujisato.akita.jp", 3, false},
+	{1, "gojome.akita.jp", 3, false},
+	{1, "hachirogata.akita.jp", 3, false},
+	{1, "happou.akita.jp", 3, false},
+	{1, "higashinaruse.akita.jp", 3, false},
+	{1, "honjo.akita.jp", 3, false},
+	{1, "honjyo.akita.jp", 3, false},
+	{1, "ikawa.akita.jp", 3, false},
+	{1, "kamikoani.akita.jp", 3, false},
+	{1, "kamioka.akita.jp", 3, false},
+	{1, "katagami.akita.jp", 3, false},
+	{1, "kazuno.akita.jp", 3, false},
+	{1, "kitaakita.akita.jp", 3, false},
+	{1, "kosaka.akita.jp", 3, false},
+	{1, "kyowa.akita.jp", 3, false},
+	{1, "misato.akita.jp", 3, false},
+	{1, "mitane.akita.jp", 3, false},
+	{1, "moriyoshi.akita.jp", 3, false},
+	{1, "nikaho.akita.jp", 3, false},
+	{1, "noshiro.akita.jp", 3, false},
+	{1, "odate.akita.jp", 3, false},
+	{1, "oga.akita.jp", 3, false},
+	{1, "ogata.akita.jp", 3, false},
+	{1, "semboku.akita.jp", 3, false},
+	{1, "yokote.akita.jp", 3, false},
+	{1, "yurihonjo.akita.jp", 3, false},
+	{1, "aomori.aomori.jp", 3, false},
+	{1, "gonohe.aomori.jp", 3, false},
+	{1, "hachinohe.aomori.jp", 3, false},
+	{1, "hashikami.aomori.jp", 3, false},
+	{1, "hiranai.aomori.jp", 3, false},
+	{1, "hirosaki.aomori.jp", 3, false},
+	{1, "itayanagi.aomori.jp", 3, false},
+	{1, "kuroishi.aomori.jp", 3, false},
+	{1, "misawa.aomori.jp", 3, false},
+	{1, "mutsu.aomori.jp", 3, false},
+	{1, "nakadomari.aomori.jp", 3, false},
+	{1, "noheji.aomori.jp", 3, false},
+	{1, "oirase.aomori.jp", 3, false},
+	{1, "owani.aomori.jp", 3, false},
+	{1, "rokunohe.aomori.jp", 3, false},
+	{1, "sannohe.aomori.jp", 3, false},
+	{1, "shichinohe.aomori.jp", 3, false},
+	{1, "shingo.aomori.jp", 3, false},
+	{1, "takko.aomori.jp", 3, false},
+	{1, "towada.aomori.jp", 3, false},
+	{1, "tsugaru.aomori.jp", 3, false},
+	{1, "tsuruta.aomori.jp", 3, false},
+	{1, "abiko.chiba.jp", 3, false},
+	{1, "asahi.chiba.jp", 3, false},
+	{1, "chonan.chiba.jp", 3, false},
+	{1, "chosei.chiba.jp", 3, false},
+	{1, "choshi.chiba.jp", 3, false},
+	{1, "chuo.chiba.jp", 3, false},
+	{1, "funabashi.chiba.jp", 3, false},
+	{1, "futtsu.chiba.jp", 3, false},
+	{1, "hanamigawa.chiba.jp", 3, false},
+	{1, "ichihara.chiba.jp", 3, false},
+	{1, "ichikawa.chiba.jp", 3, false},
+	{1, "ichinomiya.chiba.jp", 3, false},
+	{1, "inzai.chiba.jp", 3, false},
+	{1, "isumi.chiba.jp", 3, false},
+	{1, "kamagaya.chiba.jp", 3, false},
+	{1, "kamogawa.chiba.jp", 3, false},
+	{1, "kashiwa.chiba.jp", 3, false},
+	{1, "katori.chiba.jp", 3, false},
+	{1, "katsuura.chiba.jp", 3, false},
+	{1, "kimitsu.chiba.jp", 3, false},
+	{1, "kisarazu.chiba.jp", 3, false},
+	{1, "kozaki.chiba.jp", 3, false},
+	{1, "kujukuri.chiba.jp", 3, false},
+	{1, "kyonan.chiba.jp", 3, false},
+	{1, "matsudo.chiba.jp", 3, false},
+	{1, "midori.chiba.jp", 3, false},
+	{1, "mihama.chiba.jp", 3, false},
+	{1, "minamiboso.chiba.jp", 3, false},
+	{1, "mobara.chiba.jp", 3, false},
+	{1, "mutsuzawa.chiba.jp", 3, false},
+	{1, "nagara.chiba.jp", 3, false},
+	{1, "nagareyama.chiba.jp", 3, false},
+	{1, "narashino.chiba.jp", 3, false},
+	{1, "narita.chiba.jp", 3, false},
+	{1, "noda.chiba.jp", 3, false},
+	{1, "oamishirasato.chiba.jp", 3, false},
+	{1, "omigawa.chiba.jp", 3, false},
+	{1, "onjuku.chiba.jp", 3, false},
+	{1, "otaki.chiba.jp", 3, false},
+	{1, "sakae.chiba.jp", 3, false},
+	{1, "sakura.chiba.jp", 3, false},
+	{1, "shimofusa.chiba.jp", 3, false},
+	{1, "shirako.chiba.jp", 3, false},
+	{1, "shiroi.chiba.jp", 3, false},
+	{1, "shisui.chiba.jp", 3, false},
+	{1, "sodegaura.chiba.jp", 3, false},
+	{1, "sosa.chiba.jp", 3, false},
+	{1, "tako.chiba.jp", 3, false},
+	{1, "tateyama.chiba.jp", 3, false},
+	{1, "togane.chiba.jp", 3, false},
+	{1, "tohnosho.chiba.jp", 3, false},
+	{1, "tomisato.chiba.jp", 3, false},
+	{1, "urayasu.chiba.jp", 3, false},
+	{1, "yachimata.chiba.jp", 3, false},
+	{1, "yachiyo.chiba.jp", 3, false},
+	{1, "yokaichiba.chiba.jp", 3, false},
+	{1, "yokoshibahikari.chiba.jp", 3, false},
+	{1, "yotsukaido.chiba.jp", 3, false},
+	{1, "ainan.ehime.jp", 3, false},
+	{1, "honai.ehime.jp", 3, false},
+	{1, "ikata.ehime.jp", 3, false},
+	{1, "imabari.ehime.jp", 3, false},
+	{1, "iyo.ehime.jp", 3, false},
+	{1, "kamijima.ehime.jp", 3, false},
+	{1, "kihoku.ehime.jp", 3, false},
+	{1, "kumakogen.ehime.jp", 3, false},
+	{1, "masaki.ehime.jp", 3, false},
+	{1, "matsuno.ehime.jp", 3, false},
+	{1, "matsuyama.ehime.jp", 3, false},
+	{1, "namikata.ehime.jp", 3, false},
+	{1, "niihama.ehime.jp", 3, false},
+	{1, "ozu.ehime.jp", 3, false},
+	{1, "saijo.ehime.jp", 3, false},
+	{1, "seiyo.ehime.jp", 3, false},
+	{1, "shikokuchuo.ehime.jp", 3, false},
+	{1, "tobe.ehime.jp", 3, false},
+	{1, "toon.ehime.jp", 3, false},
+	{1, "uchiko.ehime.jp", 3, false},
+	{1, "uwajima.ehime.jp", 3, false},
+	{1, "yawatahama.ehime.jp", 3, false},
+	{1, "echizen.fukui.jp", 3, false},
+	{1, "eiheiji.fukui.jp", 3, false},
+	{1, "fukui.fukui.jp", 3, false},
+	{1, "ikeda.fukui.jp", 3, false},
+	{1, "katsuyama.fukui.jp", 3, false},
+	{1, "mihama.fukui.jp", 3, false},
+	{1, "minamiechizen.fukui.jp", 3, false},
+	{1, "obama.fukui.jp", 3, false},
+	{1, "ohi.fukui.jp", 3, false},
+	{1, "ono.fukui.jp", 3, false},
+	{1, "sabae.fukui.jp", 3, false},
+	{1, "sakai.fukui.jp", 3, false},
+	{1, "takahama.fukui.jp", 3, false},
+	{1, "tsuruga.fukui.jp", 3, false},
+	{1, "wakasa.fukui.jp", 3, false},
+	{1, "ashiya.fukuoka.jp", 3, false},
+	{1, "buzen.fukuoka.jp", 3, false},
+	{1, "chikugo.fukuoka.jp", 3, false},
+	{1, "chikuho.fukuoka.jp", 3, false},
+	{1, "chikujo.fukuoka.jp", 3, false},
+	{1, "chikushino.fukuoka.jp", 3, false},
+	{1, "chikuzen.fukuoka.jp", 3, false},
+	{1, "chuo.fukuoka.jp", 3, false},
+	{1, "dazaifu.fukuoka.jp", 3, false},
+	{1, "fukuchi.fukuoka.jp", 3, false},
+	{1, "hakata.fukuoka.jp", 3, false},
+	{1, "higashi.fukuoka.jp", 3, false},
+	{1, "hirokawa.fukuoka.jp", 3, false},
+	{1, "hisayama.fukuoka.jp", 3, false},
+	{1, "iizuka.fukuoka.jp", 3, false},
+	{1, "inatsuki.fukuoka.jp", 3, false},
+	{1, "kaho.fukuoka.jp", 3, false},
+	{1, "kasuga.fukuoka.jp", 3, false},
+	{1, "kasuya.fukuoka.jp", 3, false},
+	{1, "kawara.fukuoka.jp", 3, false},
+	{1, "keisen.fukuoka.jp", 3, false},
+	{1, "koga.fukuoka.jp", 3, false},
+	{1, "kurate.fukuoka.jp", 3, false},
+	{1, "kurogi.fukuoka.jp", 3, false},
+	{1, "kurume.fukuoka.jp", 3, false},
+	{1, "minami.fukuoka.jp", 3, false},
+	{1, "miyako.fukuoka.jp", 3, false},
+	{1, "miyama.fukuoka.jp", 3, false},
+	{1, "miyawaka.fukuoka.jp", 3, false},
+	{1, "mizumaki.fukuoka.jp", 3, false},
+	{1, "munakata.fukuoka.jp", 3, false},
+	{1, "nakagawa.fukuoka.jp", 3, false},
+	{1, "nakama.fukuoka.jp", 3, false},
+	{1, "nishi.fukuoka.jp", 3, false},
+	{1, "nogata.fukuoka.jp", 3, false},
+	{1, "ogori.fukuoka.jp", 3, false},
+	{1, "okagaki.fukuoka.jp", 3, false},
+	{1, "okawa.fukuoka.jp", 3, false},
+	{1, "oki.fukuoka.jp", 3, false},
+	{1, "omuta.fukuoka.jp", 3, false},
+	{1, "onga.fukuoka.jp", 3, false},
+	{1, "onojo.fukuoka.jp", 3, false},
+	{1, "oto.fukuoka.jp", 3, false},
+	{1, "saigawa.fukuoka.jp", 3, false},
+	{1, "sasaguri.fukuoka.jp", 3, false},
+	{1, "shingu.fukuoka.jp", 3, false},
+	{1, "shinyoshitomi.fukuoka.jp", 3, false},
+	{1, "shonai.fukuoka.jp", 3, false},
+	{1, "soeda.fukuoka.jp", 3, false},
+	{1, "sue.fukuoka.jp", 3, false},
+	{1, "tachiarai.fukuoka.jp", 3, false},
+	{1, "tagawa.fukuoka.jp", 3, false},
+	{1, "takata.fukuoka.jp", 3, false},
+	{1, "toho.fukuoka.jp", 3, false},
+	{1, "toyotsu.fukuoka.jp", 3, false},
+	{1, "tsuiki.fukuoka.jp", 3, false},
+	{1, "ukiha.fukuoka.jp", 3, false},
+	{1, "umi.fukuoka.jp", 3, false},
+	{1, "usui.fukuoka.jp", 3, false},
+	{1, "yamada.fukuoka.jp", 3, false},
+	{1, "yame.fukuoka.jp", 3, false},
+	{1, "yanagawa.fukuoka.jp", 3, false},
+	{1, "yukuhashi.fukuoka.jp", 3, false},
+	{1, "aizubange.fukushima.jp", 3, false},
+	{1, "aizumisato.fukushima.jp", 3, false},
+	{1, "aizuwakamatsu.fukushima.jp", 3, false},
+	{1, "asakawa.fukushima.jp", 3, false},
+	{1, "bandai.fukushima.jp", 3, false},
+	{1, "date.fukushima.jp", 3, false},
+	{1, "fukushima.fukushima.jp", 3, false},
+	{1, "furudono.fukushima.jp", 3, false},
+	{1, "futaba.fukushima.jp", 3, false},
+	{1, "hanawa.fukushima.jp", 3, false},
+	{1, "higashi.fukushima.jp", 3, false},
+	{1, "hirata.fukushima.jp", 3, false},
+	{1, "hirono.fukushima.jp", 3, false},
+	{1, "iitate.fukushima.jp", 3, false},
+	{1, "inawashiro.fukushima.jp", 3, false},
+	{1, "ishikawa.fukushima.jp", 3, false},
+	{1, "iwaki.fukushima.jp", 3, false},
+	{1, "izumizaki.fukushima.jp", 3, false},
+	{1, "kagamiishi.fukushima.jp", 3, false},
+	{1, "kaneyama.fukushima.jp", 3, false},
+	{1, "kawamata.fukushima.jp", 3, false},
+	{1, "kitakata.fukushima.jp", 3, false},
+	{1, "kitashiobara.fukushima.jp", 3, false},
+	{1, "koori.fukushima.jp", 3, false},
+	{1, "koriyama.fukushima.jp", 3, false},
+	{1, "kunimi.fukushima.jp", 3, false},
+	{1, "miharu.fukushima.jp", 3, false},
+	{1, "mishima.fukushima.jp", 3, false},
+	{1, "namie.fukushima.jp", 3, false},
+	{1, "nango.fukushima.jp", 3, false},
+	{1, "nishiaizu.fukushima.jp", 3, false},
+	{1, "nishigo.fukushima.jp", 3, false},
+	{1, "okuma.fukushima.jp", 3, false},
+	{1, "omotego.fukushima.jp", 3, false},
+	{1, "ono.fukushima.jp", 3, false},
+	{1, "otama.fukushima.jp", 3, false},
+	{1, "samegawa.fukushima.jp", 3, false},
+	{1, "shimogo.fukushima.jp", 3, false},
+	{1, "shirakawa.fukushima.jp", 3, false},
+	{1, "showa.fukushima.jp", 3, false},
+	{1, "soma.fukushima.jp", 3, false},
+	{1, "sukagawa.fukushima.jp", 3, false},
+	{1, "taishin.fukushima.jp", 3, false},
+	{1, "tamakawa.fukushima.jp", 3, false},
+	{1, "tanagura.fukushima.jp", 3, false},
+	{1, "tenei.fukushima.jp", 3, false},
+	{1, "yabuki.fukushima.jp", 3, false},
+	{1, "yamato.fukushima.jp", 3, false},
+	{1, "yamatsuri.fukushima.jp", 3, false},
+	{1, "yanaizu.fukushima.jp", 3, false},
+	{1, "yugawa.fukushima.jp", 3, false},
+	{1, "anpachi.gifu.jp", 3, false},
+	{1, "ena.gifu.jp", 3, false},
+	{1, "gifu.gifu.jp", 3, false},
+	{1, "ginan.gifu.jp", 3, false},
+	{1, "godo.gifu.jp", 3, false},
+	{1, "gujo.gifu.jp", 3, false},
+	{1, "hashima.gifu.jp", 3, false},
+	{1, "hichiso.gifu.jp", 3, false},
+	{1, "hida.gifu.jp", 3, false},
+	{1, "higashishirakawa.gifu.jp", 3, false},
+	{1, "ibigawa.gifu.jp", 3, false},
+	{1, "ikeda.gifu.jp", 3, false},
+	{1, "kakamigahara.gifu.jp", 3, false},
+	{1, "kani.gifu.jp", 3, false},
+	{1, "kasahara.gifu.jp", 3, false},
+	{1, "kasamatsu.gifu.jp", 3, false},
+	{1, "kawaue.gifu.jp", 3, false},
+	{1, "kitagata.gifu.jp", 3, false},
+	{1, "mino.gifu.jp", 3, false},
+	{1, "minokamo.gifu.jp", 3, false},
+	{1, "mitake.gifu.jp", 3, false},
+	{1, "mizunami.gifu.jp", 3, false},
+	{1, "motosu.gifu.jp", 3, false},
+	{1, "nakatsugawa.gifu.jp", 3, false},
+	{1, "ogaki.gifu.jp", 3, false},
+	{1, "sakahogi.gifu.jp", 3, false},
+	{1, "seki.gifu.jp", 3, false},
+	{1, "sekigahara.gifu.jp", 3, false},
+	{1, "shirakawa.gifu.jp", 3, false},
+	{1, "tajimi.gifu.jp", 3, false},
+	{1, "takayama.gifu.jp", 3, false},
+	{1, "tarui.gifu.jp", 3, false},
+	{1, "toki.gifu.jp", 3, false},
+	{1, "tomika.gifu.jp", 3, false},
+	{1, "wanouchi.gifu.jp", 3, false},
+	{1, "yamagata.gifu.jp", 3, false},
+	{1, "yaotsu.gifu.jp", 3, false},
+	{1, "yoro.gifu.jp", 3, false},
+	{1, "annaka.gunma.jp", 3, false},
+	{1, "chiyoda.gunma.jp", 3, false},
+	{1, "fujioka.gunma.jp", 3, false},
+	{1, "higashiagatsuma.gunma.jp", 3, false},
+	{1, "isesaki.gunma.jp", 3, false},
+	{1, "itakura.gunma.jp", 3, false},
+	{1, "kanna.gunma.jp", 3, false},
+	{1, "kanra.gunma.jp", 3, false},
+	{1, "katashina.gunma.jp", 3, false},
+	{1, "kawaba.gunma.jp", 3, false},
+	{1, "kiryu.gunma.jp", 3, false},
+	{1, "kusatsu.gunma.jp", 3, false},
+	{1, "maebashi.gunma.jp", 3, false},
+	{1, "meiwa.gunma.jp", 3, false},
+	{1, "midori.gunma.jp", 3, false},
+	{1, "minakami.gunma.jp", 3, false},
+	{1, "naganohara.gunma.jp", 3, false},
+	{1, "nakanojo.gunma.jp", 3, false},
+	{1, "nanmoku.gunma.jp", 3, false},
+	{1, "numata.gunma.jp", 3, false},
+	{1, "oizumi.gunma.jp", 3, false},
+	{1, "ora.gunma.jp", 3, false},
+	{1, "ota.gunma.jp", 3, false},
+	{1, "shibukawa.gunma.jp", 3, false},
+	{1, "shimonita.gunma.jp", 3, false},
+	{1, "shinto.gunma.jp", 3, false},
+	{1, "showa.gunma.jp", 3, false},
+	{1, "takasaki.gunma.jp", 3, false},
+	{1, "takayama.gunma.jp", 3, false},
+	{1, "tamamura.gunma.jp", 3, false},
+	{1, "tatebayashi.gunma.jp", 3, false},
+	{1, "tomioka.gunma.jp", 3, false},
+	{1, "tsukiyono.gunma.jp", 3, false},
+	{1, "tsumagoi.gunma.jp", 3, false},
+	{1, "ueno.gunma.jp", 3, false},
+	{1, "yoshioka.gunma.jp", 3, false},
+	{1, "asaminami.hiroshima.jp", 3, false},
+	{1, "daiwa.hiroshima.jp", 3, false},
+	{1, "etajima.hiroshima.jp", 3, false},
+	{1, "fuchu.hiroshima.jp", 3, false},
+	{1, "fukuyama.hiroshima.jp", 3, false},
+	{1, "hatsukaichi.hiroshima.jp", 3, false},
+	{1, "higashihiroshima.hiroshima.jp", 3, false},
+	{1, "hongo.hiroshima.jp", 3, false},
+	{1, "jinsekikogen.hiroshima.jp", 3, false},
+	{1, "kaita.hiroshima.jp", 3, false},
+	{1, "kui.hiroshima.jp", 3, false},
+	{1, "kumano.hiroshima.jp", 3, false},
+	{1, "kure.hiroshima.jp", 3, false},
+	{1, "mihara.hiroshima.jp", 3, false},
+	{1, "miyoshi.hiroshima.jp", 3, false},
+	{1, "naka.hiroshima.jp", 3, false},
+	{1, "onomichi.hiroshima.jp", 3, false},
+	{1, "osakikamijima.hiroshima.jp", 3, false},
+	{1, "otake.hiroshima.jp", 3, false},
+	{1, "saka.hiroshima.jp", 3, false},
+	{1, "sera.hiroshima.jp", 3, false},
+	{1, "seranishi.hiroshima.jp", 3, false},
+	{1, "shinichi.hiroshima.jp", 3, false},
+	{1, "shobara.hiroshima.jp", 3, false},
+	{1, "takehara.hiroshima.jp", 3, false},
+	{1, "abashiri.hokkaido.jp", 3, false},
+	{1, "abira.hokkaido.jp", 3, false},
+	{1, "aibetsu.hokkaido.jp", 3, false},
+	{1, "akabira.hokkaido.jp", 3, false},
+	{1, "akkeshi.hokkaido.jp", 3, false},
+	{1, "asahikawa.hokkaido.jp", 3, false},
+	{1, "ashibetsu.hokkaido.jp", 3, false},
+	{1, "ashoro.hokkaido.jp", 3, false},
+	{1, "assabu.hokkaido.jp", 3, false},
+	{1, "atsuma.hokkaido.jp", 3, false},
+	{1, "bibai.hokkaido.jp", 3, false},
+	{1, "biei.hokkaido.jp", 3, false},
+	{1, "bifuka.hokkaido.jp", 3, false},
+	{1, "bihoro.hokkaido.jp", 3, false},
+	{1, "biratori.hokkaido.jp", 3, false},
+	{1, "chippubetsu.hokkaido.jp", 3, false},
+	{1, "chitose.hokkaido.jp", 3, false},
+	{1, "date.hokkaido.jp", 3, false},
+	{1, "ebetsu.hokkaido.jp", 3, false},
+	{1, "embetsu.hokkaido.jp", 3, false},
+	{1, "eniwa.hokkaido.jp", 3, false},
+	{1, "erimo.hokkaido.jp", 3, false},
+	{1, "esan.hokkaido.jp", 3, false},
+	{1, "esashi.hokkaido.jp", 3, false},
+	{1, "fukagawa.hokkaido.jp", 3, false},
+	{1, "fukushima.hokkaido.jp", 3, false},
+	{1, "furano.hokkaido.jp", 3, false},
+	{1, "furubira.hokkaido.jp", 3, false},
+	{1, "haboro.hokkaido.jp", 3, false},
+	{1, "hakodate.hokkaido.jp", 3, false},
+	{1, "hamatonbetsu.hokkaido.jp", 3, false},
+	{1, "hidaka.hokkaido.jp", 3, false},
+	{1, "higashikagura.hokkaido.jp", 3, false},
+	{1, "higashikawa.hokkaido.jp", 3, false},
+	{1, "hiroo.hokkaido.jp", 3, false},
+	{1, "hokuryu.hokkaido.jp", 3, false},
+	{1, "hokuto.hokkaido.jp", 3, false},
+	{1, "honbetsu.hokkaido.jp", 3, false},
+	{1, "horokanai.hokkaido.jp", 3, false},
+	{1, "horonobe.hokkaido.jp", 3, false},
+	{1, "ikeda.hokkaido.jp", 3, false},
+	{1, "imakane.hokkaido.jp", 3, false},
+	{1, "ishikari.hokkaido.jp", 3, false},
+	{1, "iwamizawa.hokkaido.jp", 3, false},
+	{1, "iwanai.hokkaido.jp", 3, false},
+	{1, "kamifurano.hokkaido.jp", 3, false},
+	{1, "kamikawa.hokkaido.jp", 3, false},
+	{1, "kamishihoro.hokkaido.jp", 3, false},
+	{1, "kamisunagawa.hokkaido.jp", 3, false},
+	{1, "kamoenai.hokkaido.jp", 3, false},
+	{1, "kayabe.hokkaido.jp", 3, false},
+	{1, "kembuchi.hokkaido.jp", 3, false},
+	{1, "kikonai.hokkaido.jp", 3, false},
+	{1, "kimobetsu.hokkaido.jp", 3, false},
+	{1, "kitahiroshima.hokkaido.jp", 3, false},
+	{1, "kitami.hokkaido.jp", 3, false},
+	{1, "kiyosato.hokkaido.jp", 3, false},
+	{1, "koshimizu.hokkaido.jp", 3, false},
+	{1, "kunneppu.hokkaido.jp", 3, false},
+	{1, "kuriyama.hokkaido.jp", 3, false},
+	{1, "kuromatsunai.hokkaido.jp", 3, false},
+	{1, "kushiro.hokkaido.jp", 3, false},
+	{1, "kutchan.hokkaido.jp", 3, false},
+	{1, "kyowa.hokkaido.jp", 3, false},
+	{1, "mashike.hokkaido.jp", 3, false},
+	{1, "matsumae.hokkaido.jp", 3, false},
+	{1, "mikasa.hokkaido.jp", 3, false},
+	{1, "minamifurano.hokkaido.jp", 3, false},
+	{1, "mombetsu.hokkaido.jp", 3, false},
+	{1, "moseushi.hokkaido.jp", 3, false},
+	{1, "mukawa.hokkaido.jp", 3, false},
+	{1, "muroran.hokkaido.jp", 3, false},
+	{1, "naie.hokkaido.jp", 3, false},
+	{1, "nakagawa.hokkaido.jp", 3, false},
+	{1, "nakasatsunai.hokkaido.jp", 3, false},
+	{1, "nakatombetsu.hokkaido.jp", 3, false},
+	{1, "nanae.hokkaido.jp", 3, false},
+	{1, "nanporo.hokkaido.jp", 3, false},
+	{1, "nayoro.hokkaido.jp", 3, false},
+	{1, "nemuro.hokkaido.jp", 3, false},
+	{1, "niikappu.hokkaido.jp", 3, false},
+	{1, "niki.hokkaido.jp", 3, false},
+	{1, "nishiokoppe.hokkaido.jp", 3, false},
+	{1, "noboribetsu.hokkaido.jp", 3, false},
+	{1, "numata.hokkaido.jp", 3, false},
+	{1, "obihiro.hokkaido.jp", 3, false},
+	{1, "obira.hokkaido.jp", 3, false},
+	{1, "oketo.hokkaido.jp", 3, false},
+	{1, "okoppe.hokkaido.jp", 3, false},
+	{1, "otaru.hokkaido.jp", 3, false},
+	{1, "otobe.hokkaido.jp", 3, false},
+	{1, "otofuke.hokkaido.jp", 3, false},
+	{1, "otoineppu.hokkaido.jp", 3, false},
+	{1, "oumu.hokkaido.jp", 3, false},
+	{1, "ozora.hokkaido.jp", 3, false},
+	{1, "pippu.hokkaido.jp", 3, false},
+	{1, "rankoshi.hokkaido.jp", 3, false},
+	{1, "rebun.hokkaido.jp", 3, false},
+	{1, "rikubetsu.hokkaido.jp", 3, false},
+	{1, "rishiri.hokkaido.jp", 3, false},
+	{1, "rishirifuji.hokkaido.jp", 3, false},
+	{1, "saroma.hokkaido.jp", 3, false},
+	{1, "sarufutsu.hokkaido.jp", 3, false},
+	{1, "shakotan.hokkaido.jp", 3, false},
+	{1, "shari.hokkaido.jp", 3, false},
+	{1, "shibecha.hokkaido.jp", 3, false},
+	{1, "shibetsu.hokkaido.jp", 3, false},
+	{1, "shikabe.hokkaido.jp", 3, false},
+	{1, "shikaoi.hokkaido.jp", 3, false},
+	{1, "shimamaki.hokkaido.jp", 3, false},
+	{1, "shimizu.hokkaido.jp", 3, false},
+	{1, "shimokawa.hokkaido.jp", 3, false},
+	{1, "shinshinotsu.hokkaido.jp", 3, false},
+	{1, "shintoku.hokkaido.jp", 3, false},
+	{1, "shiranuka.hokkaido.jp", 3, false},
+	{1, "shiraoi.hokkaido.jp", 3, false},
+	{1, "shiriuchi.hokkaido.jp", 3, false},
+	{1, "sobetsu.hokkaido.jp", 3, false},
+	{1, "sunagawa.hokkaido.jp", 3, false},
+	{1, "taiki.hokkaido.jp", 3, false},
+	{1, "takasu.hokkaido.jp", 3, false},
+	{1, "takikawa.hokkaido.jp", 3, false},
+	{1, "takinoue.hokkaido.jp", 3, false},
+	{1, "teshikaga.hokkaido.jp", 3, false},
+	{1, "tobetsu.hokkaido.jp", 3, false},
+	{1, "tohma.hokkaido.jp", 3, false},
+	{1, "tomakomai.hokkaido.jp", 3, false},
+	{1, "tomari.hokkaido.jp", 3, false},
+	{1, "toya.hokkaido.jp", 3, false},
+	{1, "toyako.hokkaido.jp", 3, false},
+	{1, "toyotomi.hokkaido.jp", 3, false},
+	{1, "toyoura.hokkaido.jp", 3, false},
+	{1, "tsubetsu.hokkaido.jp", 3, false},
+	{1, "tsukigata.hokkaido.jp", 3, false},
+	{1, "urakawa.hokkaido.jp", 3, false},
+	{1, "urausu.hokkaido.jp", 3, false},
+	{1, "uryu.hokkaido.jp", 3, false},
+	{1, "utashinai.hokkaido.jp", 3, false},
+	{1, "wakkanai.hokkaido.jp", 3, false},
+	{1, "wassamu.hokkaido.jp", 3, false},
+	{1, "yakumo.hokkaido.jp", 3, false},
+	{1, "yoichi.hokkaido.jp", 3, false},
+	{1, "aioi.hyogo.jp", 3, false},
+	{1, "akashi.hyogo.jp", 3, false},
+	{1, "ako.hyogo.jp", 3, false},
+	{1, "amagasaki.hyogo.jp", 3, false},
+	{1, "aogaki.hyogo.jp", 3, false},
+	{1, "asago.hyogo.jp", 3, false},
+	{1, "ashiya.hyogo.jp", 3, false},
+	{1, "awaji.hyogo.jp", 3, false},
+	{1, "fukusaki.hyogo.jp", 3, false},
+	{1, "goshiki.hyogo.jp", 3, false},
+	{1, "harima.hyogo.jp", 3, false},
+	{1, "himeji.hyogo.jp", 3, false},
+	{1, "ichikawa.hyogo.jp", 3, false},
+	{1, "inagawa.hyogo.jp", 3, false},
+	{1, "itami.hyogo.jp", 3, false},
+	{1, "kakogawa.hyogo.jp", 3, false},
+	{1, "kamigori.hyogo.jp", 3, false},
+	{1, "kamikawa.hyogo.jp", 3, false},
+	{1, "kasai.hyogo.jp", 3, false},
+	{1, "kasuga.hyogo.jp", 3, false},
+	{1, "kawanishi.hyogo.jp", 3, false},
+	{1, "miki.hyogo.jp", 3, false},
+	{1, "minamiawaji.hyogo.jp", 3, false},
+	{1, "nishinomiya.hyogo.jp", 3, false},
+	{1, "nishiwaki.hyogo.jp", 3, false},
+	{1, "ono.hyogo.jp", 3, false},
+	{1, "sanda.hyogo.jp", 3, false},
+	{1, "sannan.hyogo.jp", 3, false},
+	{1, "sasayama.hyogo.jp", 3, false},
+	{1, "sayo.hyogo.jp", 3, false},
+	{1, "shingu.hyogo.jp", 3, false},
+	{1, "shinonsen.hyogo.jp", 3, false},
+	{1, "shiso.hyogo.jp", 3, false},
+	{1, "sumoto.hyogo.jp", 3, false},
+	{1, "taishi.hyogo.jp", 3, false},
+	{1, "taka.hyogo.jp", 3, false},
+	{1, "takarazuka.hyogo.jp", 3, false},
+	{1, "takasago.hyogo.jp", 3, false},
+	{1, "takino.hyogo.jp", 3, false},
+	{1, "tamba.hyogo.jp", 3, false},
+	{1, "tatsuno.hyogo.jp", 3, false},
+	{1, "toyooka.hyogo.jp", 3, false},
+	{1, "yabu.hyogo.jp", 3, false},
+	{1, "yashiro.hyogo.jp", 3, false},
+	{1, "yoka.hyogo.jp", 3, false},
+	{1, "yokawa.hyogo.jp", 3, false},
+	{1, "ami.ibaraki.jp", 3, false},
+	{1, "asahi.ibaraki.jp", 3, false},
+	{1, "bando.ibaraki.jp", 3, false},
+	{1, "chikusei.ibaraki.jp", 3, false},
+	{1, "daigo.ibaraki.jp", 3, false},
+	{1, "fujishiro.ibaraki.jp", 3, false},
+	{1, "hitachi.ibaraki.jp", 3, false},
+	{1, "hitachinaka.ibaraki.jp", 3, false},
+	{1, "hitachiomiya.ibaraki.jp", 3, false},
+	{1, "hitachiota.ibaraki.jp", 3, false},
+	{1, "ibaraki.ibaraki.jp", 3, false},
+	{1, "ina.ibaraki.jp", 3, false},
+	{1, "inashiki.ibaraki.jp", 3, false},
+	{1, "itako.ibaraki.jp", 3, false},
+	{1, "iwama.ibaraki.jp", 3, false},
+	{1, "joso.ibaraki.jp", 3, false},
+	{1, "kamisu.ibaraki.jp", 3, false},
+	{1, "kasama.ibaraki.jp", 3, false},
+	{1, "kashima.ibaraki.jp", 3, false},
+	{1, "kasumigaura.ibaraki.jp", 3, false},
+	{1, "koga.ibaraki.jp", 3, false},
+	{1, "miho.ibaraki.jp", 3, false},
+	{1, "mito.ibaraki.jp", 3, false},
+	{1, "moriya.ibaraki.jp", 3, false},
+	{1, "naka.ibaraki.jp", 3, false},
+	{1, "namegata.ibaraki.jp", 3, false},
+	{1, "oarai.ibaraki.jp", 3, false},
+	{1, "ogawa.ibaraki.jp", 3, false},
+	{1, "omitama.ibaraki.jp", 3, false},
+	{1, "ryugasaki.ibaraki.jp", 3, false},
+	{1, "sakai.ibaraki.jp", 3, false},
+	{1, "sakuragawa.ibaraki.jp", 3, false},
+	{1, "shimodate.ibaraki.jp", 3, false},
+	{1, "shimotsuma.ibaraki.jp", 3, false},
+	{1, "shirosato.ibaraki.jp", 3, false},
+	{1, "sowa.ibaraki.jp", 3, false},
+	{1, "suifu.ibaraki.jp", 3, false},
+	{1, "takahagi.ibaraki.jp", 3, false},
+	{1, "tamatsukuri.ibaraki.jp", 3, false},
+	{1, "tokai.ibaraki.jp", 3, false},
+	{1, "tomobe.ibaraki.jp", 3, false},
+	{1, "tone.ibaraki.jp", 3, false},
+	{1, "toride.ibaraki.jp", 3, false},
+	{1, "tsuchiura.ibaraki.jp", 3, false},
+	{1, "tsukuba.ibaraki.jp", 3, false},
+	{1, "uchihara.ibaraki.jp", 3, false},
+	{1, "ushiku.ibaraki.jp", 3, false},
+	{1, "yachiyo.ibaraki.jp", 3, false},
+	{1, "yamagata.ibaraki.jp", 3, false},
+	{1, "yawara.ibaraki.jp", 3, false},
+	{1, "yuki.ibaraki.jp", 3, false},
+	{1, "anamizu.ishikawa.jp", 3, false},
+	{1, "hakui.ishikawa.jp", 3, false},
+	{1, "hakusan.ishikawa.jp", 3, false},
+	{1, "kaga.ishikawa.jp", 3, false},
+	{1, "kahoku.ishikawa.jp", 3, false},
+	{1, "kanazawa.ishikawa.jp", 3, false},
+	{1, "kawakita.ishikawa.jp", 3, false},
+	{1, "komatsu.ishikawa.jp", 3, false},
+	{1, "nakanoto.ishikawa.jp", 3, false},
+	{1, "nanao.ishikawa.jp", 3, false},
+	{1, "nomi.ishikawa.jp", 3, false},
+	{1, "nonoichi.ishikawa.jp", 3, false},
+	{1, "noto.ishikawa.jp", 3, false},
+	{1, "shika.ishikawa.jp", 3, false},
+	{1, "suzu.ishikawa.jp", 3, false},
+	{1, "tsubata.ishikawa.jp", 3, false},
+	{1, "tsurugi.ishikawa.jp", 3, false},
+	{1, "uchinada.ishikawa.jp", 3, false},
+	{1, "wajima.ishikawa.jp", 3, false},
+	{1, "fudai.iwate.jp", 3, false},
+	{1, "fujisawa.iwate.jp", 3, false},
+	{1, "hanamaki.iwate.jp", 3, false},
+	{1, "hiraizumi.iwate.jp", 3, false},
+	{1, "hirono.iwate.jp", 3, false},
+	{1, "ichinohe.iwate.jp", 3, false},
+	{1, "ichinoseki.iwate.jp", 3, false},
+	{1, "iwaizumi.iwate.jp", 3, false},
+	{1, "iwate.iwate.jp", 3, false},
+	{1, "joboji.iwate.jp", 3, false},
+	{1, "kamaishi.iwate.jp", 3, false},
+	{1, "kanegasaki.iwate.jp", 3, false},
+	{1, "karumai.iwate.jp", 3, false},
+	{1, "kawai.iwate.jp", 3, false},
+	{1, "kitakami.iwate.jp", 3, false},
+	{1, "kuji.iwate.jp", 3, false},
+	{1, "kunohe.iwate.jp", 3, false},
+	{1, "kuzumaki.iwate.jp", 3, false},
+	{1, "miyako.iwate.jp", 3, false},
+	{1, "mizusawa.iwate.jp", 3, false},
+	{1, "morioka.iwate.jp", 3, false},
+	{1, "ninohe.iwate.jp", 3, false},
+	{1, "noda.iwate.jp", 3, false},
+	{1, "ofunato.iwate.jp", 3, false},
+	{1, "oshu.iwate.jp", 3, false},
+	{1, "otsuchi.iwate.jp", 3, false},
+	{1, "rikuzentakata.iwate.jp", 3, false},
+	{1, "shiwa.iwate.jp", 3, false},
+	{1, "shizukuishi.iwate.jp", 3, false},
+	{1, "sumita.iwate.jp", 3, false},
+	{1, "tanohata.iwate.jp", 3, false},
+	{1, "tono.iwate.jp", 3, false},
+	{1, "yahaba.iwate.jp", 3, false},
+	{1, "yamada.iwate.jp", 3, false},
+	{1, "ayagawa.kagawa.jp", 3, false},
+	{1, "higashikagawa.kagawa.jp", 3, false},
+	{1, "kanonji.kagawa.jp", 3, false},
+	{1, "kotohira.kagawa.jp", 3, false},
+	{1, "manno.kagawa.jp", 3, false},
+	{1, "marugame.kagawa.jp", 3, false},
+	{1, "mitoyo.kagawa.jp", 3, false},
+	{1, "naoshima.kagawa.jp", 3, false},
+	{1, "sanuki.kagawa.jp", 3, false},
+	{1, "tadotsu.kagawa.jp", 3, false},
+	{1, "takamatsu.kagawa.jp", 3, false},
+	{1, "tonosho.kagawa.jp", 3, false},
+	{1, "uchinomi.kagawa.jp", 3, false},
+	{1, "utazu.kagawa.jp", 3, false},
+	{1, "zentsuji.kagawa.jp", 3, false},
+	{1, "akune.kagoshima.jp", 3, false},
+	{1, "amami.kagoshima.jp", 3, false},
+	{1, "hioki.kagoshima.jp", 3, false},
+	{1, "isa.kagoshima.jp", 3, false},
+	{1, "isen.kagoshima.jp", 3, false},
+	{1, "izumi.kagoshima.jp", 3, false},
+	{1, "kagoshima.kagoshima.jp", 3, false},
+	{1, "kanoya.kagoshima.jp", 3, false},
+	{1, "kawanabe.kagoshima.jp", 3, false},
+	{1, "kinko.kagoshima.jp", 3, false},
+	{1, "kouyama.kagoshima.jp", 3, false},
+	{1, "makurazaki.kagoshima.jp", 3, false},
+	{1, "matsumoto.kagoshima.jp", 3, false},
+	{1, "minamitane.kagoshima.jp", 3, false},
+	{1, "nakatane.kagoshima.jp", 3, false},
+	{1, "nishinoomote.kagoshima.jp", 3, false},
+	{1, "satsumasendai.kagoshima.jp", 3, false},
+	{1, "soo.kagoshima.jp", 3, false},
+	{1, "tarumizu.kagoshima.jp", 3, false},
+	{1, "yusui.kagoshima.jp", 3, false},
+	{1, "aikawa.kanagawa.jp", 3, false},
+	{1, "atsugi.kanagawa.jp", 3, false},
+	{1, "ayase.kanagawa.jp", 3, false},
+	{1, "chigasaki.kanagawa.jp", 3, false},
+	{1, "ebina.kanagawa.jp", 3, false},
+	{1, "fujisawa.kanagawa.jp", 3, false},
+	{1, "hadano.kanagawa.jp", 3, false},
+	{1, "hakone.kanagawa.jp", 3, false},
+	{1, "hiratsuka.kanagawa.jp", 3, false},
+	{1, "isehara.kanagawa.jp", 3, false},
+	{1, "kaisei.kanagawa.jp", 3, false},
+	{1, "kamakura.kanagawa.jp", 3, false},
+	{1, "kiyokawa.kanagawa.jp", 3, false},
+	{1, "matsuda.kanagawa.jp", 3, false},
+	{1, "minamiashigara.kanagawa.jp", 3, false},
+	{1, "miura.kanagawa.jp", 3, false},
+	{1, "nakai.kanagawa.jp", 3, false},
+	{1, "ninomiya.kanagawa.jp", 3, false},
+	{1, "odawara.kanagawa.jp", 3, false},
+	{1, "oi.kanagawa.jp", 3, false},
+	{1, "oiso.kanagawa.jp", 3, false},
+	{1, "sagamihara.kanagawa.jp", 3, false},
+	{1, "samukawa.kanagawa.jp", 3, false},
+	{1, "tsukui.kanagawa.jp", 3, false},
+	{1, "yamakita.kanagawa.jp", 3, false},
+	{1, "yamato.kanagawa.jp", 3, false},
+	{1, "yokosuka.kanagawa.jp", 3, false},
+	{1, "yugawara.kanagawa.jp", 3, false},
+	{1, "zama.kanagawa.jp", 3, false},
+	{1, "zushi.kanagawa.jp", 3, false},
+	{1, "aki.kochi.jp", 3, false},
+	{1, "geisei.kochi.jp", 3, false},
+	{1, "hidaka.kochi.jp", 3, false},
+	{1, "higashitsuno.kochi.jp", 3, false},
+	{1, "ino.kochi.jp", 3, false},
+	{1, "kagami.kochi.jp", 3, false},
+	{1, "kami.kochi.jp", 3, false},
+	{1, "kitagawa.kochi.jp", 3, false},
+	{1, "kochi.kochi.jp", 3, false},
+	{1, "mihara.kochi.jp", 3, false},
+	{1, "motoyama.kochi.jp", 3, false},
+	{1, "muroto.kochi.jp", 3, false},
+	{1, "nahari.kochi.jp", 3, false},
+	{1, "nakamura.kochi.jp", 3, false},
+	{1, "nankoku.kochi.jp", 3, false},
+	{1, "nishitosa.kochi.jp", 3, false},
+	{1, "niyodogawa.kochi.jp", 3, false},
+	{1, "ochi.kochi.jp", 3, false},
+	{1, "okawa.kochi.jp", 3, false},
+	{1, "otoyo.kochi.jp", 3, false},
+	{1, "otsuki.kochi.jp", 3, false},
+	{1, "sakawa.kochi.jp", 3, false},
+	{1, "sukumo.kochi.jp", 3, false},
+	{1, "susaki.kochi.jp", 3, false},
+	{1, "tosa.kochi.jp", 3, false},
+	{1, "tosashimizu.kochi.jp", 3, false},
+	{1, "toyo.kochi.jp", 3, false},
+	{1, "tsuno.kochi.jp", 3, false},
+	{1, "umaji.kochi.jp", 3, false},
+	{1, "yasuda.kochi.jp", 3, false},
+	{1, "yusuhara.kochi.jp", 3, false},
+	{1, "amakusa.kumamoto.jp", 3, false},
+	{1, "arao.kumamoto.jp", 3, false},
+	{1, "aso.kumamoto.jp", 3, false},
+	{1, "choyo.kumamoto.jp", 3, false},
+	{1, "gyokuto.kumamoto.jp", 3, false},
+	{1, "kamiamakusa.kumamoto.jp", 3, false},
+	{1, "kikuchi.kumamoto.jp", 3, false},
+	{1, "kumamoto.kumamoto.jp", 3, false},
+	{1, "mashiki.kumamoto.jp", 3, false},
+	{1, "mifune.kumamoto.jp", 3, false},
+	{1, "minamata.kumamoto.jp", 3, false},
+	{1, "minamioguni.kumamoto.jp", 3, false},
+	{1, "nagasu.kumamoto.jp", 3, false},
+	{1, "nishihara.kumamoto.jp", 3, false},
+	{1, "oguni.kumamoto.jp", 3, false},
+	{1, "ozu.kumamoto.jp", 3, false},
+	{1, "sumoto.kumamoto.jp", 3, false},
+	{1, "takamori.kumamoto.jp", 3, false},
+	{1, "uki.kumamoto.jp", 3, false},
+	{1, "uto.kumamoto.jp", 3, false},
+	{1, "yamaga.kumamoto.jp", 3, false},
+	{1, "yamato.kumamoto.jp", 3, false},
+	{1, "yatsushiro.kumamoto.jp", 3, false},
+	{1, "ayabe.kyoto.jp", 3, false},
+	{1, "fukuchiyama.kyoto.jp", 3, false},
+	{1, "higashiyama.kyoto.jp", 3, false},
+	{1, "ide.kyoto.jp", 3, false},
+	{1, "ine.kyoto.jp", 3, false},
+	{1, "joyo.kyoto.jp", 3, false},
+	{1, "kameoka.kyoto.jp", 3, false},
+	{1, "kamo.kyoto.jp", 3, false},
+	{1, "kita.kyoto.jp", 3, false},
+	{1, "kizu.kyoto.jp", 3, false},
+	{1, "kumiyama.kyoto.jp", 3, false},
+	{1, "kyotamba.kyoto.jp", 3, false},
+	{1, "kyotanabe.kyoto.jp", 3, false},
+	{1, "kyotango.kyoto.jp", 3, false},
+	{1, "maizuru.kyoto.jp", 3, false},
+	{1, "minami.kyoto.jp", 3, false},
+	{1, "minamiyamashiro.kyoto.jp", 3, false},
+	{1, "miyazu.kyoto.jp", 3, false},
+	{1, "muko.kyoto.jp", 3, false},
+	{1, "nagaokakyo.kyoto.jp", 3, false},
+	{1, "nakagyo.kyoto.jp", 3, false},
+	{1, "nantan.kyoto.jp", 3, false},
+	{1, "oyamazaki.kyoto.jp", 3, false},
+	{1, "sakyo.kyoto.jp", 3, false},
+	{1, "seika.kyoto.jp", 3, false},
+	{1, "tanabe.kyoto.jp", 3, false},
+	{1, "uji.kyoto.jp", 3, false},
+	{1, "ujitawara.kyoto.jp", 3, false},
+	{1, "wazuka.kyoto.jp", 3, false},
+	{1, "yamashina.kyoto.jp", 3, false},
+	{1, "yawata.kyoto.jp", 3, false},
+	{1, "asahi.mie.jp", 3, false},
+	{1, "inabe.mie.jp", 3, false},
+	{1, "ise.mie.jp", 3, false},
+	{1, "kameyama.mie.jp", 3, false},
+	{1, "kawagoe.mie.jp", 3, false},
+	{1, "kiho.mie.jp", 3, false},
+	{1, "kisosaki.mie.jp", 3, false},
+	{1, "kiwa.mie.jp", 3, false},
+	{1, "komono.mie.jp", 3, false},
+	{1, "kumano.mie.jp", 3, false},
+	{1, "kuwana.mie.jp", 3, false},
+	{1, "matsusaka.mie.jp", 3, false},
+	{1, "meiwa.mie.jp", 3, false},
+	{1, "mihama.mie.jp", 3, false},
+	{1, "minamiise.mie.jp", 3, false},
+	{1, "misugi.mie.jp", 3, false},
+	{1, "miyama.mie.jp", 3, false},
+	{1, "nabari.mie.jp", 3, false},
+	{1, "shima.mie.jp", 3, false},
+	{1, "suzuka.mie.jp", 3, false},
+	{1, "tado.mie.jp", 3, false},
+	{1, "taiki.mie.jp", 3, false},
+	{1, "taki.mie.jp", 3, false},
+	{1, "tamaki.mie.jp", 3, false},
+	{1, "toba.mie.jp", 3, false},
+	{1, "tsu.mie.jp", 3, false},
+	{1, "udono.mie.jp", 3, false},
+	{1, "ureshino.mie.jp", 3, false},
+	{1, "watarai.mie.jp", 3, false},
+	{1, "yokkaichi.mie.jp", 3, false},
+	{1, "furukawa.miyagi.jp", 3, false},
+	{1, "higashimatsushima.miyagi.jp", 3, false},
+	{1, "ishinomaki.miyagi.jp", 3, false},
+	{1, "iwanuma.miyagi.jp", 3, false},
+	{1, "kakuda.miyagi.jp", 3, false},
+	{1, "kami.miyagi.jp", 3, false},
+	{1, "kawasaki.miyagi.jp", 3, false},
+	{1, "marumori.miyagi.jp", 3, false},
+	{1, "matsushima.miyagi.jp", 3, false},
+	{1, "minamisanriku.miyagi.jp", 3, false},
+	{1, "misato.miyagi.jp", 3, false},
+	{1, "murata.miyagi.jp", 3, false},
+	{1, "natori.miyagi.jp", 3, false},
+	{1, "ogawara.miyagi.jp", 3, false},
+	{1, "ohira.miyagi.jp", 3, false},
+	{1, "onagawa.miyagi.jp", 3, false},
+	{1, "osaki.miyagi.jp", 3, false},
+	{1, "rifu.miyagi.jp", 3, false},
+	{1, "semine.miyagi.jp", 3, false},
+	{1, "shibata.miyagi.jp", 3, false},
+	{1, "shichikashuku.miyagi.jp", 3, false},
+	{1, "shikama.miyagi.jp", 3, false},
+	{1, "shiogama.miyagi.jp", 3, false},
+	{1, "shiroishi.miyagi.jp", 3, false},
+	{1, "tagajo.miyagi.jp", 3, false},
+	{1, "taiwa.miyagi.jp", 3, false},
+	{1, "tome.miyagi.jp", 3, false},
+	{1, "tomiya.miyagi.jp", 3, false},
+	{1, "wakuya.miyagi.jp", 3, false},
+	{1, "watari.miyagi.jp", 3, false},
+	{1, "yamamoto.miyagi.jp", 3, false},
+	{1, "zao.miyagi.jp", 3, false},
+	{1, "aya.miyazaki.jp", 3, false},
+	{1, "ebino.miyazaki.jp", 3, false},
+	{1, "gokase.miyazaki.jp", 3, false},
+	{1, "hyuga.miyazaki.jp", 3, false},
+	{1, "kadogawa.miyazaki.jp", 3, false},
+	{1, "kawaminami.miyazaki.jp", 3, false},
+	{1, "kijo.miyazaki.jp", 3, false},
+	{1, "kitagawa.miyazaki.jp", 3, false},
+	{1, "kitakata.miyazaki.jp", 3, false},
+	{1, "kitaura.miyazaki.jp", 3, false},
+	{1, "kobayashi.miyazaki.jp", 3, false},
+	{1, "kunitomi.miyazaki.jp", 3, false},
+	{1, "kushima.miyazaki.jp", 3, false},
+	{1, "mimata.miyazaki.jp", 3, false},
+	{1, "miyakonojo.miyazaki.jp", 3, false},
+	{1, "miyazaki.miyazaki.jp", 3, false},
+	{1, "morotsuka.miyazaki.jp", 3, false},
+	{1, "nichinan.miyazaki.jp", 3, false},
+	{1, "nishimera.miyazaki.jp", 3, false},
+	{1, "nobeoka.miyazaki.jp", 3, false},
+	{1, "saito.miyazaki.jp", 3, false},
+	{1, "shiiba.miyazaki.jp", 3, false},
+	{1, "shintomi.miyazaki.jp", 3, false},
+	{1, "takaharu.miyazaki.jp", 3, false},
+	{1, "takanabe.miyazaki.jp", 3, false},
+	{1, "takazaki.miyazaki.jp", 3, false},
+	{1, "tsuno.miyazaki.jp", 3, false},
+	{1, "achi.nagano.jp", 3, false},
+	{1, "agematsu.nagano.jp", 3, false},
+	{1, "anan.nagano.jp", 3, false},
+	{1, "aoki.nagano.jp", 3, false},
+	{1, "asahi.nagano.jp", 3, false},
+	{1, "azumino.nagano.jp", 3, false},
+	{1, "chikuhoku.nagano.jp", 3, false},
+	{1, "chikuma.nagano.jp", 3, false},
+	{1, "chino.nagano.jp", 3, false},
+	{1, "fujimi.nagano.jp", 3, false},
+	{1, "hakuba.nagano.jp", 3, false},
+	{1, "hara.nagano.jp", 3, false},
+	{1, "hiraya.nagano.jp", 3, false},
+	{1, "iida.nagano.jp", 3, false},
+	{1, "iijima.nagano.jp", 3, false},
+	{1, "iiyama.nagano.jp", 3, false},
+	{1, "iizuna.nagano.jp", 3, false},
+	{1, "ikeda.nagano.jp", 3, false},
+	{1, "ikusaka.nagano.jp", 3, false},
+	{1, "ina.nagano.jp", 3, false},
+	{1, "karuizawa.nagano.jp", 3, false},
+	{1, "kawakami.nagano.jp", 3, false},
+	{1, "kiso.nagano.jp", 3, false},
+	{1, "kisofukushima.nagano.jp", 3, false},
+	{1, "kitaaiki.nagano.jp", 3, false},
+	{1, "komagane.nagano.jp", 3, false},
+	{1, "komoro.nagano.jp", 3, false},
+	{1, "matsukawa.nagano.jp", 3, false},
+	{1, "matsumoto.nagano.jp", 3, false},
+	{1, "miasa.nagano.jp", 3, false},
+	{1, "minamiaiki.nagano.jp", 3, false},
+	{1, "minamimaki.nagano.jp", 3, false},
+	{1, "minamiminowa.nagano.jp", 3, false},
+	{1, "minowa.nagano.jp", 3, false},
+	{1, "miyada.nagano.jp", 3, false},
+	{1, "miyota.nagano.jp", 3, false},
+	{1, "mochizuki.nagano.jp", 3, false},
+	{1, "nagano.nagano.jp", 3, false},
+	{1, "nagawa.nagano.jp", 3, false},
+	{1, "nagiso.nagano.jp", 3, false},
+	{1, "nakagawa.nagano.jp", 3, false},
+	{1, "nakano.nagano.jp", 3, false},
+	{1, "nozawaonsen.nagano.jp", 3, false},
+	{1, "obuse.nagano.jp", 3, false},
+	{1, "ogawa.nagano.jp", 3, false},
+	{1, "okaya.nagano.jp", 3, false},
+	{1, "omachi.nagano.jp", 3, false},
+	{1, "omi.nagano.jp", 3, false},
+	{1, "ookuwa.nagano.jp", 3, false},
+	{1, "ooshika.nagano.jp", 3, false},
+	{1, "otaki.nagano.jp", 3, false},
+	{1, "otari.nagano.jp", 3, false},
+	{1, "sakae.nagano.jp", 3, false},
+	{1, "sakaki.nagano.jp", 3, false},
+	{1, "saku.nagano.jp", 3, false},
+	{1, "sakuho.nagano.jp", 3, false},
+	{1, "shimosuwa.nagano.jp", 3, false},
+	{1, "shinanomachi.nagano.jp", 3, false},
+	{1, "shiojiri.nagano.jp", 3, false},
+	{1, "suwa.nagano.jp", 3, false},
+	{1, "suzaka.nagano.jp", 3, false},
+	{1, "takagi.nagano.jp", 3, false},
+	{1, "takamori.nagano.jp", 3, false},
+	{1, "takayama.nagano.jp", 3, false},
+	{1, "tateshina.nagano.jp", 3, false},
+	{1, "tatsuno.nagano.jp", 3, false},
+	{1, "togakushi.nagano.jp", 3, false},
+	{1, "togura.nagano.jp", 3, false},
+	{1, "tomi.nagano.jp", 3, false},
+	{1, "ueda.nagano.jp", 3, false},
+	{1, "wada.nagano.jp", 3, false},
+	{1, "yamagata.nagano.jp", 3, false},
+	{1, "yamanouchi.nagano.jp", 3, false},
+	{1, "yasaka.nagano.jp", 3, false},
+	{1, "yasuoka.nagano.jp", 3, false},
+	{1, "chijiwa.nagasaki.jp", 3, false},
+	{1, "futsu.nagasaki.jp", 3, false},
+	{1, "goto.nagasaki.jp", 3, false},
+	{1, "hasami.nagasaki.jp", 3, false},
+	{1, "hirado.nagasaki.jp", 3, false},
+	{1, "iki.nagasaki.jp", 3, false},
+	{1, "isahaya.nagasaki.jp", 3, false},
+	{1, "kawatana.nagasaki.jp", 3, false},
+	{1, "kuchinotsu.nagasaki.jp", 3, false},
+	{1, "matsuura.nagasaki.jp", 3, false},
+	{1, "nagasaki.nagasaki.jp", 3, false},
+	{1, "obama.nagasaki.jp", 3, false},
+	{1, "omura.nagasaki.jp", 3, false},
+	{1, "oseto.nagasaki.jp", 3, false},
+	{1, "saikai.nagasaki.jp", 3, false},
+	{1, "sasebo.nagasaki.jp", 3, false},
+	{1, "seihi.nagasaki.jp", 3, false},
+	{1, "shimabara.nagasaki.jp", 3, false},
+	{1, "shinkamigoto.nagasaki.jp", 3, false},
+	{1, "togitsu.nagasaki.jp", 3, false},
+	{1, "tsushima.nagasaki.jp", 3, false},
+	{1, "unzen.nagasaki.jp", 3, false},
+	{1, "ando.nara.jp", 3, false},
+	{1, "gose.nara.jp", 3, false},
+	{1, "heguri.nara.jp", 3, false},
+	{1, "higashiyoshino.nara.jp", 3, false},
+	{1, "ikaruga.nara.jp", 3, false},
+	{1, "ikoma.nara.jp", 3, false},
+	{1, "kamikitayama.nara.jp", 3, false},
+	{1, "kanmaki.nara.jp", 3, false},
+	{1, "kashiba.nara.jp", 3, false},
+	{1, "kashihara.nara.jp", 3, false},
+	{1, "katsuragi.nara.jp", 3, false},
+	{1, "kawai.nara.jp", 3, false},
+	{1, "kawakami.nara.jp", 3, false},
+	{1, "kawanishi.nara.jp", 3, false},
+	{1, "koryo.nara.jp", 3, false},
+	{1, "kurotaki.nara.jp", 3, false},
+	{1, "mitsue.nara.jp", 3, false},
+	{1, "miyake.nara.jp", 3, false},
+	{1, "nara.nara.jp", 3, false},
+	{1, "nosegawa.nara.jp", 3, false},
+	{1, "oji.nara.jp", 3, false},
+	{1, "ouda.nara.jp", 3, false},
+	{1, "oyodo.nara.jp", 3, false},
+	{1, "sakurai.nara.jp", 3, false},
+	{1, "sango.nara.jp", 3, false},
+	{1, "shimoichi.nara.jp", 3, false},
+	{1, "shimokitayama.nara.jp", 3, false},
+	{1, "shinjo.nara.jp", 3, false},
+	{1, "soni.nara.jp", 3, false},
+	{1, "takatori.nara.jp", 3, false},
+	{1, "tawaramoto.nara.jp", 3, false},
+	{1, "tenkawa.nara.jp", 3, false},
+	{1, "tenri.nara.jp", 3, false},
+	{1, "uda.nara.jp", 3, false},
+	{1, "yamatokoriyama.nara.jp", 3, false},
+	{1, "yamatotakada.nara.jp", 3, false},
+	{1, "yamazoe.nara.jp", 3, false},
+	{1, "yoshino.nara.jp", 3, false},
+	{1, "aga.niigata.jp", 3, false},
+	{1, "agano.niigata.jp", 3, false},
+	{1, "gosen.niigata.jp", 3, false},
+	{1, "itoigawa.niigata.jp", 3, false},
+	{1, "izumozaki.niigata.jp", 3, false},
+	{1, "joetsu.niigata.jp", 3, false},
+	{1, "kamo.niigata.jp", 3, false},
+	{1, "kariwa.niigata.jp", 3, false},
+	{1, "kashiwazaki.niigata.jp", 3, false},
+	{1, "minamiuonuma.niigata.jp", 3, false},
+	{1, "mitsuke.niigata.jp", 3, false},
+	{1, "muika.niigata.jp", 3, false},
+	{1, "murakami.niigata.jp", 3, false},
+	{1, "myoko.niigata.jp", 3, false},
+	{1, "nagaoka.niigata.jp", 3, false},
+	{1, "niigata.niigata.jp", 3, false},
+	{1, "ojiya.niigata.jp", 3, false},
+	{1, "omi.niigata.jp", 3, false},
+	{1, "sado.niigata.jp", 3, false},
+	{1, "sanjo.niigata.jp", 3, false},
+	{1, "seiro.niigata.jp", 3, false},
+	{1, "seirou.niigata.jp", 3, false},
+	{1, "sekikawa.niigata.jp", 3, false},
+	{1, "shibata.niigata.jp", 3, false},
+	{1, "tagami.niigata.jp", 3, false},
+	{1, "tainai.niigata.jp", 3, false},
+	{1, "tochio.niigata.jp", 3, false},
+	{1, "tokamachi.niigata.jp", 3, false},
+	{1, "tsubame.niigata.jp", 3, false},
+	{1, "tsunan.niigata.jp", 3, false},
+	{1, "uonuma.niigata.jp", 3, false},
+	{1, "yahiko.niigata.jp", 3, false},
+	{1, "yoita.niigata.jp", 3, false},
+	{1, "yuzawa.niigata.jp", 3, false},
+	{1, "beppu.oita.jp", 3, false},
+	{1, "bungoono.oita.jp", 3, false},
+	{1, "bungotakada.oita.jp", 3, false},
+	{1, "hasama.oita.jp", 3, false},
+	{1, "hiji.oita.jp", 3, false},
+	{1, "himeshima.oita.jp", 3, false},
+	{1, "hita.oita.jp", 3, false},
+	{1, "kamitsue.oita.jp", 3, false},
+	{1, "kokonoe.oita.jp", 3, false},
+	{1, "kuju.oita.jp", 3, false},
+	{1, "kunisaki.oita.jp", 3, false},
+	{1, "kusu.oita.jp", 3, false},
+	{1, "oita.oita.jp", 3, false},
+	{1, "saiki.oita.jp", 3, false},
+	{1, "taketa.oita.jp", 3, false},
+	{1, "tsukumi.oita.jp", 3, false},
+	{1, "usa.oita.jp", 3, false},
+	{1, "usuki.oita.jp", 3, false},
+	{1, "yufu.oita.jp", 3, false},
+	{1, "akaiwa.okayama.jp", 3, false},
+	{1, "asakuchi.okayama.jp", 3, false},
+	{1, "bizen.okayama.jp", 3, false},
+	{1, "hayashima.okayama.jp", 3, false},
+	{1, "ibara.okayama.jp", 3, false},
+	{1, "kagamino.okayama.jp", 3, false},
+	{1, "kasaoka.okayama.jp", 3, false},
+	{1, "kibichuo.okayama.jp", 3, false},
+	{1, "kumenan.okayama.jp", 3, false},
+	{1, "kurashiki.okayama.jp", 3, false},
+	{1, "maniwa.okayama.jp", 3, false},
+	{1, "misaki.okayama.jp", 3, false},
+	{1, "nagi.okayama.jp", 3, false},
+	{1, "niimi.okayama.jp", 3, false},
+	{1, "nishiawakura.okayama.jp", 3, false},
+	{1, "okayama.okayama.jp", 3, false},
+	{1, "satosho.okayama.jp", 3, false},
+	{1, "setouchi.okayama.jp", 3, false},
+	{1, "shinjo.okayama.jp", 3, false},
+	{1, "shoo.okayama.jp", 3, false},
+	{1, "soja.okayama.jp", 3, false},
+	{1, "takahashi.okayama.jp", 3, false},
+	{1, "tamano.okayama.jp", 3, false},
+	{1, "tsuyama.okayama.jp", 3, false},
+	{1, "wake.okayama.jp", 3, false},
+	{1, "yakage.okayama.jp", 3, false},
+	{1, "aguni.okinawa.jp", 3, false},
+	{1, "ginowan.okinawa.jp", 3, false},
+	{1, "ginoza.okinawa.jp", 3, false},
+	{1, "gushikami.okinawa.jp", 3, false},
+	{1, "haebaru.okinawa.jp", 3, false},
+	{1, "higashi.okinawa.jp", 3, false},
+	{1, "hirara.okinawa.jp", 3, false},
+	{1, "iheya.okinawa.jp", 3, false},
+	{1, "ishigaki.okinawa.jp", 3, false},
+	{1, "ishikawa.okinawa.jp", 3, false},
+	{1, "itoman.okinawa.jp", 3, false},
+	{1, "izena.okinawa.jp", 3, false},
+	{1, "kadena.okinawa.jp", 3, false},
+	{1, "kin.okinawa.jp", 3, false},
+	{1, "kitadaito.okinawa.jp", 3, false},
+	{1, "kitanakagusuku.okinawa.jp", 3, false},
+	{1, "kumejima.okinawa.jp", 3, false},
+	{1, "kunigami.okinawa.jp", 3, false},
+	{1, "minamidaito.okinawa.jp", 3, false},
+	{1, "motobu.okinawa.jp", 3, false},
+	{1, "nago.okinawa.jp", 3, false},
+	{1, "naha.okinawa.jp", 3, false},
+	{1, "nakagusuku.okinawa.jp", 3, false},
+	{1, "nakijin.okinawa.jp", 3, false},
+	{1, "nanjo.okinawa.jp", 3, false},
+	{1, "nishihara.okinawa.jp", 3, false},
+	{1, "ogimi.okinawa.jp", 3, false},
+	{1, "okinawa.okinawa.jp", 3, false},
+	{1, "onna.okinawa.jp", 3, false},
+	{1, "shimoji.okinawa.jp", 3, false},
+	{1, "taketomi.okinawa.jp", 3, false},
+	{1, "tarama.okinawa.jp", 3, false},
+	{1, "tokashiki.okinawa.jp", 3, false},
+	{1, "tomigusuku.okinawa.jp", 3, false},
+	{1, "tonaki.okinawa.jp", 3, false},
+	{1, "urasoe.okinawa.jp", 3, false},
+	{1, "uruma.okinawa.jp", 3, false},
+	{1, "yaese.okinawa.jp", 3, false},
+	{1, "yomitan.okinawa.jp", 3, false},
+	{1, "yonabaru.okinawa.jp", 3, false},
+	{1, "yonaguni.okinawa.jp", 3, false},
+	{1, "zamami.okinawa.jp", 3, false},
+	{1, "abeno.osaka.jp", 3, false},
+	{1, "chihayaakasaka.osaka.jp", 3, false},
+	{1, "chuo.osaka.jp", 3, false},
+	{1, "daito.osaka.jp", 3, false},
+	{1, "fujiidera.osaka.jp", 3, false},
+	{1, "habikino.osaka.jp", 3, false},
+	{1, "hannan.osaka.jp", 3, false},
+	{1, "higashiosaka.osaka.jp", 3, false},
+	{1, "higashisumiyoshi.osaka.jp", 3, false},
+	{1, "higashiyodogawa.osaka.jp", 3, false},
+	{1, "hirakata.osaka.jp", 3, false},
+	{1, "ibaraki.osaka.jp", 3, false},
+	{1, "ikeda.osaka.jp", 3, false},
+	{1, "izumi.osaka.jp", 3, false},
+	{1, "izumiotsu.osaka.jp", 3, false},
+	{1, "izumisano.osaka.jp", 3, false},
+	{1, "kadoma.osaka.jp", 3, false},
+	{1, "kaizuka.osaka.jp", 3, false},
+	{1, "kanan.osaka.jp", 3, false},
+	{1, "kashiwara.osaka.jp", 3, false},
+	{1, "katano.osaka.jp", 3, false},
+	{1, "kawachinagano.osaka.jp", 3, false},
+	{1, "kishiwada.osaka.jp", 3, false},
+	{1, "kita.osaka.jp", 3, false},
+	{1, "kumatori.osaka.jp", 3, false},
+	{1, "matsubara.osaka.jp", 3, false},
+	{1, "minato.osaka.jp", 3, false},
+	{1, "minoh.osaka.jp", 3, false},
+	{1, "misaki.osaka.jp", 3, false},
+	{1, "moriguchi.osaka.jp", 3, false},
+	{1, "neyagawa.osaka.jp", 3, false},
+	{1, "nishi.osaka.jp", 3, false},
+	{1, "nose.osaka.jp", 3, false},
+	{1, "osakasayama.osaka.jp", 3, false},
+	{1, "sakai.osaka.jp", 3, false},
+	{1, "sayama.osaka.jp", 3, false},
+	{1, "sennan.osaka.jp", 3, false},
+	{1, "settsu.osaka.jp", 3, false},
+	{1, "shijonawate.osaka.jp", 3, false},
+	{1, "shimamoto.osaka.jp", 3, false},
+	{1, "suita.osaka.jp", 3, false},
+	{1, "tadaoka.osaka.jp", 3, false},
+	{1, "taishi.osaka.jp", 3, false},
+	{1, "tajiri.osaka.jp", 3, false},
+	{1, "takaishi.osaka.jp", 3, false},
+	{1, "takatsuki.osaka.jp", 3, false},
+	{1, "tondabayashi.osaka.jp", 3, false},
+	{1, "toyonaka.osaka.jp", 3, false},
+	{1, "toyono.osaka.jp", 3, false},
+	{1, "yao.osaka.jp", 3, false},
+	{1, "ariake.saga.jp", 3, false},
+	{1, "arita.saga.jp", 3, false},
+	{1, "fukudomi.saga.jp", 3, false},
+	{1, "genkai.saga.jp", 3, false},
+	{1, "hamatama.saga.jp", 3, false},
+	{1, "hizen.saga.jp", 3, false},
+	{1, "imari.saga.jp", 3, false},
+	{1, "kamimine.saga.jp", 3, false},
+	{1, "kanzaki.saga.jp", 3, false},
+	{1, "karatsu.saga.jp", 3, false},
+	{1, "kashima.saga.jp", 3, false},
+	{1, "kitagata.saga.jp", 3, false},
+	{1, "kitahata.saga.jp", 3, false},
+	{1, "kiyama.saga.jp", 3, false},
+	{1, "kouhoku.saga.jp", 3, false},
+	{1, "kyuragi.saga.jp", 3, false},
+	{1, "nishiarita.saga.jp", 3, false},
+	{1, "ogi.saga.jp", 3, false},
+	{1, "omachi.saga.jp", 3, false},
+	{1, "ouchi.saga.jp", 3, false},
+	{1, "saga.saga.jp", 3, false},
+	{1, "shiroishi.saga.jp", 3, false},
+	{1, "taku.saga.jp", 3, false},
+	{1, "tara.saga.jp", 3, false},
+	{1, "tosu.saga.jp", 3, false},
+	{1, "yoshinogari.saga.jp", 3, false},
+	{1, "arakawa.saitama.jp", 3, false},
+	{1, "asaka.saitama.jp", 3, false},
+	{1, "chichibu.saitama.jp", 3, false},
+	{1, "fujimi.saitama.jp", 3, false},
+	{1, "fujimino.saitama.jp", 3, false},
+	{1, "fukaya.saitama.jp", 3, false},
+	{1, "hanno.saitama.jp", 3, false},
+	{1, "hanyu.saitama.jp", 3, false},
+	{1, "hasuda.saitama.jp", 3, false},
+	{1, "hatogaya.saitama.jp", 3, false},
+	{1, "hatoyama.saitama.jp", 3, false},
+	{1, "hidaka.saitama.jp", 3, false},
+	{1, "higashichichibu.saitama.jp", 3, false},
+	{1, "higashimatsuyama.saitama.jp", 3, false},
+	{1, "honjo.saitama.jp", 3, false},
+	{1, "ina.saitama.jp", 3, false},
+	{1, "iruma.saitama.jp", 3, false},
+	{1, "iwatsuki.saitama.jp", 3, false},
+	{1, "kamiizumi.saitama.jp", 3, false},
+	{1, "kamikawa.saitama.jp", 3, false},
+	{1, "kamisato.saitama.jp", 3, false},
+	{1, "kasukabe.saitama.jp", 3, false},
+	{1, "kawagoe.saitama.jp", 3, false},
+	{1, "kawaguchi.saitama.jp", 3, false},
+	{1, "kawajima.saitama.jp", 3, false},
+	{1, "kazo.saitama.jp", 3, false},
+	{1, "kitamoto.saitama.jp", 3, false},
+	{1, "koshigaya.saitama.jp", 3, false},
+	{1, "kounosu.saitama.jp", 3, false},
+	{1, "kuki.saitama.jp", 3, false},
+	{1, "kumagaya.saitama.jp", 3, false},
+	{1, "matsubushi.saitama.jp", 3, false},
+	{1, "minano.saitama.jp", 3, false},
+	{1, "misato.saitama.jp", 3, false},
+	{1, "miyashiro.saitama.jp", 3, false},
+	{1, "miyoshi.saitama.jp", 3, false},
+	{1, "moroyama.saitama.jp", 3, false},
+	{1, "nagatoro.saitama.jp", 3, false},
+	{1, "namegawa.saitama.jp", 3, false},
+	{1, "niiza.saitama.jp", 3, false},
+	{1, "ogano.saitama.jp", 3, false},
+	{1, "ogawa.saitama.jp", 3, false},
+	{1, "ogose.saitama.jp", 3, false},
+	{1, "okegawa.saitama.jp", 3, false},
+	{1, "omiya.saitama.jp", 3, false},
+	{1, "otaki.saitama.jp", 3, false},
+	{1, "ranzan.saitama.jp", 3, false},
+	{1, "ryokami.saitama.jp", 3, false},
+	{1, "saitama.saitama.jp", 3, false},
+	{1, "sakado.saitama.jp", 3, false},
+	{1, "satte.saitama.jp", 3, false},
+	{1, "sayama.saitama.jp", 3, false},
+	{1, "shiki.saitama.jp", 3, false},
+	{1, "shiraoka.saitama.jp", 3, false},
+	{1, "soka.saitama.jp", 3, false},
+	{1, "sugito.saitama.jp", 3, false},
+	{1, "toda.saitama.jp", 3, false},
+	{1, "tokigawa.saitama.jp", 3, false},
+	{1, "tokorozawa.saitama.jp", 3, false},
+	{1, "tsurugashima.saitama.jp", 3, false},
+	{1, "urawa.saitama.jp", 3, false},
+	{1, "warabi.saitama.jp", 3, false},
+	{1, "yashio.saitama.jp", 3, false},
+	{1, "yokoze.saitama.jp", 3, false},
+	{1, "yono.saitama.jp", 3, false},
+	{1, "yorii.saitama.jp", 3, false},
+	{1, "yoshida.saitama.jp", 3, false},
+	{1, "yoshikawa.saitama.jp", 3, false},
+	{1, "yoshimi.saitama.jp", 3, false},
+	{1, "aisho.shiga.jp", 3, false},
+	{1, "gamo.shiga.jp", 3, false},
+	{1, "higashiomi.shiga.jp", 3, false},
+	{1, "hikone.shiga.jp", 3, false},
+	{1, "koka.shiga.jp", 3, false},
+	{1, "konan.shiga.jp", 3, false},
+	{1, "kosei.shiga.jp", 3, false},
+	{1, "koto.shiga.jp", 3, false},
+	{1, "kusatsu.shiga.jp", 3, false},
+	{1, "maibara.shiga.jp", 3, false},
+	{1, "moriyama.shiga.jp", 3, false},
+	{1, "nagahama.shiga.jp", 3, false},
+	{1, "nishiazai.shiga.jp", 3, false},
+	{1, "notogawa.shiga.jp", 3, false},
+	{1, "omihachiman.shiga.jp", 3, false},
+	{1, "otsu.shiga.jp", 3, false},
+	{1, "ritto.shiga.jp", 3, false},
+	{1, "ryuoh.shiga.jp", 3, false},
+	{1, "takashima.shiga.jp", 3, false},
+	{1, "takatsuki.shiga.jp", 3, false},
+	{1, "torahime.shiga.jp", 3, false},
+	{1, "toyosato.shiga.jp", 3, false},
+	{1, "yasu.shiga.jp", 3, false},
+	{1, "akagi.shimane.jp", 3, false},
+	{1, "ama.shimane.jp", 3, false},
+	{1, "gotsu.shimane.jp", 3, false},
+	{1, "hamada.shimane.jp", 3, false},
+	{1, "higashiizumo.shimane.jp", 3, false},
+	{1, "hikawa.shimane.jp", 3, false},
+	{1, "hikimi.shimane.jp", 3, false},
+	{1, "izumo.shimane.jp", 3, false},
+	{1, "kakinoki.shimane.jp", 3, false},
+	{1, "masuda.shimane.jp", 3, false},
+	{1, "matsue.shimane.jp", 3, false},
+	{1, "misato.shimane.jp", 3, false},
+	{1, "nishinoshima.shimane.jp", 3, false},
+	{1, "ohda.shimane.jp", 3, false},
+	{1, "okinoshima.shimane.jp", 3, false},
+	{1, "okuizumo.shimane.jp", 3, false},
+	{1, "shimane.shimane.jp", 3, false},
+	{1, "tamayu.shimane.jp", 3, false},
+	{1, "tsuwano.shimane.jp", 3, false},
+	{1, "unnan.shimane.jp", 3, false},
+	{1, "yakumo.shimane.jp", 3, false},
+	{1, "yasugi.shimane.jp", 3, false},
+	{1, "yatsuka.shimane.jp", 3, false},
+	{1, "arai.shizuoka.jp", 3, false},
+	{1, "atami.shizuoka.jp", 3, false},
+	{1, "fuji.shizuoka.jp", 3, false},
+	{1, "fujieda.shizuoka.jp", 3, false},
+	{1, "fujikawa.shizuoka.jp", 3, false},
+	{1, "fujinomiya.shizuoka.jp", 3, false},
+	{1, "fukuroi.shizuoka.jp", 3, false},
+	{1, "gotemba.shizuoka.jp", 3, false},
+	{1, "haibara.shizuoka.jp", 3, false},
+	{1, "hamamatsu.shizuoka.jp", 3, false},
+	{1, "higashiizu.shizuoka.jp", 3, false},
+	{1, "ito.shizuoka.jp", 3, false},
+	{1, "iwata.shizuoka.jp", 3, false},
+	{1, "izu.shizuoka.jp", 3, false},
+	{1, "izunokuni.shizuoka.jp", 3, false},
+	{1, "kakegawa.shizuoka.jp", 3, false},
+	{1, "kannami.shizuoka.jp", 3, false},
+	{1, "kawanehon.shizuoka.jp", 3, false},
+	{1, "kawazu.shizuoka.jp", 3, false},
+	{1, "kikugawa.shizuoka.jp", 3, false},
+	{1, "kosai.shizuoka.jp", 3, false},
+	{1, "makinohara.shizuoka.jp", 3, false},
+	{1, "matsuzaki.shizuoka.jp", 3, false},
+	{1, "minamiizu.shizuoka.jp", 3, false},
+	{1, "mishima.shizuoka.jp", 3, false},
+	{1, "morimachi.shizuoka.jp", 3, false},
+	{1, "nishiizu.shizuoka.jp", 3, false},
+	{1, "numazu.shizuoka.jp", 3, false},
+	{1, "omaezaki.shizuoka.jp", 3, false},
+	{1, "shimada.shizuoka.jp", 3, false},
+	{1, "shimizu.shizuoka.jp", 3, false},
+	{1, "shimoda.shizuoka.jp", 3, false},
+	{1, "shizuoka.shizuoka.jp", 3, false},
+	{1, "susono.shizuoka.jp", 3, false},
+	{1, "yaizu.shizuoka.jp", 3, false},
+	{1, "yoshida.shizuoka.jp", 3, false},
+	{1, "ashikaga.tochigi.jp", 3, false},
+	{1, "bato.tochigi.jp", 3, false},
+	{1, "haga.tochigi.jp", 3, false},
+	{1, "ichikai.tochigi.jp", 3, false},
+	{1, "iwafune.tochigi.jp", 3, false},
+	{1, "kaminokawa.tochigi.jp", 3, false},
+	{1, "kanuma.tochigi.jp", 3, false},
+	{1, "karasuyama.tochigi.jp", 3, false},
+	{1, "kuroiso.tochigi.jp", 3, false},
+	{1, "mashiko.tochigi.jp", 3, false},
+	{1, "mibu.tochigi.jp", 3, false},
+	{1, "moka.tochigi.jp", 3, false},
+	{1, "motegi.tochigi.jp", 3, false},
+	{1, "nasu.tochigi.jp", 3, false},
+	{1, "nasushiobara.tochigi.jp", 3, false},
+	{1, "nikko.tochigi.jp", 3, false},
+	{1, "nishikata.tochigi.jp", 3, false},
+	{1, "nogi.tochigi.jp", 3, false},
+	{1, "ohira.tochigi.jp", 3, false},
+	{1, "ohtawara.tochigi.jp", 3, false},
+	{1, "oyama.tochigi.jp", 3, false},
+	{1, "sakura.tochigi.jp", 3, false},
+	{1, "sano.tochigi.jp", 3, false},
+	{1, "shimotsuke.tochigi.jp", 3, false},
+	{1, "shioya.tochigi.jp", 3, false},
+	{1, "takanezawa.tochigi.jp", 3, false},
+	{1, "tochigi.tochigi.jp", 3, false},
+	{1, "tsuga.tochigi.jp", 3, false},
+	{1, "ujiie.tochigi.jp", 3, false},
+	{1, "utsunomiya.tochigi.jp", 3, false},
+	{1, "yaita.tochigi.jp", 3, false},
+	{1, "aizumi.tokushima.jp", 3, false},
+	{1, "anan.tokushima.jp", 3, false},
+	{1, "ichiba.tokushima.jp", 3, false},
+	{1, "itano.tokushima.jp", 3, false},
+	{1, "kainan.tokushima.jp", 3, false},
+	{1, "komatsushima.tokushima.jp", 3, false},
+	{1, "matsushige.tokushima.jp", 3, false},
+	{1, "mima.tokushima.jp", 3, false},
+	{1, "minami.tokushima.jp", 3, false},
+	{1, "miyoshi.tokushima.jp", 3, false},
+	{1, "mugi.tokushima.jp", 3, false},
+	{1, "nakagawa.tokushima.jp", 3, false},
+	{1, "naruto.tokushima.jp", 3, false},
+	{1, "sanagochi.tokushima.jp", 3, false},
+	{1, "shishikui.tokushima.jp", 3, false},
+	{1, "tokushima.tokushima.jp", 3, false},
+	{1, "wajiki.tokushima.jp", 3, false},
+	{1, "adachi.tokyo.jp", 3, false},
+	{1, "akiruno.tokyo.jp", 3, false},
+	{1, "akishima.tokyo.jp", 3, false},
+	{1, "aogashima.tokyo.jp", 3, false},
+	{1, "arakawa.tokyo.jp", 3, false},
+	{1, "bunkyo.tokyo.jp", 3, false},
+	{1, "chiyoda.tokyo.jp", 3, false},
+	{1, "chofu.tokyo.jp", 3, false},
+	{1, "chuo.tokyo.jp", 3, false},
+	{1, "edogawa.tokyo.jp", 3, false},
+	{1, "fuchu.tokyo.jp", 3, false},
+	{1, "fussa.tokyo.jp", 3, false},
+	{1, "hachijo.tokyo.jp", 3, false},
+	{1, "hachioji.tokyo.jp", 3, false},
+	{1, "hamura.tokyo.jp", 3, false},
+	{1, "higashikurume.tokyo.jp", 3, false},
+	{1, "higashimurayama.tokyo.jp", 3, false},
+	{1, "higashiyamato.tokyo.jp", 3, false},
+	{1, "hino.tokyo.jp", 3, false},
+	{1, "hinode.tokyo.jp", 3, false},
+	{1, "hinohara.tokyo.jp", 3, false},
+	{1, "inagi.tokyo.jp", 3, false},
+	{1, "itabashi.tokyo.jp", 3, false},
+	{1, "katsushika.tokyo.jp", 3, false},
+	{1, "kita.tokyo.jp", 3, false},
+	{1, "kiyose.tokyo.jp", 3, false},
+	{1, "kodaira.tokyo.jp", 3, false},
+	{1, "koganei.tokyo.jp", 3, false},
+	{1, "kokubunji.tokyo.jp", 3, false},
+	{1, "komae.tokyo.jp", 3, false},
+	{1, "koto.tokyo.jp", 3, false},
+	{1, "kouzushima.tokyo.jp", 3, false},
+	{1, "kunitachi.tokyo.jp", 3, false},
+	{1, "machida.tokyo.jp", 3, false},
+	{1, "meguro.tokyo.jp", 3, false},
+	{1, "minato.tokyo.jp", 3, false},
+	{1, "mitaka.tokyo.jp", 3, false},
+	{1, "mizuho.tokyo.jp", 3, false},
+	{1, "musashimurayama.tokyo.jp", 3, false},
+	{1, "musashino.tokyo.jp", 3, false},
+	{1, "nakano.tokyo.jp", 3, false},
+	{1, "nerima.tokyo.jp", 3, false},
+	{1, "ogasawara.tokyo.jp", 3, false},
+	{1, "okutama.tokyo.jp", 3, false},
+	{1, "ome.tokyo.jp", 3, false},
+	{1, "oshima.tokyo.jp", 3, false},
+	{1, "ota.tokyo.jp", 3, false},
+	{1, "setagaya.tokyo.jp", 3, false},
+	{1, "shibuya.tokyo.jp", 3, false},
+	{1, "shinagawa.tokyo.jp", 3, false},
+	{1, "shinjuku.tokyo.jp", 3, false},
+	{1, "suginami.tokyo.jp", 3, false},
+	{1, "sumida.tokyo.jp", 3, false},
+	{1, "tachikawa.tokyo.jp", 3, false},
+	{1, "taito.tokyo.jp", 3, false},
+	{1, "tama.tokyo.jp", 3, false},
+	{1, "toshima.tokyo.jp", 3, false},
+	{1, "chizu.tottori.jp", 3, false},
+	{1, "hino.tottori.jp", 3, false},
+	{1, "kawahara.tottori.jp", 3, false},
+	{1, "koge.tottori.jp", 3, false},
+	{1, "kotoura.tottori.jp", 3, false},
+	{1, "misasa.tottori.jp", 3, false},
+	{1, "nanbu.tottori.jp", 3, false},
+	{1, "nichinan.tottori.jp", 3, false},
+	{1, "sakaiminato.tottori.jp", 3, false},
+	{1, "tottori.tottori.jp", 3, false},
+	{1, "wakasa.tottori.jp", 3, false},
+	{1, "yazu.tottori.jp", 3, false},
+	{1, "yonago.tottori.jp", 3, false},
+	{1, "asahi.toyama.jp", 3, false},
+	{1, "fuchu.toyama.jp", 3, false},
+	{1, "fukumitsu.toyama.jp", 3, false},
+	{1, "funahashi.toyama.jp", 3, false},
+	{1, "himi.toyama.jp", 3, false},
+	{1, "imizu.toyama.jp", 3, false},
+	{1, "inami.toyama.jp", 3, false},
+	{1, "johana.toyama.jp", 3, false},
+	{1, "kamiichi.toyama.jp", 3, false},
+	{1, "kurobe.toyama.jp", 3, false},
+	{1, "nakaniikawa.toyama.jp", 3, false},
+	{1, "namerikawa.toyama.jp", 3, false},
+	{1, "nanto.toyama.jp", 3, false},
+	{1, "nyuzen.toyama.jp", 3, false},
+	{1, "oyabe.toyama.jp", 3, false},
+	{1, "taira.toyama.jp", 3, false},
+	{1, "takaoka.toyama.jp", 3, false},
+	{1, "tateyama.toyama.jp", 3, false},
+	{1, "toga.toyama.jp", 3, false},
+	{1, "tonami.toyama.jp", 3, false},
+	{1, "toyama.toyama.jp", 3, false},
+	{1, "unazuki.toyama.jp", 3, false},
+	{1, "uozu.toyama.jp", 3, false},
+	{1, "yamada.toyama.jp", 3, false},
+	{1, "arida.wakayama.jp", 3, false},
+	{1, "aridagawa.wakayama.jp", 3, false},
+	{1, "gobo.wakayama.jp", 3, false},
+	{1, "hashimoto.wakayama.jp", 3, false},
+	{1, "hidaka.wakayama.jp", 3, false},
+	{1, "hirogawa.wakayama.jp", 3, false},
+	{1, "inami.wakayama.jp", 3, false},
+	{1, "iwade.wakayama.jp", 3, false},
+	{1, "kainan.wakayama.jp", 3, false},
+	{1, "kamitonda.wakayama.jp", 3, false},
+	{1, "katsuragi.wakayama.jp", 3, false},
+	{1, "kimino.wakayama.jp", 3, false},
+	{1, "kinokawa.wakayama.jp", 3, false},
+	{1, "kitayama.wakayama.jp", 3, false},
+	{1, "koya.wakayama.jp", 3, false},
+	{1, "koza.wakayama.jp", 3, false},
+	{1, "kozagawa.wakayama.jp", 3, false},
+	{1, "kudoyama.wakayama.jp", 3, false},
+	{1, "kushimoto.wakayama.jp", 3, false},
+	{1, "mihama.wakayama.jp", 3, false},
+	{1, "misato.wakayama.jp", 3, false},
+	{1, "nachikatsuura.wakayama.jp", 3, false},
+	{1, "shingu.wakayama.jp", 3, false},
+	{1, "shirahama.wakayama.jp", 3, false},
+	{1, "taiji.wakayama.jp", 3, false},
+	{1, "tanabe.wakayama.jp", 3, false},
+	{1, "wakayama.wakayama.jp", 3, false},
+	{1, "yuasa.wakayama.jp", 3, false},
+	{1, "yura.wakayama.jp", 3, false},
+	{1, "asahi.yamagata.jp", 3, false},
+	{1, "funagata.yamagata.jp", 3, false},
+	{1, "higashine.yamagata.jp", 3, false},
+	{1, "iide.yamagata.jp", 3, false},
+	{1, "kahoku.yamagata.jp", 3, false},
+	{1, "kaminoyama.yamagata.jp", 3, false},
+	{1, "kaneyama.yamagata.jp", 3, false},
+	{1, "kawanishi.yamagata.jp", 3, false},
+	{1, "mamurogawa.yamagata.jp", 3, false},
+	{1, "mikawa.yamagata.jp", 3, false},
+	{1, "murayama.yamagata.jp", 3, false},
+	{1, "nagai.yamagata.jp", 3, false},
+	{1, "nakayama.yamagata.jp", 3, false},
+	{1, "nanyo.yamagata.jp", 3, false},
+	{1, "nishikawa.yamagata.jp", 3, false},
+	{1, "obanazawa.yamagata.jp", 3, false},
+	{1, "oe.yamagata.jp", 3, false},
+	{1, "oguni.yamagata.jp", 3, false},
+	{1, "ohkura.yamagata.jp", 3, false},
+	{1, "oishida.yamagata.jp", 3, false},
+	{1, "sagae.yamagata.jp", 3, false},
+	{1, "sakata.yamagata.jp", 3, false},
+	{1, "sakegawa.yamagata.jp", 3, false},
+	{1, "shinjo.yamagata.jp", 3, false},
+	{1, "shirataka.yamagata.jp", 3, false},
+	{1, "shonai.yamagata.jp", 3, false},
+	{1, "takahata.yamagata.jp", 3, false},
+	{1, "tendo.yamagata.jp", 3, false},
+	{1, "tozawa.yamagata.jp", 3, false},
+	{1, "tsuruoka.yamagata.jp", 3, false},
+	{1, "yamagata.yamagata.jp", 3, false},
+	{1, "yamanobe.yamagata.jp", 3, false},
+	{1, "yonezawa.yamagata.jp", 3, false},
+	{1, "yuza.yamagata.jp", 3, false},
+	{1, "abu.yamaguchi.jp", 3, false},
+	{1, "hagi.yamaguchi.jp", 3, false},
+	{1, "hikari.yamaguchi.jp", 3, false},
+	{1, "hofu.yamaguchi.jp", 3, false},
+	{1, "iwakuni.yamaguchi.jp", 3, false},
+	{1, "kudamatsu.yamaguchi.jp", 3, false},
+	{1, "mitou.yamaguchi.jp", 3, false},
+	{1, "nagato.yamaguchi.jp", 3, false},
+	{1, "oshima.yamaguchi.jp", 3, false},
+	{1, "shimonoseki.yamaguchi.jp", 3, false},
+	{1, "shunan.yamaguchi.jp", 3, false},
+	{1, "tabuse.yamaguchi.jp", 3, false},
+	{1, "tokuyama.yamaguchi.jp", 3, false},
+	{1, "toyota.yamaguchi.jp", 3, false},
+	{1, "ube.yamaguchi.jp", 3, false},
+	{1, "yuu.yamaguchi.jp", 3, false},
+	{1, "chuo.yamanashi.jp", 3, false},
+	{1, "doshi.yamanashi.jp", 3, false},
+	{1, "fuefuki.yamanashi.jp", 3, false},
+	{1, "fujikawa.yamanashi.jp", 3, false},
+	{1, "fujikawaguchiko.yamanashi.jp", 3, false},
+	{1, "fujiyoshida.yamanashi.jp", 3, false},
+	{1, "hayakawa.yamanashi.jp", 3, false},
+	{1, "hokuto.yamanashi.jp", 3, false},
+	{1, "ichikawamisato.yamanashi.jp", 3, false},
+	{1, "kai.yamanashi.jp", 3, false},
+	{1, "kofu.yamanashi.jp", 3, false},
+	{1, "koshu.yamanashi.jp", 3, false},
+	{1, "kosuge.yamanashi.jp", 3, false},
+	{1, "minami-alps.yamanashi.jp", 3, false},
+	{1, "minobu.yamanashi.jp", 3, false},
+	{1, "nakamichi.yamanashi.jp", 3, false},
+	{1, "nanbu.yamanashi.jp", 3, false},
+	{1, "narusawa.yamanashi.jp", 3, false},
+	{1, "nirasaki.yamanashi.jp", 3, false},
+	{1, "nishikatsura.yamanashi.jp", 3, false},
+	{1, "oshino.yamanashi.jp", 3, false},
+	{1, "otsuki.yamanashi.jp", 3, false},
+	{1, "showa.yamanashi.jp", 3, false},
+	{1, "tabayama.yamanashi.jp", 3, false},
+	{1, "tsuru.yamanashi.jp", 3, false},
+	{1, "uenohara.yamanashi.jp", 3, false},
+	{1, "yamanakako.yamanashi.jp", 3, false},
+	{1, "yamanashi.yamanashi.jp", 3, false},
+	{1, "ke", 1, false},
+	{1, "ac.ke", 2, false},
+	{1, "co.ke", 2, false},
+	{1, "go.ke", 2, false},
+	{1, "info.ke", 2, false},
+	{1, "me.ke", 2, false},
+	{1, "mobi.ke", 2, false},
+	{1, "ne.ke", 2, false},
+	{1, "or.ke", 2, false},
+	{1, "sc.ke", 2, false},
+	{1, "kg", 1, false},
+	{1, "org.kg", 2, false},
+	{1, "net.kg", 2, false},
+	{1, "com.kg", 2, false},
+	{1, "edu.kg", 2, false},
+	{1, "gov.kg", 2, false},
+	{1, "mil.kg", 2, false},
+	{2, "kh", 2, false},
+	{1, "ki", 1, false},
+	{1, "edu.ki", 2, false},
+	{1, "biz.ki", 2, false},
+	{1, "net.ki", 2, false},
+	{1, "org.ki", 2, false},
+	{1, "gov.ki", 2, false},
+	{1, "info.ki", 2, false},
+	{1, "com.ki", 2, false},
+	{1, "km", 1, false},
+	{1, "org.km", 2, false},
+	{1, "nom.km", 2, false},
+	{1, "gov.km", 2, false},
+	{1, "prd.km", 2, false},
+	{1, "tm.km", 2, false},
+	{1, "edu.km", 2, false},
+	{1, "mil.km", 2, false},
+	{1, "ass.km", 2, false},
+	{1, "com.km", 2, false},
+	{1, "coop.km", 2, false},
+	{1, "asso.km", 2, false},
+	{1, "presse.km", 2, false},
+	{1, "medecin.km", 2, false},
+	{1, "notaires.km", 2, false},
+	{1, "pharmaciens.km", 2, false},
+	{1, "veterinaire.km", 2, false},
+	{1, "gouv.km", 2, false},
+	{1, "kn", 1, false},
+	{1, "net.kn", 2, false},
+	{1, "org.kn", 2, false},
+	{1, "edu.kn", 2, false},
+	{1, "gov.kn", 2, false},
+	{1, "kp", 1, false},
+	{1, "com.kp", 2, false},
+	{1, "edu.kp", 2, false},
+	{1, "gov.kp", 2, false},
+	{1, "org.kp", 2, false},
+	{1, "rep.kp", 2, false},
+	{1, "tra.kp", 2, false},
+	{1, "kr", 1, false},
+	{1, "ac.kr", 2, false},
+	{1, "co.kr", 2, false},
+	{1, "es.kr", 2, false},
+	{1, "go.kr", 2, false},
+	{1, "hs.kr", 2, false},
+	{1, "kg.kr", 2, false},
+	{1, "mil.kr", 2, false},
+	{1, "ms.kr", 2, false},
+	{1, "ne.kr", 2, false},
+	{1, "or.kr", 2, false},
+	{1, "pe.kr", 2, false},
+	{1, "re.kr", 2, false},
+	{1, "sc.kr", 2, false},
+	{1, "busan.kr", 2, false},
+	{1, "chungbuk.kr", 2, false},
+	{1, "chungnam.kr", 2, false},
+	{1, "daegu.kr", 2, false},
+	{1, "daejeon.kr", 2, false},
+	{1, "gangwon.kr", 2, false},
+	{1, "gwangju.kr", 2, false},
+	{1, "gyeongbuk.kr", 2, false},
+	{1, "gyeonggi.kr", 2, false},
+	{1, "gyeongnam.kr", 2, false},
+	{1, "incheon.kr", 2, false},
+	{1, "jeju.kr", 2, false},
+	{1, "jeonbuk.kr", 2, false},
+	{1, "jeonnam.kr", 2, false},
+	{1, "seoul.kr", 2, false},
+	{1, "ulsan.kr", 2, false},
+	{1, "kw", 1, false},
+	{1, "com.kw", 2, false},
+	{1, "edu.kw", 2, false},
+	{1, "emb.kw", 2, false},
+	{1, "gov.kw", 2, false},
+	{1, "ind.kw", 2, false},
+	{1, "net.kw", 2, false},
+	{1, "org.kw", 2, false},
+	{1, "ky", 1, false},
+	{1, "edu.ky", 2, false},
+	{1, "gov.ky", 2, false},
+	{1, "com.ky", 2, false},
+	{1, "org.ky", 2, false},
+	{1, "net.ky", 2, false},
+	{1, "kz", 1, false},
+	{1, "org.kz", 2, false},
+	{1, "edu.kz", 2, false},
+	{1, "net.kz", 2, false},
+	{1, "gov.kz", 2, false},
+	{1, "mil.kz", 2, false},
+	{1, "com.kz", 2, false},
+	{1, "la", 1, false},
+	{1, "int.la", 2, false},
+	{1, "net.la", 2, false},
+	{1, "info.la", 2, false},
+	{1, "edu.la", 2, false},
+	{1, "gov.la", 2, false},
+	{1, "per.la", 2, false},
+	{1, "com.la", 2, false},
+	{1, "org.la", 2, false},
+	{1, "lb", 1, false},
+	{1, "com.lb", 2, false},
+	{1, "edu.lb", 2, false},
+	{1, "gov.lb", 2, false},
+	{1, "net.lb", 2, false},
+	{1, "org.lb", 2, false},
+	{1, "lc", 1, false},
+	{1, "com.lc", 2, false},
+	{1, "net.lc", 2, false},
+	{1, "co.lc", 2, false},
+	{1, "org.lc", 2, false},
+	{1, "edu.lc", 2, false},
+	{1, "gov.lc", 2, false},
+	{1, "li", 1, false},
+	{1, "lk", 1, false},
+	{1, "gov.lk", 2, false},
+	{1, "sch.lk", 2, false},
+	{1, "net.lk", 2, false},
+	{1, "int.lk", 2, false},
+	{1, "com.lk", 2, false},
+	{1, "org.lk", 2, false},
+	{1, "edu.lk", 2, false},
+	{1, "ngo.lk", 2, false},
+	{1, "soc.lk", 2, false},
+	{1, "web.lk", 2, false},
+	{1, "ltd.lk", 2, false},
+	{1, "assn.lk", 2, false},
+	{1, "grp.lk", 2, false},
+	{1, "hotel.lk", 2, false},
+	{1, "ac.lk", 2, false},
+	{1, "lr", 1, false},
+	{1, "com.lr", 2, false},
+	{1, "edu.lr", 2, false},
+	{1, "gov.lr", 2, false},
+	{1, "org.lr", 2, false},
+	{1, "net.lr", 2, false},
+	{1, "ls", 1, false},
+	{1, "ac.ls", 2, false},
+	{1, "biz.ls", 2, false},
+	{1, "co.ls", 2, false},
+	{1, "edu.ls", 2, false},
+	{1, "gov.ls", 2, false},
+	{1, "info.ls", 2, false},
+	{1, "net.ls", 2, false},
+	{1, "org.ls", 2, false},
+	{1, "sc.ls", 2, false},
+	{1, "lt", 1, false},
+	{1, "gov.lt", 2, false},
+	{1, "lu", 1, false},
+	{1, "lv", 1, false},
+	{1, "com.lv", 2, false},
+	{1, "edu.lv", 2, false},
+	{1, "gov.lv", 2, false},
+	{1, "org.lv", 2, false},
+	{1, "mil.lv", 2, false},
+	{1, "id.lv", 2, false},
+	{1, "net.lv", 2, false},
+	{1, "asn.lv", 2, false},
+	{1, "conf.lv", 2, false},
+	{1, "ly", 1, false},
+	{1, "com.ly", 2, false},
+	{1, "net.ly", 2, false},
+	{1, "gov.ly", 2, false},
+	{1, "plc.ly", 2, false},
+	{1, "edu.ly", 2, false},
+	{1, "sch.ly", 2, false},
+	{1, "med.ly", 2, false},
+	{1, "org.ly", 2, false},
+	{1, "id.ly", 2, false},
+	{1, "ma", 1, false},
+	{1, "co.ma", 2, false},
+	{1, "net.ma", 2, false},
+	{1, "gov.ma", 2, false},
+	{1, "org.ma", 2, false},
+	{1, "ac.ma", 2, false},
+	{1, "press.ma", 2, false},
+	{1, "mc", 1, false},
+	{1, "tm.mc", 2, false},
+	{1, "asso.mc", 2, false},
+	{1, "md", 1, false},
+	{1, "me", 1, false},
+	{1, "co.me", 2, false},
+	{1, "net.me", 2, false},
+	{1, "org.me", 2, false},
+	{1, "edu.me", 2, false},
+	{1, "ac.me", 2, false},
+	{1, "gov.me", 2, false},
+	{1, "its.me", 2, false},
+	{1, "priv.me", 2, false},
+	{1, "mg", 1, false},
+	{1, "org.mg", 2, false},
+	{1, "nom.mg", 2, false},
+	{1, "gov.mg", 2, false},
+	{1, "prd.mg", 2, false},
+	{1, "tm.mg", 2, false},
+	{1, "edu.mg", 2, false},
+	{1, "mil.mg", 2, false},
+	{1, "com.mg", 2, false},
+	{1, "co.mg", 2, false},
+	{1, "mh", 1, false},
+	{1, "mil", 1, false},
+	{1, "mk", 1, false},
+	{1, "com.mk", 2, false},
+	{1, "org.mk", 2, false},
+	{1, "net.mk", 2, false},
+	{1, "edu.mk", 2, false},
+	{1, "gov.mk", 2, false},
+	{1, "inf.mk", 2, false},
+	{1, "name.mk", 2, false},
+	{1, "ml", 1, false},
+	{1, "com.ml", 2, false},
+	{1, "edu.ml", 2, false},
+	{1, "gouv.ml", 2, false},
+	{1, "gov.ml", 2, false},
+	{1, "net.ml", 2, false},
+	{1, "org.ml", 2, false},
+	{1, "presse.ml", 2, false},
+	{2, "mm", 2, false},
+	{1, "mn", 1, false},
+	{1, "gov.mn", 2, false},
+	{1, "edu.mn", 2, false},
+	{1, "org.mn", 2, false},
+	{1, "mo", 1, false},
+	{1, "com.mo", 2, false},
+	{1, "net.mo", 2, false},
+	{1, "org.mo", 2, false},
+	{1, "edu.mo", 2, false},
+	{1, "gov.mo", 2, false},
+	{1, "mobi", 1, false},
+	{1, "mp", 1, false},
+	{1, "mq", 1, false},
+	{1, "mr", 1, false},
+	{1, "gov.mr", 2, false},
+	{1, "ms", 1, false},
+	{1, "com.ms", 2, false},
+	{1, "edu.ms", 2, false},
+	{1, "gov.ms", 2, false},
+	{1, "net.ms", 2, false},
+	{1, "org.ms", 2, false},
+	{1, "mt", 1, false},
+	{1, "com.mt", 2, false},
+	{1, "edu.mt", 2, false},
+	{1, "net.mt", 2, false},
+	{1, "org.mt", 2, false},
+	{1, "mu", 1, false},
+	{1, "com.mu", 2, false},
+	{1, "net.mu", 2, false},
+	{1, "org.mu", 2, false},
+	{1, "gov.mu", 2, false},
+	{1, "ac.mu", 2, false},
+	{1, "co.mu", 2, false},
+	{1, "or.mu", 2, false},
+	{1, "museum", 1, false},
+	{1, "academy.museum", 2, false},
+	{1, "agriculture.museum", 2, false},
+	{1, "air.museum", 2, false},
+	{1, "airguard.museum", 2, false},
+	{1, "alabama.museum", 2, false},
+	{1, "alaska.museum", 2, false},
+	{1, "amber.museum", 2, false},
+	{1, "ambulance.museum", 2, false},
+	{1, "american.museum", 2, false},
+	{1, "americana.museum", 2, false},
+	{1, "americanantiques.museum", 2, false},
+	{1, "americanart.museum", 2, false},
+	{1, "amsterdam.museum", 2, false},
+	{1, "and.museum", 2, false},
+	{1, "annefrank.museum", 2, false},
+	{1, "anthro.museum", 2, false},
+	{1, "anthropology.museum", 2, false},
+	{1, "antiques.museum", 2, false},
+	{1, "aquarium.museum", 2, false},
+	{1, "arboretum.museum", 2, false},
+	{1, "archaeological.museum", 2, false},
+	{1, "archaeology.museum", 2, false},
+	{1, "architecture.museum", 2, false},
+	{1, "art.museum", 2, false},
+	{1, "artanddesign.museum", 2, false},
+	{1, "artcenter.museum", 2, false},
+	{1, "artdeco.museum", 2, false},
+	{1, "arteducation.museum", 2, false},
+	{1, "artgallery.museum", 2, false},
+	{1, "arts.museum", 2, false},
+	{1, "artsandcrafts.museum", 2, false},
+	{1, "asmatart.museum", 2, false},
+	{1, "assassination.museum", 2, false},
+	{1, "assisi.museum", 2, false},
+	{1, "association.museum", 2, false},
+	{1, "astronomy.museum", 2, false},
+	{1, "atlanta.museum", 2, false},
+	{1, "austin.museum", 2, false},
+	{1, "australia.museum", 2, false},
+	{1, "automotive.museum", 2, false},
+	{1, "aviation.museum", 2, false},
+	{1, "axis.museum", 2, false},
+	{1, "badajoz.museum", 2, false},
+	{1, "baghdad.museum", 2, false},
+	{1, "bahn.museum", 2, false},
+	{1, "bale.museum", 2, false},
+	{1, "baltimore.museum", 2, false},
+	{1, "barcelona.museum", 2, false},
+	{1, "baseball.museum", 2, false},
+	{1, "basel.museum", 2, false},
+	{1, "baths.museum", 2, false},
+	{1, "bauern.museum", 2, false},
+	{1, "beauxarts.museum", 2, false},
+	{1, "beeldengeluid.museum", 2, false},
+	{1, "bellevue.museum", 2, false},
+	{1, "bergbau.museum", 2, false},
+	{1, "berkeley.museum", 2, false},
+	{1, "berlin.museum", 2, false},
+	{1, "bern.museum", 2, false},
+	{1, "bible.museum", 2, false},
+	{1, "bilbao.museum", 2, false},
+	{1, "bill.museum", 2, false},
+	{1, "birdart.museum", 2, false},
+	{1, "birthplace.museum", 2, false},
+	{1, "bonn.museum", 2, false},
+	{1, "boston.museum", 2, false},
+	{1, "botanical.museum", 2, false},
+	{1, "botanicalgarden.museum", 2, false},
+	{1, "botanicgarden.museum", 2, false},
+	{1, "botany.museum", 2, false},
+	{1, "brandywinevalley.museum", 2, false},
+	{1, "brasil.museum", 2, false},
+	{1, "bristol.museum", 2, false},
+	{1, "british.museum", 2, false},
+	{1, "britishcolumbia.museum", 2, false},
+	{1, "broadcast.museum", 2, false},
+	{1, "brunel.museum", 2, false},
+	{1, "brussel.museum", 2, false},
+	{1, "brussels.museum", 2, false},
+	{1, "bruxelles.museum", 2, false},
+	{1, "building.museum", 2, false},
+	{1, "burghof.museum", 2, false},
+	{1, "bus.museum", 2, false},
+	{1, "bushey.museum", 2, false},
+	{1, "cadaques.museum", 2, false},
+	{1, "california.museum", 2, false},
+	{1, "cambridge.museum", 2, false},
+	{1, "can.museum", 2, false},
+	{1, "canada.museum", 2, false},
+	{1, "capebreton.museum", 2, false},
+	{1, "carrier.museum", 2, false},
+	{1, "cartoonart.museum", 2, false},
+	{1, "casadelamoneda.museum", 2, false},
+	{1, "castle.museum", 2, false},
+	{1, "castres.museum", 2, false},
+	{1, "celtic.museum", 2, false},
+	{1, "center.museum", 2, false},
+	{1, "chattanooga.museum", 2, false},
+	{1, "cheltenham.museum", 2, false},
+	{1, "chesapeakebay.museum", 2, false},
+	{1, "chicago.museum", 2, false},
+	{1, "children.museum", 2, false},
+	{1, "childrens.museum", 2, false},
+	{1, "childrensgarden.museum", 2, false},
+	{1, "chiropractic.museum", 2, false},
+	{1, "chocolate.museum", 2, false},
+	{1, "christiansburg.museum", 2, false},
+	{1, "cincinnati.museum", 2, false},
+	{1, "cinema.museum", 2, false},
+	{1, "circus.museum", 2, false},
+	{1, "civilisation.museum", 2, false},
+	{1, "civilization.museum", 2, false},
+	{1, "civilwar.museum", 2, false},
+	{1, "clinton.museum", 2, false},
+	{1, "clock.museum", 2, false},
+	{1, "coal.museum", 2, false},
+	{1, "coastaldefence.museum", 2, false},
+	{1, "cody.museum", 2, false},
+	{1, "coldwar.museum", 2, false},
+	{1, "collection.museum", 2, false},
+	{1, "colonialwilliamsburg.museum", 2, false},
+	{1, "coloradoplateau.museum", 2, false},
+	{1, "columbia.museum", 2, false},
+	{1, "columbus.museum", 2, false},
+	{1, "communication.museum", 2, false},
+	{1, "communications.museum", 2, false},
+	{1, "community.museum", 2, false},
+	{1, "computer.museum", 2, false},
+	{1, "computerhistory.museum", 2, false},
+	{1, "xn--comunicaes-v6a2o.museum", 2, false},
+	{1, "contemporary.museum", 2, false},
+	{1, "contemporaryart.museum", 2, false},
+	{1, "convent.museum", 2, false},
+	{1, "copenhagen.museum", 2, false},
+	{1, "corporation.museum", 2, false},
+	{1, "xn--correios-e-telecomunicaes-ghc29a.museum", 2, false},
+	{1, "corvette.museum", 2, false},
+	{1, "costume.museum", 2, false},
+	{1, "countryestate.museum", 2, false},
+	{1, "county.museum", 2, false},
+	{1, "crafts.museum", 2, false},
+	{1, "cranbrook.museum", 2, false},
+	{1, "creation.museum", 2, false},
+	{1, "cultural.museum", 2, false},
+	{1, "culturalcenter.museum", 2, false},
+	{1, "culture.museum", 2, false},
+	{1, "cyber.museum", 2, false},
+	{1, "cymru.museum", 2, false},
+	{1, "dali.museum", 2, false},
+	{1, "dallas.museum", 2, false},
+	{1, "database.museum", 2, false},
+	{1, "ddr.museum", 2, false},
+	{1, "decorativearts.museum", 2, false},
+	{1, "delaware.museum", 2, false},
+	{1, "delmenhorst.museum", 2, false},
+	{1, "denmark.museum", 2, false},
+	{1, "depot.museum", 2, false},
+	{1, "design.museum", 2, false},
+	{1, "detroit.museum", 2, false},
+	{1, "dinosaur.museum", 2, false},
+	{1, "discovery.museum", 2, false},
+	{1, "dolls.museum", 2, false},
+	{1, "donostia.museum", 2, false},
+	{1, "durham.museum", 2, false},
+	{1, "eastafrica.museum", 2, false},
+	{1, "eastcoast.museum", 2, false},
+	{1, "education.museum", 2, false},
+	{1, "educational.museum", 2, false},
+	{1, "egyptian.museum", 2, false},
+	{1, "eisenbahn.museum", 2, false},
+	{1, "elburg.museum", 2, false},
+	{1, "elvendrell.museum", 2, false},
+	{1, "embroidery.museum", 2, false},
+	{1, "encyclopedic.museum", 2, false},
+	{1, "england.museum", 2, false},
+	{1, "entomology.museum", 2, false},
+	{1, "environment.museum", 2, false},
+	{1, "environmentalconservation.museum", 2, false},
+	{1, "epilepsy.museum", 2, false},
+	{1, "essex.museum", 2, false},
+	{1, "estate.museum", 2, false},
+	{1, "ethnology.museum", 2, false},
+	{1, "exeter.museum", 2, false},
+	{1, "exhibition.museum", 2, false},
+	{1, "family.museum", 2, false},
+	{1, "farm.museum", 2, false},
+	{1, "farmequipment.museum", 2, false},
+	{1, "farmers.museum", 2, false},
+	{1, "farmstead.museum", 2, false},
+	{1, "field.museum", 2, false},
+	{1, "figueres.museum", 2, false},
+	{1, "filatelia.museum", 2, false},
+	{1, "film.museum", 2, false},
+	{1, "fineart.museum", 2, false},
+	{1, "finearts.museum", 2, false},
+	{1, "finland.museum", 2, false},
+	{1, "flanders.museum", 2, false},
+	{1, "florida.museum", 2, false},
+	{1, "force.museum", 2, false},
+	{1, "fortmissoula.museum", 2, false},
+	{1, "fortworth.museum", 2, false},
+	{1, "foundation.museum", 2, false},
+	{1, "francaise.museum", 2, false},
+	{1, "frankfurt.museum", 2, false},
+	{1, "franziskaner.museum", 2, false},
+	{1, "freemasonry.museum", 2, false},
+	{1, "freiburg.museum", 2, false},
+	{1, "fribourg.museum", 2, false},
+	{1, "frog.museum", 2, false},
+	{1, "fundacio.museum", 2, false},
+	{1, "furniture.museum", 2, false},
+	{1, "gallery.museum", 2, false},
+	{1, "garden.museum", 2, false},
+	{1, "gateway.museum", 2, false},
+	{1, "geelvinck.museum", 2, false},
+	{1, "gemological.museum", 2, false},
+	{1, "geology.museum", 2, false},
+	{1, "georgia.museum", 2, false},
+	{1, "giessen.museum", 2, false},
+	{1, "glas.museum", 2, false},
+	{1, "glass.museum", 2, false},
+	{1, "gorge.museum", 2, false},
+	{1, "grandrapids.museum", 2, false},
+	{1, "graz.museum", 2, false},
+	{1, "guernsey.museum", 2, false},
+	{1, "halloffame.museum", 2, false},
+	{1, "hamburg.museum", 2, false},
+	{1, "handson.museum", 2, false},
+	{1, "harvestcelebration.museum", 2, false},
+	{1, "hawaii.museum", 2, false},
+	{1, "health.museum", 2, false},
+	{1, "heimatunduhren.museum", 2, false},
+	{1, "hellas.museum", 2, false},
+	{1, "helsinki.museum", 2, false},
+	{1, "hembygdsforbund.museum", 2, false},
+	{1, "heritage.museum", 2, false},
+	{1, "histoire.museum", 2, false},
+	{1, "historical.museum", 2, false},
+	{1, "historicalsociety.museum", 2, false},
+	{1, "historichouses.museum", 2, false},
+	{1, "historisch.museum", 2, false},
+	{1, "historisches.museum", 2, false},
+	{1, "history.museum", 2, false},
+	{1, "historyofscience.museum", 2, false},
+	{1, "horology.museum", 2, false},
+	{1, "house.museum", 2, false},
+	{1, "humanities.museum", 2, false},
+	{1, "illustration.museum", 2, false},
+	{1, "imageandsound.museum", 2, false},
+	{1, "indian.museum", 2, false},
+	{1, "indiana.museum", 2, false},
+	{1, "indianapolis.museum", 2, false},
+	{1, "indianmarket.museum", 2, false},
+	{1, "intelligence.museum", 2, false},
+	{1, "interactive.museum", 2, false},
+	{1, "iraq.museum", 2, false},
+	{1, "iron.museum", 2, false},
+	{1, "isleofman.museum", 2, false},
+	{1, "jamison.museum", 2, false},
+	{1, "jefferson.museum", 2, false},
+	{1, "jerusalem.museum", 2, false},
+	{1, "jewelry.museum", 2, false},
+	{1, "jewish.museum", 2, false},
+	{1, "jewishart.museum", 2, false},
+	{1, "jfk.museum", 2, false},
+	{1, "journalism.museum", 2, false},
+	{1, "judaica.museum", 2, false},
+	{1, "judygarland.museum", 2, false},
+	{1, "juedisches.museum", 2, false},
+	{1, "juif.museum", 2, false},
+	{1, "karate.museum", 2, false},
+	{1, "karikatur.museum", 2, false},
+	{1, "kids.museum", 2, false},
+	{1, "koebenhavn.museum", 2, false},
+	{1, "koeln.museum", 2, false},
+	{1, "kunst.museum", 2, false},
+	{1, "kunstsammlung.museum", 2, false},
+	{1, "kunstunddesign.museum", 2, false},
+	{1, "labor.museum", 2, false},
+	{1, "labour.museum", 2, false},
+	{1, "lajolla.museum", 2, false},
+	{1, "lancashire.museum", 2, false},
+	{1, "landes.museum", 2, false},
+	{1, "lans.museum", 2, false},
+	{1, "xn--lns-qla.museum", 2, false},
+	{1, "larsson.museum", 2, false},
+	{1, "lewismiller.museum", 2, false},
+	{1, "lincoln.museum", 2, false},
+	{1, "linz.museum", 2, false},
+	{1, "living.museum", 2, false},
+	{1, "livinghistory.museum", 2, false},
+	{1, "localhistory.museum", 2, false},
+	{1, "london.museum", 2, false},
+	{1, "losangeles.museum", 2, false},
+	{1, "louvre.museum", 2, false},
+	{1, "loyalist.museum", 2, false},
+	{1, "lucerne.museum", 2, false},
+	{1, "luxembourg.museum", 2, false},
+	{1, "luzern.museum", 2, false},
+	{1, "mad.museum", 2, false},
+	{1, "madrid.museum", 2, false},
+	{1, "mallorca.museum", 2, false},
+	{1, "manchester.museum", 2, false},
+	{1, "mansion.museum", 2, false},
+	{1, "mansions.museum", 2, false},
+	{1, "manx.museum", 2, false},
+	{1, "marburg.museum", 2, false},
+	{1, "maritime.museum", 2, false},
+	{1, "maritimo.museum", 2, false},
+	{1, "maryland.museum", 2, false},
+	{1, "marylhurst.museum", 2, false},
+	{1, "media.museum", 2, false},
+	{1, "medical.museum", 2, false},
+	{1, "medizinhistorisches.museum", 2, false},
+	{1, "meeres.museum", 2, false},
+	{1, "memorial.museum", 2, false},
+	{1, "mesaverde.museum", 2, false},
+	{1, "michigan.museum", 2, false},
+	{1, "midatlantic.museum", 2, false},
+	{1, "military.museum", 2, false},
+	{1, "mill.museum", 2, false},
+	{1, "miners.museum", 2, false},
+	{1, "mining.museum", 2, false},
+	{1, "minnesota.museum", 2, false},
+	{1, "missile.museum", 2, false},
+	{1, "missoula.museum", 2, false},
+	{1, "modern.museum", 2, false},
+	{1, "moma.museum", 2, false},
+	{1, "money.museum", 2, false},
+	{1, "monmouth.museum", 2, false},
+	{1, "monticello.museum", 2, false},
+	{1, "montreal.museum", 2, false},
+	{1, "moscow.museum", 2, false},
+	{1, "motorcycle.museum", 2, false},
+	{1, "muenchen.museum", 2, false},
+	{1, "muenster.museum", 2, false},
+	{1, "mulhouse.museum", 2, false},
+	{1, "muncie.museum", 2, false},
+	{1, "museet.museum", 2, false},
+	{1, "museumcenter.museum", 2, false},
+	{1, "museumvereniging.museum", 2, false},
+	{1, "music.museum", 2, false},
+	{1, "national.museum", 2, false},
+	{1, "nationalfirearms.museum", 2, false},
+	{1, "nationalheritage.museum", 2, false},
+	{1, "nativeamerican.museum", 2, false},
+	{1, "naturalhistory.museum", 2, false},
+	{1, "naturalhistorymuseum.museum", 2, false},
+	{1, "naturalsciences.museum", 2, false},
+	{1, "nature.museum", 2, false},
+	{1, "naturhistorisches.museum", 2, false},
+	{1, "natuurwetenschappen.museum", 2, false},
+	{1, "naumburg.museum", 2, false},
+	{1, "naval.museum", 2, false},
+	{1, "nebraska.museum", 2, false},
+	{1, "neues.museum", 2, false},
+	{1, "newhampshire.museum", 2, false},
+	{1, "newjersey.museum", 2, false},
+	{1, "newmexico.museum", 2, false},
+	{1, "newport.museum", 2, false},
+	{1, "newspaper.museum", 2, false},
+	{1, "newyork.museum", 2, false},
+	{1, "niepce.museum", 2, false},
+	{1, "norfolk.museum", 2, false},
+	{1, "north.museum", 2, false},
+	{1, "nrw.museum", 2, false},
+	{1, "nyc.museum", 2, false},
+	{1, "nyny.museum", 2, false},
+	{1, "oceanographic.museum", 2, false},
+	{1, "oceanographique.museum", 2, false},
+	{1, "omaha.museum", 2, false},
+	{1, "online.museum", 2, false},
+	{1, "ontario.museum", 2, false},
+	{1, "openair.museum", 2, false},
+	{1, "oregon.museum", 2, false},
+	{1, "oregontrail.museum", 2, false},
+	{1, "otago.museum", 2, false},
+	{1, "oxford.museum", 2, false},
+	{1, "pacific.museum", 2, false},
+	{1, "paderborn.museum", 2, false},
+	{1, "palace.museum", 2, false},
+	{1, "paleo.museum", 2, false},
+	{1, "palmsprings.museum", 2, false},
+	{1, "panama.museum", 2, false},
+	{1, "paris.museum", 2, false},
+	{1, "pasadena.museum", 2, false},
+	{1, "pharmacy.museum", 2, false},
+	{1, "philadelphia.museum", 2, false},
+	{1, "philadelphiaarea.museum", 2, false},
+	{1, "philately.museum", 2, false},
+	{1, "phoenix.museum", 2, false},
+	{1, "photography.museum", 2, false},
+	{1, "pilots.museum", 2, false},
+	{1, "pittsburgh.museum", 2, false},
+	{1, "planetarium.museum", 2, false},
+	{1, "plantation.museum", 2, false},
+	{1, "plants.museum", 2, false},
+	{1, "plaza.museum", 2, false},
+	{1, "portal.museum", 2, false},
+	{1, "portland.museum", 2, false},
+	{1, "portlligat.museum", 2, false},
+	{1, "posts-and-telecommunications.museum", 2, false},
+	{1, "preservation.museum", 2, false},
+	{1, "presidio.museum", 2, false},
+	{1, "press.museum", 2, false},
+	{1, "project.museum", 2, false},
+	{1, "public.museum", 2, false},
+	{1, "pubol.museum", 2, false},
+	{1, "quebec.museum", 2, false},
+	{1, "railroad.museum", 2, false},
+	{1, "railway.museum", 2, false},
+	{1, "research.museum", 2, false},
+	{1, "resistance.museum", 2, false},
+	{1, "riodejaneiro.museum", 2, false},
+	{1, "rochester.museum", 2, false},
+	{1, "rockart.museum", 2, false},
+	{1, "roma.museum", 2, false},
+	{1, "russia.museum", 2, false},
+	{1, "saintlouis.museum", 2, false},
+	{1, "salem.museum", 2, false},
+	{1, "salvadordali.museum", 2, false},
+	{1, "salzburg.museum", 2, false},
+	{1, "sandiego.museum", 2, false},
+	{1, "sanfrancisco.museum", 2, false},
+	{1, "santabarbara.museum", 2, false},
+	{1, "santacruz.museum", 2, false},
+	{1, "santafe.museum", 2, false},
+	{1, "saskatchewan.museum", 2, false},
+	{1, "satx.museum", 2, false},
+	{1, "savannahga.museum", 2, false},
+	{1, "schlesisches.museum", 2, false},
+	{1, "schoenbrunn.museum", 2, false},
+	{1, "schokoladen.museum", 2, false},
+	{1, "school.museum", 2, false},
+	{1, "schweiz.museum", 2, false},
+	{1, "science.museum", 2, false},
+	{1, "scienceandhistory.museum", 2, false},
+	{1, "scienceandindustry.museum", 2, false},
+	{1, "sciencecenter.museum", 2, false},
+	{1, "sciencecenters.museum", 2, false},
+	{1, "science-fiction.museum", 2, false},
+	{1, "sciencehistory.museum", 2, false},
+	{1, "sciences.museum", 2, false},
+	{1, "sciencesnaturelles.museum", 2, false},
+	{1, "scotland.museum", 2, false},
+	{1, "seaport.museum", 2, false},
+	{1, "settlement.museum", 2, false},
+	{1, "settlers.museum", 2, false},
+	{1, "shell.museum", 2, false},
+	{1, "sherbrooke.museum", 2, false},
+	{1, "sibenik.museum", 2, false},
+	{1, "silk.museum", 2, false},
+	{1, "ski.museum", 2, false},
+	{1, "skole.museum", 2, false},
+	{1, "society.museum", 2, false},
+	{1, "sologne.museum", 2, false},
+	{1, "soundandvision.museum", 2, false},
+	{1, "southcarolina.museum", 2, false},
+	{1, "southwest.museum", 2, false},
+	{1, "space.museum", 2, false},
+	{1, "spy.museum", 2, false},
+	{1, "square.museum", 2, false},
+	{1, "stadt.museum", 2, false},
+	{1, "stalbans.museum", 2, false},
+	{1, "starnberg.museum", 2, false},
+	{1, "state.museum", 2, false},
+	{1, "stateofdelaware.museum", 2, false},
+	{1, "station.museum", 2, false},
+	{1, "steam.museum", 2, false},
+	{1, "steiermark.museum", 2, false},
+	{1, "stjohn.museum", 2, false},
+	{1, "stockholm.museum", 2, false},
+	{1, "stpetersburg.museum", 2, false},
+	{1, "stuttgart.museum", 2, false},
+	{1, "suisse.museum", 2, false},
+	{1, "surgeonshall.museum", 2, false},
+	{1, "surrey.museum", 2, false},
+	{1, "svizzera.museum", 2, false},
+	{1, "sweden.museum", 2, false},
+	{1, "sydney.museum", 2, false},
+	{1, "tank.museum", 2, false},
+	{1, "tcm.museum", 2, false},
+	{1, "technology.museum", 2, false},
+	{1, "telekommunikation.museum", 2, false},
+	{1, "television.museum", 2, false},
+	{1, "texas.museum", 2, false},
+	{1, "textile.museum", 2, false},
+	{1, "theater.museum", 2, false},
+	{1, "time.museum", 2, false},
+	{1, "timekeeping.museum", 2, false},
+	{1, "topology.museum", 2, false},
+	{1, "torino.museum", 2, false},
+	{1, "touch.museum", 2, false},
+	{1, "town.museum", 2, false},
+	{1, "transport.museum", 2, false},
+	{1, "tree.museum", 2, false},
+	{1, "trolley.museum", 2, false},
+	{1, "trust.museum", 2, false},
+	{1, "trustee.museum", 2, false},
+	{1, "uhren.museum", 2, false},
+	{1, "ulm.museum", 2, false},
+	{1, "undersea.museum", 2, false},
+	{1, "university.museum", 2, false},
+	{1, "usa.museum", 2, false},
+	{1, "usantiques.museum", 2, false},
+	{1, "usarts.museum", 2, false},
+	{1, "uscountryestate.museum", 2, false},
+	{1, "usculture.museum", 2, false},
+	{1, "usdecorativearts.museum", 2, false},
+	{1, "usgarden.museum", 2, false},
+	{1, "ushistory.museum", 2, false},
+	{1, "ushuaia.museum", 2, false},
+	{1, "uslivinghistory.museum", 2, false},
+	{1, "utah.museum", 2, false},
+	{1, "uvic.museum", 2, false},
+	{1, "valley.museum", 2, false},
+	{1, "vantaa.museum", 2, false},
+	{1, "versailles.museum", 2, false},
+	{1, "viking.museum", 2, false},
+	{1, "village.museum", 2, false},
+	{1, "virginia.museum", 2, false},
+	{1, "virtual.museum", 2, false},
+	{1, "virtuel.museum", 2, false},
+	{1, "vlaanderen.museum", 2, false},
+	{1, "volkenkunde.museum", 2, false},
+	{1, "wales.museum", 2, false},
+	{1, "wallonie.museum", 2, false},
+	{1, "war.museum", 2, false},
+	{1, "washingtondc.museum", 2, false},
+	{1, "watchandclock.museum", 2, false},
+	{1, "watch-and-clock.museum", 2, false},
+	{1, "western.museum", 2, false},
+	{1, "westfalen.museum", 2, false},
+	{1, "whaling.museum", 2, false},
+	{1, "wildlife.museum", 2, false},
+	{1, "williamsburg.museum", 2, false},
+	{1, "windmill.museum", 2, false},
+	{1, "workshop.museum", 2, false},
+	{1, "york.museum", 2, false},
+	{1, "yorkshire.museum", 2, false},
+	{1, "yosemite.museum", 2, false},
+	{1, "youth.museum", 2, false},
+	{1, "zoological.museum", 2, false},
+	{1, "zoology.museum", 2, false},
+	{1, "xn--9dbhblg6di.museum", 2, false},
+	{1, "xn--h1aegh.museum", 2, false},
+	{1, "mv", 1, false},
+	{1, "aero.mv", 2, false},
+	{1, "biz.mv", 2, false},
+	{1, "com.mv", 2, false},
+	{1, "coop.mv", 2, false},
+	{1, "edu.mv", 2, false},
+	{1, "gov.mv", 2, false},
+	{1, "info.mv", 2, false},
+	{1, "int.mv", 2, false},
+	{1, "mil.mv", 2, false},
+	{1, "museum.mv", 2, false},
+	{1, "name.mv", 2, false},
+	{1, "net.mv", 2, false},
+	{1, "org.mv", 2, false},
+	{1, "pro.mv", 2, false},
+	{1, "mw", 1, false},
+	{1, "ac.mw", 2, false},
+	{1, "biz.mw", 2, false},
+	{1, "co.mw", 2, false},
+	{1, "com.mw", 2, false},
+	{1, "coop.mw", 2, false},
+	{1, "edu.mw", 2, false},
+	{1, "gov.mw", 2, false},
+	{1, "int.mw", 2, false},
+	{1, "museum.mw", 2, false},
+	{1, "net.mw", 2, false},
+	{1, "org.mw", 2, false},
+	{1, "mx", 1, false},
+	{1, "com.mx", 2, false},
+	{1, "org.mx", 2, false},
+	{1, "gob.mx", 2, false},
+	{1, "edu.mx", 2, false},
+	{1, "net.mx", 2, false},
+	{1, "my", 1, false},
+	{1, "biz.my", 2, false},
+	{1, "com.my", 2, false},
+	{1, "edu.my", 2, false},
+	{1, "gov.my", 2, false},
+	{1, "mil.my", 2, false},
+	{1, "name.my", 2, false},
+	{1, "net.my", 2, false},
+	{1, "org.my", 2, false},
+	{1, "mz", 1, false},
+	{1, "ac.mz", 2, false},
+	{1, "adv.mz", 2, false},
+	{1, "co.mz", 2, false},
+	{1, "edu.mz", 2, false},
+	{1, "gov.mz", 2, false},
+	{1, "mil.mz", 2, false},
+	{1, "net.mz", 2, false},
+	{1, "org.mz", 2, false},
+	{1, "na", 1, false},
+	{1, "info.na", 2, false},
+	{1, "pro.na", 2, false},
+	{1, "name.na", 2, false},
+	{1, "school.na", 2, false},
+	{1, "or.na", 2, false},
+	{1, "dr.na", 2, false},
+	{1, "us.na", 2, false},
+	{1, "mx.na", 2, false},
+	{1, "ca.na", 2, false},
+	{1, "in.na", 2, false},
+	{1, "cc.na", 2, false},
+	{1, "tv.na", 2, false},
+	{1, "ws.na", 2, false},
+	{1, "mobi.na", 2, false},
+	{1, "co.na", 2, false},
+	{1, "com.na", 2, false},
+	{1, "org.na", 2, false},
+	{1, "name", 1, false},
+	{1, "nc", 1, false},
+	{1, "asso.nc", 2, false},
+	{1, "nom.nc", 2, false},
+	{1, "ne", 1, false},
+	{1, "net", 1, false},
+	{1, "nf", 1, false},
+	{1, "com.nf", 2, false},
+	{1, "net.nf", 2, false},
+	{1, "per.nf", 2, false},
+	{1, "rec.nf", 2, false},
+	{1, "web.nf", 2, false},
+	{1, "arts.nf", 2, false},
+	{1, "firm.nf", 2, false},
+	{1, "info.nf", 2, false},
+	{1, "other.nf", 2, false},
+	{1, "store.nf", 2, false},
+	{1, "ng", 1, false},
+	{1, "com.ng", 2, false},
+	{1, "edu.ng", 2, false},
+	{1, "gov.ng", 2, false},
+	{1, "i.ng", 2, false},
+	{1, "mil.ng", 2, false},
+	{1, "mobi.ng", 2, false},
+	{1, "name.ng", 2, false},
+	{1, "net.ng", 2, false},
+	{1, "org.ng", 2, false},
+	{1, "sch.ng", 2, false},
+	{1, "ni", 1, false},
+	{1, "ac.ni", 2, false},
+	{1, "biz.ni", 2, false},
+	{1, "co.ni", 2, false},
+	{1, "com.ni", 2, false},
+	{1, "edu.ni", 2, false},
+	{1, "gob.ni", 2, false},
+	{1, "in.ni", 2, false},
+	{1, "info.ni", 2, false},
+	{1, "int.ni", 2, false},
+	{1, "mil.ni", 2, false},
+	{1, "net.ni", 2, false},
+	{1, "nom.ni", 2, false},
+	{1, "org.ni", 2, false},
+	{1, "web.ni", 2, false},
+	{1, "nl", 1, false},
+	{1, "no", 1, false},
+	{1, "fhs.no", 2, false},
+	{1, "vgs.no", 2, false},
+	{1, "fylkesbibl.no", 2, false},
+	{1, "folkebibl.no", 2, false},
+	{1, "museum.no", 2, false},
+	{1, "idrett.no", 2, false},
+	{1, "priv.no", 2, false},
+	{1, "mil.no", 2, false},
+	{1, "stat.no", 2, false},
+	{1, "dep.no", 2, false},
+	{1, "kommune.no", 2, false},
+	{1, "herad.no", 2, false},
+	{1, "aa.no", 2, false},
+	{1, "ah.no", 2, false},
+	{1, "bu.no", 2, false},
+	{1, "fm.no", 2, false},
+	{1, "hl.no", 2, false},
+	{1, "hm.no", 2, false},
+	{1, "jan-mayen.no", 2, false},
+	{1, "mr.no", 2, false},
+	{1, "nl.no", 2, false},
+	{1, "nt.no", 2, false},
+	{1, "of.no", 2, false},
+	{1, "ol.no", 2, false},
+	{1, "oslo.no", 2, false},
+	{1, "rl.no", 2, false},
+	{1, "sf.no", 2, false},
+	{1, "st.no", 2, false},
+	{1, "svalbard.no", 2, false},
+	{1, "tm.no", 2, false},
+	{1, "tr.no", 2, false},
+	{1, "va.no", 2, false},
+	{1, "vf.no", 2, false},
+	{1, "gs.aa.no", 3, false},
+	{1, "gs.ah.no", 3, false},
+	{1, "gs.bu.no", 3, false},
+	{1, "gs.fm.no", 3, false},
+	{1, "gs.hl.no", 3, false},
+	{1, "gs.hm.no", 3, false},
+	{1, "gs.jan-mayen.no", 3, false},
+	{1, "gs.mr.no", 3, false},
+	{1, "gs.nl.no", 3, false},
+	{1, "gs.nt.no", 3, false},
+	{1, "gs.of.no", 3, false},
+	{1, "gs.ol.no", 3, false},
+	{1, "gs.oslo.no", 3, false},
+	{1, "gs.rl.no", 3, false},
+	{1, "gs.sf.no", 3, false},
+	{1, "gs.st.no", 3, false},
+	{1, "gs.svalbard.no", 3, false},
+	{1, "gs.tm.no", 3, false},
+	{1, "gs.tr.no", 3, false},
+	{1, "gs.va.no", 3, false},
+	{1, "gs.vf.no", 3, false},
+	{1, "akrehamn.no", 2, false},
+	{1, "xn--krehamn-dxa.no", 2, false},
+	{1, "algard.no", 2, false},
+	{1, "xn--lgrd-poac.no", 2, false},
+	{1, "arna.no", 2, false},
+	{1, "brumunddal.no", 2, false},
+	{1, "bryne.no", 2, false},
+	{1, "bronnoysund.no", 2, false},
+	{1, "xn--brnnysund-m8ac.no", 2, false},
+	{1, "drobak.no", 2, false},
+	{1, "xn--drbak-wua.no", 2, false},
+	{1, "egersund.no", 2, false},
+	{1, "fetsund.no", 2, false},
+	{1, "floro.no", 2, false},
+	{1, "xn--flor-jra.no", 2, false},
+	{1, "fredrikstad.no", 2, false},
+	{1, "hokksund.no", 2, false},
+	{1, "honefoss.no", 2, false},
+	{1, "xn--hnefoss-q1a.no", 2, false},
+	{1, "jessheim.no", 2, false},
+	{1, "jorpeland.no", 2, false},
+	{1, "xn--jrpeland-54a.no", 2, false},
+	{1, "kirkenes.no", 2, false},
+	{1, "kopervik.no", 2, false},
+	{1, "krokstadelva.no", 2, false},
+	{1, "langevag.no", 2, false},
+	{1, "xn--langevg-jxa.no", 2, false},
+	{1, "leirvik.no", 2, false},
+	{1, "mjondalen.no", 2, false},
+	{1, "xn--mjndalen-64a.no", 2, false},
+	{1, "mo-i-rana.no", 2, false},
+	{1, "mosjoen.no", 2, false},
+	{1, "xn--mosjen-eya.no", 2, false},
+	{1, "nesoddtangen.no", 2, false},
+	{1, "orkanger.no", 2, false},
+	{1, "osoyro.no", 2, false},
+	{1, "xn--osyro-wua.no", 2, false},
+	{1, "raholt.no", 2, false},
+	{1, "xn--rholt-mra.no", 2, false},
+	{1, "sandnessjoen.no", 2, false},
+	{1, "xn--sandnessjen-ogb.no", 2, false},
+	{1, "skedsmokorset.no", 2, false},
+	{1, "slattum.no", 2, false},
+	{1, "spjelkavik.no", 2, false},
+	{1, "stathelle.no", 2, false},
+	{1, "stavern.no", 2, false},
+	{1, "stjordalshalsen.no", 2, false},
+	{1, "xn--stjrdalshalsen-sqb.no", 2, false},
+	{1, "tananger.no", 2, false},
+	{1, "tranby.no", 2, false},
+	{1, "vossevangen.no", 2, false},
+	{1, "afjord.no", 2, false},
+	{1, "xn--fjord-lra.no", 2, false},
+	{1, "agdenes.no", 2, false},
+	{1, "al.no", 2, false},
+	{1, "xn--l-1fa.no", 2, false},
+	{1, "alesund.no", 2, false},
+	{1, "xn--lesund-hua.no", 2, false},
+	{1, "alstahaug.no", 2, false},
+	{1, "alta.no", 2, false},
+	{1, "xn--lt-liac.no", 2, false},
+	{1, "alaheadju.no", 2, false},
+	{1, "xn--laheadju-7ya.no", 2, false},
+	{1, "alvdal.no", 2, false},
+	{1, "amli.no", 2, false},
+	{1, "xn--mli-tla.no", 2, false},
+	{1, "amot.no", 2, false},
+	{1, "xn--mot-tla.no", 2, false},
+	{1, "andebu.no", 2, false},
+	{1, "andoy.no", 2, false},
+	{1, "xn--andy-ira.no", 2, false},
+	{1, "andasuolo.no", 2, false},
+	{1, "ardal.no", 2, false},
+	{1, "xn--rdal-poa.no", 2, false},
+	{1, "aremark.no", 2, false},
+	{1, "arendal.no", 2, false},
+	{1, "xn--s-1fa.no", 2, false},
+	{1, "aseral.no", 2, false},
+	{1, "xn--seral-lra.no", 2, false},
+	{1, "asker.no", 2, false},
+	{1, "askim.no", 2, false},
+	{1, "askvoll.no", 2, false},
+	{1, "askoy.no", 2, false},
+	{1, "xn--asky-ira.no", 2, false},
+	{1, "asnes.no", 2, false},
+	{1, "xn--snes-poa.no", 2, false},
+	{1, "audnedaln.no", 2, false},
+	{1, "aukra.no", 2, false},
+	{1, "aure.no", 2, false},
+	{1, "aurland.no", 2, false},
+	{1, "aurskog-holand.no", 2, false},
+	{1, "xn--aurskog-hland-jnb.no", 2, false},
+	{1, "austevoll.no", 2, false},
+	{1, "austrheim.no", 2, false},
+	{1, "averoy.no", 2, false},
+	{1, "xn--avery-yua.no", 2, false},
+	{1, "balestrand.no", 2, false},
+	{1, "ballangen.no", 2, false},
+	{1, "balat.no", 2, false},
+	{1, "xn--blt-elab.no", 2, false},
+	{1, "balsfjord.no", 2, false},
+	{1, "bahccavuotna.no", 2, false},
+	{1, "xn--bhccavuotna-k7a.no", 2, false},
+	{1, "bamble.no", 2, false},
+	{1, "bardu.no", 2, false},
+	{1, "beardu.no", 2, false},
+	{1, "beiarn.no", 2, false},
+	{1, "bajddar.no", 2, false},
+	{1, "xn--bjddar-pta.no", 2, false},
+	{1, "baidar.no", 2, false},
+	{1, "xn--bidr-5nac.no", 2, false},
+	{1, "berg.no", 2, false},
+	{1, "bergen.no", 2, false},
+	{1, "berlevag.no", 2, false},
+	{1, "xn--berlevg-jxa.no", 2, false},
+	{1, "bearalvahki.no", 2, false},
+	{1, "xn--bearalvhki-y4a.no", 2, false},
+	{1, "bindal.no", 2, false},
+	{1, "birkenes.no", 2, false},
+	{1, "bjarkoy.no", 2, false},
+	{1, "xn--bjarky-fya.no", 2, false},
+	{1, "bjerkreim.no", 2, false},
+	{1, "bjugn.no", 2, false},
+	{1, "bodo.no", 2, false},
+	{1, "xn--bod-2na.no", 2, false},
+	{1, "badaddja.no", 2, false},
+	{1, "xn--bdddj-mrabd.no", 2, false},
+	{1, "budejju.no", 2, false},
+	{1, "bokn.no", 2, false},
+	{1, "bremanger.no", 2, false},
+	{1, "bronnoy.no", 2, false},
+	{1, "xn--brnny-wuac.no", 2, false},
+	{1, "bygland.no", 2, false},
+	{1, "bykle.no", 2, false},
+	{1, "barum.no", 2, false},
+	{1, "xn--brum-voa.no", 2, false},
+	{1, "bo.telemark.no", 3, false},
+	{1, "xn--b-5ga.telemark.no", 3, false},
+	{1, "bo.nordland.no", 3, false},
+	{1, "xn--b-5ga.nordland.no", 3, false},
+	{1, "bievat.no", 2, false},
+	{1, "xn--bievt-0qa.no", 2, false},
+	{1, "bomlo.no", 2, false},
+	{1, "xn--bmlo-gra.no", 2, false},
+	{1, "batsfjord.no", 2, false},
+	{1, "xn--btsfjord-9za.no", 2, false},
+	{1, "bahcavuotna.no", 2, false},
+	{1, "xn--bhcavuotna-s4a.no", 2, false},
+	{1, "dovre.no", 2, false},
+	{1, "drammen.no", 2, false},
+	{1, "drangedal.no", 2, false},
+	{1, "dyroy.no", 2, false},
+	{1, "xn--dyry-ira.no", 2, false},
+	{1, "donna.no", 2, false},
+	{1, "xn--dnna-gra.no", 2, false},
+	{1, "eid.no", 2, false},
+	{1, "eidfjord.no", 2, false},
+	{1, "eidsberg.no", 2, false},
+	{1, "eidskog.no", 2, false},
+	{1, "eidsvoll.no", 2, false},
+	{1, "eigersund.no", 2, false},
+	{1, "elverum.no", 2, false},
+	{1, "enebakk.no", 2, false},
+	{1, "engerdal.no", 2, false},
+	{1, "etne.no", 2, false},
+	{1, "etnedal.no", 2, false},
+	{1, "evenes.no", 2, false},
+	{1, "evenassi.no", 2, false},
+	{1, "xn--eveni-0qa01ga.no", 2, false},
+	{1, "evje-og-hornnes.no", 2, false},
+	{1, "farsund.no", 2, false},
+	{1, "fauske.no", 2, false},
+	{1, "fuossko.no", 2, false},
+	{1, "fuoisku.no", 2, false},
+	{1, "fedje.no", 2, false},
+	{1, "fet.no", 2, false},
+	{1, "finnoy.no", 2, false},
+	{1, "xn--finny-yua.no", 2, false},
+	{1, "fitjar.no", 2, false},
+	{1, "fjaler.no", 2, false},
+	{1, "fjell.no", 2, false},
+	{1, "flakstad.no", 2, false},
+	{1, "flatanger.no", 2, false},
+	{1, "flekkefjord.no", 2, false},
+	{1, "flesberg.no", 2, false},
+	{1, "flora.no", 2, false},
+	{1, "fla.no", 2, false},
+	{1, "xn--fl-zia.no", 2, false},
+	{1, "folldal.no", 2, false},
+	{1, "forsand.no", 2, false},
+	{1, "fosnes.no", 2, false},
+	{1, "frei.no", 2, false},
+	{1, "frogn.no", 2, false},
+	{1, "froland.no", 2, false},
+	{1, "frosta.no", 2, false},
+	{1, "frana.no", 2, false},
+	{1, "xn--frna-woa.no", 2, false},
+	{1, "froya.no", 2, false},
+	{1, "xn--frya-hra.no", 2, false},
+	{1, "fusa.no", 2, false},
+	{1, "fyresdal.no", 2, false},
+	{1, "forde.no", 2, false},
+	{1, "xn--frde-gra.no", 2, false},
+	{1, "gamvik.no", 2, false},
+	{1, "gangaviika.no", 2, false},
+	{1, "xn--ggaviika-8ya47h.no", 2, false},
+	{1, "gaular.no", 2, false},
+	{1, "gausdal.no", 2, false},
+	{1, "gildeskal.no", 2, false},
+	{1, "xn--gildeskl-g0a.no", 2, false},
+	{1, "giske.no", 2, false},
+	{1, "gjemnes.no", 2, false},
+	{1, "gjerdrum.no", 2, false},
+	{1, "gjerstad.no", 2, false},
+	{1, "gjesdal.no", 2, false},
+	{1, "gjovik.no", 2, false},
+	{1, "xn--gjvik-wua.no", 2, false},
+	{1, "gloppen.no", 2, false},
+	{1, "gol.no", 2, false},
+	{1, "gran.no", 2, false},
+	{1, "grane.no", 2, false},
+	{1, "granvin.no", 2, false},
+	{1, "gratangen.no", 2, false},
+	{1, "grimstad.no", 2, false},
+	{1, "grong.no", 2, false},
+	{1, "kraanghke.no", 2, false},
+	{1, "xn--kranghke-b0a.no", 2, false},
+	{1, "grue.no", 2, false},
+	{1, "gulen.no", 2, false},
+	{1, "hadsel.no", 2, false},
+	{1, "halden.no", 2, false},
+	{1, "halsa.no", 2, false},
+	{1, "hamar.no", 2, false},
+	{1, "hamaroy.no", 2, false},
+	{1, "habmer.no", 2, false},
+	{1, "xn--hbmer-xqa.no", 2, false},
+	{1, "hapmir.no", 2, false},
+	{1, "xn--hpmir-xqa.no", 2, false},
+	{1, "hammerfest.no", 2, false},
+	{1, "hammarfeasta.no", 2, false},
+	{1, "xn--hmmrfeasta-s4ac.no", 2, false},
+	{1, "haram.no", 2, false},
+	{1, "hareid.no", 2, false},
+	{1, "harstad.no", 2, false},
+	{1, "hasvik.no", 2, false},
+	{1, "aknoluokta.no", 2, false},
+	{1, "xn--koluokta-7ya57h.no", 2, false},
+	{1, "hattfjelldal.no", 2, false},
+	{1, "aarborte.no", 2, false},
+	{1, "haugesund.no", 2, false},
+	{1, "hemne.no", 2, false},
+	{1, "hemnes.no", 2, false},
+	{1, "hemsedal.no", 2, false},
+	{1, "heroy.more-og-romsdal.no", 3, false},
+	{1, "xn--hery-ira.xn--mre-og-romsdal-qqb.no", 3, false},
+	{1, "heroy.nordland.no", 3, false},
+	{1, "xn--hery-ira.nordland.no", 3, false},
+	{1, "hitra.no", 2, false},
+	{1, "hjartdal.no", 2, false},
+	{1, "hjelmeland.no", 2, false},
+	{1, "hobol.no", 2, false},
+	{1, "xn--hobl-ira.no", 2, false},
+	{1, "hof.no", 2, false},
+	{1, "hol.no", 2, false},
+	{1, "hole.no", 2, false},
+	{1, "holmestrand.no", 2, false},
+	{1, "holtalen.no", 2, false},
+	{1, "xn--holtlen-hxa.no", 2, false},
+	{1, "hornindal.no", 2, false},
+	{1, "horten.no", 2, false},
+	{1, "hurdal.no", 2, false},
+	{1, "hurum.no", 2, false},
+	{1, "hvaler.no", 2, false},
+	{1, "hyllestad.no", 2, false},
+	{1, "hagebostad.no", 2, false},
+	{1, "xn--hgebostad-g3a.no", 2, false},
+	{1, "hoyanger.no", 2, false},
+	{1, "xn--hyanger-q1a.no", 2, false},
+	{1, "hoylandet.no", 2, false},
+	{1, "xn--hylandet-54a.no", 2, false},
+	{1, "ha.no", 2, false},
+	{1, "xn--h-2fa.no", 2, false},
+	{1, "ibestad.no", 2, false},
+	{1, "inderoy.no", 2, false},
+	{1, "xn--indery-fya.no", 2, false},
+	{1, "iveland.no", 2, false},
+	{1, "jevnaker.no", 2, false},
+	{1, "jondal.no", 2, false},
+	{1, "jolster.no", 2, false},
+	{1, "xn--jlster-bya.no", 2, false},
+	{1, "karasjok.no", 2, false},
+	{1, "karasjohka.no", 2, false},
+	{1, "xn--krjohka-hwab49j.no", 2, false},
+	{1, "karlsoy.no", 2, false},
+	{1, "galsa.no", 2, false},
+	{1, "xn--gls-elac.no", 2, false},
+	{1, "karmoy.no", 2, false},
+	{1, "xn--karmy-yua.no", 2, false},
+	{1, "kautokeino.no", 2, false},
+	{1, "guovdageaidnu.no", 2, false},
+	{1, "klepp.no", 2, false},
+	{1, "klabu.no", 2, false},
+	{1, "xn--klbu-woa.no", 2, false},
+	{1, "kongsberg.no", 2, false},
+	{1, "kongsvinger.no", 2, false},
+	{1, "kragero.no", 2, false},
+	{1, "xn--krager-gya.no", 2, false},
+	{1, "kristiansand.no", 2, false},
+	{1, "kristiansund.no", 2, false},
+	{1, "krodsherad.no", 2, false},
+	{1, "xn--krdsherad-m8a.no", 2, false},
+	{1, "kvalsund.no", 2, false},
+	{1, "rahkkeravju.no", 2, false},
+	{1, "xn--rhkkervju-01af.no", 2, false},
+	{1, "kvam.no", 2, false},
+	{1, "kvinesdal.no", 2, false},
+	{1, "kvinnherad.no", 2, false},
+	{1, "kviteseid.no", 2, false},
+	{1, "kvitsoy.no", 2, false},
+	{1, "xn--kvitsy-fya.no", 2, false},
+	{1, "kvafjord.no", 2, false},
+	{1, "xn--kvfjord-nxa.no", 2, false},
+	{1, "giehtavuoatna.no", 2, false},
+	{1, "kvanangen.no", 2, false},
+	{1, "xn--kvnangen-k0a.no", 2, false},
+	{1, "navuotna.no", 2, false},
+	{1, "xn--nvuotna-hwa.no", 2, false},
+	{1, "kafjord.no", 2, false},
+	{1, "xn--kfjord-iua.no", 2, false},
+	{1, "gaivuotna.no", 2, false},
+	{1, "xn--givuotna-8ya.no", 2, false},
+	{1, "larvik.no", 2, false},
+	{1, "lavangen.no", 2, false},
+	{1, "lavagis.no", 2, false},
+	{1, "loabat.no", 2, false},
+	{1, "xn--loabt-0qa.no", 2, false},
+	{1, "lebesby.no", 2, false},
+	{1, "davvesiida.no", 2, false},
+	{1, "leikanger.no", 2, false},
+	{1, "leirfjord.no", 2, false},
+	{1, "leka.no", 2, false},
+	{1, "leksvik.no", 2, false},
+	{1, "lenvik.no", 2, false},
+	{1, "leangaviika.no", 2, false},
+	{1, "xn--leagaviika-52b.no", 2, false},
+	{1, "lesja.no", 2, false},
+	{1, "levanger.no", 2, false},
+	{1, "lier.no", 2, false},
+	{1, "lierne.no", 2, false},
+	{1, "lillehammer.no", 2, false},
+	{1, "lillesand.no", 2, false},
+	{1, "lindesnes.no", 2, false},
+	{1, "lindas.no", 2, false},
+	{1, "xn--linds-pra.no", 2, false},
+	{1, "lom.no", 2, false},
+	{1, "loppa.no", 2, false},
+	{1, "lahppi.no", 2, false},
+	{1, "xn--lhppi-xqa.no", 2, false},
+	{1, "lund.no", 2, false},
+	{1, "lunner.no", 2, false},
+	{1, "luroy.no", 2, false},
+	{1, "xn--lury-ira.no", 2, false},
+	{1, "luster.no", 2, false},
+	{1, "lyngdal.no", 2, false},
+	{1, "lyngen.no", 2, false},
+	{1, "ivgu.no", 2, false},
+	{1, "lardal.no", 2, false},
+	{1, "lerdal.no", 2, false},
+	{1, "xn--lrdal-sra.no", 2, false},
+	{1, "lodingen.no", 2, false},
+	{1, "xn--ldingen-q1a.no", 2, false},
+	{1, "lorenskog.no", 2, false},
+	{1, "xn--lrenskog-54a.no", 2, false},
+	{1, "loten.no", 2, false},
+	{1, "xn--lten-gra.no", 2, false},
+	{1, "malvik.no", 2, false},
+	{1, "masoy.no", 2, false},
+	{1, "xn--msy-ula0h.no", 2, false},
+	{1, "muosat.no", 2, false},
+	{1, "xn--muost-0qa.no", 2, false},
+	{1, "mandal.no", 2, false},
+	{1, "marker.no", 2, false},
+	{1, "marnardal.no", 2, false},
+	{1, "masfjorden.no", 2, false},
+	{1, "meland.no", 2, false},
+	{1, "meldal.no", 2, false},
+	{1, "melhus.no", 2, false},
+	{1, "meloy.no", 2, false},
+	{1, "xn--mely-ira.no", 2, false},
+	{1, "meraker.no", 2, false},
+	{1, "xn--merker-kua.no", 2, false},
+	{1, "moareke.no", 2, false},
+	{1, "xn--moreke-jua.no", 2, false},
+	{1, "midsund.no", 2, false},
+	{1, "midtre-gauldal.no", 2, false},
+	{1, "modalen.no", 2, false},
+	{1, "modum.no", 2, false},
+	{1, "molde.no", 2, false},
+	{1, "moskenes.no", 2, false},
+	{1, "moss.no", 2, false},
+	{1, "mosvik.no", 2, false},
+	{1, "malselv.no", 2, false},
+	{1, "xn--mlselv-iua.no", 2, false},
+	{1, "malatvuopmi.no", 2, false},
+	{1, "xn--mlatvuopmi-s4a.no", 2, false},
+	{1, "namdalseid.no", 2, false},
+	{1, "aejrie.no", 2, false},
+	{1, "namsos.no", 2, false},
+	{1, "namsskogan.no", 2, false},
+	{1, "naamesjevuemie.no", 2, false},
+	{1, "xn--nmesjevuemie-tcba.no", 2, false},
+	{1, "laakesvuemie.no", 2, false},
+	{1, "nannestad.no", 2, false},
+	{1, "narvik.no", 2, false},
+	{1, "narviika.no", 2, false},
+	{1, "naustdal.no", 2, false},
+	{1, "nedre-eiker.no", 2, false},
+	{1, "nes.akershus.no", 3, false},
+	{1, "nes.buskerud.no", 3, false},
+	{1, "nesna.no", 2, false},
+	{1, "nesodden.no", 2, false},
+	{1, "nesseby.no", 2, false},
+	{1, "unjarga.no", 2, false},
+	{1, "xn--unjrga-rta.no", 2, false},
+	{1, "nesset.no", 2, false},
+	{1, "nissedal.no", 2, false},
+	{1, "nittedal.no", 2, false},
+	{1, "nord-aurdal.no", 2, false},
+	{1, "nord-fron.no", 2, false},
+	{1, "nord-odal.no", 2, false},
+	{1, "norddal.no", 2, false},
+	{1, "nordkapp.no", 2, false},
+	{1, "davvenjarga.no", 2, false},
+	{1, "xn--davvenjrga-y4a.no", 2, false},
+	{1, "nordre-land.no", 2, false},
+	{1, "nordreisa.no", 2, false},
+	{1, "raisa.no", 2, false},
+	{1, "xn--risa-5na.no", 2, false},
+	{1, "nore-og-uvdal.no", 2, false},
+	{1, "notodden.no", 2, false},
+	{1, "naroy.no", 2, false},
+	{1, "xn--nry-yla5g.no", 2, false},
+	{1, "notteroy.no", 2, false},
+	{1, "xn--nttery-byae.no", 2, false},
+	{1, "odda.no", 2, false},
+	{1, "oksnes.no", 2, false},
+	{1, "xn--ksnes-uua.no", 2, false},
+	{1, "oppdal.no", 2, false},
+	{1, "oppegard.no", 2, false},
+	{1, "xn--oppegrd-ixa.no", 2, false},
+	{1, "orkdal.no", 2, false},
+	{1, "orland.no", 2, false},
+	{1, "xn--rland-uua.no", 2, false},
+	{1, "orskog.no", 2, false},
+	{1, "xn--rskog-uua.no", 2, false},
+	{1, "orsta.no", 2, false},
+	{1, "xn--rsta-fra.no", 2, false},
+	{1, "os.hedmark.no", 3, false},
+	{1, "os.hordaland.no", 3, false},
+	{1, "osen.no", 2, false},
+	{1, "osteroy.no", 2, false},
+	{1, "xn--ostery-fya.no", 2, false},
+	{1, "ostre-toten.no", 2, false},
+	{1, "xn--stre-toten-zcb.no", 2, false},
+	{1, "overhalla.no", 2, false},
+	{1, "ovre-eiker.no", 2, false},
+	{1, "xn--vre-eiker-k8a.no", 2, false},
+	{1, "oyer.no", 2, false},
+	{1, "xn--yer-zna.no", 2, false},
+	{1, "oygarden.no", 2, false},
+	{1, "xn--ygarden-p1a.no", 2, false},
+	{1, "oystre-slidre.no", 2, false},
+	{1, "xn--ystre-slidre-ujb.no", 2, false},
+	{1, "porsanger.no", 2, false},
+	{1, "porsangu.no", 2, false},
+	{1, "xn--porsgu-sta26f.no", 2, false},
+	{1, "porsgrunn.no", 2, false},
+	{1, "radoy.no", 2, false},
+	{1, "xn--rady-ira.no", 2, false},
+	{1, "rakkestad.no", 2, false},
+	{1, "rana.no", 2, false},
+	{1, "ruovat.no", 2, false},
+	{1, "randaberg.no", 2, false},
+	{1, "rauma.no", 2, false},
+	{1, "rendalen.no", 2, false},
+	{1, "rennebu.no", 2, false},
+	{1, "rennesoy.no", 2, false},
+	{1, "xn--rennesy-v1a.no", 2, false},
+	{1, "rindal.no", 2, false},
+	{1, "ringebu.no", 2, false},
+	{1, "ringerike.no", 2, false},
+	{1, "ringsaker.no", 2, false},
+	{1, "rissa.no", 2, false},
+	{1, "risor.no", 2, false},
+	{1, "xn--risr-ira.no", 2, false},
+	{1, "roan.no", 2, false},
+	{1, "rollag.no", 2, false},
+	{1, "rygge.no", 2, false},
+	{1, "ralingen.no", 2, false},
+	{1, "xn--rlingen-mxa.no", 2, false},
+	{1, "rodoy.no", 2, false},
+	{1, "xn--rdy-0nab.no", 2, false},
+	{1, "romskog.no", 2, false},
+	{1, "xn--rmskog-bya.no", 2, false},
+	{1, "roros.no", 2, false},
+	{1, "xn--rros-gra.no", 2, false},
+	{1, "rost.no", 2, false},
+	{1, "xn--rst-0na.no", 2, false},
+	{1, "royken.no", 2, false},
+	{1, "xn--ryken-vua.no", 2, false},
+	{1, "royrvik.no", 2, false},
+	{1, "xn--ryrvik-bya.no", 2, false},
+	{1, "rade.no", 2, false},
+	{1, "xn--rde-ula.no", 2, false},
+	{1, "salangen.no", 2, false},
+	{1, "siellak.no", 2, false},
+	{1, "saltdal.no", 2, false},
+	{1, "salat.no", 2, false},
+	{1, "xn--slt-elab.no", 2, false},
+	{1, "xn--slat-5na.no", 2, false},
+	{1, "samnanger.no", 2, false},
+	{1, "sande.more-og-romsdal.no", 3, false},
+	{1, "sande.xn--mre-og-romsdal-qqb.no", 3, false},
+	{1, "sande.vestfold.no", 3, false},
+	{1, "sandefjord.no", 2, false},
+	{1, "sandnes.no", 2, false},
+	{1, "sandoy.no", 2, false},
+	{1, "xn--sandy-yua.no", 2, false},
+	{1, "sarpsborg.no", 2, false},
+	{1, "sauda.no", 2, false},
+	{1, "sauherad.no", 2, false},
+	{1, "sel.no", 2, false},
+	{1, "selbu.no", 2, false},
+	{1, "selje.no", 2, false},
+	{1, "seljord.no", 2, false},
+	{1, "sigdal.no", 2, false},
+	{1, "siljan.no", 2, false},
+	{1, "sirdal.no", 2, false},
+	{1, "skaun.no", 2, false},
+	{1, "skedsmo.no", 2, false},
+	{1, "ski.no", 2, false},
+	{1, "skien.no", 2, false},
+	{1, "skiptvet.no", 2, false},
+	{1, "skjervoy.no", 2, false},
+	{1, "xn--skjervy-v1a.no", 2, false},
+	{1, "skierva.no", 2, false},
+	{1, "xn--skierv-uta.no", 2, false},
+	{1, "skjak.no", 2, false},
+	{1, "xn--skjk-soa.no", 2, false},
+	{1, "skodje.no", 2, false},
+	{1, "skanland.no", 2, false},
+	{1, "xn--sknland-fxa.no", 2, false},
+	{1, "skanit.no", 2, false},
+	{1, "xn--sknit-yqa.no", 2, false},
+	{1, "smola.no", 2, false},
+	{1, "xn--smla-hra.no", 2, false},
+	{1, "snillfjord.no", 2, false},
+	{1, "snasa.no", 2, false},
+	{1, "xn--snsa-roa.no", 2, false},
+	{1, "snoasa.no", 2, false},
+	{1, "snaase.no", 2, false},
+	{1, "xn--snase-nra.no", 2, false},
+	{1, "sogndal.no", 2, false},
+	{1, "sokndal.no", 2, false},
+	{1, "sola.no", 2, false},
+	{1, "solund.no", 2, false},
+	{1, "songdalen.no", 2, false},
+	{1, "sortland.no", 2, false},
+	{1, "spydeberg.no", 2, false},
+	{1, "stange.no", 2, false},
+	{1, "stavanger.no", 2, false},
+	{1, "steigen.no", 2, false},
+	{1, "steinkjer.no", 2, false},
+	{1, "stjordal.no", 2, false},
+	{1, "xn--stjrdal-s1a.no", 2, false},
+	{1, "stokke.no", 2, false},
+	{1, "stor-elvdal.no", 2, false},
+	{1, "stord.no", 2, false},
+	{1, "stordal.no", 2, false},
+	{1, "storfjord.no", 2, false},
+	{1, "omasvuotna.no", 2, false},
+	{1, "strand.no", 2, false},
+	{1, "stranda.no", 2, false},
+	{1, "stryn.no", 2, false},
+	{1, "sula.no", 2, false},
+	{1, "suldal.no", 2, false},
+	{1, "sund.no", 2, false},
+	{1, "sunndal.no", 2, false},
+	{1, "surnadal.no", 2, false},
+	{1, "sveio.no", 2, false},
+	{1, "svelvik.no", 2, false},
+	{1, "sykkylven.no", 2, false},
+	{1, "sogne.no", 2, false},
+	{1, "xn--sgne-gra.no", 2, false},
+	{1, "somna.no", 2, false},
+	{1, "xn--smna-gra.no", 2, false},
+	{1, "sondre-land.no", 2, false},
+	{1, "xn--sndre-land-0cb.no", 2, false},
+	{1, "sor-aurdal.no", 2, false},
+	{1, "xn--sr-aurdal-l8a.no", 2, false},
+	{1, "sor-fron.no", 2, false},
+	{1, "xn--sr-fron-q1a.no", 2, false},
+	{1, "sor-odal.no", 2, false},
+	{1, "xn--sr-odal-q1a.no", 2, false},
+	{1, "sor-varanger.no", 2, false},
+	{1, "xn--sr-varanger-ggb.no", 2, false},
+	{1, "matta-varjjat.no", 2, false},
+	{1, "xn--mtta-vrjjat-k7af.no", 2, false},
+	{1, "sorfold.no", 2, false},
+	{1, "xn--srfold-bya.no", 2, false},
+	{1, "sorreisa.no", 2, false},
+	{1, "xn--srreisa-q1a.no", 2, false},
+	{1, "sorum.no", 2, false},
+	{1, "xn--srum-gra.no", 2, false},
+	{1, "tana.no", 2, false},
+	{1, "deatnu.no", 2, false},
+	{1, "time.no", 2, false},
+	{1, "tingvoll.no", 2, false},
+	{1, "tinn.no", 2, false},
+	{1, "tjeldsund.no", 2, false},
+	{1, "dielddanuorri.no", 2, false},
+	{1, "tjome.no", 2, false},
+	{1, "xn--tjme-hra.no", 2, false},
+	{1, "tokke.no", 2, false},
+	{1, "tolga.no", 2, false},
+	{1, "torsken.no", 2, false},
+	{1, "tranoy.no", 2, false},
+	{1, "xn--trany-yua.no", 2, false},
+	{1, "tromso.no", 2, false},
+	{1, "xn--troms-zua.no", 2, false},
+	{1, "tromsa.no", 2, false},
+	{1, "romsa.no", 2, false},
+	{1, "trondheim.no", 2, false},
+	{1, "troandin.no", 2, false},
+	{1, "trysil.no", 2, false},
+	{1, "trana.no", 2, false},
+	{1, "xn--trna-woa.no", 2, false},
+	{1, "trogstad.no", 2, false},
+	{1, "xn--trgstad-r1a.no", 2, false},
+	{1, "tvedestrand.no", 2, false},
+	{1, "tydal.no", 2, false},
+	{1, "tynset.no", 2, false},
+	{1, "tysfjord.no", 2, false},
+	{1, "divtasvuodna.no", 2, false},
+	{1, "divttasvuotna.no", 2, false},
+	{1, "tysnes.no", 2, false},
+	{1, "tysvar.no", 2, false},
+	{1, "xn--tysvr-vra.no", 2, false},
+	{1, "tonsberg.no", 2, false},
+	{1, "xn--tnsberg-q1a.no", 2, false},
+	{1, "ullensaker.no", 2, false},
+	{1, "ullensvang.no", 2, false},
+	{1, "ulvik.no", 2, false},
+	{1, "utsira.no", 2, false},
+	{1, "vadso.no", 2, false},
+	{1, "xn--vads-jra.no", 2, false},
+	{1, "cahcesuolo.no", 2, false},
+	{1, "xn--hcesuolo-7ya35b.no", 2, false},
+	{1, "vaksdal.no", 2, false},
+	{1, "valle.no", 2, false},
+	{1, "vang.no", 2, false},
+	{1, "vanylven.no", 2, false},
+	{1, "vardo.no", 2, false},
+	{1, "xn--vard-jra.no", 2, false},
+	{1, "varggat.no", 2, false},
+	{1, "xn--vrggt-xqad.no", 2, false},
+	{1, "vefsn.no", 2, false},
+	{1, "vaapste.no", 2, false},
+	{1, "vega.no", 2, false},
+	{1, "vegarshei.no", 2, false},
+	{1, "xn--vegrshei-c0a.no", 2, false},
+	{1, "vennesla.no", 2, false},
+	{1, "verdal.no", 2, false},
+	{1, "verran.no", 2, false},
+	{1, "vestby.no", 2, false},
+	{1, "vestnes.no", 2, false},
+	{1, "vestre-slidre.no", 2, false},
+	{1, "vestre-toten.no", 2, false},
+	{1, "vestvagoy.no", 2, false},
+	{1, "xn--vestvgy-ixa6o.no", 2, false},
+	{1, "vevelstad.no", 2, false},
+	{1, "vik.no", 2, false},
+	{1, "vikna.no", 2, false},
+	{1, "vindafjord.no", 2, false},
+	{1, "volda.no", 2, false},
+	{1, "voss.no", 2, false},
+	{1, "varoy.no", 2, false},
+	{1, "xn--vry-yla5g.no", 2, false},
+	{1, "vagan.no", 2, false},
+	{1, "xn--vgan-qoa.no", 2, false},
+	{1, "voagat.no", 2, false},
+	{1, "vagsoy.no", 2, false},
+	{1, "xn--vgsy-qoa0j.no", 2, false},
+	{1, "vaga.no", 2, false},
+	{1, "xn--vg-yiab.no", 2, false},
+	{1, "valer.ostfold.no", 3, false},
+	{1, "xn--vler-qoa.xn--stfold-9xa.no", 3, false},
+	{1, "valer.hedmark.no", 3, false},
+	{1, "xn--vler-qoa.hedmark.no", 3, false},
+	{2, "np", 2, false},
+	{1, "nr", 1, false},
+	{1, "biz.nr", 2, false},
+	{1, "info.nr", 2, false},
+	{1, "gov.nr", 2, false},
+	{1, "edu.nr", 2, false},
+	{1, "org.nr", 2, false},
+	{1, "net.nr", 2, false},
+	{1, "com.nr", 2, false},
+	{1, "nu", 1, false},
+	{1, "nz", 1, false},
+	{1, "ac.nz", 2, false},
+	{1, "co.nz", 2, false},
+	{1, "cri.nz", 2, false},
+	{1, "geek.nz", 2, false},
+	{1, "gen.nz", 2, false},
+	{1, "govt.nz", 2, false},
+	{1, "health.nz", 2, false},
+	{1, "iwi.nz", 2, false},
+	{1, "kiwi.nz", 2, false},
+	{1, "maori.nz", 2, false},
+	{1, "mil.nz", 2, false},
+	{1, "xn--mori-qsa.nz", 2, false},
+	{1, "net.nz", 2, false},
+	{1, "org.nz", 2, false},
+	{1, "parliament.nz", 2, false},
+	{1, "school.nz", 2, false},
+	{1, "om", 1, false},
+	{1, "co.om", 2, false},
+	{1, "com.om", 2, false},
+	{1, "edu.om", 2, false},
+	{1, "gov.om", 2, false},
+	{1, "med.om", 2, false},
+	{1, "museum.om", 2, false},
+	{1, "net.om", 2, false},
+	{1, "org.om", 2, false},
+	{1, "pro.om", 2, false},
+	{1, "onion", 1, false},
+	{1, "org", 1, false},
+	{1, "pa", 1, false},
+	{1, "ac.pa", 2, false},
+	{1, "gob.pa", 2, false},
+	{1, "com.pa", 2, false},
+	{1, "org.pa", 2, false},
+	{1, "sld.pa", 2, false},
+	{1, "edu.pa", 2, false},
+	{1, "net.pa", 2, false},
+	{1, "ing.pa", 2, false},
+	{1, "abo.pa", 2, false},
+	{1, "med.pa", 2, false},
+	{1, "nom.pa", 2, false},
+	{1, "pe", 1, false},
+	{1, "edu.pe", 2, false},
+	{1, "gob.pe", 2, false},
+	{1, "nom.pe", 2, false},
+	{1, "mil.pe", 2, false},
+	{1, "org.pe", 2, false},
+	{1, "com.pe", 2, false},
+	{1, "net.pe", 2, false},
+	{1, "pf", 1, false},
+	{1, "com.pf", 2, false},
+	{1, "org.pf", 2, false},
+	{1, "edu.pf", 2, false},
+	{2, "pg", 2, false},
+	{1, "ph", 1, false},
+	{1, "com.ph", 2, false},
+	{1, "net.ph", 2, false},
+	{1, "org.ph", 2, false},
+	{1, "gov.ph", 2, false},
+	{1, "edu.ph", 2, false},
+	{1, "ngo.ph", 2, false},
+	{1, "mil.ph", 2, false},
+	{1, "i.ph", 2, false},
+	{1, "pk", 1, false},
+	{1, "com.pk", 2, false},
+	{1, "net.pk", 2, false},
+	{1, "edu.pk", 2, false},
+	{1, "org.pk", 2, false},
+	{1, "fam.pk", 2, false},
+	{1, "biz.pk", 2, false},
+	{1, "web.pk", 2, false},
+	{1, "gov.pk", 2, false},
+	{1, "gob.pk", 2, false},
+	{1, "gok.pk", 2, false},
+	{1, "gon.pk", 2, false},
+	{1, "gop.pk", 2, false},
+	{1, "gos.pk", 2, false},
+	{1, "info.pk", 2, false},
+	{1, "pl", 1, false},
+	{1, "com.pl", 2, false},
+	{1, "net.pl", 2, false},
+	{1, "org.pl", 2, false},
+	{1, "aid.pl", 2, false},
+	{1, "agro.pl", 2, false},
+	{1, "atm.pl", 2, false},
+	{1, "auto.pl", 2, false},
+	{1, "biz.pl", 2, false},
+	{1, "edu.pl", 2, false},
+	{1, "gmina.pl", 2, false},
+	{1, "gsm.pl", 2, false},
+	{1, "info.pl", 2, false},
+	{1, "mail.pl", 2, false},
+	{1, "miasta.pl", 2, false},
+	{1, "media.pl", 2, false},
+	{1, "mil.pl", 2, false},
+	{1, "nieruchomosci.pl", 2, false},
+	{1, "nom.pl", 2, false},
+	{1, "pc.pl", 2, false},
+	{1, "powiat.pl", 2, false},
+	{1, "priv.pl", 2, false},
+	{1, "realestate.pl", 2, false},
+	{1, "rel.pl", 2, false},
+	{1, "sex.pl", 2, false},
+	{1, "shop.pl", 2, false},
+	{1, "sklep.pl", 2, false},
+	{1, "sos.pl", 2, false},
+	{1, "szkola.pl", 2, false},
+	{1, "targi.pl", 2, false},
+	{1, "tm.pl", 2, false},
+	{1, "tourism.pl", 2, false},
+	{1, "travel.pl", 2, false},
+	{1, "turystyka.pl", 2, false},
+	{1, "gov.pl", 2, false},
+	{1, "ap.gov.pl", 3, false},
+	{1, "ic.gov.pl", 3, false},
+	{1, "is.gov.pl", 3, false},
+	{1, "us.gov.pl", 3, false},
+	{1, "kmpsp.gov.pl", 3, false},
+	{1, "kppsp.gov.pl", 3, false},
+	{1, "kwpsp.gov.pl", 3, false},
+	{1, "psp.gov.pl", 3, false},
+	{1, "wskr.gov.pl", 3, false},
+	{1, "kwp.gov.pl", 3, false},
+	{1, "mw.gov.pl", 3, false},
+	{1, "ug.gov.pl", 3, false},
+	{1, "um.gov.pl", 3, false},
+	{1, "umig.gov.pl", 3, false},
+	{1, "ugim.gov.pl", 3, false},
+	{1, "upow.gov.pl", 3, false},
+	{1, "uw.gov.pl", 3, false},
+	{1, "starostwo.gov.pl", 3, false},
+	{1, "pa.gov.pl", 3, false},
+	{1, "po.gov.pl", 3, false},
+	{1, "psse.gov.pl", 3, false},
+	{1, "pup.gov.pl", 3, false},
+	{1, "rzgw.gov.pl", 3, false},
+	{1, "sa.gov.pl", 3, false},
+	{1, "so.gov.pl", 3, false},
+	{1, "sr.gov.pl", 3, false},
+	{1, "wsa.gov.pl", 3, false},
+	{1, "sko.gov.pl", 3, false},
+	{1, "uzs.gov.pl", 3, false},
+	{1, "wiih.gov.pl", 3, false},
+	{1, "winb.gov.pl", 3, false},
+	{1, "pinb.gov.pl", 3, false},
+	{1, "wios.gov.pl", 3, false},
+	{1, "witd.gov.pl", 3, false},
+	{1, "wzmiuw.gov.pl", 3, false},
+	{1, "piw.gov.pl", 3, false},
+	{1, "wiw.gov.pl", 3, false},
+	{1, "griw.gov.pl", 3, false},
+	{1, "wif.gov.pl", 3, false},
+	{1, "oum.gov.pl", 3, false},
+	{1, "sdn.gov.pl", 3, false},
+	{1, "zp.gov.pl", 3, false},
+	{1, "uppo.gov.pl", 3, false},
+	{1, "mup.gov.pl", 3, false},
+	{1, "wuoz.gov.pl", 3, false},
+	{1, "konsulat.gov.pl", 3, false},
+	{1, "oirm.gov.pl", 3, false},
+	{1, "augustow.pl", 2, false},
+	{1, "babia-gora.pl", 2, false},
+	{1, "bedzin.pl", 2, false},
+	{1, "beskidy.pl", 2, false},
+	{1, "bialowieza.pl", 2, false},
+	{1, "bialystok.pl", 2, false},
+	{1, "bielawa.pl", 2, false},
+	{1, "bieszczady.pl", 2, false},
+	{1, "boleslawiec.pl", 2, false},
+	{1, "bydgoszcz.pl", 2, false},
+	{1, "bytom.pl", 2, false},
+	{1, "cieszyn.pl", 2, false},
+	{1, "czeladz.pl", 2, false},
+	{1, "czest.pl", 2, false},
+	{1, "dlugoleka.pl", 2, false},
+	{1, "elblag.pl", 2, false},
+	{1, "elk.pl", 2, false},
+	{1, "glogow.pl", 2, false},
+	{1, "gniezno.pl", 2, false},
+	{1, "gorlice.pl", 2, false},
+	{1, "grajewo.pl", 2, false},
+	{1, "ilawa.pl", 2, false},
+	{1, "jaworzno.pl", 2, false},
+	{1, "jelenia-gora.pl", 2, false},
+	{1, "jgora.pl", 2, false},
+	{1, "kalisz.pl", 2, false},
+	{1, "kazimierz-dolny.pl", 2, false},
+	{1, "karpacz.pl", 2, false},
+	{1, "kartuzy.pl", 2, false},
+	{1, "kaszuby.pl", 2, false},
+	{1, "katowice.pl", 2, false},
+	{1, "kepno.pl", 2, false},
+	{1, "ketrzyn.pl", 2, false},
+	{1, "klodzko.pl", 2, false},
+	{1, "kobierzyce.pl", 2, false},
+	{1, "kolobrzeg.pl", 2, false},
+	{1, "konin.pl", 2, false},
+	{1, "konskowola.pl", 2, false},
+	{1, "kutno.pl", 2, false},
+	{1, "lapy.pl", 2, false},
+	{1, "lebork.pl", 2, false},
+	{1, "legnica.pl", 2, false},
+	{1, "lezajsk.pl", 2, false},
+	{1, "limanowa.pl", 2, false},
+	{1, "lomza.pl", 2, false},
+	{1, "lowicz.pl", 2, false},
+	{1, "lubin.pl", 2, false},
+	{1, "lukow.pl", 2, false},
+	{1, "malbork.pl", 2, false},
+	{1, "malopolska.pl", 2, false},
+	{1, "mazowsze.pl", 2, false},
+	{1, "mazury.pl", 2, false},
+	{1, "mielec.pl", 2, false},
+	{1, "mielno.pl", 2, false},
+	{1, "mragowo.pl", 2, false},
+	{1, "naklo.pl", 2, false},
+	{1, "nowaruda.pl", 2, false},
+	{1, "nysa.pl", 2, false},
+	{1, "olawa.pl", 2, false},
+	{1, "olecko.pl", 2, false},
+	{1, "olkusz.pl", 2, false},
+	{1, "olsztyn.pl", 2, false},
+	{1, "opoczno.pl", 2, false},
+	{1, "opole.pl", 2, false},
+	{1, "ostroda.pl", 2, false},
+	{1, "ostroleka.pl", 2, false},
+	{1, "ostrowiec.pl", 2, false},
+	{1, "ostrowwlkp.pl", 2, false},
+	{1, "pila.pl", 2, false},
+	{1, "pisz.pl", 2, false},
+	{1, "podhale.pl", 2, false},
+	{1, "podlasie.pl", 2, false},
+	{1, "polkowice.pl", 2, false},
+	{1, "pomorze.pl", 2, false},
+	{1, "pomorskie.pl", 2, false},
+	{1, "prochowice.pl", 2, false},
+	{1, "pruszkow.pl", 2, false},
+	{1, "przeworsk.pl", 2, false},
+	{1, "pulawy.pl", 2, false},
+	{1, "radom.pl", 2, false},
+	{1, "rawa-maz.pl", 2, false},
+	{1, "rybnik.pl", 2, false},
+	{1, "rzeszow.pl", 2, false},
+	{1, "sanok.pl", 2, false},
+	{1, "sejny.pl", 2, false},
+	{1, "slask.pl", 2, false},
+	{1, "slupsk.pl", 2, false},
+	{1, "sosnowiec.pl", 2, false},
+	{1, "stalowa-wola.pl", 2, false},
+	{1, "skoczow.pl", 2, false},
+	{1, "starachowice.pl", 2, false},
+	{1, "stargard.pl", 2, false},
+	{1, "suwalki.pl", 2, false},
+	{1, "swidnica.pl", 2, false},
+	{1, "swiebodzin.pl", 2, false},
+	{1, "swinoujscie.pl", 2, false},
+	{1, "szczecin.pl", 2, false},
+	{1, "szczytno.pl", 2, false},
+	{1, "tarnobrzeg.pl", 2, false},
+	{1, "tgory.pl", 2, false},
+	{1, "turek.pl", 2, false},
+	{1, "tychy.pl", 2, false},
+	{1, "ustka.pl", 2, false},
+	{1, "walbrzych.pl", 2, false},
+	{1, "warmia.pl", 2, false},
+	{1, "warszawa.pl", 2, false},
+	{1, "waw.pl", 2, false},
+	{1, "wegrow.pl", 2, false},
+	{1, "wielun.pl", 2, false},
+	{1, "wlocl.pl", 2, false},
+	{1, "wloclawek.pl", 2, false},
+	{1, "wodzislaw.pl", 2, false},
+	{1, "wolomin.pl", 2, false},
+	{1, "wroclaw.pl", 2, false},
+	{1, "zachpomor.pl", 2, false},
+	{1, "zagan.pl", 2, false},
+	{1, "zarow.pl", 2, false},
+	{1, "zgora.pl", 2, false},
+	{1, "zgorzelec.pl", 2, false},
+	{1, "pm", 1, false},
+	{1, "pn", 1, false},
+	{1, "gov.pn", 2, false},
+	{1, "co.pn", 2, false},
+	{1, "org.pn", 2, false},
+	{1, "edu.pn", 2, false},
+	{1, "net.pn", 2, false},
+	{1, "post", 1, false},
+	{1, "pr", 1, false},
+	{1, "com.pr", 2, false},
+	{1, "net.pr", 2, false},
+	{1, "org.pr", 2, false},
+	{1, "gov.pr", 2, false},
+	{1, "edu.pr", 2, false},
+	{1, "isla.pr", 2, false},
+	{1, "pro.pr", 2, false},
+	{1, "biz.pr", 2, false},
+	{1, "info.pr", 2, false},
+	{1, "name.pr", 2, false},
+	{1, "est.pr", 2, false},
+	{1, "prof.pr", 2, false},
+	{1, "ac.pr", 2, false},
+	{1, "pro", 1, false},
+	{1, "aaa.pro", 2, false},
+	{1, "aca.pro", 2, false},
+	{1, "acct.pro", 2, false},
+	{1, "avocat.pro", 2, false},
+	{1, "bar.pro", 2, false},
+	{1, "cpa.pro", 2, false},
+	{1, "eng.pro", 2, false},
+	{1, "jur.pro", 2, false},
+	{1, "law.pro", 2, false},
+	{1, "med.pro", 2, false},
+	{1, "recht.pro", 2, false},
+	{1, "ps", 1, false},
+	{1, "edu.ps", 2, false},
+	{1, "gov.ps", 2, false},
+	{1, "sec.ps", 2, false},
+	{1, "plo.ps", 2, false},
+	{1, "com.ps", 2, false},
+	{1, "org.ps", 2, false},
+	{1, "net.ps", 2, false},
+	{1, "pt", 1, false},
+	{1, "net.pt", 2, false},
+	{1, "gov.pt", 2, false},
+	{1, "org.pt", 2, false},
+	{1, "edu.pt", 2, false},
+	{1, "int.pt", 2, false},
+	{1, "publ.pt", 2, false},
+	{1, "com.pt", 2, false},
+	{1, "nome.pt", 2, false},
+	{1, "pw", 1, false},
+	{1, "co.pw", 2, false},
+	{1, "ne.pw", 2, false},
+	{1, "or.pw", 2, false},
+	{1, "ed.pw", 2, false},
+	{1, "go.pw", 2, false},
+	{1, "belau.pw", 2, false},
+	{1, "py", 1, false},
+	{1, "com.py", 2, false},
+	{1, "coop.py", 2, false},
+	{1, "edu.py", 2, false},
+	{1, "gov.py", 2, false},
+	{1, "mil.py", 2, false},
+	{1, "net.py", 2, false},
+	{1, "org.py", 2, false},
+	{1, "qa", 1, false},
+	{1, "com.qa", 2, false},
+	{1, "edu.qa", 2, false},
+	{1, "gov.qa", 2, false},
+	{1, "mil.qa", 2, false},
+	{1, "name.qa", 2, false},
+	{1, "net.qa", 2, false},
+	{1, "org.qa", 2, false},
+	{1, "sch.qa", 2, false},
+	{1, "re", 1, false},
+	{1, "asso.re", 2, false},
+	{1, "com.re", 2, false},
+	{1, "nom.re", 2, false},
+	{1, "ro", 1, false},
+	{1, "arts.ro", 2, false},
+	{1, "com.ro", 2, false},
+	{1, "firm.ro", 2, false},
+	{1, "info.ro", 2, false},
+	{1, "nom.ro", 2, false},
+	{1, "nt.ro", 2, false},
+	{1, "org.ro", 2, false},
+	{1, "rec.ro", 2, false},
+	{1, "store.ro", 2, false},
+	{1, "tm.ro", 2, false},
+	{1, "www.ro", 2, false},
+	{1, "rs", 1, false},
+	{1, "ac.rs", 2, false},
+	{1, "co.rs", 2, false},
+	{1, "edu.rs", 2, false},
+	{1, "gov.rs", 2, false},
+	{1, "in.rs", 2, false},
+	{1, "org.rs", 2, false},
+	{1, "ru", 1, false},
+	{1, "rw", 1, false},
+	{1, "ac.rw", 2, false},
+	{1, "co.rw", 2, false},
+	{1, "coop.rw", 2, false},
+	{1, "gov.rw", 2, false},
+	{1, "mil.rw", 2, false},
+	{1, "net.rw", 2, false},
+	{1, "org.rw", 2, false},
+	{1, "sa", 1, false},
+	{1, "com.sa", 2, false},
+	{1, "net.sa", 2, false},
+	{1, "org.sa", 2, false},
+	{1, "gov.sa", 2, false},
+	{1, "med.sa", 2, false},
+	{1, "pub.sa", 2, false},
+	{1, "edu.sa", 2, false},
+	{1, "sch.sa", 2, false},
+	{1, "sb", 1, false},
+	{1, "com.sb", 2, false},
+	{1, "edu.sb", 2, false},
+	{1, "gov.sb", 2, false},
+	{1, "net.sb", 2, false},
+	{1, "org.sb", 2, false},
+	{1, "sc", 1, false},
+	{1, "com.sc", 2, false},
+	{1, "gov.sc", 2, false},
+	{1, "net.sc", 2, false},
+	{1, "org.sc", 2, false},
+	{1, "edu.sc", 2, false},
+	{1, "sd", 1, false},
+	{1, "com.sd", 2, false},
+	{1, "net.sd", 2, false},
+	{1, "org.sd", 2, false},
+	{1, "edu.sd", 2, false},
+	{1, "med.sd", 2, false},
+	{1, "tv.sd", 2, false},
+	{1, "gov.sd", 2, false},
+	{1, "info.sd", 2, false},
+	{1, "se", 1, false},
+	{1, "a.se", 2, false},
+	{1, "ac.se", 2, false},
+	{1, "b.se", 2, false},
+	{1, "bd.se", 2, false},
+	{1, "brand.se", 2, false},
+	{1, "c.se", 2, false},
+	{1, "d.se", 2, false},
+	{1, "e.se", 2, false},
+	{1, "f.se", 2, false},
+	{1, "fh.se", 2, false},
+	{1, "fhsk.se", 2, false},
+	{1, "fhv.se", 2, false},
+	{1, "g.se", 2, false},
+	{1, "h.se", 2, false},
+	{1, "i.se", 2, false},
+	{1, "k.se", 2, false},
+	{1, "komforb.se", 2, false},
+	{1, "kommunalforbund.se", 2, false},
+	{1, "komvux.se", 2, false},
+	{1, "l.se", 2, false},
+	{1, "lanbib.se", 2, false},
+	{1, "m.se", 2, false},
+	{1, "n.se", 2, false},
+	{1, "naturbruksgymn.se", 2, false},
+	{1, "o.se", 2, false},
+	{1, "org.se", 2, false},
+	{1, "p.se", 2, false},
+	{1, "parti.se", 2, false},
+	{1, "pp.se", 2, false},
+	{1, "press.se", 2, false},
+	{1, "r.se", 2, false},
+	{1, "s.se", 2, false},
+	{1, "t.se", 2, false},
+	{1, "tm.se", 2, false},
+	{1, "u.se", 2, false},
+	{1, "w.se", 2, false},
+	{1, "x.se", 2, false},
+	{1, "y.se", 2, false},
+	{1, "z.se", 2, false},
+	{1, "sg", 1, false},
+	{1, "com.sg", 2, false},
+	{1, "net.sg", 2, false},
+	{1, "org.sg", 2, false},
+	{1, "gov.sg", 2, false},
+	{1, "edu.sg", 2, false},
+	{1, "per.sg", 2, false},
+	{1, "sh", 1, false},
+	{1, "com.sh", 2, false},
+	{1, "net.sh", 2, false},
+	{1, "gov.sh", 2, false},
+	{1, "org.sh", 2, false},
+	{1, "mil.sh", 2, false},
+	{1, "si", 1, false},
+	{1, "sj", 1, false},
+	{1, "sk", 1, false},
+	{1, "sl", 1, false},
+	{1, "com.sl", 2, false},
+	{1, "net.sl", 2, false},
+	{1, "edu.sl", 2, false},
+	{1, "gov.sl", 2, false},
+	{1, "org.sl", 2, false},
+	{1, "sm", 1, false},
+	{1, "sn", 1, false},
+	{1, "art.sn", 2, false},
+	{1, "com.sn", 2, false},
+	{1, "edu.sn", 2, false},
+	{1, "gouv.sn", 2, false},
+	{1, "org.sn", 2, false},
+	{1, "perso.sn", 2, false},
+	{1, "univ.sn", 2, false},
+	{1, "so", 1, false},
+	{1, "com.so", 2, false},
+	{1, "edu.so", 2, false},
+	{1, "gov.so", 2, false},
+	{1, "me.so", 2, false},
+	{1, "net.so", 2, false},
+	{1, "org.so", 2, false},
+	{1, "sr", 1, false},
+	{1, "ss", 1, false},
+	{1, "biz.ss", 2, false},
+	{1, "com.ss", 2, false},
+	{1, "edu.ss", 2, false},
+	{1, "gov.ss", 2, false},
+	{1, "me.ss", 2, false},
+	{1, "net.ss", 2, false},
+	{1, "org.ss", 2, false},
+	{1, "sch.ss", 2, false},
+	{1, "st", 1, false},
+	{1, "co.st", 2, false},
+	{1, "com.st", 2, false},
+	{1, "consulado.st", 2, false},
+	{1, "edu.st", 2, false},
+	{1, "embaixada.st", 2, false},
+	{1, "mil.st", 2, false},
+	{1, "net.st", 2, false},
+	{1, "org.st", 2, false},
+	{1, "principe.st", 2, false},
+	{1, "saotome.st", 2, false},
+	{1, "store.st", 2, false},
+	{1, "su", 1, false},
+	{1, "sv", 1, false},
+	{1, "com.sv", 2, false},
+	{1, "edu.sv", 2, false},
+	{1, "gob.sv", 2, false},
+	{1, "org.sv", 2, false},
+	{1, "red.sv", 2, false},
+	{1, "sx", 1, false},
+	{1, "gov.sx", 2, false},
+	{1, "sy", 1, false},
+	{1, "edu.sy", 2, false},
+	{1, "gov.sy", 2, false},
+	{1, "net.sy", 2, false},
+	{1, "mil.sy", 2, false},
+	{1, "com.sy", 2, false},
+	{1, "org.sy", 2, false},
+	{1, "sz", 1, false},
+	{1, "co.sz", 2, false},
+	{1, "ac.sz", 2, false},
+	{1, "org.sz", 2, false},
+	{1, "tc", 1, false},
+	{1, "td", 1, false},
+	{1, "tel", 1, false},
+	{1, "tf", 1, false},
+	{1, "tg", 1, false},
+	{1, "th", 1, false},
+	{1, "ac.th", 2, false},
+	{1, "co.th", 2, false},
+	{1, "go.th", 2, false},
+	{1, "in.th", 2, false},
+	{1, "mi.th", 2, false},
+	{1, "net.th", 2, false},
+	{1, "or.th", 2, false},
+	{1, "tj", 1, false},
+	{1, "ac.tj", 2, false},
+	{1, "biz.tj", 2, false},
+	{1, "co.tj", 2, false},
+	{1, "com.tj", 2, false},
+	{1, "edu.tj", 2, false},
+	{1, "go.tj", 2, false},
+	{1, "gov.tj", 2, false},
+	{1, "int.tj", 2, false},
+	{1, "mil.tj", 2, false},
+	{1, "name.tj", 2, false},
+	{1, "net.tj", 2, false},
+	{1, "nic.tj", 2, false},
+	{1, "org.tj", 2, false},
+	{1, "test.tj", 2, false},
+	{1, "web.tj", 2, false},
+	{1, "tk", 1, false},
+	{1, "tl", 1, false},
+	{1, "gov.tl", 2, false},
+	{1, "tm", 1, false},
+	{1, "com.tm", 2, false},
+	{1, "co.tm", 2, false},
+	{1, "org.tm", 2, false},
+	{1, "net.tm", 2, false},
+	{1, "nom.tm", 2, false},
+	{1, "gov.tm", 2, false},
+	{1, "mil.tm", 2, false},
+	{1, "edu.tm", 2, false},
+	{1, "tn", 1, false},
+	{1, "com.tn", 2, false},
+	{1, "ens.tn", 2, false},
+	{1, "fin.tn", 2, false},
+	{1, "gov.tn", 2, false},
+	{1, "ind.tn", 2, false},
+	{1, "intl.tn", 2, false},
+	{1, "nat.tn", 2, false},
+	{1, "net.tn", 2, false},
+	{1, "org.tn", 2, false},
+	{1, "info.tn", 2, false},
+	{1, "perso.tn", 2, false},
+	{1, "tourism.tn", 2, false},
+	{1, "edunet.tn", 2, false},
+	{1, "rnrt.tn", 2, false},
+	{1, "rns.tn", 2, false},
+	{1, "rnu.tn", 2, false},
+	{1, "mincom.tn", 2, false},
+	{1, "agrinet.tn", 2, false},
+	{1, "defense.tn", 2, false},
+	{1, "turen.tn", 2, false},
+	{1, "to", 1, false},
+	{1, "com.to", 2, false},
+	{1, "gov.to", 2, false},
+	{1, "net.to", 2, false},
+	{1, "org.to", 2, false},
+	{1, "edu.to", 2, false},
+	{1, "mil.to", 2, false},
+	{1, "tr", 1, false},
+	{1, "av.tr", 2, false},
+	{1, "bbs.tr", 2, false},
+	{1, "bel.tr", 2, false},
+	{1, "biz.tr", 2, false},
+	{1, "com.tr", 2, false},
+	{1, "dr.tr", 2, false},
+	{1, "edu.tr", 2, false},
+	{1, "gen.tr", 2, false},
+	{1, "gov.tr", 2, false},
+	{1, "info.tr", 2, false},
+	{1, "mil.tr", 2, false},
+	{1, "k12.tr", 2, false},
+	{1, "kep.tr", 2, false},
+	{1, "name.tr", 2, false},
+	{1, "net.tr", 2, false},
+	{1, "org.tr", 2, false},
+	{1, "pol.tr", 2, false},
+	{1, "tel.tr", 2, false},
+	{1, "tsk.tr", 2, false},
+	{1, "tv.tr", 2, false},
+	{1, "web.tr", 2, false},
+	{1, "nc.tr", 2, false},
+	{1, "gov.nc.tr", 3, false},
+	{1, "tt", 1, false},
+	{1, "co.tt", 2, false},
+	{1, "com.tt", 2, false},
+	{1, "org.tt", 2, false},
+	{1, "net.tt", 2, false},
+	{1, "biz.tt", 2, false},
+	{1, "info.tt", 2, false},
+	{1, "pro.tt", 2, false},
+	{1, "int.tt", 2, false},
+	{1, "coop.tt", 2, false},
+	{1, "jobs.tt", 2, false},
+	{1, "mobi.tt", 2, false},
+	{1, "travel.tt", 2, false},
+	{1, "museum.tt", 2, false},
+	{1, "aero.tt", 2, false},
+	{1, "name.tt", 2, false},
+	{1, "gov.tt", 2, false},
+	{1, "edu.tt", 2, false},
+	{1, "tv", 1, false},
+	{1, "tw", 1, false},
+	{1, "edu.tw", 2, false},
+	{1, "gov.tw", 2, false},
+	{1, "mil.tw", 2, false},
+	{1, "com.tw", 2, false},
+	{1, "net.tw", 2, false},
+	{1, "org.tw", 2, false},
+	{1, "idv.tw", 2, false},
+	{1, "game.tw", 2, false},
+	{1, "ebiz.tw", 2, false},
+	{1, "club.tw", 2, false},
+	{1, "xn--zf0ao64a.tw", 2, false},
+	{1, "xn--uc0atv.tw", 2, false},
+	{1, "xn--czrw28b.tw", 2, false},
+	{1, "tz", 1, false},
+	{1, "ac.tz", 2, false},
+	{1, "co.tz", 2, false},
+	{1, "go.tz", 2, false},
+	{1, "hotel.tz", 2, false},
+	{1, "info.tz", 2, false},
+	{1, "me.tz", 2, false},
+	{1, "mil.tz", 2, false},
+	{1, "mobi.tz", 2, false},
+	{1, "ne.tz", 2, false},
+	{1, "or.tz", 2, false},
+	{1, "sc.tz", 2, false},
+	{1, "tv.tz", 2, false},
+	{1, "ua", 1, false},
+	{1, "com.ua", 2, false},
+	{1, "edu.ua", 2, false},
+	{1, "gov.ua", 2, false},
+	{1, "in.ua", 2, false},
+	{1, "net.ua", 2, false},
+	{1, "org.ua", 2, false},
+	{1, "cherkassy.ua", 2, false},
+	{1, "cherkasy.ua", 2, false},
+	{1, "chernigov.ua", 2, false},
+	{1, "chernihiv.ua", 2, false},
+	{1, "chernivtsi.ua", 2, false},
+	{1, "chernovtsy.ua", 2, false},
+	{1, "ck.ua", 2, false},
+	{1, "cn.ua", 2, false},
+	{1, "cr.ua", 2, false},
+	{1, "crimea.ua", 2, false},
+	{1, "cv.ua", 2, false},
+	{1, "dn.ua", 2, false},
+	{1, "dnepropetrovsk.ua", 2, false},
+	{1, "dnipropetrovsk.ua", 2, false},
+	{1, "donetsk.ua", 2, false},
+	{1, "dp.ua", 2, false},
+	{1, "if.ua", 2, false},
+	{1, "ivano-frankivsk.ua", 2, false},
+	{1, "kh.ua", 2, false},
+	{1, "kharkiv.ua", 2, false},
+	{1, "kharkov.ua", 2, false},
+	{1, "kherson.ua", 2, false},
+	{1, "khmelnitskiy.ua", 2, false},
+	{1, "khmelnytskyi.ua", 2, false},
+	{1, "kiev.ua", 2, false},
+	{1, "kirovograd.ua", 2, false},
+	{1, "km.ua", 2, false},
+	{1, "kr.ua", 2, false},
+	{1, "krym.ua", 2, false},
+	{1, "ks.ua", 2, false},
+	{1, "kv.ua", 2, false},
+	{1, "kyiv.ua", 2, false},
+	{1, "lg.ua", 2, false},
+	{1, "lt.ua", 2, false},
+	{1, "lugansk.ua", 2, false},
+	{1, "lutsk.ua", 2, false},
+	{1, "lv.ua", 2, false},
+	{1, "lviv.ua", 2, false},
+	{1, "mk.ua", 2, false},
+	{1, "mykolaiv.ua", 2, false},
+	{1, "nikolaev.ua", 2, false},
+	{1, "od.ua", 2, false},
+	{1, "odesa.ua", 2, false},
+	{1, "odessa.ua", 2, false},
+	{1, "pl.ua", 2, false},
+	{1, "poltava.ua", 2, false},
+	{1, "rivne.ua", 2, false},
+	{1, "rovno.ua", 2, false},
+	{1, "rv.ua", 2, false},
+	{1, "sb.ua", 2, false},
+	{1, "sebastopol.ua", 2, false},
+	{1, "sevastopol.ua", 2, false},
+	{1, "sm.ua", 2, false},
+	{1, "sumy.ua", 2, false},
+	{1, "te.ua", 2, false},
+	{1, "ternopil.ua", 2, false},
+	{1, "uz.ua", 2, false},
+	{1, "uzhgorod.ua", 2, false},
+	{1, "vinnica.ua", 2, false},
+	{1, "vinnytsia.ua", 2, false},
+	{1, "vn.ua", 2, false},
+	{1, "volyn.ua", 2, false},
+	{1, "yalta.ua", 2, false},
+	{1, "zaporizhzhe.ua", 2, false},
+	{1, "zaporizhzhia.ua", 2, false},
+	{1, "zhitomir.ua", 2, false},
+	{1, "zhytomyr.ua", 2, false},
+	{1, "zp.ua", 2, false},
+	{1, "zt.ua", 2, false},
+	{1, "ug", 1, false},
+	{1, "co.ug", 2, false},
+	{1, "or.ug", 2, false},
+	{1, "ac.ug", 2, false},
+	{1, "sc.ug", 2, false},
+	{1, "go.ug", 2, false},
+	{1, "ne.ug", 2, false},
+	{1, "com.ug", 2, false},
+	{1, "org.ug", 2, false},
+	{1, "uk", 1, false},
+	{1, "ac.uk", 2, false},
+	{1, "co.uk", 2, false},
+	{1, "gov.uk", 2, false},
+	{1, "ltd.uk", 2, false},
+	{1, "me.uk", 2, false},
+	{1, "net.uk", 2, false},
+	{1, "nhs.uk", 2, false},
+	{1, "org.uk", 2, false},
+	{1, "plc.uk", 2, false},
+	{1, "police.uk", 2, false},
+	{2, "sch.uk", 3, false},
+	{1, "us", 1, false},
+	{1, "dni.us", 2, false},
+	{1, "fed.us", 2, false},
+	{1, "isa.us", 2, false},
+	{1, "kids.us", 2, false},
+	{1, "nsn.us", 2, false},
+	{1, "ak.us", 2, false},
+	{1, "al.us", 2, false},
+	{1, "ar.us", 2, false},
+	{1, "as.us", 2, false},
+	{1, "az.us", 2, false},
+	{1, "ca.us", 2, false},
+	{1, "co.us", 2, false},
+	{1, "ct.us", 2, false},
+	{1, "dc.us", 2, false},
+	{1, "de.us", 2, false},
+	{1, "fl.us", 2, false},
+	{1, "ga.us", 2, false},
+	{1, "gu.us", 2, false},
+	{1, "hi.us", 2, false},
+	{1, "ia.us", 2, false},
+	{1, "id.us", 2, false},
+	{1, "il.us", 2, false},
+	{1, "in.us", 2, false},
+	{1, "ks.us", 2, false},
+	{1, "ky.us", 2, false},
+	{1, "la.us", 2, false},
+	{1, "ma.us", 2, false},
+	{1, "md.us", 2, false},
+	{1, "me.us", 2, false},
+	{1, "mi.us", 2, false},
+	{1, "mn.us", 2, false},
+	{1, "mo.us", 2, false},
+	{1, "ms.us", 2, false},
+	{1, "mt.us", 2, false},
+	{1, "nc.us", 2, false},
+	{1, "nd.us", 2, false},
+	{1, "ne.us", 2, false},
+	{1, "nh.us", 2, false},
+	{1, "nj.us", 2, false},
+	{1, "nm.us", 2, false},
+	{1, "nv.us", 2, false},
+	{1, "ny.us", 2, false},
+	{1, "oh.us", 2, false},
+	{1, "ok.us", 2, false},
+	{1, "or.us", 2, false},
+	{1, "pa.us", 2, false},
+	{1, "pr.us", 2, false},
+	{1, "ri.us", 2, false},
+	{1, "sc.us", 2, false},
+	{1, "sd.us", 2, false},
+	{1, "tn.us", 2, false},
+	{1, "tx.us", 2, false},
+	{1, "ut.us", 2, false},
+	{1, "vi.us", 2, false},
+	{1, "vt.us", 2, false},
+	{1, "va.us", 2, false},
+	{1, "wa.us", 2, false},
+	{1, "wi.us", 2, false},
+	{1, "wv.us", 2, false},
+	{1, "wy.us", 2, false},
+	{1, "k12.ak.us", 3, false},
+	{1, "k12.al.us", 3, false},
+	{1, "k12.ar.us", 3, false},
+	{1, "k12.as.us", 3, false},
+	{1, "k12.az.us", 3, false},
+	{1, "k12.ca.us", 3, false},
+	{1, "k12.co.us", 3, false},
+	{1, "k12.ct.us", 3, false},
+	{1, "k12.dc.us", 3, false},
+	{1, "k12.de.us", 3, false},
+	{1, "k12.fl.us", 3, false},
+	{1, "k12.ga.us", 3, false},
+	{1, "k12.gu.us", 3, false},
+	{1, "k12.ia.us", 3, false},
+	{1, "k12.id.us", 3, false},
+	{1, "k12.il.us", 3, false},
+	{1, "k12.in.us", 3, false},
+	{1, "k12.ks.us", 3, false},
+	{1, "k12.ky.us", 3, false},
+	{1, "k12.la.us", 3, false},
+	{1, "k12.ma.us", 3, false},
+	{1, "k12.md.us", 3, false},
+	{1, "k12.me.us", 3, false},
+	{1, "k12.mi.us", 3, false},
+	{1, "k12.mn.us", 3, false},
+	{1, "k12.mo.us", 3, false},
+	{1, "k12.ms.us", 3, false},
+	{1, "k12.mt.us", 3, false},
+	{1, "k12.nc.us", 3, false},
+	{1, "k12.ne.us", 3, false},
+	{1, "k12.nh.us", 3, false},
+	{1, "k12.nj.us", 3, false},
+	{1, "k12.nm.us", 3, false},
+	{1, "k12.nv.us", 3, false},
+	{1, "k12.ny.us", 3, false},
+	{1, "k12.oh.us", 3, false},
+	{1, "k12.ok.us", 3, false},
+	{1, "k12.or.us", 3, false},
+	{1, "k12.pa.us", 3, false},
+	{1, "k12.pr.us", 3, false},
+	{1, "k12.sc.us", 3, false},
+	{1, "k12.tn.us", 3, false},
+	{1, "k12.tx.us", 3, false},
+	{1, "k12.ut.us", 3, false},
+	{1, "k12.vi.us", 3, false},
+	{1, "k12.vt.us", 3, false},
+	{1, "k12.va.us", 3, false},
+	{1, "k12.wa.us", 3, false},
+	{1, "k12.wi.us", 3, false},
+	{1, "k12.wy.us", 3, false},
+	{1, "cc.ak.us", 3, false},
+	{1, "cc.al.us", 3, false},
+	{1, "cc.ar.us", 3, false},
+	{1, "cc.as.us", 3, false},
+	{1, "cc.az.us", 3, false},
+	{1, "cc.ca.us", 3, false},
+	{1, "cc.co.us", 3, false},
+	{1, "cc.ct.us", 3, false},
+	{1, "cc.dc.us", 3, false},
+	{1, "cc.de.us", 3, false},
+	{1, "cc.fl.us", 3, false},
+	{1, "cc.ga.us", 3, false},
+	{1, "cc.gu.us", 3, false},
+	{1, "cc.hi.us", 3, false},
+	{1, "cc.ia.us", 3, false},
+	{1, "cc.id.us", 3, false},
+	{1, "cc.il.us", 3, false},
+	{1, "cc.in.us", 3, false},
+	{1, "cc.ks.us", 3, false},
+	{1, "cc.ky.us", 3, false},
+	{1, "cc.la.us", 3, false},
+	{1, "cc.ma.us", 3, false},
+	{1, "cc.md.us", 3, false},
+	{1, "cc.me.us", 3, false},
+	{1, "cc.mi.us", 3, false},
+	{1, "cc.mn.us", 3, false},
+	{1, "cc.mo.us", 3, false},
+	{1, "cc.ms.us", 3, false},
+	{1, "cc.mt.us", 3, false},
+	{1, "cc.nc.us", 3, false},
+	{1, "cc.nd.us", 3, false},
+	{1, "cc.ne.us", 3, false},
+	{1, "cc.nh.us", 3, false},
+	{1, "cc.nj.us", 3, false},
+	{1, "cc.nm.us", 3, false},
+	{1, "cc.nv.us", 3, false},
+	{1, "cc.ny.us", 3, false},
+	{1, "cc.oh.us", 3, false},
+	{1, "cc.ok.us", 3, false},
+	{1, "cc.or.us", 3, false},
+	{1, "cc.pa.us", 3, false},
+	{1, "cc.pr.us", 3, false},
+	{1, "cc.ri.us", 3, false},
+	{1, "cc.sc.us", 3, false},
+	{1, "cc.sd.us", 3, false},
+	{1, "cc.tn.us", 3, false},
+	{1, "cc.tx.us", 3, false},
+	{1, "cc.ut.us", 3, false},
+	{1, "cc.vi.us", 3, false},
+	{1, "cc.vt.us", 3, false},
+	{1, "cc.va.us", 3, false},
+	{1, "cc.wa.us", 3, false},
+	{1, "cc.wi.us", 3, false},
+	{1, "cc.wv.us", 3, false},
+	{1, "cc.wy.us", 3, false},
+	{1, "lib.ak.us", 3, false},
+	{1, "lib.al.us", 3, false},
+	{1, "lib.ar.us", 3, false},
+	{1, "lib.as.us", 3, false},
+	{1, "lib.az.us", 3, false},
+	{1, "lib.ca.us", 3, false},
+	{1, "lib.co.us", 3, false},
+	{1, "lib.ct.us", 3, false},
+	{1, "lib.dc.us", 3, false},
+	{1, "lib.fl.us", 3, false},
+	{1, "lib.ga.us", 3, false},
+	{1, "lib.gu.us", 3, false},
+	{1, "lib.hi.us", 3, false},
+	{1, "lib.ia.us", 3, false},
+	{1, "lib.id.us", 3, false},
+	{1, "lib.il.us", 3, false},
+	{1, "lib.in.us", 3, false},
+	{1, "lib.ks.us", 3, false},
+	{1, "lib.ky.us", 3, false},
+	{1, "lib.la.us", 3, false},
+	{1, "lib.ma.us", 3, false},
+	{1, "lib.md.us", 3, false},
+	{1, "lib.me.us", 3, false},
+	{1, "lib.mi.us", 3, false},
+	{1, "lib.mn.us", 3, false},
+	{1, "lib.mo.us", 3, false},
+	{1, "lib.ms.us", 3, false},
+	{1, "lib.mt.us", 3, false},
+	{1, "lib.nc.us", 3, false},
+	{1, "lib.nd.us", 3, false},
+	{1, "lib.ne.us", 3, false},
+	{1, "lib.nh.us", 3, false},
+	{1, "lib.nj.us", 3, false},
+	{1, "lib.nm.us", 3, false},
+	{1, "lib.nv.us", 3, false},
+	{1, "lib.ny.us", 3, false},
+	{1, "lib.oh.us", 3, false},
+	{1, "lib.ok.us", 3, false},
+	{1, "lib.or.us", 3, false},
+	{1, "lib.pa.us", 3, false},
+	{1, "lib.pr.us", 3, false},
+	{1, "lib.ri.us", 3, false},
+	{1, "lib.sc.us", 3, false},
+	{1, "lib.sd.us", 3, false},
+	{1, "lib.tn.us", 3, false},
+	{1, "lib.tx.us", 3, false},
+	{1, "lib.ut.us", 3, false},
+	{1, "lib.vi.us", 3, false},
+	{1, "lib.vt.us", 3, false},
+	{1, "lib.va.us", 3, false},
+	{1, "lib.wa.us", 3, false},
+	{1, "lib.wi.us", 3, false},
+	{1, "lib.wy.us", 3, false},
+	{1, "pvt.k12.ma.us", 4, false},
+	{1, "chtr.k12.ma.us", 4, false},
+	{1, "paroch.k12.ma.us", 4, false},
+	{1, "ann-arbor.mi.us", 3, false},
+	{1, "cog.mi.us", 3, false},
+	{1, "dst.mi.us", 3, false},
+	{1, "eaton.mi.us", 3, false},
+	{1, "gen.mi.us", 3, false},
+	{1, "mus.mi.us", 3, false},
+	{1, "tec.mi.us", 3, false},
+	{1, "washtenaw.mi.us", 3, false},
+	{1, "uy", 1, false},
+	{1, "com.uy", 2, false},
+	{1, "edu.uy", 2, false},
+	{1, "gub.uy", 2, false},
+	{1, "mil.uy", 2, false},
+	{1, "net.uy", 2, false},
+	{1, "org.uy", 2, false},
+	{1, "uz", 1, false},
+	{1, "co.uz", 2, false},
+	{1, "com.uz", 2, false},
+	{1, "net.uz", 2, false},
+	{1, "org.uz", 2, false},
+	{1, "va", 1, false},
+	{1, "vc", 1, false},
+	{1, "com.vc", 2, false},
+	{1, "net.vc", 2, false},
+	{1, "org.vc", 2, false},
+	{1, "gov.vc", 2, false},
+	{1, "mil.vc", 2, false},
+	{1, "edu.vc", 2, false},
+	{1, "ve", 1, false},
+	{1, "arts.ve", 2, false},
+	{1, "co.ve", 2, false},
+	{1, "com.ve", 2, false},
+	{1, "e12.ve", 2, false},
+	{1, "edu.ve", 2, false},
+	{1, "firm.ve", 2, false},
+	{1, "gob.ve", 2, false},
+	{1, "gov.ve", 2, false},
+	{1, "info.ve", 2, false},
+	{1, "int.ve", 2, false},
+	{1, "mil.ve", 2, false},
+	{1, "net.ve", 2, false},
+	{1, "org.ve", 2, false},
+	{1, "rec.ve", 2, false},
+	{1, "store.ve", 2, false},
+	{1, "tec.ve", 2, false},
+	{1, "web.ve", 2, false},
+	{1, "vg", 1, false},
+	{1, "vi", 1, false},
+	{1, "co.vi", 2, false},
+	{1, "com.vi", 2, false},
+	{1, "k12.vi", 2, false},
+	{1, "net.vi", 2, false},
+	{1, "org.vi", 2, false},
+	{1, "vn", 1, false},
+	{1, "com.vn", 2, false},
+	{1, "net.vn", 2, false},
+	{1, "org.vn", 2, false},
+	{1, "edu.vn", 2, false},
+	{1, "gov.vn", 2, false},
+	{1, "int.vn", 2, false},
+	{1, "ac.vn", 2, false},
+	{1, "biz.vn", 2, false},
+	{1, "info.vn", 2, false},
+	{1, "name.vn", 2, false},
+	{1, "pro.vn", 2, false},
+	{1, "health.vn", 2, false},
+	{1, "vu", 1, false},
+	{1, "com.vu", 2, false},
+	{1, "edu.vu", 2, false},
+	{1, "net.vu", 2, false},
+	{1, "org.vu", 2, false},
+	{1, "wf", 1, false},
+	{1, "ws", 1, false},
+	{1, "com.ws", 2, false},
+	{1, "net.ws", 2, false},
+	{1, "org.ws", 2, false},
+	{1, "gov.ws", 2, false},
+	{1, "edu.ws", 2, false},
+	{1, "yt", 1, false},
+	{1, "xn--mgbaam7a8h", 1, false},
+	{1, "xn--y9a3aq", 1, false},
+	{1, "xn--54b7fta0cc", 1, false},
+	{1, "xn--90ae", 1, false},
+	{1, "xn--mgbcpq6gpa1a", 1, false},
+	{1, "xn--90ais", 1, false},
+	{1, "xn--fiqs8s", 1, false},
+	{1, "xn--fiqz9s", 1, false},
+	{1, "xn--lgbbat1ad8j", 1, false},
+	{1, "xn--wgbh1c", 1, false},
+	{1, "xn--e1a4c", 1, false},
+	{1, "xn--qxa6a", 1, false},
+	{1, "xn--mgbah1a3hjkrd", 1, false},
+	{1, "xn--node", 1, false},
+	{1, "xn--qxam", 1, false},
+	{1, "xn--j6w193g", 1, false},
+	{1, "xn--55qx5d.xn--j6w193g", 2, false},
+	{1, "xn--wcvs22d.xn--j6w193g", 2, false},
+	{1, "xn--mxtq1m.xn--j6w193g", 2, false},
+	{1, "xn--gmqw5a.xn--j6w193g", 2, false},
+	{1, "xn--od0alg.xn--j6w193g", 2, false},
+	{1, "xn--uc0atv.xn--j6w193g", 2, false},
+	{1, "xn--2scrj9c", 1, false},
+	{1, "xn--3hcrj9c", 1, false},
+	{1, "xn--45br5cyl", 1, false},
+	{1, "xn--h2breg3eve", 1, false},
+	{1, "xn--h2brj9c8c", 1, false},
+	{1, "xn--mgbgu82a", 1, false},
+	{1, "xn--rvc1e0am3e", 1, false},
+	{1, "xn--h2brj9c", 1, false},
+	{1, "xn--mgbbh1a", 1, false},
+	{1, "xn--mgbbh1a71e", 1, false},
+	{1, "xn--fpcrj9c3d", 1, false},
+	{1, "xn--gecrj9c", 1, false},
+	{1, "xn--s9brj9c", 1, false},
+	{1, "xn--45brj9c", 1, false},
+	{1, "xn--xkc2dl3a5ee0h", 1, false},
+	{1, "xn--mgba3a4f16a", 1, false},
+	{1, "xn--mgba3a4fra", 1, false},
+	{1, "xn--mgbtx2b", 1, false},
+	{1, "xn--mgbayh7gpa", 1, false},
+	{1, "xn--3e0b707e", 1, false},
+	{1, "xn--80ao21a", 1, false},
+	{1, "xn--q7ce6a", 1, false},
+	{1, "xn--fzc2c9e2c", 1, false},
+	{1, "xn--xkc2al3hye2a", 1, false},
+	{1, "xn--mgbc0a9azcg", 1, false},
+	{1, "xn--d1alf", 1, false},
+	{1, "xn--l1acc", 1, false},
+	{1, "xn--mix891f", 1, false},
+	{1, "xn--mix082f", 1, false},
+	{1, "xn--mgbx4cd0ab", 1, false},
+	{1, "xn--mgb9awbf", 1, false},
+	{1, "xn--mgbai9azgqp6j", 1, false},
+	{1, "xn--mgbai9a5eva00b", 1, false},
+	{1, "xn--ygbi2ammx", 1, false},
+	{1, "xn--90a3ac", 1, false},
+	{1, "xn--o1ac.xn--90a3ac", 2, false},
+	{1, "xn--c1avg.xn--90a3ac", 2, false},
+	{1, "xn--90azh.xn--90a3ac", 2, false},
+	{1, "xn--d1at.xn--90a3ac", 2, false},
+	{1, "xn--o1ach.xn--90a3ac", 2, false},
+	{1, "xn--80au.xn--90a3ac", 2, false},
+	{1, "xn--p1ai", 1, false},
+	{1, "xn--wgbl6a", 1, false},
+	{1, "xn--mgberp4a5d4ar", 1, false},
+	{1, "xn--mgberp4a5d4a87g", 1, false},
+	{1, "xn--mgbqly7c0a67fbc", 1, false},
+	{1, "xn--mgbqly7cvafr", 1, false},
+	{1, "xn--mgbpl2fh", 1, false},
+	{1, "xn--yfro4i67o", 1, false},
+	{1, "xn--clchc0ea0b2g2a9gcd", 1, false},
+	{1, "xn--ogbpf8fl", 1, false},
+	{1, "xn--mgbtf8fl", 1, false},
+	{1, "xn--o3cw4h", 1, false},
+	{1, "xn--12c1fe0br.xn--o3cw4h", 2, false},
+	{1, "xn--12co0c3b4eva.xn--o3cw4h", 2, false},
+	{1, "xn--h3cuzk1di.xn--o3cw4h", 2, false},
+	{1, "xn--o3cyx2a.xn--o3cw4h", 2, false},
+	{1, "xn--m3ch0j3a.xn--o3cw4h", 2, false},
+	{1, "xn--12cfi8ixb8l.xn--o3cw4h", 2, false},
+	{1, "xn--pgbs0dh", 1, false},
+	{1, "xn--kpry57d", 1, false},
+	{1, "xn--kprw13d", 1, false},
+	{1, "xn--nnx388a", 1, false},
+	{1, "xn--j1amh", 1, false},
+	{1, "xn--mgb2ddes", 1, false},
+	{1, "xxx", 1, false},
+	{1, "ye", 1, false},
+	{1, "com.ye", 2, false},
+	{1, "edu.ye", 2, false},
+	{1, "gov.ye", 2, false},
+	{1, "net.ye", 2, false},
+	{1, "mil.ye", 2, false},
+	{1, "org.ye", 2, false},
+	{1, "ac.za", 2, false},
+	{1, "agric.za", 2, false},
+	{1, "alt.za", 2, false},
+	{1, "co.za", 2, false},
+	{1, "edu.za", 2, false},
+	{1, "gov.za", 2, false},
+	{1, "grondar.za", 2, false},
+	{1, "law.za", 2, false},
+	{1, "mil.za", 2, false},
+	{1, "net.za", 2, false},
+	{1, "ngo.za", 2, false},
+	{1, "nic.za", 2, false},
+	{1, "nis.za", 2, false},
+	{1, "nom.za", 2, false},
+	{1, "org.za", 2, false},
+	{1, "school.za", 2, false},
+	{1, "tm.za", 2, false},
+	{1, "web.za", 2, false},
+	{1, "zm", 1, false},
+	{1, "ac.zm", 2, false},
+	{1, "biz.zm", 2, false},
+	{1, "co.zm", 2, false},
+	{1, "com.zm", 2, false},
+	{1, "edu.zm", 2, false},
+	{1, "gov.zm", 2, false},
+	{1, "info.zm", 2, false},
+	{1, "mil.zm", 2, false},
+	{1, "net.zm", 2, false},
+	{1, "org.zm", 2, false},
+	{1, "sch.zm", 2, false},
+	{1, "zw", 1, false},
+	{1, "ac.zw", 2, false},
+	{1, "co.zw", 2, false},
+	{1, "gov.zw", 2, false},
+	{1, "mil.zw", 2, false},
+	{1, "org.zw", 2, false},
+	{1, "aaa", 1, false},
+	{1, "aarp", 1, false},
+	{1, "abarth", 1, false},
+	{1, "abb", 1, false},
+	{1, "abbott", 1, false},
+	{1, "abbvie", 1, false},
+	{1, "abc", 1, false},
+	{1, "able", 1, false},
+	{1, "abogado", 1, false},
+	{1, "abudhabi", 1, false},
+	{1, "academy", 1, false},
+	{1, "accenture", 1, false},
+	{1, "accountant", 1, false},
+	{1, "accountants", 1, false},
+	{1, "aco", 1, false},
+	{1, "actor", 1, false},
+	{1, "adac", 1, false},
+	{1, "ads", 1, false},
+	{1, "adult", 1, false},
+	{1, "aeg", 1, false},
+	{1, "aetna", 1, false},
+	{1, "afamilycompany", 1, false},
+	{1, "afl", 1, false},
+	{1, "africa", 1, false},
+	{1, "agakhan", 1, false},
+	{1, "agency", 1, false},
+	{1, "aig", 1, false},
+	{1, "airbus", 1, false},
+	{1, "airforce", 1, false},
+	{1, "airtel", 1, false},
+	{1, "akdn", 1, false},
+	{1, "alfaromeo", 1, false},
+	{1, "alibaba", 1, false},
+	{1, "alipay", 1, false},
+	{1, "allfinanz", 1, false},
+	{1, "allstate", 1, false},
+	{1, "ally", 1, false},
+	{1, "alsace", 1, false},
+	{1, "alstom", 1, false},
+	{1, "amazon", 1, false},
+	{1, "americanexpress", 1, false},
+	{1, "americanfamily", 1, false},
+	{1, "amex", 1, false},
+	{1, "amfam", 1, false},
+	{1, "amica", 1, false},
+	{1, "amsterdam", 1, false},
+	{1, "analytics", 1, false},
+	{1, "android", 1, false},
+	{1, "anquan", 1, false},
+	{1, "anz", 1, false},
+	{1, "aol", 1, false},
+	{1, "apartments", 1, false},
+	{1, "app", 1, false},
+	{1, "apple", 1, false},
+	{1, "aquarelle", 1, false},
+	{1, "arab", 1, false},
+	{1, "aramco", 1, false},
+	{1, "archi", 1, false},
+	{1, "army", 1, false},
+	{1, "art", 1, false},
+	{1, "arte", 1, false},
+	{1, "asda", 1, false},
+	{1, "associates", 1, false},
+	{1, "athleta", 1, false},
+	{1, "attorney", 1, false},
+	{1, "auction", 1, false},
+	{1, "audi", 1, false},
+	{1, "audible", 1, false},
+	{1, "audio", 1, false},
+	{1, "auspost", 1, false},
+	{1, "author", 1, false},
+	{1, "auto", 1, false},
+	{1, "autos", 1, false},
+	{1, "avianca", 1, false},
+	{1, "aws", 1, false},
+	{1, "axa", 1, false},
+	{1, "azure", 1, false},
+	{1, "baby", 1, false},
+	{1, "baidu", 1, false},
+	{1, "banamex", 1, false},
+	{1, "bananarepublic", 1, false},
+	{1, "band", 1, false},
+	{1, "bank", 1, false},
+	{1, "bar", 1, false},
+	{1, "barcelona", 1, false},
+	{1, "barclaycard", 1, false},
+	{1, "barclays", 1, false},
+	{1, "barefoot", 1, false},
+	{1, "bargains", 1, false},
+	{1, "baseball", 1, false},
+	{1, "basketball", 1, false},
+	{1, "bauhaus", 1, false},
+	{1, "bayern", 1, false},
+	{1, "bbc", 1, false},
+	{1, "bbt", 1, false},
+	{1, "bbva", 1, false},
+	{1, "bcg", 1, false},
+	{1, "bcn", 1, false},
+	{1, "beats", 1, false},
+	{1, "beauty", 1, false},
+	{1, "beer", 1, false},
+	{1, "bentley", 1, false},
+	{1, "berlin", 1, false},
+	{1, "best", 1, false},
+	{1, "bestbuy", 1, false},
+	{1, "bet", 1, false},
+	{1, "bharti", 1, false},
+	{1, "bible", 1, false},
+	{1, "bid", 1, false},
+	{1, "bike", 1, false},
+	{1, "bing", 1, false},
+	{1, "bingo", 1, false},
+	{1, "bio", 1, false},
+	{1, "black", 1, false},
+	{1, "blackfriday", 1, false},
+	{1, "blockbuster", 1, false},
+	{1, "blog", 1, false},
+	{1, "bloomberg", 1, false},
+	{1, "blue", 1, false},
+	{1, "bms", 1, false},
+	{1, "bmw", 1, false},
+	{1, "bnpparibas", 1, false},
+	{1, "boats", 1, false},
+	{1, "boehringer", 1, false},
+	{1, "bofa", 1, false},
+	{1, "bom", 1, false},
+	{1, "bond", 1, false},
+	{1, "boo", 1, false},
+	{1, "book", 1, false},
+	{1, "booking", 1, false},
+	{1, "bosch", 1, false},
+	{1, "bostik", 1, false},
+	{1, "boston", 1, false},
+	{1, "bot", 1, false},
+	{1, "boutique", 1, false},
+	{1, "box", 1, false},
+	{1, "bradesco", 1, false},
+	{1, "bridgestone", 1, false},
+	{1, "broadway", 1, false},
+	{1, "broker", 1, false},
+	{1, "brother", 1, false},
+	{1, "brussels", 1, false},
+	{1, "budapest", 1, false},
+	{1, "bugatti", 1, false},
+	{1, "build", 1, false},
+	{1, "builders", 1, false},
+	{1, "business", 1, false},
+	{1, "buy", 1, false},
+	{1, "buzz", 1, false},
+	{1, "bzh", 1, false},
+	{1, "cab", 1, false},
+	{1, "cafe", 1, false},
+	{1, "cal", 1, false},
+	{1, "call", 1, false},
+	{1, "calvinklein", 1, false},
+	{1, "cam", 1, false},
+	{1, "camera", 1, false},
+	{1, "camp", 1, false},
+	{1, "cancerresearch", 1, false},
+	{1, "canon", 1, false},
+	{1, "capetown", 1, false},
+	{1, "capital", 1, false},
+	{1, "capitalone", 1, false},
+	{1, "car", 1, false},
+	{1, "caravan", 1, false},
+	{1, "cards", 1, false},
+	{1, "care", 1, false},
+	{1, "career", 1, false},
+	{1, "careers", 1, false},
+	{1, "cars", 1, false},
+	{1, "casa", 1, false},
+	{1, "case", 1, false},
+	{1, "cash", 1, false},
+	{1, "casino", 1, false},
+	{1, "catering", 1, false},
+	{1, "catholic", 1, false},
+	{1, "cba", 1, false},
+	{1, "cbn", 1, false},
+	{1, "cbre", 1, false},
+	{1, "cbs", 1, false},
+	{1, "center", 1, false},
+	{1, "ceo", 1, false},
+	{1, "cern", 1, false},
+	{1, "cfa", 1, false},
+	{1, "cfd", 1, false},
+	{1, "chanel", 1, false},
+	{1, "channel", 1, false},
+	{1, "charity", 1, false},
+	{1, "chase", 1, false},
+	{1, "chat", 1, false},
+	{1, "cheap", 1, false},
+	{1, "chintai", 1, false},
+	{1, "christmas", 1, false},
+	{1, "chrome", 1, false},
+	{1, "church", 1, false},
+	{1, "cipriani", 1, false},
+	{1, "circle", 1, false},
+	{1, "cisco", 1, false},
+	{1, "citadel", 1, false},
+	{1, "citi", 1, false},
+	{1, "citic", 1, false},
+	{1, "city", 1, false},
+	{1, "cityeats", 1, false},
+	{1, "claims", 1, false},
+	{1, "cleaning", 1, false},
+	{1, "click", 1, false},
+	{1, "clinic", 1, false},
+	{1, "clinique", 1, false},
+	{1, "clothing", 1, false},
+	{1, "cloud", 1, false},
+	{1, "club", 1, false},
+	{1, "clubmed", 1, false},
+	{1, "coach", 1, false},
+	{1, "codes", 1, false},
+	{1, "coffee", 1, false},
+	{1, "college", 1, false},
+	{1, "cologne", 1, false},
+	{1, "comcast", 1, false},
+	{1, "commbank", 1, false},
+	{1, "community", 1, false},
+	{1, "company", 1, false},
+	{1, "compare", 1, false},
+	{1, "computer", 1, false},
+	{1, "comsec", 1, false},
+	{1, "condos", 1, false},
+	{1, "construction", 1, false},
+	{1, "consulting", 1, false},
+	{1, "contact", 1, false},
+	{1, "contractors", 1, false},
+	{1, "cooking", 1, false},
+	{1, "cookingchannel", 1, false},
+	{1, "cool", 1, false},
+	{1, "corsica", 1, false},
+	{1, "country", 1, false},
+	{1, "coupon", 1, false},
+	{1, "coupons", 1, false},
+	{1, "courses", 1, false},
+	{1, "cpa", 1, false},
+	{1, "credit", 1, false},
+	{1, "creditcard", 1, false},
+	{1, "creditunion", 1, false},
+	{1, "cricket", 1, false},
+	{1, "crown", 1, false},
+	{1, "crs", 1, false},
+	{1, "cruise", 1, false},
+	{1, "cruises", 1, false},
+	{1, "csc", 1, false},
+	{1, "cuisinella", 1, false},
+	{1, "cymru", 1, false},
+	{1, "cyou", 1, false},
+	{1, "dabur", 1, false},
+	{1, "dad", 1, false},
+	{1, "dance", 1, false},
+	{1, "data", 1, false},
+	{1, "date", 1, false},
+	{1, "dating", 1, false},
+	{1, "datsun", 1, false},
+	{1, "day", 1, false},
+	{1, "dclk", 1, false},
+	{1, "dds", 1, false},
+	{1, "deal", 1, false},
+	{1, "dealer", 1, false},
+	{1, "deals", 1, false},
+	{1, "degree", 1, false},
+	{1, "delivery", 1, false},
+	{1, "dell", 1, false},
+	{1, "deloitte", 1, false},
+	{1, "delta", 1, false},
+	{1, "democrat", 1, false},
+	{1, "dental", 1, false},
+	{1, "dentist", 1, false},
+	{1, "desi", 1, false},
+	{1, "design", 1, false},
+	{1, "dev", 1, false},
+	{1, "dhl", 1, false},
+	{1, "diamonds", 1, false},
+	{1, "diet", 1, false},
+	{1, "digital", 1, false},
+	{1, "direct", 1, false},
+	{1, "directory", 1, false},
+	{1, "discount", 1, false},
+	{1, "discover", 1, false},
+	{1, "dish", 1, false},
+	{1, "diy", 1, false},
+	{1, "dnp", 1, false},
+	{1, "docs", 1, false},
+	{1, "doctor", 1, false},
+	{1, "dog", 1, false},
+	{1, "domains", 1, false},
+	{1, "dot", 1, false},
+	{1, "download", 1, false},
+	{1, "drive", 1, false},
+	{1, "dtv", 1, false},
+	{1, "dubai", 1, false},
+	{1, "duck", 1, false},
+	{1, "dunlop", 1, false},
+	{1, "dupont", 1, false},
+	{1, "durban", 1, false},
+	{1, "dvag", 1, false},
+	{1, "dvr", 1, false},
+	{1, "earth", 1, false},
+	{1, "eat", 1, false},
+	{1, "eco", 1, false},
+	{1, "edeka", 1, false},
+	{1, "education", 1, false},
+	{1, "email", 1, false},
+	{1, "emerck", 1, false},
+	{1, "energy", 1, false},
+	{1, "engineer", 1, false},
+	{1, "engineering", 1, false},
+	{1, "enterprises", 1, false},
+	{1, "epson", 1, false},
+	{1, "equipment", 1, false},
+	{1, "ericsson", 1, false},
+	{1, "erni", 1, false},
+	{1, "esq", 1, false},
+	{1, "estate", 1, false},
+	{1, "etisalat", 1, false},
+	{1, "eurovision", 1, false},
+	{1, "eus", 1, false},
+	{1, "events", 1, false},
+	{1, "exchange", 1, false},
+	{1, "expert", 1, false},
+	{1, "exposed", 1, false},
+	{1, "express", 1, false},
+	{1, "extraspace", 1, false},
+	{1, "fage", 1, false},
+	{1, "fail", 1, false},
+	{1, "fairwinds", 1, false},
+	{1, "faith", 1, false},
+	{1, "family", 1, false},
+	{1, "fan", 1, false},
+	{1, "fans", 1, false},
+	{1, "farm", 1, false},
+	{1, "farmers", 1, false},
+	{1, "fashion", 1, false},
+	{1, "fast", 1, false},
+	{1, "fedex", 1, false},
+	{1, "feedback", 1, false},
+	{1, "ferrari", 1, false},
+	{1, "ferrero", 1, false},
+	{1, "fiat", 1, false},
+	{1, "fidelity", 1, false},
+	{1, "fido", 1, false},
+	{1, "film", 1, false},
+	{1, "final", 1, false},
+	{1, "finance", 1, false},
+	{1, "financial", 1, false},
+	{1, "fire", 1, false},
+	{1, "firestone", 1, false},
+	{1, "firmdale", 1, false},
+	{1, "fish", 1, false},
+	{1, "fishing", 1, false},
+	{1, "fit", 1, false},
+	{1, "fitness", 1, false},
+	{1, "flickr", 1, false},
+	{1, "flights", 1, false},
+	{1, "flir", 1, false},
+	{1, "florist", 1, false},
+	{1, "flowers", 1, false},
+	{1, "fly", 1, false},
+	{1, "foo", 1, false},
+	{1, "food", 1, false},
+	{1, "foodnetwork", 1, false},
+	{1, "football", 1, false},
+	{1, "ford", 1, false},
+	{1, "forex", 1, false},
+	{1, "forsale", 1, false},
+	{1, "forum", 1, false},
+	{1, "foundation", 1, false},
+	{1, "fox", 1, false},
+	{1, "free", 1, false},
+	{1, "fresenius", 1, false},
+	{1, "frl", 1, false},
+	{1, "frogans", 1, false},
+	{1, "frontdoor", 1, false},
+	{1, "frontier", 1, false},
+	{1, "ftr", 1, false},
+	{1, "fujitsu", 1, false},
+	{1, "fun", 1, false},
+	{1, "fund", 1, false},
+	{1, "furniture", 1, false},
+	{1, "futbol", 1, false},
+	{1, "fyi", 1, false},
+	{1, "gal", 1, false},
+	{1, "gallery", 1, false},
+	{1, "gallo", 1, false},
+	{1, "gallup", 1, false},
+	{1, "game", 1, false},
+	{1, "games", 1, false},
+	{1, "gap", 1, false},
+	{1, "garden", 1, false},
+	{1, "gay", 1, false},
+	{1, "gbiz", 1, false},
+	{1, "gdn", 1, false},
+	{1, "gea", 1, false},
+	{1, "gent", 1, false},
+	{1, "genting", 1, false},
+	{1, "george", 1, false},
+	{1, "ggee", 1, false},
+	{1, "gift", 1, false},
+	{1, "gifts", 1, false},
+	{1, "gives", 1, false},
+	{1, "giving", 1, false},
+	{1, "glade", 1, false},
+	{1, "glass", 1, false},
+	{1, "gle", 1, false},
+	{1, "global", 1, false},
+	{1, "globo", 1, false},
+	{1, "gmail", 1, false},
+	{1, "gmbh", 1, false},
+	{1, "gmo", 1, false},
+	{1, "gmx", 1, false},
+	{1, "godaddy", 1, false},
+	{1, "gold", 1, false},
+	{1, "goldpoint", 1, false},
+	{1, "golf", 1, false},
+	{1, "goo", 1, false},
+	{1, "goodyear", 1, false},
+	{1, "goog", 1, false},
+	{1, "google", 1, false},
+	{1, "gop", 1, false},
+	{1, "got", 1, false},
+	{1, "grainger", 1, false},
+	{1, "graphics", 1, false},
+	{1, "gratis", 1, false},
+	{1, "green", 1, false},
+	{1, "gripe", 1, false},
+	{1, "grocery", 1, false},
+	{1, "group", 1, false},
+	{1, "guardian", 1, false},
+	{1, "gucci", 1, false},
+	{1, "guge", 1, false},
+	{1, "guide", 1, false},
+	{1, "guitars", 1, false},
+	{1, "guru", 1, false},
+	{1, "hair", 1, false},
+	{1, "hamburg", 1, false},
+	{1, "hangout", 1, false},
+	{1, "haus", 1, false},
+	{1, "hbo", 1, false},
+	{1, "hdfc", 1, false},
+	{1, "hdfcbank", 1, false},
+	{1, "health", 1, false},
+	{1, "healthcare", 1, false},
+	{1, "help", 1, false},
+	{1, "helsinki", 1, false},
+	{1, "here", 1, false},
+	{1, "hermes", 1, false},
+	{1, "hgtv", 1, false},
+	{1, "hiphop", 1, false},
+	{1, "hisamitsu", 1, false},
+	{1, "hitachi", 1, false},
+	{1, "hiv", 1, false},
+	{1, "hkt", 1, false},
+	{1, "hockey", 1, false},
+	{1, "holdings", 1, false},
+	{1, "holiday", 1, false},
+	{1, "homedepot", 1, false},
+	{1, "homegoods", 1, false},
+	{1, "homes", 1, false},
+	{1, "homesense", 1, false},
+	{1, "honda", 1, false},
+	{1, "horse", 1, false},
+	{1, "hospital", 1, false},
+	{1, "host", 1, false},
+	{1, "hosting", 1, false},
+	{1, "hot", 1, false},
+	{1, "hoteles", 1, false},
+	{1, "hotels", 1, false},
+	{1, "hotmail", 1, false},
+	{1, "house", 1, false},
+	{1, "how", 1, false},
+	{1, "hsbc", 1, false},
+	{1, "hughes", 1, false},
+	{1, "hyatt", 1, false},
+	{1, "hyundai", 1, false},
+	{1, "ibm", 1, false},
+	{1, "icbc", 1, false},
+	{1, "ice", 1, false},
+	{1, "icu", 1, false},
+	{1, "ieee", 1, false},
+	{1, "ifm", 1, false},
+	{1, "ikano", 1, false},
+	{1, "imamat", 1, false},
+	{1, "imdb", 1, false},
+	{1, "immo", 1, false},
+	{1, "immobilien", 1, false},
+	{1, "inc", 1, false},
+	{1, "industries", 1, false},
+	{1, "infiniti", 1, false},
+	{1, "ing", 1, false},
+	{1, "ink", 1, false},
+	{1, "institute", 1, false},
+	{1, "insurance", 1, false},
+	{1, "insure", 1, false},
+	{1, "international", 1, false},
+	{1, "intuit", 1, false},
+	{1, "investments", 1, false},
+	{1, "ipiranga", 1, false},
+	{1, "irish", 1, false},
+	{1, "ismaili", 1, false},
+	{1, "ist", 1, false},
+	{1, "istanbul", 1, false},
+	{1, "itau", 1, false},
+	{1, "itv", 1, false},
+	{1, "jaguar", 1, false},
+	{1, "java", 1, false},
+	{1, "jcb", 1, false},
+	{1, "jeep", 1, false},
+	{1, "jetzt", 1, false},
+	{1, "jewelry", 1, false},
+	{1, "jio", 1, false},
+	{1, "jll", 1, false},
+	{1, "jmp", 1, false},
+	{1, "jnj", 1, false},
+	{1, "joburg", 1, false},
+	{1, "jot", 1, false},
+	{1, "joy", 1, false},
+	{1, "jpmorgan", 1, false},
+	{1, "jprs", 1, false},
+	{1, "juegos", 1, false},
+	{1, "juniper", 1, false},
+	{1, "kaufen", 1, false},
+	{1, "kddi", 1, false},
+	{1, "kerryhotels", 1, false},
+	{1, "kerrylogistics", 1, false},
+	{1, "kerryproperties", 1, false},
+	{1, "kfh", 1, false},
+	{1, "kia", 1, false},
+	{1, "kim", 1, false},
+	{1, "kinder", 1, false},
+	{1, "kindle", 1, false},
+	{1, "kitchen", 1, false},
+	{1, "kiwi", 1, false},
+	{1, "koeln", 1, false},
+	{1, "komatsu", 1, false},
+	{1, "kosher", 1, false},
+	{1, "kpmg", 1, false},
+	{1, "kpn", 1, false},
+	{1, "krd", 1, false},
+	{1, "kred", 1, false},
+	{1, "kuokgroup", 1, false},
+	{1, "kyoto", 1, false},
+	{1, "lacaixa", 1, false},
+	{1, "lamborghini", 1, false},
+	{1, "lamer", 1, false},
+	{1, "lancaster", 1, false},
+	{1, "lancia", 1, false},
+	{1, "land", 1, false},
+	{1, "landrover", 1, false},
+	{1, "lanxess", 1, false},
+	{1, "lasalle", 1, false},
+	{1, "lat", 1, false},
+	{1, "latino", 1, false},
+	{1, "latrobe", 1, false},
+	{1, "law", 1, false},
+	{1, "lawyer", 1, false},
+	{1, "lds", 1, false},
+	{1, "lease", 1, false},
+	{1, "leclerc", 1, false},
+	{1, "lefrak", 1, false},
+	{1, "legal", 1, false},
+	{1, "lego", 1, false},
+	{1, "lexus", 1, false},
+	{1, "lgbt", 1, false},
+	{1, "lidl", 1, false},
+	{1, "life", 1, false},
+	{1, "lifeinsurance", 1, false},
+	{1, "lifestyle", 1, false},
+	{1, "lighting", 1, false},
+	{1, "like", 1, false},
+	{1, "lilly", 1, false},
+	{1, "limited", 1, false},
+	{1, "limo", 1, false},
+	{1, "lincoln", 1, false},
+	{1, "linde", 1, false},
+	{1, "link", 1, false},
+	{1, "lipsy", 1, false},
+	{1, "live", 1, false},
+	{1, "living", 1, false},
+	{1, "lixil", 1, false},
+	{1, "llc", 1, false},
+	{1, "llp", 1, false},
+	{1, "loan", 1, false},
+	{1, "loans", 1, false},
+	{1, "locker", 1, false},
+	{1, "locus", 1, false},
+	{1, "loft", 1, false},
+	{1, "lol", 1, false},
+	{1, "london", 1, false},
+	{1, "lotte", 1, false},
+	{1, "lotto", 1, false},
+	{1, "love", 1, false},
+	{1, "lpl", 1, false},
+	{1, "lplfinancial", 1, false},
+	{1, "ltd", 1, false},
+	{1, "ltda", 1, false},
+	{1, "lundbeck", 1, false},
+	{1, "luxe", 1, false},
+	{1, "luxury", 1, false},
+	{1, "macys", 1, false},
+	{1, "madrid", 1, false},
+	{1, "maif", 1, false},
+	{1, "maison", 1, false},
+	{1, "makeup", 1, false},
+	{1, "man", 1, false},
+	{1, "management", 1, false},
+	{1, "mango", 1, false},
+	{1, "map", 1, false},
+	{1, "market", 1, false},
+	{1, "marketing", 1, false},
+	{1, "markets", 1, false},
+	{1, "marriott", 1, false},
+	{1, "marshalls", 1, false},
+	{1, "maserati", 1, false},
+	{1, "mattel", 1, false},
+	{1, "mba", 1, false},
+	{1, "mckinsey", 1, false},
+	{1, "med", 1, false},
+	{1, "media", 1, false},
+	{1, "meet", 1, false},
+	{1, "melbourne", 1, false},
+	{1, "meme", 1, false},
+	{1, "memorial", 1, false},
+	{1, "men", 1, false},
+	{1, "menu", 1, false},
+	{1, "merckmsd", 1, false},
+	{1, "miami", 1, false},
+	{1, "microsoft", 1, false},
+	{1, "mini", 1, false},
+	{1, "mint", 1, false},
+	{1, "mit", 1, false},
+	{1, "mitsubishi", 1, false},
+	{1, "mlb", 1, false},
+	{1, "mls", 1, false},
+	{1, "mma", 1, false},
+	{1, "mobile", 1, false},
+	{1, "moda", 1, false},
+	{1, "moe", 1, false},
+	{1, "moi", 1, false},
+	{1, "mom", 1, false},
+	{1, "monash", 1, false},
+	{1, "money", 1, false},
+	{1, "monster", 1, false},
+	{1, "mormon", 1, false},
+	{1, "mortgage", 1, false},
+	{1, "moscow", 1, false},
+	{1, "moto", 1, false},
+	{1, "motorcycles", 1, false},
+	{1, "mov", 1, false},
+	{1, "movie", 1, false},
+	{1, "msd", 1, false},
+	{1, "mtn", 1, false},
+	{1, "mtr", 1, false},
+	{1, "mutual", 1, false},
+	{1, "nab", 1, false},
+	{1, "nagoya", 1, false},
+	{1, "natura", 1, false},
+	{1, "navy", 1, false},
+	{1, "nba", 1, false},
+	{1, "nec", 1, false},
+	{1, "netbank", 1, false},
+	{1, "netflix", 1, false},
+	{1, "network", 1, false},
+	{1, "neustar", 1, false},
+	{1, "new", 1, false},
+	{1, "news", 1, false},
+	{1, "next", 1, false},
+	{1, "nextdirect", 1, false},
+	{1, "nexus", 1, false},
+	{1, "nfl", 1, false},
+	{1, "ngo", 1, false},
+	{1, "nhk", 1, false},
+	{1, "nico", 1, false},
+	{1, "nike", 1, false},
+	{1, "nikon", 1, false},
+	{1, "ninja", 1, false},
+	{1, "nissan", 1, false},
+	{1, "nissay", 1, false},
+	{1, "nokia", 1, false},
+	{1, "northwesternmutual", 1, false},
+	{1, "norton", 1, false},
+	{1, "now", 1, false},
+	{1, "nowruz", 1, false},
+	{1, "nowtv", 1, false},
+	{1, "nra", 1, false},
+	{1, "nrw", 1, false},
+	{1, "ntt", 1, false},
+	{1, "nyc", 1, false},
+	{1, "obi", 1, false},
+	{1, "observer", 1, false},
+	{1, "off", 1, false},
+	{1, "office", 1, false},
+	{1, "okinawa", 1, false},
+	{1, "olayan", 1, false},
+	{1, "olayangroup", 1, false},
+	{1, "oldnavy", 1, false},
+	{1, "ollo", 1, false},
+	{1, "omega", 1, false},
+	{1, "one", 1, false},
+	{1, "ong", 1, false},
+	{1, "onl", 1, false},
+	{1, "online", 1, false},
+	{1, "ooo", 1, false},
+	{1, "open", 1, false},
+	{1, "oracle", 1, false},
+	{1, "orange", 1, false},
+	{1, "organic", 1, false},
+	{1, "origins", 1, false},
+	{1, "osaka", 1, false},
+	{1, "otsuka", 1, false},
+	{1, "ott", 1, false},
+	{1, "ovh", 1, false},
+	{1, "page", 1, false},
+	{1, "panasonic", 1, false},
+	{1, "paris", 1, false},
+	{1, "pars", 1, false},
+	{1, "partners", 1, false},
+	{1, "parts", 1, false},
+	{1, "party", 1, false},
+	{1, "passagens", 1, false},
+	{1, "pay", 1, false},
+	{1, "pccw", 1, false},
+	{1, "pet", 1, false},
+	{1, "pfizer", 1, false},
+	{1, "pharmacy", 1, false},
+	{1, "phd", 1, false},
+	{1, "philips", 1, false},
+	{1, "phone", 1, false},
+	{1, "photo", 1, false},
+	{1, "photography", 1, false},
+	{1, "photos", 1, false},
+	{1, "physio", 1, false},
+	{1, "pics", 1, false},
+	{1, "pictet", 1, false},
+	{1, "pictures", 1, false},
+	{1, "pid", 1, false},
+	{1, "pin", 1, false},
+	{1, "ping", 1, false},
+	{1, "pink", 1, false},
+	{1, "pioneer", 1, false},
+	{1, "pizza", 1, false},
+	{1, "place", 1, false},
+	{1, "play", 1, false},
+	{1, "playstation", 1, false},
+	{1, "plumbing", 1, false},
+	{1, "plus", 1, false},
+	{1, "pnc", 1, false},
+	{1, "pohl", 1, false},
+	{1, "poker", 1, false},
+	{1, "politie", 1, false},
+	{1, "porn", 1, false},
+	{1, "pramerica", 1, false},
+	{1, "praxi", 1, false},
+	{1, "press", 1, false},
+	{1, "prime", 1, false},
+	{1, "prod", 1, false},
+	{1, "productions", 1, false},
+	{1, "prof", 1, false},
+	{1, "progressive", 1, false},
+	{1, "promo", 1, false},
+	{1, "properties", 1, false},
+	{1, "property", 1, false},
+	{1, "protection", 1, false},
+	{1, "pru", 1, false},
+	{1, "prudential", 1, false},
+	{1, "pub", 1, false},
+	{1, "pwc", 1, false},
+	{1, "qpon", 1, false},
+	{1, "quebec", 1, false},
+	{1, "quest", 1, false},
+	{1, "qvc", 1, false},
+	{1, "racing", 1, false},
+	{1, "radio", 1, false},
+	{1, "raid", 1, false},
+	{1, "read", 1, false},
+	{1, "realestate", 1, false},
+	{1, "realtor", 1, false},
+	{1, "realty", 1, false},
+	{1, "recipes", 1, false},
+	{1, "red", 1, false},
+	{1, "redstone", 1, false},
+	{1, "redumbrella", 1, false},
+	{1, "rehab", 1, false},
+	{1, "reise", 1, false},
+	{1, "reisen", 1, false},
+	{1, "reit", 1, false},
+	{1, "reliance", 1, false},
+	{1, "ren", 1, false},
+	{1, "rent", 1, false},
+	{1, "rentals", 1, false},
+	{1, "repair", 1, false},
+	{1, "report", 1, false},
+	{1, "republican", 1, false},
+	{1, "rest", 1, false},
+	{1, "restaurant", 1, false},
+	{1, "review", 1, false},
+	{1, "reviews", 1, false},
+	{1, "rexroth", 1, false},
+	{1, "rich", 1, false},
+	{1, "richardli", 1, false},
+	{1, "ricoh", 1, false},
+	{1, "ril", 1, false},
+	{1, "rio", 1, false},
+	{1, "rip", 1, false},
+	{1, "rmit", 1, false},
+	{1, "rocher", 1, false},
+	{1, "rocks", 1, false},
+	{1, "rodeo", 1, false},
+	{1, "rogers", 1, false},
+	{1, "room", 1, false},
+	{1, "rsvp", 1, false},
+	{1, "rugby", 1, false},
+	{1, "ruhr", 1, false},
+	{1, "run", 1, false},
+	{1, "rwe", 1, false},
+	{1, "ryukyu", 1, false},
+	{1, "saarland", 1, false},
+	{1, "safe", 1, false},
+	{1, "safety", 1, false},
+	{1, "sakura", 1, false},
+	{1, "sale", 1, false},
+	{1, "salon", 1, false},
+	{1, "samsclub", 1, false},
+	{1, "samsung", 1, false},
+	{1, "sandvik", 1, false},
+	{1, "sandvikcoromant", 1, false},
+	{1, "sanofi", 1, false},
+	{1, "sap", 1, false},
+	{1, "sarl", 1, false},
+	{1, "sas", 1, false},
+	{1, "save", 1, false},
+	{1, "saxo", 1, false},
+	{1, "sbi", 1, false},
+	{1, "sbs", 1, false},
+	{1, "sca", 1, false},
+	{1, "scb", 1, false},
+	{1, "schaeffler", 1, false},
+	{1, "schmidt", 1, false},
+	{1, "scholarships", 1, false},
+	{1, "school", 1, false},
+	{1, "schule", 1, false},
+	{1, "schwarz", 1, false},
+	{1, "science", 1, false},
+	{1, "scjohnson", 1, false},
+	{1, "scot", 1, false},
+	{1, "search", 1, false},
+	{1, "seat", 1, false},
+	{1, "secure", 1, false},
+	{1, "security", 1, false},
+	{1, "seek", 1, false},
+	{1, "select", 1, false},
+	{1, "sener", 1, false},
+	{1, "services", 1, false},
+	{1, "ses", 1, false},
+	{1, "seven", 1, false},
+	{1, "sew", 1, false},
+	{1, "sex", 1, false},
+	{1, "sexy", 1, false},
+	{1, "sfr", 1, false},
+	{1, "shangrila", 1, false},
+	{1, "sharp", 1, false},
+	{1, "shaw", 1, false},
+	{1, "shell", 1, false},
+	{1, "shia", 1, false},
+	{1, "shiksha", 1, false},
+	{1, "shoes", 1, false},
+	{1, "shop", 1, false},
+	{1, "shopping", 1, false},
+	{1, "shouji", 1, false},
+	{1, "show", 1, false},
+	{1, "showtime", 1, false},
+	{1, "silk", 1, false},
+	{1, "sina", 1, false},
+	{1, "singles", 1, false},
+	{1, "site", 1, false},
+	{1, "ski", 1, false},
+	{1, "skin", 1, false},
+	{1, "sky", 1, false},
+	{1, "skype", 1, false},
+	{1, "sling", 1, false},
+	{1, "smart", 1, false},
+	{1, "smile", 1, false},
+	{1, "sncf", 1, false},
+	{1, "soccer", 1, false},
+	{1, "social", 1, false},
+	{1, "softbank", 1, false},
+	{1, "software", 1, false},
+	{1, "sohu", 1, false},
+	{1, "solar", 1, false},
+	{1, "solutions", 1, false},
+	{1, "song", 1, false},
+	{1, "sony", 1, false},
+	{1, "soy", 1, false},
+	{1, "spa", 1, false},
+	{1, "space", 1, false},
+	{1, "sport", 1, false},
+	{1, "spot", 1, false},
+	{1, "srl", 1, false},
+	{1, "stada", 1, false},
+	{1, "staples", 1, false},
+	{1, "star", 1, false},
+	{1, "statebank", 1, false},
+	{1, "statefarm", 1, false},
+	{1, "stc", 1, false},
+	{1, "stcgroup", 1, false},
+	{1, "stockholm", 1, false},
+	{1, "storage", 1, false},
+	{1, "store", 1, false},
+	{1, "stream", 1, false},
+	{1, "studio", 1, false},
+	{1, "study", 1, false},
+	{1, "style", 1, false},
+	{1, "sucks", 1, false},
+	{1, "supplies", 1, false},
+	{1, "supply", 1, false},
+	{1, "support", 1, false},
+	{1, "surf", 1, false},
+	{1, "surgery", 1, false},
+	{1, "suzuki", 1, false},
+	{1, "swatch", 1, false},
+	{1, "swiftcover", 1, false},
+	{1, "swiss", 1, false},
+	{1, "sydney", 1, false},
+	{1, "systems", 1, false},
+	{1, "tab", 1, false},
+	{1, "taipei", 1, false},
+	{1, "talk", 1, false},
+	{1, "taobao", 1, false},
+	{1, "target", 1, false},
+	{1, "tatamotors", 1, false},
+	{1, "tatar", 1, false},
+	{1, "tattoo", 1, false},
+	{1, "tax", 1, false},
+	{1, "taxi", 1, false},
+	{1, "tci", 1, false},
+	{1, "tdk", 1, false},
+	{1, "team", 1, false},
+	{1, "tech", 1, false},
+	{1, "technology", 1, false},
+	{1, "temasek", 1, false},
+	{1, "tennis", 1, false},
+	{1, "teva", 1, false},
+	{1, "thd", 1, false},
+	{1, "theater", 1, false},
+	{1, "theatre", 1, false},
+	{1, "tiaa", 1, false},
+	{1, "tickets", 1, false},
+	{1, "tienda", 1, false},
+	{1, "tiffany", 1, false},
+	{1, "tips", 1, false},
+	{1, "tires", 1, false},
+	{1, "tirol", 1, false},
+	{1, "tjmaxx", 1, false},
+	{1, "tjx", 1, false},
+	{1, "tkmaxx", 1, false},
+	{1, "tmall", 1, false},
+	{1, "today", 1, false},
+	{1, "tokyo", 1, false},
+	{1, "tools", 1, false},
+	{1, "top", 1, false},
+	{1, "toray", 1, false},
+	{1, "toshiba", 1, false},
+	{1, "total", 1, false},
+	{1, "tours", 1, false},
+	{1, "town", 1, false},
+	{1, "toyota", 1, false},
+	{1, "toys", 1, false},
+	{1, "trade", 1, false},
+	{1, "trading", 1, false},
+	{1, "training", 1, false},
+	{1, "travel", 1, false},
+	{1, "travelchannel", 1, false},
+	{1, "travelers", 1, false},
+	{1, "travelersinsurance", 1, false},
+	{1, "trust", 1, false},
+	{1, "trv", 1, false},
+	{1, "tube", 1, false},
+	{1, "tui", 1, false},
+	{1, "tunes", 1, false},
+	{1, "tushu", 1, false},
+	{1, "tvs", 1, false},
+	{1, "ubank", 1, false},
+	{1, "ubs", 1, false},
+	{1, "unicom", 1, false},
+	{1, "university", 1, false},
+	{1, "uno", 1, false},
+	{1, "uol", 1, false},
+	{1, "ups", 1, false},
+	{1, "vacations", 1, false},
+	{1, "vana", 1, false},
+	{1, "vanguard", 1, false},
+	{1, "vegas", 1, false},
+	{1, "ventures", 1, false},
+	{1, "verisign", 1, false},
+	{1, "versicherung", 1, false},
+	{1, "vet", 1, false},
+	{1, "viajes", 1, false},
+	{1, "video", 1, false},
+	{1, "vig", 1, false},
+	{1, "viking", 1, false},
+	{1, "villas", 1, false},
+	{1, "vin", 1, false},
+	{1, "vip", 1, false},
+	{1, "virgin", 1, false},
+	{1, "visa", 1, false},
+	{1, "vision", 1, false},
+	{1, "viva", 1, false},
+	{1, "vivo", 1, false},
+	{1, "vlaanderen", 1, false},
+	{1, "vodka", 1, false},
+	{1, "volkswagen", 1, false},
+	{1, "volvo", 1, false},
+	{1, "vote", 1, false},
+	{1, "voting", 1, false},
+	{1, "voto", 1, false},
+	{1, "voyage", 1, false},
+	{1, "vuelos", 1, false},
+	{1, "wales", 1, false},
+	{1, "walmart", 1, false},
+	{1, "walter", 1, false},
+	{1, "wang", 1, false},
+	{1, "wanggou", 1, false},
+	{1, "watch", 1, false},
+	{1, "watches", 1, false},
+	{1, "weather", 1, false},
+	{1, "weatherchannel", 1, false},
+	{1, "webcam", 1, false},
+	{1, "weber", 1, false},
+	{1, "website", 1, false},
+	{1, "wedding", 1, false},
+	{1, "weibo", 1, false},
+	{1, "weir", 1, false},
+	{1, "whoswho", 1, false},
+	{1, "wien", 1, false},
+	{1, "wiki", 1, false},
+	{1, "williamhill", 1, false},
+	{1, "win", 1, false},
+	{1, "windows", 1, false},
+	{1, "wine", 1, false},
+	{1, "winners", 1, false},
+	{1, "wme", 1, false},
+	{1, "wolterskluwer", 1, false},
+	{1, "woodside", 1, false},
+	{1, "work", 1, false},
+	{1, "works", 1, false},
+	{1, "world", 1, false},
+	{1, "wow", 1, false},
+	{1, "wtc", 1, false},
+	{1, "wtf", 1, false},
+	{1, "xbox", 1, false},
+	{1, "xerox", 1, false},
+	{1, "xfinity", 1, false},
+	{1, "xihuan", 1, false},
+	{1, "xin", 1, false},
+	{1, "xn--11b4c3d", 1, false},
+	{1, "xn--1ck2e1b", 1, false},
+	{1, "xn--1qqw23a", 1, false},
+	{1, "xn--30rr7y", 1, false},
+	{1, "xn--3bst00m", 1, false},
+	{1, "xn--3ds443g", 1, false},
+	{1, "xn--3oq18vl8pn36a", 1, false},
+	{1, "xn--3pxu8k", 1, false},
+	{1, "xn--42c2d9a", 1, false},
+	{1, "xn--45q11c", 1, false},
+	{1, "xn--4gbrim", 1, false},
+	{1, "xn--55qw42g", 1, false},
+	{1, "xn--55qx5d", 1, false},
+	{1, "xn--5su34j936bgsg", 1, false},
+	{1, "xn--5tzm5g", 1, false},
+	{1, "xn--6frz82g", 1, false},
+	{1, "xn--6qq986b3xl", 1, false},
+	{1, "xn--80adxhks", 1, false},
+	{1, "xn--80aqecdr1a", 1, false},
+	{1, "xn--80asehdb", 1, false},
+	{1, "xn--80aswg", 1, false},
+	{1, "xn--8y0a063a", 1, false},
+	{1, "xn--9dbq2a", 1, false},
+	{1, "xn--9et52u", 1, false},
+	{1, "xn--9krt00a", 1, false},
+	{1, "xn--b4w605ferd", 1, false},
+	{1, "xn--bck1b9a5dre4c", 1, false},
+	{1, "xn--c1avg", 1, false},
+	{1, "xn--c2br7g", 1, false},
+	{1, "xn--cck2b3b", 1, false},
+	{1, "xn--cckwcxetd", 1, false},
+	{1, "xn--cg4bki", 1, false},
+	{1, "xn--czr694b", 1, false},
+	{1, "xn--czrs0t", 1, false},
+	{1, "xn--czru2d", 1, false},
+	{1, "xn--d1acj3b", 1, false},
+	{1, "xn--eckvdtc9d", 1, false},
+	{1, "xn--efvy88h", 1, false},
+	{1, "xn--fct429k", 1, false},
+	{1, "xn--fhbei", 1, false},
+	{1, "xn--fiq228c5hs", 1, false},
+	{1, "xn--fiq64b", 1, false},
+	{1, "xn--fjq720a", 1, false},
+	{1, "xn--flw351e", 1, false},
+	{1, "xn--fzys8d69uvgm", 1, false},
+	{1, "xn--g2xx48c", 1, false},
+	{1, "xn--gckr3f0f", 1, false},
+	{1, "xn--gk3at1e", 1, false},
+	{1, "xn--hxt814e", 1, false},
+	{1, "xn--i1b6b1a6a2e", 1, false},
+	{1, "xn--imr513n", 1, false},
+	{1, "xn--io0a7i", 1, false},
+	{1, "xn--j1aef", 1, false},
+	{1, "xn--jlq480n2rg", 1, false},
+	{1, "xn--jlq61u9w7b", 1, false},
+	{1, "xn--jvr189m", 1, false},
+	{1, "xn--kcrx77d1x4a", 1, false},
+	{1, "xn--kput3i", 1, false},
+	{1, "xn--mgba3a3ejt", 1, false},
+	{1, "xn--mgba7c0bbn0a", 1, false},
+	{1, "xn--mgbaakc7dvf", 1, false},
+	{1, "xn--mgbab2bd", 1, false},
+	{1, "xn--mgbca7dzdo", 1, false},
+	{1, "xn--mgbi4ecexp", 1, false},
+	{1, "xn--mgbt3dhd", 1, false},
+	{1, "xn--mk1bu44c", 1, false},
+	{1, "xn--mxtq1m", 1, false},
+	{1, "xn--ngbc5azd", 1, false},
+	{1, "xn--ngbe9e0a", 1, false},
+	{1, "xn--ngbrx", 1, false},
+	{1, "xn--nqv7f", 1, false},
+	{1, "xn--nqv7fs00ema", 1, false},
+	{1, "xn--nyqy26a", 1, false},
+	{1, "xn--otu796d", 1, false},
+	{1, "xn--p1acf", 1, false},
+	{1, "xn--pssy2u", 1, false},
+	{1, "xn--q9jyb4c", 1, false},
+	{1, "xn--qcka1pmc", 1, false},
+	{1, "xn--rhqv96g", 1, false},
+	{1, "xn--rovu88b", 1, false},
+	{1, "xn--ses554g", 1, false},
+	{1, "xn--t60b56a", 1, false},
+	{1, "xn--tckwe", 1, false},
+	{1, "xn--tiq49xqyj", 1, false},
+	{1, "xn--unup4y", 1, false},
+	{1, "xn--vermgensberater-ctb", 1, false},
+	{1, "xn--vermgensberatung-pwb", 1, false},
+	{1, "xn--vhquv", 1, false},
+	{1, "xn--vuq861b", 1, false},
+	{1, "xn--w4r85el8fhu5dnra", 1, false},
+	{1, "xn--w4rs40l", 1, false},
+	{1, "xn--xhq521b", 1, false},
+	{1, "xn--zfr164b", 1, false},
+	{1, "xyz", 1, false},
+	{1, "yachts", 1, false},
+	{1, "yahoo", 1, false},
+	{1, "yamaxun", 1, false},
+	{1, "yandex", 1, false},
+	{1, "yodobashi", 1, false},
+	{1, "yoga", 1, false},
+	{1, "yokohama", 1, false},
+	{1, "you", 1, false},
+	{1, "youtube", 1, false},
+	{1, "yun", 1, false},
+	{1, "zappos", 1, false},
+	{1, "zara", 1, false},
+	{1, "zero", 1, false},
+	{1, "zip", 1, false},
+	{1, "zone", 1, false},
+	{1, "zuerich", 1, false},
+	{1, "cc.ua", 2, true},
+	{1, "inf.ua", 2, true},
+	{1, "ltd.ua", 2, true},
+	{1, "611.to", 2, true},
+	{1, "graphox.us", 2, true},
+	{2, "devcdnaccesso.com", 3, true},
+	{1, "adobeaemcloud.com", 2, true},
+	{1, "adobeaemcloud.net", 2, true},
+	{2, "dev.adobeaemcloud.com", 4, true},
+	{1, "beep.pl", 2, true},
+	{1, "barsy.ca", 2, true},
+	{2, "compute.estate", 3, true},
+	{2, "alces.network", 3, true},
+	{1, "kasserver.com", 2, true},
+	{1, "altervista.org", 2, true},
+	{1, "alwaysdata.net", 2, true},
+	{1, "cloudfront.net", 2, true},
+	{2, "compute.amazonaws.com", 4, true},
+	{2, "compute-1.amazonaws.com", 4, true},
+	{2, "compute.amazonaws.com.cn", 5, true},
+	{1, "us-east-1.amazonaws.com", 3, true},
+	{1, "cn-north-1.eb.amazonaws.com.cn", 5, true},
+	{1, "cn-northwest-1.eb.amazonaws.com.cn", 5, true},
+	{1, "elasticbeanstalk.com", 2, true},
+	{1, "ap-northeast-1.elasticbeanstalk.com", 3, true},
+	{1, "ap-northeast-2.elasticbeanstalk.com", 3, true},
+	{1, "ap-northeast-3.elasticbeanstalk.com", 3, true},
+	{1, "ap-south-1.elasticbeanstalk.com", 3, true},
+	{1, "ap-southeast-1.elasticbeanstalk.com", 3, true},
+	{1, "ap-southeast-2.elasticbeanstalk.com", 3, true},
+	{1, "ca-central-1.elasticbeanstalk.com", 3, true},
+	{1, "eu-central-1.elasticbeanstalk.com", 3, true},
+	{1, "eu-west-1.elasticbeanstalk.com", 3, true},
+	{1, "eu-west-2.elasticbeanstalk.com", 3, true},
+	{1, "eu-west-3.elasticbeanstalk.com", 3, true},
+	{1, "sa-east-1.elasticbeanstalk.com", 3, true},
+	{1, "us-east-1.elasticbeanstalk.com", 3, true},
+	{1, "us-east-2.elasticbeanstalk.com", 3, true},
+	{1, "us-gov-west-1.elasticbeanstalk.com", 3, true},
+	{1, "us-west-1.elasticbeanstalk.com", 3, true},
+	{1, "us-west-2.elasticbeanstalk.com", 3, true},
+	{2, "elb.amazonaws.com", 4, true},
+	{2, "elb.amazonaws.com.cn", 5, true},
+	{1, "awsglobalaccelerator.com", 2, true},
+	{1, "s3.amazonaws.com", 3, true},
+	{1, "s3-ap-northeast-1.amazonaws.com", 3, true},
+	{1, "s3-ap-northeast-2.amazonaws.com", 3, true},
+	{1, "s3-ap-south-1.amazonaws.com", 3, true},
+	{1, "s3-ap-southeast-1.amazonaws.com", 3, true},
+	{1, "s3-ap-southeast-2.amazonaws.com", 3, true},
+	{1, "s3-ca-central-1.amazonaws.com", 3, true},
+	{1, "s3-eu-central-1.amazonaws.com", 3, true},
+	{1, "s3-eu-west-1.amazonaws.com", 3, true},
+	{1, "s3-eu-west-2.amazonaws.com", 3, true},
+	{1, "s3-eu-west-3.amazonaws.com", 3, true},
+	{1, "s3-external-1.amazonaws.com", 3, true},
+	{1, "s3-fips-us-gov-west-1.amazonaws.com", 3, true},
+	{1, "s3-sa-east-1.amazonaws.com", 3, true},
+	{1, "s3-us-gov-west-1.amazonaws.com", 3, true},
+	{1, "s3-us-east-2.amazonaws.com", 3, true},
+	{1, "s3-us-west-1.amazonaws.com", 3, true},
+	{1, "s3-us-west-2.amazonaws.com", 3, true},
+	{1, "s3.ap-northeast-2.amazonaws.com", 4, true},
+	{1, "s3.ap-south-1.amazonaws.com", 4, true},
+	{1, "s3.cn-north-1.amazonaws.com.cn", 5, true},
+	{1, "s3.ca-central-1.amazonaws.com", 4, true},
+	{1, "s3.eu-central-1.amazonaws.com", 4, true},
+	{1, "s3.eu-west-2.amazonaws.com", 4, true},
+	{1, "s3.eu-west-3.amazonaws.com", 4, true},
+	{1, "s3.us-east-2.amazonaws.com", 4, true},
+	{1, "s3.dualstack.ap-northeast-1.amazonaws.com", 5, true},
+	{1, "s3.dualstack.ap-northeast-2.amazonaws.com", 5, true},
+	{1, "s3.dualstack.ap-south-1.amazonaws.com", 5, true},
+	{1, "s3.dualstack.ap-southeast-1.amazonaws.com", 5, true},
+	{1, "s3.dualstack.ap-southeast-2.amazonaws.com", 5, true},
+	{1, "s3.dualstack.ca-central-1.amazonaws.com", 5, true},
+	{1, "s3.dualstack.eu-central-1.amazonaws.com", 5, true},
+	{1, "s3.dualstack.eu-west-1.amazonaws.com", 5, true},
+	{1, "s3.dualstack.eu-west-2.amazonaws.com", 5, true},
+	{1, "s3.dualstack.eu-west-3.amazonaws.com", 5, true},
+	{1, "s3.dualstack.sa-east-1.amazonaws.com", 5, true},
+	{1, "s3.dualstack.us-east-1.amazonaws.com", 5, true},
+	{1, "s3.dualstack.us-east-2.amazonaws.com", 5, true},
+	{1, "s3-website-us-east-1.amazonaws.com", 3, true},
+	{1, "s3-website-us-west-1.amazonaws.com", 3, true},
+	{1, "s3-website-us-west-2.amazonaws.com", 3, true},
+	{1, "s3-website-ap-northeast-1.amazonaws.com", 3, true},
+	{1, "s3-website-ap-southeast-1.amazonaws.com", 3, true},
+	{1, "s3-website-ap-southeast-2.amazonaws.com", 3, true},
+	{1, "s3-website-eu-west-1.amazonaws.com", 3, true},
+	{1, "s3-website-sa-east-1.amazonaws.com", 3, true},
+	{1, "s3-website.ap-northeast-2.amazonaws.com", 4, true},
+	{1, "s3-website.ap-south-1.amazonaws.com", 4, true},
+	{1, "s3-website.ca-central-1.amazonaws.com", 4, true},
+	{1, "s3-website.eu-central-1.amazonaws.com", 4, true},
+	{1, "s3-website.eu-west-2.amazonaws.com", 4, true},
+	{1, "s3-website.eu-west-3.amazonaws.com", 4, true},
+	{1, "s3-website.us-east-2.amazonaws.com", 4, true},
+	{1, "amsw.nl", 2, true},
+	{1, "t3l3p0rt.net", 2, true},
+	{1, "tele.amune.org", 3, true},
+	{1, "apigee.io", 2, true},
+	{1, "appspacehosted.com", 2, true},
+	{1, "appspaceusercontent.com", 2, true},
+	{1, "on-aptible.com", 2, true},
+	{1, "user.aseinet.ne.jp", 4, true},
+	{1, "gv.vc", 2, true},
+	{1, "d.gv.vc", 3, true},
+	{1, "user.party.eus", 3, true},
+	{1, "pimienta.org", 2, true},
+	{1, "poivron.org", 2, true},
+	{1, "potager.org", 2, true},
+	{1, "sweetpepper.org", 2, true},
+	{1, "myasustor.com", 2, true},
+	{1, "myfritz.net", 2, true},
+	{2, "awdev.ca", 3, true},
+	{2, "advisor.ws", 3, true},
+	{1, "b-data.io", 2, true},
+	{1, "backplaneapp.io", 2, true},
+	{1, "balena-devices.com", 2, true},
+	{2, "banzai.cloud", 3, true},
+	{1, "app.banzaicloud.io", 3, true},
+	{2, "backyards.banzaicloud.io", 4, true},
+	{1, "betainabox.com", 2, true},
+	{1, "bnr.la", 2, true},
+	{1, "blackbaudcdn.net", 2, true},
+	{1, "of.je", 2, true},
+	{1, "boomla.net", 2, true},
+	{1, "boutir.com", 2, true},
+	{1, "boxfuse.io", 2, true},
+	{1, "square7.ch", 2, true},
+	{1, "bplaced.com", 2, true},
+	{1, "bplaced.de", 2, true},
+	{1, "square7.de", 2, true},
+	{1, "bplaced.net", 2, true},
+	{1, "square7.net", 2, true},
+	{1, "browsersafetymark.io", 2, true},
+	{1, "uk0.bigv.io", 3, true},
+	{1, "dh.bytemark.co.uk", 4, true},
+	{1, "vm.bytemark.co.uk", 4, true},
+	{1, "cafjs.com", 2, true},
+	{1, "mycd.eu", 2, true},
+	{1, "carrd.co", 2, true},
+	{1, "crd.co", 2, true},
+	{1, "uwu.ai", 2, true},
+	{1, "ae.org", 2, true},
+	{1, "br.com", 2, true},
+	{1, "cn.com", 2, true},
+	{1, "com.de", 2, true},
+	{1, "com.se", 2, true},
+	{1, "de.com", 2, true},
+	{1, "eu.com", 2, true},
+	{1, "gb.net", 2, true},
+	{1, "hu.net", 2, true},
+	{1, "jp.net", 2, true},
+	{1, "jpn.com", 2, true},
+	{1, "mex.com", 2, true},
+	{1, "ru.com", 2, true},
+	{1, "sa.com", 2, true},
+	{1, "se.net", 2, true},
+	{1, "uk.com", 2, true},
+	{1, "uk.net", 2, true},
+	{1, "us.com", 2, true},
+	{1, "za.bz", 2, true},
+	{1, "za.com", 2, true},
+	{1, "ar.com", 2, true},
+	{1, "gb.com", 2, true},
+	{1, "hu.com", 2, true},
+	{1, "kr.com", 2, true},
+	{1, "no.com", 2, true},
+	{1, "qc.com", 2, true},
+	{1, "uy.com", 2, true},
+	{1, "africa.com", 2, true},
+	{1, "gr.com", 2, true},
+	{1, "in.net", 2, true},
+	{1, "web.in", 2, true},
+	{1, "us.org", 2, true},
+	{1, "co.com", 2, true},
+	{1, "aus.basketball", 2, true},
+	{1, "nz.basketball", 2, true},
+	{1, "radio.am", 2, true},
+	{1, "radio.fm", 2, true},
+	{1, "c.la", 2, true},
+	{1, "certmgr.org", 2, true},
+	{1, "cx.ua", 2, true},
+	{1, "discourse.group", 2, true},
+	{1, "discourse.team", 2, true},
+	{1, "virtueeldomein.nl", 2, true},
+	{1, "cleverapps.io", 2, true},
+	{2, "lcl.dev", 3, true},
+	{2, "lclstage.dev", 3, true},
+	{2, "stg.dev", 3, true},
+	{2, "stgstage.dev", 3, true},
+	{1, "clic2000.net", 2, true},
+	{1, "clickrising.net", 2, true},
+	{1, "c66.me", 2, true},
+	{1, "cloud66.ws", 2, true},
+	{1, "cloud66.zone", 2, true},
+	{1, "jdevcloud.com", 2, true},
+	{1, "wpdevcloud.com", 2, true},
+	{1, "cloudaccess.host", 2, true},
+	{1, "freesite.host", 2, true},
+	{1, "cloudaccess.net", 2, true},
+	{1, "cloudcontrolled.com", 2, true},
+	{1, "cloudcontrolapp.com", 2, true},
+	{1, "cloudera.site", 2, true},
+	{1, "pages.dev", 2, true},
+	{1, "trycloudflare.com", 2, true},
+	{1, "workers.dev", 2, true},
+	{1, "wnext.app", 2, true},
+	{1, "co.ca", 2, true},
+	{2, "otap.co", 3, true},
+	{1, "co.cz", 2, true},
+	{1, "c.cdn77.org", 3, true},
+	{1, "cdn77-ssl.net", 2, true},
+	{1, "r.cdn77.net", 3, true},
+	{1, "rsc.cdn77.org", 3, true},
+	{1, "ssl.origin.cdn77-secure.org", 4, true},
+	{1, "cloudns.asia", 2, true},
+	{1, "cloudns.biz", 2, true},
+	{1, "cloudns.club", 2, true},
+	{1, "cloudns.cc", 2, true},
+	{1, "cloudns.eu", 2, true},
+	{1, "cloudns.in", 2, true},
+	{1, "cloudns.info", 2, true},
+	{1, "cloudns.org", 2, true},
+	{1, "cloudns.pro", 2, true},
+	{1, "cloudns.pw", 2, true},
+	{1, "cloudns.us", 2, true},
+	{1, "cnpy.gdn", 2, true},
+	{1, "co.nl", 2, true},
+	{1, "co.no", 2, true},
+	{1, "webhosting.be", 2, true},
+	{1, "hosting-cluster.nl", 2, true},
+	{1, "ac.ru", 2, true},
+	{1, "edu.ru", 2, true},
+	{1, "gov.ru", 2, true},
+	{1, "int.ru", 2, true},
+	{1, "mil.ru", 2, true},
+	{1, "test.ru", 2, true},
+	{1, "dyn.cosidns.de", 3, true},
+	{1, "dynamisches-dns.de", 2, true},
+	{1, "dnsupdater.de", 2, true},
+	{1, "internet-dns.de", 2, true},
+	{1, "l-o-g-i-n.de", 2, true},
+	{1, "dynamic-dns.info", 2, true},
+	{1, "feste-ip.net", 2, true},
+	{1, "knx-server.net", 2, true},
+	{1, "static-access.net", 2, true},
+	{1, "realm.cz", 2, true},
+	{2, "cryptonomic.net", 3, true},
+	{1, "cupcake.is", 2, true},
+	{1, "curv.dev", 2, true},
+	{1, "multibaas.app", 2, true},
+	{1, "multibaas.com", 2, true},
+	{2, "customer-oci.com", 3, true},
+	{2, "oci.customer-oci.com", 4, true},
+	{2, "ocp.customer-oci.com", 4, true},
+	{2, "ocs.customer-oci.com", 4, true},
+	{1, "cyon.link", 2, true},
+	{1, "cyon.site", 2, true},
+	{1, "fnwk.site", 2, true},
+	{1, "folionetwork.site", 2, true},
+	{1, "platform0.app", 2, true},
+	{1, "daplie.me", 2, true},
+	{1, "localhost.daplie.me", 3, true},
+	{1, "dattolocal.com", 2, true},
+	{1, "dattorelay.com", 2, true},
+	{1, "dattoweb.com", 2, true},
+	{1, "mydatto.com", 2, true},
+	{1, "dattolocal.net", 2, true},
+	{1, "mydatto.net", 2, true},
+	{1, "biz.dk", 2, true},
+	{1, "co.dk", 2, true},
+	{1, "firm.dk", 2, true},
+	{1, "reg.dk", 2, true},
+	{1, "store.dk", 2, true},
+	{1, "dyndns.dappnode.io", 3, true},
+	{2, "dapps.earth", 3, true},
+	{2, "bzz.dapps.earth", 4, true},
+	{1, "builtwithdark.com", 2, true},
+	{1, "edgestack.me", 2, true},
+	{1, "debian.net", 2, true},
+	{1, "deno.dev", 2, true},
+	{1, "deno-staging.dev", 2, true},
+	{1, "dedyn.io", 2, true},
+	{1, "jozi.biz", 2, true},
+	{1, "dnshome.de", 2, true},
+	{1, "online.th", 2, true},
+	{1, "shop.th", 2, true},
+	{1, "drayddns.com", 2, true},
+	{1, "shoparena.pl", 2, true},
+	{1, "dreamhosters.com", 2, true},
+	{1, "mydrobo.com", 2, true},
+	{1, "drud.io", 2, true},
+	{1, "drud.us", 2, true},
+	{1, "duckdns.org", 2, true},
+	{1, "bip.sh", 2, true},
+	{1, "bitbridge.net", 2, true},
+	{1, "dy.fi", 2, true},
+	{1, "tunk.org", 2, true},
+	{1, "dyndns-at-home.com", 2, true},
+	{1, "dyndns-at-work.com", 2, true},
+	{1, "dyndns-blog.com", 2, true},
+	{1, "dyndns-free.com", 2, true},
+	{1, "dyndns-home.com", 2, true},
+	{1, "dyndns-ip.com", 2, true},
+	{1, "dyndns-mail.com", 2, true},
+	{1, "dyndns-office.com", 2, true},
+	{1, "dyndns-pics.com", 2, true},
+	{1, "dyndns-remote.com", 2, true},
+	{1, "dyndns-server.com", 2, true},
+	{1, "dyndns-web.com", 2, true},
+	{1, "dyndns-wiki.com", 2, true},
+	{1, "dyndns-work.com", 2, true},
+	{1, "dyndns.biz", 2, true},
+	{1, "dyndns.info", 2, true},
+	{1, "dyndns.org", 2, true},
+	{1, "dyndns.tv", 2, true},
+	{1, "at-band-camp.net", 2, true},
+	{1, "ath.cx", 2, true},
+	{1, "barrel-of-knowledge.info", 2, true},
+	{1, "barrell-of-knowledge.info", 2, true},
+	{1, "better-than.tv", 2, true},
+	{1, "blogdns.com", 2, true},
+	{1, "blogdns.net", 2, true},
+	{1, "blogdns.org", 2, true},
+	{1, "blogsite.org", 2, true},
+	{1, "boldlygoingnowhere.org", 2, true},
+	{1, "broke-it.net", 2, true},
+	{1, "buyshouses.net", 2, true},
+	{1, "cechire.com", 2, true},
+	{1, "dnsalias.com", 2, true},
+	{1, "dnsalias.net", 2, true},
+	{1, "dnsalias.org", 2, true},
+	{1, "dnsdojo.com", 2, true},
+	{1, "dnsdojo.net", 2, true},
+	{1, "dnsdojo.org", 2, true},
+	{1, "does-it.net", 2, true},
+	{1, "doesntexist.com", 2, true},
+	{1, "doesntexist.org", 2, true},
+	{1, "dontexist.com", 2, true},
+	{1, "dontexist.net", 2, true},
+	{1, "dontexist.org", 2, true},
+	{1, "doomdns.com", 2, true},
+	{1, "doomdns.org", 2, true},
+	{1, "dvrdns.org", 2, true},
+	{1, "dyn-o-saur.com", 2, true},
+	{1, "dynalias.com", 2, true},
+	{1, "dynalias.net", 2, true},
+	{1, "dynalias.org", 2, true},
+	{1, "dynathome.net", 2, true},
+	{1, "dyndns.ws", 2, true},
+	{1, "endofinternet.net", 2, true},
+	{1, "endofinternet.org", 2, true},
+	{1, "endoftheinternet.org", 2, true},
+	{1, "est-a-la-maison.com", 2, true},
+	{1, "est-a-la-masion.com", 2, true},
+	{1, "est-le-patron.com", 2, true},
+	{1, "est-mon-blogueur.com", 2, true},
+	{1, "for-better.biz", 2, true},
+	{1, "for-more.biz", 2, true},
+	{1, "for-our.info", 2, true},
+	{1, "for-some.biz", 2, true},
+	{1, "for-the.biz", 2, true},
+	{1, "forgot.her.name", 3, true},
+	{1, "forgot.his.name", 3, true},
+	{1, "from-ak.com", 2, true},
+	{1, "from-al.com", 2, true},
+	{1, "from-ar.com", 2, true},
+	{1, "from-az.net", 2, true},
+	{1, "from-ca.com", 2, true},
+	{1, "from-co.net", 2, true},
+	{1, "from-ct.com", 2, true},
+	{1, "from-dc.com", 2, true},
+	{1, "from-de.com", 2, true},
+	{1, "from-fl.com", 2, true},
+	{1, "from-ga.com", 2, true},
+	{1, "from-hi.com", 2, true},
+	{1, "from-ia.com", 2, true},
+	{1, "from-id.com", 2, true},
+	{1, "from-il.com", 2, true},
+	{1, "from-in.com", 2, true},
+	{1, "from-ks.com", 2, true},
+	{1, "from-ky.com", 2, true},
+	{1, "from-la.net", 2, true},
+	{1, "from-ma.com", 2, true},
+	{1, "from-md.com", 2, true},
+	{1, "from-me.org", 2, true},
+	{1, "from-mi.com", 2, true},
+	{1, "from-mn.com", 2, true},
+	{1, "from-mo.com", 2, true},
+	{1, "from-ms.com", 2, true},
+	{1, "from-mt.com", 2, true},
+	{1, "from-nc.com", 2, true},
+	{1, "from-nd.com", 2, true},
+	{1, "from-ne.com", 2, true},
+	{1, "from-nh.com", 2, true},
+	{1, "from-nj.com", 2, true},
+	{1, "from-nm.com", 2, true},
+	{1, "from-nv.com", 2, true},
+	{1, "from-ny.net", 2, true},
+	{1, "from-oh.com", 2, true},
+	{1, "from-ok.com", 2, true},
+	{1, "from-or.com", 2, true},
+	{1, "from-pa.com", 2, true},
+	{1, "from-pr.com", 2, true},
+	{1, "from-ri.com", 2, true},
+	{1, "from-sc.com", 2, true},
+	{1, "from-sd.com", 2, true},
+	{1, "from-tn.com", 2, true},
+	{1, "from-tx.com", 2, true},
+	{1, "from-ut.com", 2, true},
+	{1, "from-va.com", 2, true},
+	{1, "from-vt.com", 2, true},
+	{1, "from-wa.com", 2, true},
+	{1, "from-wi.com", 2, true},
+	{1, "from-wv.com", 2, true},
+	{1, "from-wy.com", 2, true},
+	{1, "ftpaccess.cc", 2, true},
+	{1, "fuettertdasnetz.de", 2, true},
+	{1, "game-host.org", 2, true},
+	{1, "game-server.cc", 2, true},
+	{1, "getmyip.com", 2, true},
+	{1, "gets-it.net", 2, true},
+	{1, "go.dyndns.org", 3, true},
+	{1, "gotdns.com", 2, true},
+	{1, "gotdns.org", 2, true},
+	{1, "groks-the.info", 2, true},
+	{1, "groks-this.info", 2, true},
+	{1, "ham-radio-op.net", 2, true},
+	{1, "here-for-more.info", 2, true},
+	{1, "hobby-site.com", 2, true},
+	{1, "hobby-site.org", 2, true},
+	{1, "home.dyndns.org", 3, true},
+	{1, "homedns.org", 2, true},
+	{1, "homeftp.net", 2, true},
+	{1, "homeftp.org", 2, true},
+	{1, "homeip.net", 2, true},
+	{1, "homelinux.com", 2, true},
+	{1, "homelinux.net", 2, true},
+	{1, "homelinux.org", 2, true},
+	{1, "homeunix.com", 2, true},
+	{1, "homeunix.net", 2, true},
+	{1, "homeunix.org", 2, true},
+	{1, "iamallama.com", 2, true},
+	{1, "in-the-band.net", 2, true},
+	{1, "is-a-anarchist.com", 2, true},
+	{1, "is-a-blogger.com", 2, true},
+	{1, "is-a-bookkeeper.com", 2, true},
+	{1, "is-a-bruinsfan.org", 2, true},
+	{1, "is-a-bulls-fan.com", 2, true},
+	{1, "is-a-candidate.org", 2, true},
+	{1, "is-a-caterer.com", 2, true},
+	{1, "is-a-celticsfan.org", 2, true},
+	{1, "is-a-chef.com", 2, true},
+	{1, "is-a-chef.net", 2, true},
+	{1, "is-a-chef.org", 2, true},
+	{1, "is-a-conservative.com", 2, true},
+	{1, "is-a-cpa.com", 2, true},
+	{1, "is-a-cubicle-slave.com", 2, true},
+	{1, "is-a-democrat.com", 2, true},
+	{1, "is-a-designer.com", 2, true},
+	{1, "is-a-doctor.com", 2, true},
+	{1, "is-a-financialadvisor.com", 2, true},
+	{1, "is-a-geek.com", 2, true},
+	{1, "is-a-geek.net", 2, true},
+	{1, "is-a-geek.org", 2, true},
+	{1, "is-a-green.com", 2, true},
+	{1, "is-a-guru.com", 2, true},
+	{1, "is-a-hard-worker.com", 2, true},
+	{1, "is-a-hunter.com", 2, true},
+	{1, "is-a-knight.org", 2, true},
+	{1, "is-a-landscaper.com", 2, true},
+	{1, "is-a-lawyer.com", 2, true},
+	{1, "is-a-liberal.com", 2, true},
+	{1, "is-a-libertarian.com", 2, true},
+	{1, "is-a-linux-user.org", 2, true},
+	{1, "is-a-llama.com", 2, true},
+	{1, "is-a-musician.com", 2, true},
+	{1, "is-a-nascarfan.com", 2, true},
+	{1, "is-a-nurse.com", 2, true},
+	{1, "is-a-painter.com", 2, true},
+	{1, "is-a-patsfan.org", 2, true},
+	{1, "is-a-personaltrainer.com", 2, true},
+	{1, "is-a-photographer.com", 2, true},
+	{1, "is-a-player.com", 2, true},
+	{1, "is-a-republican.com", 2, true},
+	{1, "is-a-rockstar.com", 2, true},
+	{1, "is-a-socialist.com", 2, true},
+	{1, "is-a-soxfan.org", 2, true},
+	{1, "is-a-student.com", 2, true},
+	{1, "is-a-teacher.com", 2, true},
+	{1, "is-a-techie.com", 2, true},
+	{1, "is-a-therapist.com", 2, true},
+	{1, "is-an-accountant.com", 2, true},
+	{1, "is-an-actor.com", 2, true},
+	{1, "is-an-actress.com", 2, true},
+	{1, "is-an-anarchist.com", 2, true},
+	{1, "is-an-artist.com", 2, true},
+	{1, "is-an-engineer.com", 2, true},
+	{1, "is-an-entertainer.com", 2, true},
+	{1, "is-by.us", 2, true},
+	{1, "is-certified.com", 2, true},
+	{1, "is-found.org", 2, true},
+	{1, "is-gone.com", 2, true},
+	{1, "is-into-anime.com", 2, true},
+	{1, "is-into-cars.com", 2, true},
+	{1, "is-into-cartoons.com", 2, true},
+	{1, "is-into-games.com", 2, true},
+	{1, "is-leet.com", 2, true},
+	{1, "is-lost.org", 2, true},
+	{1, "is-not-certified.com", 2, true},
+	{1, "is-saved.org", 2, true},
+	{1, "is-slick.com", 2, true},
+	{1, "is-uberleet.com", 2, true},
+	{1, "is-very-bad.org", 2, true},
+	{1, "is-very-evil.org", 2, true},
+	{1, "is-very-good.org", 2, true},
+	{1, "is-very-nice.org", 2, true},
+	{1, "is-very-sweet.org", 2, true},
+	{1, "is-with-theband.com", 2, true},
+	{1, "isa-geek.com", 2, true},
+	{1, "isa-geek.net", 2, true},
+	{1, "isa-geek.org", 2, true},
+	{1, "isa-hockeynut.com", 2, true},
+	{1, "issmarterthanyou.com", 2, true},
+	{1, "isteingeek.de", 2, true},
+	{1, "istmein.de", 2, true},
+	{1, "kicks-ass.net", 2, true},
+	{1, "kicks-ass.org", 2, true},
+	{1, "knowsitall.info", 2, true},
+	{1, "land-4-sale.us", 2, true},
+	{1, "lebtimnetz.de", 2, true},
+	{1, "leitungsen.de", 2, true},
+	{1, "likes-pie.com", 2, true},
+	{1, "likescandy.com", 2, true},
+	{1, "merseine.nu", 2, true},
+	{1, "mine.nu", 2, true},
+	{1, "misconfused.org", 2, true},
+	{1, "mypets.ws", 2, true},
+	{1, "myphotos.cc", 2, true},
+	{1, "neat-url.com", 2, true},
+	{1, "office-on-the.net", 2, true},
+	{1, "on-the-web.tv", 2, true},
+	{1, "podzone.net", 2, true},
+	{1, "podzone.org", 2, true},
+	{1, "readmyblog.org", 2, true},
+	{1, "saves-the-whales.com", 2, true},
+	{1, "scrapper-site.net", 2, true},
+	{1, "scrapping.cc", 2, true},
+	{1, "selfip.biz", 2, true},
+	{1, "selfip.com", 2, true},
+	{1, "selfip.info", 2, true},
+	{1, "selfip.net", 2, true},
+	{1, "selfip.org", 2, true},
+	{1, "sells-for-less.com", 2, true},
+	{1, "sells-for-u.com", 2, true},
+	{1, "sells-it.net", 2, true},
+	{1, "sellsyourhome.org", 2, true},
+	{1, "servebbs.com", 2, true},
+	{1, "servebbs.net", 2, true},
+	{1, "servebbs.org", 2, true},
+	{1, "serveftp.net", 2, true},
+	{1, "serveftp.org", 2, true},
+	{1, "servegame.org", 2, true},
+	{1, "shacknet.nu", 2, true},
+	{1, "simple-url.com", 2, true},
+	{1, "space-to-rent.com", 2, true},
+	{1, "stuff-4-sale.org", 2, true},
+	{1, "stuff-4-sale.us", 2, true},
+	{1, "teaches-yoga.com", 2, true},
+	{1, "thruhere.net", 2, true},
+	{1, "traeumtgerade.de", 2, true},
+	{1, "webhop.biz", 2, true},
+	{1, "webhop.info", 2, true},
+	{1, "webhop.net", 2, true},
+	{1, "webhop.org", 2, true},
+	{1, "worse-than.tv", 2, true},
+	{1, "writesthisblog.com", 2, true},
+	{1, "ddnss.de", 2, true},
+	{1, "dyn.ddnss.de", 3, true},
+	{1, "dyndns.ddnss.de", 3, true},
+	{1, "dyndns1.de", 2, true},
+	{1, "dyn-ip24.de", 2, true},
+	{1, "home-webserver.de", 2, true},
+	{1, "dyn.home-webserver.de", 3, true},
+	{1, "myhome-server.de", 2, true},
+	{1, "ddnss.org", 2, true},
+	{1, "definima.net", 2, true},
+	{1, "definima.io", 2, true},
+	{1, "ondigitalocean.app", 2, true},
+	{1, "bci.dnstrace.pro", 3, true},
+	{1, "ddnsfree.com", 2, true},
+	{1, "ddnsgeek.com", 2, true},
+	{1, "giize.com", 2, true},
+	{1, "gleeze.com", 2, true},
+	{1, "kozow.com", 2, true},
+	{1, "loseyourip.com", 2, true},
+	{1, "ooguy.com", 2, true},
+	{1, "theworkpc.com", 2, true},
+	{1, "casacam.net", 2, true},
+	{1, "dynu.net", 2, true},
+	{1, "accesscam.org", 2, true},
+	{1, "camdvr.org", 2, true},
+	{1, "freeddns.org", 2, true},
+	{1, "mywire.org", 2, true},
+	{1, "webredirect.org", 2, true},
+	{1, "myddns.rocks", 2, true},
+	{1, "blogsite.xyz", 2, true},
+	{1, "dynv6.net", 2, true},
+	{1, "e4.cz", 2, true},
+	{1, "en-root.fr", 2, true},
+	{1, "mytuleap.com", 2, true},
+	{1, "onred.one", 2, true},
+	{1, "staging.onred.one", 3, true},
+	{1, "service.one", 2, true},
+	{1, "enonic.io", 2, true},
+	{1, "customer.enonic.io", 3, true},
+	{1, "eu.org", 2, true},
+	{1, "al.eu.org", 3, true},
+	{1, "asso.eu.org", 3, true},
+	{1, "at.eu.org", 3, true},
+	{1, "au.eu.org", 3, true},
+	{1, "be.eu.org", 3, true},
+	{1, "bg.eu.org", 3, true},
+	{1, "ca.eu.org", 3, true},
+	{1, "cd.eu.org", 3, true},
+	{1, "ch.eu.org", 3, true},
+	{1, "cn.eu.org", 3, true},
+	{1, "cy.eu.org", 3, true},
+	{1, "cz.eu.org", 3, true},
+	{1, "de.eu.org", 3, true},
+	{1, "dk.eu.org", 3, true},
+	{1, "edu.eu.org", 3, true},
+	{1, "ee.eu.org", 3, true},
+	{1, "es.eu.org", 3, true},
+	{1, "fi.eu.org", 3, true},
+	{1, "fr.eu.org", 3, true},
+	{1, "gr.eu.org", 3, true},
+	{1, "hr.eu.org", 3, true},
+	{1, "hu.eu.org", 3, true},
+	{1, "ie.eu.org", 3, true},
+	{1, "il.eu.org", 3, true},
+	{1, "in.eu.org", 3, true},
+	{1, "int.eu.org", 3, true},
+	{1, "is.eu.org", 3, true},
+	{1, "it.eu.org", 3, true},
+	{1, "jp.eu.org", 3, true},
+	{1, "kr.eu.org", 3, true},
+	{1, "lt.eu.org", 3, true},
+	{1, "lu.eu.org", 3, true},
+	{1, "lv.eu.org", 3, true},
+	{1, "mc.eu.org", 3, true},
+	{1, "me.eu.org", 3, true},
+	{1, "mk.eu.org", 3, true},
+	{1, "mt.eu.org", 3, true},
+	{1, "my.eu.org", 3, true},
+	{1, "net.eu.org", 3, true},
+	{1, "ng.eu.org", 3, true},
+	{1, "nl.eu.org", 3, true},
+	{1, "no.eu.org", 3, true},
+	{1, "nz.eu.org", 3, true},
+	{1, "paris.eu.org", 3, true},
+	{1, "pl.eu.org", 3, true},
+	{1, "pt.eu.org", 3, true},
+	{1, "q-a.eu.org", 3, true},
+	{1, "ro.eu.org", 3, true},
+	{1, "ru.eu.org", 3, true},
+	{1, "se.eu.org", 3, true},
+	{1, "si.eu.org", 3, true},
+	{1, "sk.eu.org", 3, true},
+	{1, "tr.eu.org", 3, true},
+	{1, "uk.eu.org", 3, true},
+	{1, "us.eu.org", 3, true},
+	{1, "eurodir.ru", 2, true},
+	{1, "eu-1.evennode.com", 3, true},
+	{1, "eu-2.evennode.com", 3, true},
+	{1, "eu-3.evennode.com", 3, true},
+	{1, "eu-4.evennode.com", 3, true},
+	{1, "us-1.evennode.com", 3, true},
+	{1, "us-2.evennode.com", 3, true},
+	{1, "us-3.evennode.com", 3, true},
+	{1, "us-4.evennode.com", 3, true},
+	{1, "twmail.cc", 2, true},
+	{1, "twmail.net", 2, true},
+	{1, "twmail.org", 2, true},
+	{1, "mymailer.com.tw", 3, true},
+	{1, "url.tw", 2, true},
+	{1, "onfabrica.com", 2, true},
+	{1, "apps.fbsbx.com", 3, true},
+	{1, "ru.net", 2, true},
+	{1, "adygeya.ru", 2, true},
+	{1, "bashkiria.ru", 2, true},
+	{1, "bir.ru", 2, true},
+	{1, "cbg.ru", 2, true},
+	{1, "com.ru", 2, true},
+	{1, "dagestan.ru", 2, true},
+	{1, "grozny.ru", 2, true},
+	{1, "kalmykia.ru", 2, true},
+	{1, "kustanai.ru", 2, true},
+	{1, "marine.ru", 2, true},
+	{1, "mordovia.ru", 2, true},
+	{1, "msk.ru", 2, true},
+	{1, "mytis.ru", 2, true},
+	{1, "nalchik.ru", 2, true},
+	{1, "nov.ru", 2, true},
+	{1, "pyatigorsk.ru", 2, true},
+	{1, "spb.ru", 2, true},
+	{1, "vladikavkaz.ru", 2, true},
+	{1, "vladimir.ru", 2, true},
+	{1, "abkhazia.su", 2, true},
+	{1, "adygeya.su", 2, true},
+	{1, "aktyubinsk.su", 2, true},
+	{1, "arkhangelsk.su", 2, true},
+	{1, "armenia.su", 2, true},
+	{1, "ashgabad.su", 2, true},
+	{1, "azerbaijan.su", 2, true},
+	{1, "balashov.su", 2, true},
+	{1, "bashkiria.su", 2, true},
+	{1, "bryansk.su", 2, true},
+	{1, "bukhara.su", 2, true},
+	{1, "chimkent.su", 2, true},
+	{1, "dagestan.su", 2, true},
+	{1, "east-kazakhstan.su", 2, true},
+	{1, "exnet.su", 2, true},
+	{1, "georgia.su", 2, true},
+	{1, "grozny.su", 2, true},
+	{1, "ivanovo.su", 2, true},
+	{1, "jambyl.su", 2, true},
+	{1, "kalmykia.su", 2, true},
+	{1, "kaluga.su", 2, true},
+	{1, "karacol.su", 2, true},
+	{1, "karaganda.su", 2, true},
+	{1, "karelia.su", 2, true},
+	{1, "khakassia.su", 2, true},
+	{1, "krasnodar.su", 2, true},
+	{1, "kurgan.su", 2, true},
+	{1, "kustanai.su", 2, true},
+	{1, "lenug.su", 2, true},
+	{1, "mangyshlak.su", 2, true},
+	{1, "mordovia.su", 2, true},
+	{1, "msk.su", 2, true},
+	{1, "murmansk.su", 2, true},
+	{1, "nalchik.su", 2, true},
+	{1, "navoi.su", 2, true},
+	{1, "north-kazakhstan.su", 2, true},
+	{1, "nov.su", 2, true},
+	{1, "obninsk.su", 2, true},
+	{1, "penza.su", 2, true},
+	{1, "pokrovsk.su", 2, true},
+	{1, "sochi.su", 2, true},
+	{1, "spb.su", 2, true},
+	{1, "tashkent.su", 2, true},
+	{1, "termez.su", 2, true},
+	{1, "togliatti.su", 2, true},
+	{1, "troitsk.su", 2, true},
+	{1, "tselinograd.su", 2, true},
+	{1, "tula.su", 2, true},
+	{1, "tuva.su", 2, true},
+	{1, "vladikavkaz.su", 2, true},
+	{1, "vladimir.su", 2, true},
+	{1, "vologda.su", 2, true},
+	{1, "channelsdvr.net", 2, true},
+	{1, "u.channelsdvr.net", 3, true},
+	{1, "edgecompute.app", 2, true},
+	{1, "fastly-terrarium.com", 2, true},
+	{1, "fastlylb.net", 2, true},
+	{1, "map.fastlylb.net", 3, true},
+	{1, "freetls.fastly.net", 3, true},
+	{1, "map.fastly.net", 3, true},
+	{1, "a.prod.fastly.net", 4, true},
+	{1, "global.prod.fastly.net", 4, true},
+	{1, "a.ssl.fastly.net", 4, true},
+	{1, "b.ssl.fastly.net", 4, true},
+	{1, "global.ssl.fastly.net", 4, true},
+	{1, "fastvps-server.com", 2, true},
+	{1, "fastvps.host", 2, true},
+	{1, "myfast.host", 2, true},
+	{1, "fastvps.site", 2, true},
+	{1, "myfast.space", 2, true},
+	{1, "fedorainfracloud.org", 2, true},
+	{1, "fedorapeople.org", 2, true},
+	{1, "cloud.fedoraproject.org", 3, true},
+	{1, "app.os.fedoraproject.org", 4, true},
+	{1, "app.os.stg.fedoraproject.org", 5, true},
+	{1, "couk.me", 2, true},
+	{1, "ukco.me", 2, true},
+	{1, "conn.uk", 2, true},
+	{1, "copro.uk", 2, true},
+	{1, "hosp.uk", 2, true},
+	{1, "mydobiss.com", 2, true},
+	{1, "fh-muenster.io", 2, true},
+	{1, "filegear.me", 2, true},
+	{1, "filegear-au.me", 2, true},
+	{1, "filegear-de.me", 2, true},
+	{1, "filegear-gb.me", 2, true},
+	{1, "filegear-ie.me", 2, true},
+	{1, "filegear-jp.me", 2, true},
+	{1, "filegear-sg.me", 2, true},
+	{1, "firebaseapp.com", 2, true},
+	{1, "fireweb.app", 2, true},
+	{1, "flap.id", 2, true},
+	{1, "fly.dev", 2, true},
+	{1, "edgeapp.net", 2, true},
+	{1, "shw.io", 2, true},
+	{1, "flynnhosting.net", 2, true},
+	{1, "forgeblocks.com", 2, true},
+	{2, "id.forgerock.io", 4, true},
+	{1, "framer.app", 2, true},
+	{1, "framercanvas.com", 2, true},
+	{1, "ravpage.co.il", 3, true},
+	{1, "0e.vc", 2, true},
+	{1, "freebox-os.com", 2, true},
+	{1, "freeboxos.com", 2, true},
+	{1, "fbx-os.fr", 2, true},
+	{1, "fbxos.fr", 2, true},
+	{1, "freebox-os.fr", 2, true},
+	{1, "freeboxos.fr", 2, true},
+	{1, "freedesktop.org", 2, true},
+	{1, "freemyip.com", 2, true},
+	{1, "wien.funkfeuer.at", 3, true},
+	{2, "futurecms.at", 3, true},
+	{2, "ex.futurecms.at", 4, true},
+	{2, "in.futurecms.at", 4, true},
+	{1, "futurehosting.at", 2, true},
+	{1, "futuremailing.at", 2, true},
+	{2, "ex.ortsinfo.at", 4, true},
+	{2, "kunden.ortsinfo.at", 4, true},
+	{2, "statics.cloud", 3, true},
+	{1, "service.gov.uk", 3, true},
+	{1, "gehirn.ne.jp", 3, true},
+	{1, "usercontent.jp", 2, true},
+	{1, "gentapps.com", 2, true},
+	{1, "gentlentapis.com", 2, true},
+	{1, "lab.ms", 2, true},
+	{1, "cdn-edges.net", 2, true},
+	{1, "ghost.io", 2, true},
+	{1, "gsj.bz", 2, true},
+	{1, "githubusercontent.com", 2, true},
+	{1, "github.dev", 2, true},
+	{1, "githubpreview.dev", 2, true},
+	{1, "github.io", 2, true},
+	{1, "gitlab.io", 2, true},
+	{1, "gitapp.si", 2, true},
+	{1, "gitpage.si", 2, true},
+	{1, "glitch.me", 2, true},
+	{1, "co.ro", 2, true},
+	{1, "shop.ro", 2, true},
+	{1, "lolipop.io", 2, true},
+	{1, "cloudapps.digital", 2, true},
+	{1, "london.cloudapps.digital", 3, true},
+	{1, "pymnt.uk", 2, true},
+	{1, "homeoffice.gov.uk", 3, true},
+	{1, "ro.im", 2, true},
+	{1, "goip.de", 2, true},
+	{1, "run.app", 2, true},
+	{1, "a.run.app", 3, true},
+	{1, "web.app", 2, true},
+	{2, "0emm.com", 3, true},
+	{1, "appspot.com", 2, true},
+	{2, "r.appspot.com", 4, true},
+	{1, "codespot.com", 2, true},
+	{1, "googleapis.com", 2, true},
+	{1, "googlecode.com", 2, true},
+	{1, "pagespeedmobilizer.com", 2, true},
+	{1, "publishproxy.com", 2, true},
+	{1, "withgoogle.com", 2, true},
+	{1, "withyoutube.com", 2, true},
+	{2, "gateway.dev", 3, true},
+	{1, "cloud.goog", 2, true},
+	{1, "translate.goog", 2, true},
+	{1, "cloudfunctions.net", 2, true},
+	{1, "blogspot.ae", 2, true},
+	{1, "blogspot.al", 2, true},
+	{1, "blogspot.am", 2, true},
+	{1, "blogspot.ba", 2, true},
+	{1, "blogspot.be", 2, true},
+	{1, "blogspot.bg", 2, true},
+	{1, "blogspot.bj", 2, true},
+	{1, "blogspot.ca", 2, true},
+	{1, "blogspot.cf", 2, true},
+	{1, "blogspot.ch", 2, true},
+	{1, "blogspot.cl", 2, true},
+	{1, "blogspot.co.at", 3, true},
+	{1, "blogspot.co.id", 3, true},
+	{1, "blogspot.co.il", 3, true},
+	{1, "blogspot.co.ke", 3, true},
+	{1, "blogspot.co.nz", 3, true},
+	{1, "blogspot.co.uk", 3, true},
+	{1, "blogspot.co.za", 3, true},
+	{1, "blogspot.com", 2, true},
+	{1, "blogspot.com.ar", 3, true},
+	{1, "blogspot.com.au", 3, true},
+	{1, "blogspot.com.br", 3, true},
+	{1, "blogspot.com.by", 3, true},
+	{1, "blogspot.com.co", 3, true},
+	{1, "blogspot.com.cy", 3, true},
+	{1, "blogspot.com.ee", 3, true},
+	{1, "blogspot.com.eg", 3, true},
+	{1, "blogspot.com.es", 3, true},
+	{1, "blogspot.com.mt", 3, true},
+	{1, "blogspot.com.ng", 3, true},
+	{1, "blogspot.com.tr", 3, true},
+	{1, "blogspot.com.uy", 3, true},
+	{1, "blogspot.cv", 2, true},
+	{1, "blogspot.cz", 2, true},
+	{1, "blogspot.de", 2, true},
+	{1, "blogspot.dk", 2, true},
+	{1, "blogspot.fi", 2, true},
+	{1, "blogspot.fr", 2, true},
+	{1, "blogspot.gr", 2, true},
+	{1, "blogspot.hk", 2, true},
+	{1, "blogspot.hr", 2, true},
+	{1, "blogspot.hu", 2, true},
+	{1, "blogspot.ie", 2, true},
+	{1, "blogspot.in", 2, true},
+	{1, "blogspot.is", 2, true},
+	{1, "blogspot.it", 2, true},
+	{1, "blogspot.jp", 2, true},
+	{1, "blogspot.kr", 2, true},
+	{1, "blogspot.li", 2, true},
+	{1, "blogspot.lt", 2, true},
+	{1, "blogspot.lu", 2, true},
+	{1, "blogspot.md", 2, true},
+	{1, "blogspot.mk", 2, true},
+	{1, "blogspot.mr", 2, true},
+	{1, "blogspot.mx", 2, true},
+	{1, "blogspot.my", 2, true},
+	{1, "blogspot.nl", 2, true},
+	{1, "blogspot.no", 2, true},
+	{1, "blogspot.pe", 2, true},
+	{1, "blogspot.pt", 2, true},
+	{1, "blogspot.qa", 2, true},
+	{1, "blogspot.re", 2, true},
+	{1, "blogspot.ro", 2, true},
+	{1, "blogspot.rs", 2, true},
+	{1, "blogspot.ru", 2, true},
+	{1, "blogspot.se", 2, true},
+	{1, "blogspot.sg", 2, true},
+	{1, "blogspot.si", 2, true},
+	{1, "blogspot.sk", 2, true},
+	{1, "blogspot.sn", 2, true},
+	{1, "blogspot.td", 2, true},
+	{1, "blogspot.tw", 2, true},
+	{1, "blogspot.ug", 2, true},
+	{1, "blogspot.vn", 2, true},
+	{1, "goupile.fr", 2, true},
+	{1, "awsmppl.com", 2, true},
+	{1, "xn--gnstigbestellen-zvb.de", 2, true},
+	{1, "xn--gnstigliefern-wob.de", 2, true},
+	{1, "fin.ci", 2, true},
+	{1, "free.hr", 2, true},
+	{1, "caa.li", 2, true},
+	{1, "ua.rs", 2, true},
+	{1, "conf.se", 2, true},
+	{1, "hs.zone", 2, true},
+	{1, "hs.run", 2, true},
+	{1, "hashbang.sh", 2, true},
+	{1, "hasura.app", 2, true},
+	{1, "hasura-app.io", 2, true},
+	{1, "hepforge.org", 2, true},
+	{1, "herokuapp.com", 2, true},
+	{1, "herokussl.com", 2, true},
+	{1, "myravendb.com", 2, true},
+	{1, "ravendb.community", 2, true},
+	{1, "ravendb.me", 2, true},
+	{1, "development.run", 2, true},
+	{1, "ravendb.run", 2, true},
+	{1, "secaas.hk", 2, true},
+	{1, "orx.biz", 2, true},
+	{1, "biz.gl", 2, true},
+	{1, "col.ng", 2, true},
+	{1, "firm.ng", 2, true},
+	{1, "gen.ng", 2, true},
+	{1, "ltd.ng", 2, true},
+	{1, "ngo.ng", 2, true},
+	{1, "edu.scot", 2, true},
+	{1, "sch.so", 2, true},
+	{1, "org.yt", 2, true},
+	{1, "hostyhosting.io", 2, true},
+	{1, "xn--hkkinen-5wa.fi", 2, true},
+	{2, "moonscale.io", 3, true},
+	{1, "moonscale.net", 2, true},
+	{1, "iki.fi", 2, true},
+	{1, "impertrixcdn.com", 2, true},
+	{1, "impertrix.com", 2, true},
+	{1, "smushcdn.com", 2, true},
+	{1, "wphostedmail.com", 2, true},
+	{1, "wpmucdn.com", 2, true},
+	{1, "tempurl.host", 2, true},
+	{1, "wpmudev.host", 2, true},
+	{1, "dyn-berlin.de", 2, true},
+	{1, "in-berlin.de", 2, true},
+	{1, "in-brb.de", 2, true},
+	{1, "in-butter.de", 2, true},
+	{1, "in-dsl.de", 2, true},
+	{1, "in-dsl.net", 2, true},
+	{1, "in-dsl.org", 2, true},
+	{1, "in-vpn.de", 2, true},
+	{1, "in-vpn.net", 2, true},
+	{1, "in-vpn.org", 2, true},
+	{1, "biz.at", 2, true},
+	{1, "info.at", 2, true},
+	{1, "info.cx", 2, true},
+	{1, "ac.leg.br", 3, true},
+	{1, "al.leg.br", 3, true},
+	{1, "am.leg.br", 3, true},
+	{1, "ap.leg.br", 3, true},
+	{1, "ba.leg.br", 3, true},
+	{1, "ce.leg.br", 3, true},
+	{1, "df.leg.br", 3, true},
+	{1, "es.leg.br", 3, true},
+	{1, "go.leg.br", 3, true},
+	{1, "ma.leg.br", 3, true},
+	{1, "mg.leg.br", 3, true},
+	{1, "ms.leg.br", 3, true},
+	{1, "mt.leg.br", 3, true},
+	{1, "pa.leg.br", 3, true},
+	{1, "pb.leg.br", 3, true},
+	{1, "pe.leg.br", 3, true},
+	{1, "pi.leg.br", 3, true},
+	{1, "pr.leg.br", 3, true},
+	{1, "rj.leg.br", 3, true},
+	{1, "rn.leg.br", 3, true},
+	{1, "ro.leg.br", 3, true},
+	{1, "rr.leg.br", 3, true},
+	{1, "rs.leg.br", 3, true},
+	{1, "sc.leg.br", 3, true},
+	{1, "se.leg.br", 3, true},
+	{1, "sp.leg.br", 3, true},
+	{1, "to.leg.br", 3, true},
+	{1, "pixolino.com", 2, true},
+	{1, "na4u.ru", 2, true},
+	{1, "iopsys.se", 2, true},
+	{1, "ipifony.net", 2, true},
+	{1, "mein-iserv.de", 2, true},
+	{1, "schulserver.de", 2, true},
+	{1, "test-iserv.de", 2, true},
+	{1, "iserv.dev", 2, true},
+	{1, "iobb.net", 2, true},
+	{1, "mel.cloudlets.com.au", 4, true},
+	{1, "cloud.interhostsolutions.be", 3, true},
+	{1, "users.scale.virtualcloud.com.br", 5, true},
+	{1, "mycloud.by", 2, true},
+	{1, "alp1.ae.flow.ch", 4, true},
+	{1, "appengine.flow.ch", 3, true},
+	{1, "es-1.axarnet.cloud", 3, true},
+	{1, "diadem.cloud", 2, true},
+	{1, "vip.jelastic.cloud", 3, true},
+	{1, "jele.cloud", 2, true},
+	{1, "it1.eur.aruba.jenv-aruba.cloud", 5, true},
+	{1, "it1.jenv-aruba.cloud", 3, true},
+	{1, "keliweb.cloud", 2, true},
+	{1, "cs.keliweb.cloud", 3, true},
+	{1, "oxa.cloud", 2, true},
+	{1, "tn.oxa.cloud", 3, true},
+	{1, "uk.oxa.cloud", 3, true},
+	{1, "primetel.cloud", 2, true},
+	{1, "uk.primetel.cloud", 3, true},
+	{1, "ca.reclaim.cloud", 3, true},
+	{1, "uk.reclaim.cloud", 3, true},
+	{1, "us.reclaim.cloud", 3, true},
+	{1, "ch.trendhosting.cloud", 3, true},
+	{1, "de.trendhosting.cloud", 3, true},
+	{1, "jele.club", 2, true},
+	{1, "amscompute.com", 2, true},
+	{1, "clicketcloud.com", 2, true},
+	{1, "dopaas.com", 2, true},
+	{1, "hidora.com", 2, true},
+	{1, "paas.hosted-by-previder.com", 3, true},
+	{1, "rag-cloud.hosteur.com", 3, true},
+	{1, "rag-cloud-ch.hosteur.com", 3, true},
+	{1, "jcloud.ik-server.com", 3, true},
+	{1, "jcloud-ver-jpc.ik-server.com", 3, true},
+	{1, "demo.jelastic.com", 3, true},
+	{1, "kilatiron.com", 2, true},
+	{1, "paas.massivegrid.com", 3, true},
+	{1, "jed.wafaicloud.com", 3, true},
+	{1, "lon.wafaicloud.com", 3, true},
+	{1, "ryd.wafaicloud.com", 3, true},
+	{1, "j.scaleforce.com.cy", 4, true},
+	{1, "jelastic.dogado.eu", 3, true},
+	{1, "fi.cloudplatform.fi", 3, true},
+	{1, "demo.datacenter.fi", 3, true},
+	{1, "paas.datacenter.fi", 3, true},
+	{1, "jele.host", 2, true},
+	{1, "mircloud.host", 2, true},
+	{1, "paas.beebyte.io", 3, true},
+	{1, "sekd1.beebyteapp.io", 3, true},
+	{1, "jele.io", 2, true},
+	{1, "cloud-fr1.unispace.io", 3, true},
+	{1, "jc.neen.it", 3, true},
+	{1, "cloud.jelastic.open.tim.it", 5, true},
+	{1, "jcloud.kz", 2, true},
+	{1, "upaas.kazteleport.kz", 3, true},
+	{1, "cloudjiffy.net", 2, true},
+	{1, "fra1-de.cloudjiffy.net", 3, true},
+	{1, "west1-us.cloudjiffy.net", 3, true},
+	{1, "jls-sto1.elastx.net", 3, true},
+	{1, "jls-sto2.elastx.net", 3, true},
+	{1, "jls-sto3.elastx.net", 3, true},
+	{1, "faststacks.net", 2, true},
+	{1, "fr-1.paas.massivegrid.net", 4, true},
+	{1, "lon-1.paas.massivegrid.net", 4, true},
+	{1, "lon-2.paas.massivegrid.net", 4, true},
+	{1, "ny-1.paas.massivegrid.net", 4, true},
+	{1, "ny-2.paas.massivegrid.net", 4, true},
+	{1, "sg-1.paas.massivegrid.net", 4, true},
+	{1, "jelastic.saveincloud.net", 3, true},
+	{1, "nordeste-idc.saveincloud.net", 3, true},
+	{1, "j.scaleforce.net", 3, true},
+	{1, "jelastic.tsukaeru.net", 3, true},
+	{1, "sdscloud.pl", 2, true},
+	{1, "unicloud.pl", 2, true},
+	{1, "mircloud.ru", 2, true},
+	{1, "jelastic.regruhosting.ru", 3, true},
+	{1, "enscaled.sg", 2, true},
+	{1, "jele.site", 2, true},
+	{1, "jelastic.team", 2, true},
+	{1, "orangecloud.tn", 2, true},
+	{1, "j.layershift.co.uk", 4, true},
+	{1, "phx.enscaled.us", 3, true},
+	{1, "mircloud.us", 2, true},
+	{1, "myjino.ru", 2, true},
+	{2, "hosting.myjino.ru", 4, true},
+	{2, "landing.myjino.ru", 4, true},
+	{2, "spectrum.myjino.ru", 4, true},
+	{2, "vps.myjino.ru", 4, true},
+	{2, "triton.zone", 3, true},
+	{2, "cns.joyent.com", 4, true},
+	{1, "js.org", 2, true},
+	{1, "kaas.gg", 2, true},
+	{1, "khplay.nl", 2, true},
+	{1, "keymachine.de", 2, true},
+	{1, "kinghost.net", 2, true},
+	{1, "uni5.net", 2, true},
+	{1, "knightpoint.systems", 2, true},
+	{1, "oya.to", 2, true},
+	{1, "kuleuven.cloud", 2, true},
+	{1, "ezproxy.kuleuven.be", 3, true},
+	{1, "co.krd", 2, true},
+	{1, "edu.krd", 2, true},
+	{1, "krellian.net", 2, true},
+	{1, "webthings.io", 2, true},
+	{1, "git-repos.de", 2, true},
+	{1, "lcube-server.de", 2, true},
+	{1, "svn-repos.de", 2, true},
+	{1, "leadpages.co", 2, true},
+	{1, "lpages.co", 2, true},
+	{1, "lpusercontent.com", 2, true},
+	{1, "lelux.site", 2, true},
+	{1, "co.business", 2, true},
+	{1, "co.education", 2, true},
+	{1, "co.events", 2, true},
+	{1, "co.financial", 2, true},
+	{1, "co.network", 2, true},
+	{1, "co.place", 2, true},
+	{1, "co.technology", 2, true},
+	{1, "app.lmpm.com", 3, true},
+	{1, "linkyard.cloud", 2, true},
+	{1, "linkyard-cloud.ch", 2, true},
+	{1, "members.linode.com", 3, true},
+	{2, "nodebalancer.linode.com", 4, true},
+	{2, "linodeobjects.com", 3, true},
+	{1, "we.bs", 2, true},
+	{1, "localzone.xyz", 2, true},
+	{1, "loginline.app", 2, true},
+	{1, "loginline.dev", 2, true},
+	{1, "loginline.io", 2, true},
+	{1, "loginline.services", 2, true},
+	{1, "loginline.site", 2, true},
+	{1, "lohmus.me", 2, true},
+	{1, "krasnik.pl", 2, true},
+	{1, "leczna.pl", 2, true},
+	{1, "lubartow.pl", 2, true},
+	{1, "lublin.pl", 2, true},
+	{1, "poniatowa.pl", 2, true},
+	{1, "swidnik.pl", 2, true},
+	{1, "glug.org.uk", 3, true},
+	{1, "lug.org.uk", 3, true},
+	{1, "lugs.org.uk", 3, true},
+	{1, "barsy.bg", 2, true},
+	{1, "barsy.co.uk", 3, true},
+	{1, "barsyonline.co.uk", 3, true},
+	{1, "barsycenter.com", 2, true},
+	{1, "barsyonline.com", 2, true},
+	{1, "barsy.club", 2, true},
+	{1, "barsy.de", 2, true},
+	{1, "barsy.eu", 2, true},
+	{1, "barsy.in", 2, true},
+	{1, "barsy.info", 2, true},
+	{1, "barsy.io", 2, true},
+	{1, "barsy.me", 2, true},
+	{1, "barsy.menu", 2, true},
+	{1, "barsy.mobi", 2, true},
+	{1, "barsy.net", 2, true},
+	{1, "barsy.online", 2, true},
+	{1, "barsy.org", 2, true},
+	{1, "barsy.pro", 2, true},
+	{1, "barsy.pub", 2, true},
+	{1, "barsy.shop", 2, true},
+	{1, "barsy.site", 2, true},
+	{1, "barsy.support", 2, true},
+	{1, "barsy.uk", 2, true},
+	{2, "magentosite.cloud", 3, true},
+	{1, "mayfirst.info", 2, true},
+	{1, "mayfirst.org", 2, true},
+	{1, "hb.cldmail.ru", 3, true},
+	{1, "cn.vu", 2, true},
+	{1, "mazeplay.com", 2, true},
+	{1, "mcpe.me", 2, true},
+	{1, "mcdir.me", 2, true},
+	{1, "mcdir.ru", 2, true},
+	{1, "mcpre.ru", 2, true},
+	{1, "vps.mcdir.ru", 3, true},
+	{1, "hra.health", 2, true},
+	{1, "miniserver.com", 2, true},
+	{1, "memset.net", 2, true},
+	{2, "cloud.metacentrum.cz", 4, true},
+	{1, "custom.metacentrum.cz", 3, true},
+	{1, "flt.cloud.muni.cz", 4, true},
+	{1, "usr.cloud.muni.cz", 4, true},
+	{1, "meteorapp.com", 2, true},
+	{1, "eu.meteorapp.com", 3, true},
+	{1, "co.pl", 2, true},
+	{2, "azurecontainer.io", 3, true},
+	{1, "azurewebsites.net", 2, true},
+	{1, "azure-mobile.net", 2, true},
+	{1, "cloudapp.net", 2, true},
+	{1, "azurestaticapps.net", 2, true},
+	{1, "centralus.azurestaticapps.net", 3, true},
+	{1, "eastasia.azurestaticapps.net", 3, true},
+	{1, "eastus2.azurestaticapps.net", 3, true},
+	{1, "westeurope.azurestaticapps.net", 3, true},
+	{1, "westus2.azurestaticapps.net", 3, true},
+	{1, "csx.cc", 2, true},
+	{1, "mintere.site", 2, true},
+	{1, "forte.id", 2, true},
+	{1, "mozilla-iot.org", 2, true},
+	{1, "bmoattachments.org", 2, true},
+	{1, "net.ru", 2, true},
+	{1, "org.ru", 2, true},
+	{1, "pp.ru", 2, true},
+	{1, "hostedpi.com", 2, true},
+	{1, "customer.mythic-beasts.com", 3, true},
+	{1, "caracal.mythic-beasts.com", 3, true},
+	{1, "fentiger.mythic-beasts.com", 3, true},
+	{1, "lynx.mythic-beasts.com", 3, true},
+	{1, "ocelot.mythic-beasts.com", 3, true},
+	{1, "oncilla.mythic-beasts.com", 3, true},
+	{1, "onza.mythic-beasts.com", 3, true},
+	{1, "sphinx.mythic-beasts.com", 3, true},
+	{1, "vs.mythic-beasts.com", 3, true},
+	{1, "x.mythic-beasts.com", 3, true},
+	{1, "yali.mythic-beasts.com", 3, true},
+	{1, "cust.retrosnub.co.uk", 4, true},
+	{1, "ui.nabu.casa", 3, true},
+	{1, "pony.club", 2, true},
+	{1, "of.fashion", 2, true},
+	{1, "in.london", 2, true},
+	{1, "of.london", 2, true},
+	{1, "from.marketing", 2, true},
+	{1, "with.marketing", 2, true},
+	{1, "for.men", 2, true},
+	{1, "repair.men", 2, true},
+	{1, "and.mom", 2, true},
+	{1, "for.mom", 2, true},
+	{1, "for.one", 2, true},
+	{1, "under.one", 2, true},
+	{1, "for.sale", 2, true},
+	{1, "that.win", 2, true},
+	{1, "from.work", 2, true},
+	{1, "to.work", 2, true},
+	{1, "nctu.me", 2, true},
+	{1, "netlify.app", 2, true},
+	{1, "4u.com", 2, true},
+	{1, "ngrok.io", 2, true},
+	{1, "nh-serv.co.uk", 3, true},
+	{1, "nfshost.com", 2, true},
+	{2, "developer.app", 3, true},
+	{1, "noop.app", 2, true},
+	{2, "northflank.app", 3, true},
+	{2, "code.run", 3, true},
+	{1, "noticeable.news", 2, true},
+	{1, "dnsking.ch", 2, true},
+	{1, "mypi.co", 2, true},
+	{1, "n4t.co", 2, true},
+	{1, "001www.com", 2, true},
+	{1, "ddnslive.com", 2, true},
+	{1, "myiphost.com", 2, true},
+	{1, "forumz.info", 2, true},
+	{1, "16-b.it", 2, true},
+	{1, "32-b.it", 2, true},
+	{1, "64-b.it", 2, true},
+	{1, "soundcast.me", 2, true},
+	{1, "tcp4.me", 2, true},
+	{1, "dnsup.net", 2, true},
+	{1, "hicam.net", 2, true},
+	{1, "now-dns.net", 2, true},
+	{1, "ownip.net", 2, true},
+	{1, "vpndns.net", 2, true},
+	{1, "dynserv.org", 2, true},
+	{1, "now-dns.org", 2, true},
+	{1, "x443.pw", 2, true},
+	{1, "now-dns.top", 2, true},
+	{1, "ntdll.top", 2, true},
+	{1, "freeddns.us", 2, true},
+	{1, "crafting.xyz", 2, true},
+	{1, "zapto.xyz", 2, true},
+	{1, "nsupdate.info", 2, true},
+	{1, "nerdpol.ovh", 2, true},
+	{1, "blogsyte.com", 2, true},
+	{1, "brasilia.me", 2, true},
+	{1, "cable-modem.org", 2, true},
+	{1, "ciscofreak.com", 2, true},
+	{1, "collegefan.org", 2, true},
+	{1, "couchpotatofries.org", 2, true},
+	{1, "damnserver.com", 2, true},
+	{1, "ddns.me", 2, true},
+	{1, "ditchyourip.com", 2, true},
+	{1, "dnsfor.me", 2, true},
+	{1, "dnsiskinky.com", 2, true},
+	{1, "dvrcam.info", 2, true},
+	{1, "dynns.com", 2, true},
+	{1, "eating-organic.net", 2, true},
+	{1, "fantasyleague.cc", 2, true},
+	{1, "geekgalaxy.com", 2, true},
+	{1, "golffan.us", 2, true},
+	{1, "health-carereform.com", 2, true},
+	{1, "homesecuritymac.com", 2, true},
+	{1, "homesecuritypc.com", 2, true},
+	{1, "hopto.me", 2, true},
+	{1, "ilovecollege.info", 2, true},
+	{1, "loginto.me", 2, true},
+	{1, "mlbfan.org", 2, true},
+	{1, "mmafan.biz", 2, true},
+	{1, "myactivedirectory.com", 2, true},
+	{1, "mydissent.net", 2, true},
+	{1, "myeffect.net", 2, true},
+	{1, "mymediapc.net", 2, true},
+	{1, "mypsx.net", 2, true},
+	{1, "mysecuritycamera.com", 2, true},
+	{1, "mysecuritycamera.net", 2, true},
+	{1, "mysecuritycamera.org", 2, true},
+	{1, "net-freaks.com", 2, true},
+	{1, "nflfan.org", 2, true},
+	{1, "nhlfan.net", 2, true},
+	{1, "no-ip.ca", 2, true},
+	{1, "no-ip.co.uk", 3, true},
+	{1, "no-ip.net", 2, true},
+	{1, "noip.us", 2, true},
+	{1, "onthewifi.com", 2, true},
+	{1, "pgafan.net", 2, true},
+	{1, "point2this.com", 2, true},
+	{1, "pointto.us", 2, true},
+	{1, "privatizehealthinsurance.net", 2, true},
+	{1, "quicksytes.com", 2, true},
+	{1, "read-books.org", 2, true},
+	{1, "securitytactics.com", 2, true},
+	{1, "serveexchange.com", 2, true},
+	{1, "servehumour.com", 2, true},
+	{1, "servep2p.com", 2, true},
+	{1, "servesarcasm.com", 2, true},
+	{1, "stufftoread.com", 2, true},
+	{1, "ufcfan.org", 2, true},
+	{1, "unusualperson.com", 2, true},
+	{1, "workisboring.com", 2, true},
+	{1, "3utilities.com", 2, true},
+	{1, "bounceme.net", 2, true},
+	{1, "ddns.net", 2, true},
+	{1, "ddnsking.com", 2, true},
+	{1, "gotdns.ch", 2, true},
+	{1, "hopto.org", 2, true},
+	{1, "myftp.biz", 2, true},
+	{1, "myftp.org", 2, true},
+	{1, "myvnc.com", 2, true},
+	{1, "no-ip.biz", 2, true},
+	{1, "no-ip.info", 2, true},
+	{1, "no-ip.org", 2, true},
+	{1, "noip.me", 2, true},
+	{1, "redirectme.net", 2, true},
+	{1, "servebeer.com", 2, true},
+	{1, "serveblog.net", 2, true},
+	{1, "servecounterstrike.com", 2, true},
+	{1, "serveftp.com", 2, true},
+	{1, "servegame.com", 2, true},
+	{1, "servehalflife.com", 2, true},
+	{1, "servehttp.com", 2, true},
+	{1, "serveirc.com", 2, true},
+	{1, "serveminecraft.net", 2, true},
+	{1, "servemp3.com", 2, true},
+	{1, "servepics.com", 2, true},
+	{1, "servequake.com", 2, true},
+	{1, "sytes.net", 2, true},
+	{1, "webhop.me", 2, true},
+	{1, "zapto.org", 2, true},
+	{1, "stage.nodeart.io", 3, true},
+	{1, "nodum.co", 2, true},
+	{1, "nodum.io", 2, true},
+	{1, "pcloud.host", 2, true},
+	{1, "nyc.mn", 2, true},
+	{1, "nom.ae", 2, true},
+	{1, "nom.af", 2, true},
+	{1, "nom.ai", 2, true},
+	{1, "nom.al", 2, true},
+	{1, "nym.by", 2, true},
+	{1, "nom.bz", 2, true},
+	{1, "nym.bz", 2, true},
+	{1, "nom.cl", 2, true},
+	{1, "nym.ec", 2, true},
+	{1, "nom.gd", 2, true},
+	{1, "nom.ge", 2, true},
+	{1, "nom.gl", 2, true},
+	{1, "nym.gr", 2, true},
+	{1, "nom.gt", 2, true},
+	{1, "nym.gy", 2, true},
+	{1, "nym.hk", 2, true},
+	{1, "nom.hn", 2, true},
+	{1, "nym.ie", 2, true},
+	{1, "nom.im", 2, true},
+	{1, "nom.ke", 2, true},
+	{1, "nym.kz", 2, true},
+	{1, "nym.la", 2, true},
+	{1, "nym.lc", 2, true},
+	{1, "nom.li", 2, true},
+	{1, "nym.li", 2, true},
+	{1, "nym.lt", 2, true},
+	{1, "nym.lu", 2, true},
+	{1, "nom.lv", 2, true},
+	{1, "nym.me", 2, true},
+	{1, "nom.mk", 2, true},
+	{1, "nym.mn", 2, true},
+	{1, "nym.mx", 2, true},
+	{1, "nom.nu", 2, true},
+	{1, "nym.nz", 2, true},
+	{1, "nym.pe", 2, true},
+	{1, "nym.pt", 2, true},
+	{1, "nom.pw", 2, true},
+	{1, "nom.qa", 2, true},
+	{1, "nym.ro", 2, true},
+	{1, "nom.rs", 2, true},
+	{1, "nom.si", 2, true},
+	{1, "nym.sk", 2, true},
+	{1, "nom.st", 2, true},
+	{1, "nym.su", 2, true},
+	{1, "nym.sx", 2, true},
+	{1, "nom.tj", 2, true},
+	{1, "nym.tw", 2, true},
+	{1, "nom.ug", 2, true},
+	{1, "nom.uy", 2, true},
+	{1, "nom.vc", 2, true},
+	{1, "nom.vg", 2, true},
+	{1, "static.observableusercontent.com", 3, true},
+	{1, "cya.gg", 2, true},
+	{1, "omg.lol", 2, true},
+	{1, "cloudycluster.net", 2, true},
+	{1, "omniwe.site", 2, true},
+	{1, "nid.io", 2, true},
+	{1, "opensocial.site", 2, true},
+	{1, "opencraft.hosting", 2, true},
+	{1, "orsites.com", 2, true},
+	{1, "operaunite.com", 2, true},
+	{1, "authgear-staging.com", 2, true},
+	{1, "authgearapps.com", 2, true},
+	{1, "skygearapp.com", 2, true},
+	{1, "outsystemscloud.com", 2, true},
+	{2, "webpaas.ovh.net", 4, true},
+	{2, "hosting.ovh.net", 4, true},
+	{1, "ownprovider.com", 2, true},
+	{1, "own.pm", 2, true},
+	{2, "owo.codes", 3, true},
+	{1, "ox.rs", 2, true},
+	{1, "oy.lc", 2, true},
+	{1, "pgfog.com", 2, true},
+	{1, "pagefrontapp.com", 2, true},
+	{1, "pagexl.com", 2, true},
+	{2, "paywhirl.com", 3, true},
+	{1, "bar0.net", 2, true},
+	{1, "bar1.net", 2, true},
+	{1, "bar2.net", 2, true},
+	{1, "rdv.to", 2, true},
+	{1, "art.pl", 2, true},
+	{1, "gliwice.pl", 2, true},
+	{1, "krakow.pl", 2, true},
+	{1, "poznan.pl", 2, true},
+	{1, "wroc.pl", 2, true},
+	{1, "zakopane.pl", 2, true},
+	{1, "pantheonsite.io", 2, true},
+	{1, "gotpantheon.com", 2, true},
+	{1, "mypep.link", 2, true},
+	{1, "perspecta.cloud", 2, true},
+	{1, "lk3.ru", 2, true},
+	{1, "ra-ru.ru", 2, true},
+	{1, "zsew.ru", 2, true},
+	{1, "on-web.fr", 2, true},
+	{1, "bc.platform.sh", 3, true},
+	{1, "ent.platform.sh", 3, true},
+	{1, "eu.platform.sh", 3, true},
+	{1, "us.platform.sh", 3, true},
+	{2, "platformsh.site", 3, true},
+	{2, "tst.site", 3, true},
+	{1, "platter-app.com", 2, true},
+	{1, "platter-app.dev", 2, true},
+	{1, "platterp.us", 2, true},
+	{1, "pdns.page", 2, true},
+	{1, "plesk.page", 2, true},
+	{1, "pleskns.com", 2, true},
+	{1, "dyn53.io", 2, true},
+	{1, "co.bn", 2, true},
+	{1, "xen.prgmr.com", 3, true},
+	{1, "priv.at", 2, true},
+	{1, "prvcy.page", 2, true},
+	{2, "dweb.link", 3, true},
+	{1, "protonet.io", 2, true},
+	{1, "chirurgiens-dentistes-en-france.fr", 2, true},
+	{1, "byen.site", 2, true},
+	{1, "pubtls.org", 2, true},
+	{1, "pythonanywhere.com", 2, true},
+	{1, "eu.pythonanywhere.com", 3, true},
+	{1, "qoto.io", 2, true},
+	{1, "qualifioapp.com", 2, true},
+	{1, "qbuser.com", 2, true},
+	{1, "cloudsite.builders", 2, true},
+	{1, "instantcloud.cn", 2, true},
+	{1, "ras.ru", 2, true},
+	{1, "qa2.com", 2, true},
+	{1, "qcx.io", 2, true},
+	{2, "sys.qcx.io", 4, true},
+	{1, "dev-myqnapcloud.com", 2, true},
+	{1, "alpha-myqnapcloud.com", 2, true},
+	{1, "myqnapcloud.com", 2, true},
+	{2, "quipelements.com", 3, true},
+	{1, "vapor.cloud", 2, true},
+	{1, "vaporcloud.io", 2, true},
+	{1, "rackmaze.com", 2, true},
+	{1, "rackmaze.net", 2, true},
+	{1, "g.vbrplsbx.io", 3, true},
+	{2, "on-k3s.io", 3, true},
+	{2, "on-rancher.cloud", 3, true},
+	{2, "on-rio.io", 3, true},
+	{1, "readthedocs.io", 2, true},
+	{1, "rhcloud.com", 2, true},
+	{1, "app.render.com", 3, true},
+	{1, "onrender.com", 2, true},
+	{1, "repl.co", 2, true},
+	{1, "id.repl.co", 3, true},
+	{1, "repl.run", 2, true},
+	{1, "resindevice.io", 2, true},
+	{1, "devices.resinstaging.io", 3, true},
+	{1, "hzc.io", 2, true},
+	{1, "wellbeingzone.eu", 2, true},
+	{1, "wellbeingzone.co.uk", 3, true},
+	{1, "git-pages.rit.edu", 3, true},
+	{1, "xn--90amc.xn--p1acf", 2, true},
+	{1, "xn--j1aef.xn--p1acf", 2, true},
+	{1, "xn--j1ael8b.xn--p1acf", 2, true},
+	{1, "xn--h1ahn.xn--p1acf", 2, true},
+	{1, "xn--j1adp.xn--p1acf", 2, true},
+	{1, "xn--c1avg.xn--p1acf", 2, true},
+	{1, "xn--80aaa0cvac.xn--p1acf", 2, true},
+	{1, "xn--h1aliz.xn--p1acf", 2, true},
+	{1, "xn--90a1af.xn--p1acf", 2, true},
+	{1, "xn--41a.xn--p1acf", 2, true},
+	{1, "sandcats.io", 2, true},
+	{1, "logoip.de", 2, true},
+	{1, "logoip.com", 2, true},
+	{1, "schokokeks.net", 2, true},
+	{1, "gov.scot", 2, true},
+	{1, "service.gov.scot", 3, true},
+	{1, "scrysec.com", 2, true},
+	{1, "firewall-gateway.com", 2, true},
+	{1, "firewall-gateway.de", 2, true},
+	{1, "my-gateway.de", 2, true},
+	{1, "my-router.de", 2, true},
+	{1, "spdns.de", 2, true},
+	{1, "spdns.eu", 2, true},
+	{1, "firewall-gateway.net", 2, true},
+	{1, "my-firewall.org", 2, true},
+	{1, "myfirewall.org", 2, true},
+	{1, "spdns.org", 2, true},
+	{1, "seidat.net", 2, true},
+	{1, "senseering.net", 2, true},
+	{1, "magnet.page", 2, true},
+	{1, "biz.ua", 2, true},
+	{1, "co.ua", 2, true},
+	{1, "pp.ua", 2, true},
+	{1, "shiftcrypto.dev", 2, true},
+	{1, "shiftcrypto.io", 2, true},
+	{1, "shiftedit.io", 2, true},
+	{1, "myshopblocks.com", 2, true},
+	{1, "myshopify.com", 2, true},
+	{1, "shopitsite.com", 2, true},
+	{1, "shopware.store", 2, true},
+	{1, "mo-siemens.io", 2, true},
+	{1, "1kapp.com", 2, true},
+	{1, "appchizi.com", 2, true},
+	{1, "applinzi.com", 2, true},
+	{1, "sinaapp.com", 2, true},
+	{1, "vipsinaapp.com", 2, true},
+	{1, "siteleaf.net", 2, true},
+	{1, "bounty-full.com", 2, true},
+	{1, "alpha.bounty-full.com", 3, true},
+	{1, "beta.bounty-full.com", 3, true},
+	{1, "small-web.org", 2, true},
+	{1, "try-snowplow.com", 2, true},
+	{1, "srht.site", 2, true},
+	{1, "stackhero-network.com", 2, true},
+	{1, "static.land", 2, true},
+	{1, "dev.static.land", 3, true},
+	{1, "sites.static.land", 3, true},
+	{1, "storebase.store", 2, true},
+	{1, "vps-host.net", 2, true},
+	{1, "atl.jelastic.vps-host.net", 4, true},
+	{1, "njs.jelastic.vps-host.net", 4, true},
+	{1, "ric.jelastic.vps-host.net", 4, true},
+	{1, "playstation-cloud.com", 2, true},
+	{1, "apps.lair.io", 3, true},
+	{2, "stolos.io", 3, true},
+	{1, "spacekit.io", 2, true},
+	{1, "customer.speedpartner.de", 3, true},
+	{1, "api.stdlib.com", 3, true},
+	{1, "storj.farm", 2, true},
+	{1, "utwente.io", 2, true},
+	{1, "soc.srcf.net", 3, true},
+	{1, "user.srcf.net", 3, true},
+	{1, "temp-dns.com", 2, true},
+	{2, "s5y.io", 3, true},
+	{2, "sensiosite.cloud", 3, true},
+	{1, "syncloud.it", 2, true},
+	{1, "diskstation.me", 2, true},
+	{1, "dscloud.biz", 2, true},
+	{1, "dscloud.me", 2, true},
+	{1, "dscloud.mobi", 2, true},
+	{1, "dsmynas.com", 2, true},
+	{1, "dsmynas.net", 2, true},
+	{1, "dsmynas.org", 2, true},
+	{1, "familyds.com", 2, true},
+	{1, "familyds.net", 2, true},
+	{1, "familyds.org", 2, true},
+	{1, "i234.me", 2, true},
+	{1, "myds.me", 2, true},
+	{1, "synology.me", 2, true},
+	{1, "vpnplus.to", 2, true},
+	{1, "direct.quickconnect.to", 3, true},
+	{1, "taifun-dns.de", 2, true},
+	{1, "gda.pl", 2, true},
+	{1, "gdansk.pl", 2, true},
+	{1, "gdynia.pl", 2, true},
+	{1, "med.pl", 2, true},
+	{1, "sopot.pl", 2, true},
+	{1, "edugit.org", 2, true},
+	{1, "telebit.app", 2, true},
+	{1, "telebit.io", 2, true},
+	{2, "telebit.xyz", 3, true},
+	{1, "gwiddle.co.uk", 3, true},
+	{1, "thingdustdata.com", 2, true},
+	{1, "cust.dev.thingdust.io", 4, true},
+	{1, "cust.disrec.thingdust.io", 4, true},
+	{1, "cust.prod.thingdust.io", 4, true},
+	{1, "cust.testing.thingdust.io", 4, true},
+	{2, "firenet.ch", 3, true},
+	{2, "svc.firenet.ch", 4, true},
+	{1, "arvo.network", 2, true},
+	{1, "azimuth.network", 2, true},
+	{1, "tlon.network", 2, true},
+	{1, "torproject.net", 2, true},
+	{1, "pages.torproject.net", 3, true},
+	{1, "bloxcms.com", 2, true},
+	{1, "townnews-staging.com", 2, true},
+	{1, "tbits.me", 2, true},
+	{1, "12hp.at", 2, true},
+	{1, "2ix.at", 2, true},
+	{1, "4lima.at", 2, true},
+	{1, "lima-city.at", 2, true},
+	{1, "12hp.ch", 2, true},
+	{1, "2ix.ch", 2, true},
+	{1, "4lima.ch", 2, true},
+	{1, "lima-city.ch", 2, true},
+	{1, "trafficplex.cloud", 2, true},
+	{1, "de.cool", 2, true},
+	{1, "12hp.de", 2, true},
+	{1, "2ix.de", 2, true},
+	{1, "4lima.de", 2, true},
+	{1, "lima-city.de", 2, true},
+	{1, "1337.pictures", 2, true},
+	{1, "clan.rip", 2, true},
+	{1, "lima-city.rocks", 2, true},
+	{1, "webspace.rocks", 2, true},
+	{1, "lima.zone", 2, true},
+	{2, "transurl.be", 3, true},
+	{2, "transurl.eu", 3, true},
+	{2, "transurl.nl", 3, true},
+	{1, "tuxfamily.org", 2, true},
+	{1, "dd-dns.de", 2, true},
+	{1, "diskstation.eu", 2, true},
+	{1, "diskstation.org", 2, true},
+	{1, "dray-dns.de", 2, true},
+	{1, "draydns.de", 2, true},
+	{1, "dyn-vpn.de", 2, true},
+	{1, "dynvpn.de", 2, true},
+	{1, "mein-vigor.de", 2, true},
+	{1, "my-vigor.de", 2, true},
+	{1, "my-wan.de", 2, true},
+	{1, "syno-ds.de", 2, true},
+	{1, "synology-diskstation.de", 2, true},
+	{1, "synology-ds.de", 2, true},
+	{1, "uber.space", 2, true},
+	{2, "uberspace.de", 3, true},
+	{1, "hk.com", 2, true},
+	{1, "hk.org", 2, true},
+	{1, "ltd.hk", 2, true},
+	{1, "inc.hk", 2, true},
+	{1, "virtualuser.de", 2, true},
+	{1, "virtual-user.de", 2, true},
+	{1, "urown.cloud", 2, true},
+	{1, "dnsupdate.info", 2, true},
+	{1, "lib.de.us", 3, true},
+	{1, "2038.io", 2, true},
+	{1, "vercel.app", 2, true},
+	{1, "vercel.dev", 2, true},
+	{1, "now.sh", 2, true},
+	{1, "router.management", 2, true},
+	{1, "v-info.info", 2, true},
+	{1, "voorloper.cloud", 2, true},
+	{1, "neko.am", 2, true},
+	{1, "nyaa.am", 2, true},
+	{1, "be.ax", 2, true},
+	{1, "cat.ax", 2, true},
+	{1, "es.ax", 2, true},
+	{1, "eu.ax", 2, true},
+	{1, "gg.ax", 2, true},
+	{1, "mc.ax", 2, true},
+	{1, "us.ax", 2, true},
+	{1, "xy.ax", 2, true},
+	{1, "nl.ci", 2, true},
+	{1, "xx.gl", 2, true},
+	{1, "app.gp", 2, true},
+	{1, "blog.gt", 2, true},
+	{1, "de.gt", 2, true},
+	{1, "to.gt", 2, true},
+	{1, "be.gy", 2, true},
+	{1, "cc.hn", 2, true},
+	{1, "blog.kg", 2, true},
+	{1, "io.kg", 2, true},
+	{1, "jp.kg", 2, true},
+	{1, "tv.kg", 2, true},
+	{1, "uk.kg", 2, true},
+	{1, "us.kg", 2, true},
+	{1, "de.ls", 2, true},
+	{1, "at.md", 2, true},
+	{1, "de.md", 2, true},
+	{1, "jp.md", 2, true},
+	{1, "to.md", 2, true},
+	{1, "uwu.nu", 2, true},
+	{1, "indie.porn", 2, true},
+	{1, "vxl.sh", 2, true},
+	{1, "ch.tc", 2, true},
+	{1, "me.tc", 2, true},
+	{1, "we.tc", 2, true},
+	{1, "nyan.to", 2, true},
+	{1, "at.vg", 2, true},
+	{1, "blog.vu", 2, true},
+	{1, "dev.vu", 2, true},
+	{1, "me.vu", 2, true},
+	{1, "v.ua", 2, true},
+	{1, "wafflecell.com", 2, true},
+	{1, "idnblogger.com", 2, true},
+	{1, "indowapblog.com", 2, true},
+	{1, "bloger.id", 2, true},
+	{1, "wblog.id", 2, true},
+	{1, "wbq.me", 2, true},
+	{1, "fastblog.net", 2, true},
+	{2, "webhare.dev", 3, true},
+	{1, "reserve-online.net", 2, true},
+	{1, "reserve-online.com", 2, true},
+	{1, "bookonline.app", 2, true},
+	{1, "hotelwithflight.com", 2, true},
+	{1, "wedeploy.io", 2, true},
+	{1, "wedeploy.me", 2, true},
+	{1, "wedeploy.sh", 2, true},
+	{1, "remotewd.com", 2, true},
+	{1, "pages.wiardweb.com", 3, true},
+	{1, "wmflabs.org", 2, true},
+	{1, "toolforge.org", 2, true},
+	{1, "wmcloud.org", 2, true},
+	{1, "panel.gg", 2, true},
+	{1, "daemon.panel.gg", 3, true},
+	{1, "woltlab-demo.com", 2, true},
+	{1, "myforum.community", 2, true},
+	{1, "community-pro.de", 2, true},
+	{1, "diskussionsbereich.de", 2, true},
+	{1, "community-pro.net", 2, true},
+	{1, "meinforum.net", 2, true},
+	{1, "wpenginepowered.com", 2, true},
+	{1, "js.wpenginepowered.com", 3, true},
+	{1, "wixsite.com", 2, true},
+	{1, "editorx.io", 2, true},
+	{1, "half.host", 2, true},
+	{1, "xnbay.com", 2, true},
+	{1, "u2.xnbay.com", 3, true},
+	{1, "u2-local.xnbay.com", 3, true},
+	{1, "cistron.nl", 2, true},
+	{1, "demon.nl", 2, true},
+	{1, "xs4all.space", 2, true},
+	{1, "yandexcloud.net", 2, true},
+	{1, "storage.yandexcloud.net", 3, true},
+	{1, "website.yandexcloud.net", 3, true},
+	{1, "official.academy", 2, true},
+	{1, "yolasite.com", 2, true},
+	{1, "ybo.faith", 2, true},
+	{1, "yombo.me", 2, true},
+	{1, "homelink.one", 2, true},
+	{1, "ybo.party", 2, true},
+	{1, "ybo.review", 2, true},
+	{1, "ybo.science", 2, true},
+	{1, "ybo.trade", 2, true},
+	{1, "nohost.me", 2, true},
+	{1, "noho.st", 2, true},
+	{1, "za.net", 2, true},
+	{1, "za.org", 2, true},
+	{1, "bss.design", 2, true},
+	{1, "basicserver.io", 2, true},
+	{1, "virtualserver.io", 2, true},
+	{1, "enterprisecloud.nu", 2, true},
+}
+
+func init() {
+	for i := range r {
+		DefaultList.AddRule(&r[i])
+	}
+}

+ 257 - 0
vendor/github.com/zmap/zcrypto/LICENSE

@@ -0,0 +1,257 @@
+ZCrypto is an original work created at the University of Michigan, and is
+licensed under the Apache 2.0 license. However, ZCrypto contains a fork of
+several packages from Golang standard library, as well as code from the
+BoringSSL test runner. Files that were created by Google, and new files in
+forks of packages maintained by Google have a Google copyright and fall under
+the ISC license. In addition ZCrypto includes a `util/isURL.go` file created by
+Alex Saskevich and licensed under the MIT license. All other files are copyright
+Regents of the University of Michigan, and fall under the Apache 2.0 license.
+All three licenses are reproduced at the bottom of this file.
+
+--------
+
+ISC License used for Google code
+
+/* Copyright (c) 2015, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+--------
+
+MIT License used for util/isURL.go adopted from https://github.com/asaskevich/govalidator
+
+  The MIT License (MIT)
+
+  Copyright (c) 2014 Alex Saskevich
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in all
+  copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  SOFTWARE.
+
+--------
+
+Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   ZCrypto Copyright 2015 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.

+ 309 - 0
vendor/github.com/zmap/zcrypto/dsa/dsa.go

@@ -0,0 +1,309 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package dsa implements the Digital Signature Algorithm, as defined in FIPS 186-3.
+//
+// The DSA operations in this package are not implemented using constant-time algorithms.
+//
+// Warning: DSA is a legacy algorithm, and modern alternatives such as
+// Ed25519 (implemented by package crypto/ed25519) should be used instead. Keys
+// with 1024-bit moduli (L1024N160 parameters) are cryptographically weak, while
+// bigger keys are not widely supported. Note that FIPS 186-5 no longer approves
+// DSA for signature generation.
+package dsa
+
+import (
+	"errors"
+	"io"
+	"math/big"
+
+	"github.com/zmap/zcrypto/internal/randutil"
+)
+
+// Parameters represents the domain parameters for a key. These parameters can
+// be shared across many keys. The bit length of Q must be a multiple of 8.
+type Parameters struct {
+	P, Q, G *big.Int
+}
+
+// PublicKey represents a DSA public key.
+type PublicKey struct {
+	Parameters
+	Y *big.Int
+}
+
+// PrivateKey represents a DSA private key.
+type PrivateKey struct {
+	PublicKey
+	X *big.Int
+}
+
+// ErrInvalidPublicKey results when a public key is not usable by this code.
+// FIPS is quite strict about the format of DSA keys, but other code may be
+// less so. Thus, when using keys which may have been generated by other code,
+// this error must be handled.
+var ErrInvalidPublicKey = errors.New("crypto/dsa: invalid public key")
+
+// ParameterSizes is an enumeration of the acceptable bit lengths of the primes
+// in a set of DSA parameters. See FIPS 186-3, section 4.2.
+type ParameterSizes int
+
+const (
+	L1024N160 ParameterSizes = iota
+	L2048N224
+	L2048N256
+	L3072N256
+)
+
+// numMRTests is the number of Miller-Rabin primality tests that we perform. We
+// pick the largest recommended number from table C.1 of FIPS 186-3.
+const numMRTests = 64
+
+// GenerateParameters puts a random, valid set of DSA parameters into params.
+// This function can take many seconds, even on fast machines.
+func GenerateParameters(params *Parameters, rand io.Reader, sizes ParameterSizes) error {
+	// This function doesn't follow FIPS 186-3 exactly in that it doesn't
+	// use a verification seed to generate the primes. The verification
+	// seed doesn't appear to be exported or used by other code and
+	// omitting it makes the code cleaner.
+
+	var L, N int
+	switch sizes {
+	case L1024N160:
+		L = 1024
+		N = 160
+	case L2048N224:
+		L = 2048
+		N = 224
+	case L2048N256:
+		L = 2048
+		N = 256
+	case L3072N256:
+		L = 3072
+		N = 256
+	default:
+		return errors.New("crypto/dsa: invalid ParameterSizes")
+	}
+
+	qBytes := make([]byte, N/8)
+	pBytes := make([]byte, L/8)
+
+	q := new(big.Int)
+	p := new(big.Int)
+	rem := new(big.Int)
+	one := new(big.Int)
+	one.SetInt64(1)
+
+GeneratePrimes:
+	for {
+		if _, err := io.ReadFull(rand, qBytes); err != nil {
+			return err
+		}
+
+		qBytes[len(qBytes)-1] |= 1
+		qBytes[0] |= 0x80
+		q.SetBytes(qBytes)
+
+		if !q.ProbablyPrime(numMRTests) {
+			continue
+		}
+
+		for i := 0; i < 4*L; i++ {
+			if _, err := io.ReadFull(rand, pBytes); err != nil {
+				return err
+			}
+
+			pBytes[len(pBytes)-1] |= 1
+			pBytes[0] |= 0x80
+
+			p.SetBytes(pBytes)
+			rem.Mod(p, q)
+			rem.Sub(rem, one)
+			p.Sub(p, rem)
+			if p.BitLen() < L {
+				continue
+			}
+
+			if !p.ProbablyPrime(numMRTests) {
+				continue
+			}
+
+			params.P = p
+			params.Q = q
+			break GeneratePrimes
+		}
+	}
+
+	h := new(big.Int)
+	h.SetInt64(2)
+	g := new(big.Int)
+
+	pm1 := new(big.Int).Sub(p, one)
+	e := new(big.Int).Div(pm1, q)
+
+	for {
+		g.Exp(h, e, p)
+		if g.Cmp(one) == 0 {
+			h.Add(h, one)
+			continue
+		}
+
+		params.G = g
+		return nil
+	}
+}
+
+// GenerateKey generates a public&private key pair. The Parameters of the
+// PrivateKey must already be valid (see GenerateParameters).
+func GenerateKey(priv *PrivateKey, rand io.Reader) error {
+	if priv.P == nil || priv.Q == nil || priv.G == nil {
+		return errors.New("crypto/dsa: parameters not set up before generating key")
+	}
+
+	x := new(big.Int)
+	xBytes := make([]byte, priv.Q.BitLen()/8)
+
+	for {
+		_, err := io.ReadFull(rand, xBytes)
+		if err != nil {
+			return err
+		}
+		x.SetBytes(xBytes)
+		if x.Sign() != 0 && x.Cmp(priv.Q) < 0 {
+			break
+		}
+	}
+
+	priv.X = x
+	priv.Y = new(big.Int)
+	priv.Y.Exp(priv.G, x, priv.P)
+	return nil
+}
+
+// fermatInverse calculates the inverse of k in GF(P) using Fermat's method.
+// This has better constant-time properties than Euclid's method (implemented
+// in math/big.Int.ModInverse) although math/big itself isn't strictly
+// constant-time so it's not perfect.
+func fermatInverse(k, P *big.Int) *big.Int {
+	two := big.NewInt(2)
+	pMinus2 := new(big.Int).Sub(P, two)
+	return new(big.Int).Exp(k, pMinus2, P)
+}
+
+// Sign signs an arbitrary length hash (which should be the result of hashing a
+// larger message) using the private key, priv. It returns the signature as a
+// pair of integers. The security of the private key depends on the entropy of
+// rand.
+//
+// Note that FIPS 186-3 section 4.6 specifies that the hash should be truncated
+// to the byte-length of the subgroup. This function does not perform that
+// truncation itself.
+//
+// Be aware that calling Sign with an attacker-controlled PrivateKey may
+// require an arbitrary amount of CPU.
+func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
+	randutil.MaybeReadByte(rand)
+
+	// FIPS 186-3, section 4.6
+
+	n := priv.Q.BitLen()
+	if priv.Q.Sign() <= 0 || priv.P.Sign() <= 0 || priv.G.Sign() <= 0 || priv.X.Sign() <= 0 || n%8 != 0 {
+		err = ErrInvalidPublicKey
+		return
+	}
+	n >>= 3
+
+	var attempts int
+	for attempts = 10; attempts > 0; attempts-- {
+		k := new(big.Int)
+		buf := make([]byte, n)
+		for {
+			_, err = io.ReadFull(rand, buf)
+			if err != nil {
+				return
+			}
+			k.SetBytes(buf)
+			// priv.Q must be >= 128 because the test above
+			// requires it to be > 0 and that
+			//    ceil(log_2(Q)) mod 8 = 0
+			// Thus this loop will quickly terminate.
+			if k.Sign() > 0 && k.Cmp(priv.Q) < 0 {
+				break
+			}
+		}
+
+		kInv := fermatInverse(k, priv.Q)
+
+		r = new(big.Int).Exp(priv.G, k, priv.P)
+		r.Mod(r, priv.Q)
+
+		if r.Sign() == 0 {
+			continue
+		}
+
+		z := k.SetBytes(hash)
+
+		s = new(big.Int).Mul(priv.X, r)
+		s.Add(s, z)
+		s.Mod(s, priv.Q)
+		s.Mul(s, kInv)
+		s.Mod(s, priv.Q)
+
+		if s.Sign() != 0 {
+			break
+		}
+	}
+
+	// Only degenerate private keys will require more than a handful of
+	// attempts.
+	if attempts == 0 {
+		return nil, nil, ErrInvalidPublicKey
+	}
+
+	return
+}
+
+// Verify verifies the signature in r, s of hash using the public key, pub. It
+// reports whether the signature is valid.
+//
+// Note that FIPS 186-3 section 4.6 specifies that the hash should be truncated
+// to the byte-length of the subgroup. This function does not perform that
+// truncation itself.
+func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
+	// FIPS 186-3, section 4.7
+
+	if pub.P.Sign() == 0 {
+		return false
+	}
+
+	if r.Sign() < 1 || r.Cmp(pub.Q) >= 0 {
+		return false
+	}
+	if s.Sign() < 1 || s.Cmp(pub.Q) >= 0 {
+		return false
+	}
+
+	w := new(big.Int).ModInverse(s, pub.Q)
+	if w == nil {
+		return false
+	}
+
+	n := pub.Q.BitLen()
+	if n%8 != 0 {
+		return false
+	}
+	z := new(big.Int).SetBytes(hash)
+
+	u1 := new(big.Int).Mul(z, w)
+	u1.Mod(u1, pub.Q)
+	u2 := w.Mul(r, w)
+	u2.Mod(u2, pub.Q)
+	v := u1.Exp(pub.G, u1, pub.P)
+	u2.Exp(pub.Y, u2, pub.P)
+	v.Mul(v, u2)
+	v.Mod(v, pub.P)
+	v.Mod(v, pub.Q)
+
+	return v.Cmp(r) == 0
+}

+ 38 - 0
vendor/github.com/zmap/zcrypto/internal/randutil/randutil.go

@@ -0,0 +1,38 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package randutil contains internal randomness utilities for various
+// crypto packages.
+package randutil
+
+import (
+	"io"
+	"sync"
+)
+
+var (
+	closedChanOnce sync.Once
+	closedChan     chan struct{}
+)
+
+// MaybeReadByte reads a single byte from r with ~50% probability. This is used
+// to ensure that callers do not depend on non-guaranteed behaviour, e.g.
+// assuming that rsa.GenerateKey is deterministic w.r.t. a given random stream.
+//
+// This does not affect tests that pass a stream of fixed bytes as the random
+// source (e.g. a zeroReader).
+func MaybeReadByte(r io.Reader) {
+	closedChanOnce.Do(func() {
+		closedChan = make(chan struct{})
+		close(closedChan)
+	})
+
+	select {
+	case <-closedChan:
+		return
+	case <-closedChan:
+		var buf [1]byte
+		r.Read(buf[:])
+	}
+}

+ 130 - 0
vendor/github.com/zmap/zcrypto/json/dhe.go

@@ -0,0 +1,130 @@
+/*
+ * ZGrab Copyright 2015 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.
+ */
+
+package json
+
+import (
+	"encoding/json"
+	"math/big"
+)
+
+// DHParams can be used to store finite-field Diffie-Hellman parameters. At any
+// point in time, it is unlikely that both OurPrivate and TheirPrivate will be
+// non-nil.
+type DHParams struct {
+	Prime         *big.Int
+	Generator     *big.Int
+	ServerPublic  *big.Int
+	ServerPrivate *big.Int
+	ClientPublic  *big.Int
+	ClientPrivate *big.Int
+	SessionKey    *big.Int
+}
+
+type auxDHParams struct {
+	Prime         *cryptoParameter `json:"prime"`
+	Generator     *cryptoParameter `json:"generator"`
+	ServerPublic  *cryptoParameter `json:"server_public,omitempty"`
+	ServerPrivate *cryptoParameter `json:"server_private,omitempty"`
+	ClientPublic  *cryptoParameter `json:"client_public,omitempty"`
+	ClientPrivate *cryptoParameter `json:"client_private,omitempty"`
+	SessionKey    *cryptoParameter `json:"session_key,omitempty"`
+}
+
+// MarshalJSON implements the json.Marshal interface
+func (p *DHParams) MarshalJSON() ([]byte, error) {
+	aux := auxDHParams{
+		Prime:     &cryptoParameter{Int: p.Prime},
+		Generator: &cryptoParameter{Int: p.Generator},
+	}
+	if p.ServerPublic != nil {
+		aux.ServerPublic = &cryptoParameter{Int: p.ServerPublic}
+	}
+	if p.ServerPrivate != nil {
+		aux.ServerPrivate = &cryptoParameter{Int: p.ServerPrivate}
+	}
+	if p.ClientPublic != nil {
+		aux.ClientPublic = &cryptoParameter{Int: p.ClientPublic}
+	}
+	if p.ClientPrivate != nil {
+		aux.ClientPrivate = &cryptoParameter{Int: p.ClientPrivate}
+	}
+	if p.SessionKey != nil {
+		aux.SessionKey = &cryptoParameter{Int: p.SessionKey}
+	}
+	return json.Marshal(aux)
+}
+
+// UnmarshalJSON implement the json.Unmarshaler interface
+func (p *DHParams) UnmarshalJSON(b []byte) error {
+	var aux auxDHParams
+	if err := json.Unmarshal(b, &aux); err != nil {
+		return err
+	}
+	if aux.Prime != nil {
+		p.Prime = aux.Prime.Int
+	}
+	if aux.Generator != nil {
+		p.Generator = aux.Generator.Int
+	}
+	if aux.ServerPublic != nil {
+		p.ServerPublic = aux.ServerPublic.Int
+	}
+	if aux.ServerPrivate != nil {
+		p.ServerPrivate = aux.ServerPrivate.Int
+	}
+	if aux.ClientPublic != nil {
+		p.ClientPublic = aux.ClientPublic.Int
+	}
+	if aux.ClientPrivate != nil {
+		p.ClientPrivate = aux.ClientPrivate.Int
+	}
+	if aux.SessionKey != nil {
+		p.SessionKey = aux.SessionKey.Int
+	}
+	return nil
+}
+
+// CryptoParameter represents a big.Int used a parameter in some cryptography.
+// It serializes to json as a tupe of a base64-encoded number and a length in
+// bits.
+type cryptoParameter struct {
+	*big.Int
+}
+
+type auxCryptoParameter struct {
+	Raw    []byte `json:"value"`
+	Length int    `json:"length"`
+}
+
+// MarshalJSON implements the json.Marshaler interface
+func (p *cryptoParameter) MarshalJSON() ([]byte, error) {
+	var aux auxCryptoParameter
+	if p.Int != nil {
+		aux.Raw = p.Bytes()
+		aux.Length = 8 * len(aux.Raw)
+	}
+	return json.Marshal(&aux)
+}
+
+// UnmarshalJSON implements the json.Unmarshal interface
+func (p *cryptoParameter) UnmarshalJSON(b []byte) error {
+	var aux auxCryptoParameter
+	if err := json.Unmarshal(b, &aux); err != nil {
+		return err
+	}
+	p.Int = new(big.Int)
+	p.SetBytes(aux.Raw)
+	return nil
+}

+ 107 - 0
vendor/github.com/zmap/zcrypto/json/ecdhe.go

@@ -0,0 +1,107 @@
+/*
+ * ZGrab Copyright 2015 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.
+ */
+
+package json
+
+import (
+	"crypto/elliptic"
+	"encoding/json"
+	"math/big"
+)
+
+// TLSCurveID is the type of a TLS identifier for an elliptic curve. See
+// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8
+type TLSCurveID uint16
+
+// ECDHPrivateParams are the TLS key exchange parameters for ECDH keys.
+type ECDHPrivateParams struct {
+	Value  []byte `json:"value,omitempty"`
+	Length int    `json:"length,omitempty"`
+}
+
+// ECDHParams stores elliptic-curve Diffie-Hellman paramters.At any point in
+// time, it is unlikely that both ServerPrivate and ClientPrivate will be non-nil.
+type ECDHParams struct {
+	TLSCurveID    TLSCurveID         `json:"curve_id,omitempty"`
+	Curve         elliptic.Curve     `json:"-"`
+	ServerPublic  *ECPoint           `json:"server_public,omitempty"`
+	ServerPrivate *ECDHPrivateParams `json:"server_private,omitempty"`
+	ClientPublic  *ECPoint           `json:"client_public,omitempty"`
+	ClientPrivate *ECDHPrivateParams `json:"client_private,omitempty"`
+}
+
+// ECPoint represents an elliptic curve point and serializes nicely to JSON
+type ECPoint struct {
+	X *big.Int
+	Y *big.Int
+}
+
+// MarshalJSON implements the json.Marshler interface
+func (p *ECPoint) MarshalJSON() ([]byte, error) {
+	aux := struct {
+		X *cryptoParameter `json:"x"`
+		Y *cryptoParameter `json:"y"`
+	}{
+		X: &cryptoParameter{Int: p.X},
+		Y: &cryptoParameter{Int: p.Y},
+	}
+	return json.Marshal(&aux)
+}
+
+// UnmarshalJSON implements the json.Unmarshler interface
+func (p *ECPoint) UnmarshalJSON(b []byte) error {
+	aux := struct {
+		X *cryptoParameter `json:"x"`
+		Y *cryptoParameter `json:"y"`
+	}{}
+	if err := json.Unmarshal(b, &aux); err != nil {
+		return err
+	}
+	p.X = aux.X.Int
+	p.Y = aux.Y.Int
+	return nil
+}
+
+// Description returns the description field for the given ID. See
+// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8
+func (c *TLSCurveID) Description() string {
+	if desc, ok := ecIDToName[*c]; ok {
+		return desc
+	}
+	return "unknown"
+}
+
+// MarshalJSON implements the json.Marshaler interface
+func (c *TLSCurveID) MarshalJSON() ([]byte, error) {
+	aux := struct {
+		Name string `json:"name"`
+		ID   uint16 `json:"id"`
+	}{
+		Name: c.Description(),
+		ID:   uint16(*c),
+	}
+	return json.Marshal(&aux)
+}
+
+//UnmarshalJSON implements the json.Unmarshaler interface
+func (c *TLSCurveID) UnmarshalJSON(b []byte) error {
+	aux := struct {
+		ID uint16 `json:"id"`
+	}{}
+	if err := json.Unmarshal(b, &aux); err != nil {
+		return err
+	}
+	*c = TLSCurveID(aux.ID)
+	return nil
+}

+ 113 - 0
vendor/github.com/zmap/zcrypto/json/names.go

@@ -0,0 +1,113 @@
+/*
+ * ZGrab Copyright 2015 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.
+ */
+
+package json
+
+// IANA-assigned curve ID values, see
+// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8
+const (
+	Sect163k1       TLSCurveID = 1
+	Sect163r1       TLSCurveID = 2
+	Sect163r2       TLSCurveID = 3
+	Sect193r1       TLSCurveID = 4
+	Sect193r2       TLSCurveID = 5
+	Sect233k1       TLSCurveID = 6
+	Sect233r1       TLSCurveID = 7
+	Sect239k1       TLSCurveID = 8
+	Sect283k1       TLSCurveID = 9
+	Sect283r1       TLSCurveID = 10
+	Sect409k1       TLSCurveID = 11
+	Sect409r1       TLSCurveID = 12
+	Sect571k1       TLSCurveID = 13
+	Sect571r1       TLSCurveID = 14
+	Secp160k1       TLSCurveID = 15
+	Secp160r1       TLSCurveID = 16
+	Secp160r2       TLSCurveID = 17
+	Secp192k1       TLSCurveID = 18
+	Secp192r1       TLSCurveID = 19
+	Secp224k1       TLSCurveID = 20
+	Secp224r1       TLSCurveID = 21
+	Secp256k1       TLSCurveID = 22
+	Secp256r1       TLSCurveID = 23
+	Secp384r1       TLSCurveID = 24
+	Secp521r1       TLSCurveID = 25
+	BrainpoolP256r1 TLSCurveID = 26
+	BrainpoolP384r1 TLSCurveID = 27
+	BrainpoolP512r1 TLSCurveID = 28
+)
+
+var ecIDToName map[TLSCurveID]string
+var ecNameToID map[string]TLSCurveID
+
+func init() {
+	ecIDToName = make(map[TLSCurveID]string, 64)
+	ecIDToName[Sect163k1] = "sect163k1"
+	ecIDToName[Sect163r1] = "sect163r1"
+	ecIDToName[Sect163r2] = "sect163r2"
+	ecIDToName[Sect193r1] = "sect193r1"
+	ecIDToName[Sect193r2] = "sect193r2"
+	ecIDToName[Sect233k1] = "sect233k1"
+	ecIDToName[Sect233r1] = "sect233r1"
+	ecIDToName[Sect239k1] = "sect239k1"
+	ecIDToName[Sect283k1] = "sect283k1"
+	ecIDToName[Sect283r1] = "sect283r1"
+	ecIDToName[Sect409k1] = "sect409k1"
+	ecIDToName[Sect409r1] = "sect409r1"
+	ecIDToName[Sect571k1] = "sect571k1"
+	ecIDToName[Sect571r1] = "sect571r1"
+	ecIDToName[Secp160k1] = "secp160k1"
+	ecIDToName[Secp160r1] = "secp160r1"
+	ecIDToName[Secp160r2] = "secp160r2"
+	ecIDToName[Secp192k1] = "secp192k1"
+	ecIDToName[Secp192r1] = "secp192r1"
+	ecIDToName[Secp224k1] = "secp224k1"
+	ecIDToName[Secp224r1] = "secp224r1"
+	ecIDToName[Secp256k1] = "secp256k1"
+	ecIDToName[Secp256r1] = "secp256r1"
+	ecIDToName[Secp384r1] = "secp384r1"
+	ecIDToName[Secp521r1] = "secp521r1"
+	ecIDToName[BrainpoolP256r1] = "brainpoolp256r1"
+	ecIDToName[BrainpoolP384r1] = "brainpoolp384r1"
+	ecIDToName[BrainpoolP512r1] = "brainpoolp512r1"
+
+	ecNameToID = make(map[string]TLSCurveID, 64)
+	ecNameToID["sect163k1"] = Sect163k1
+	ecNameToID["sect163r1"] = Sect163r1
+	ecNameToID["sect163r2"] = Sect163r2
+	ecNameToID["sect193r1"] = Sect193r1
+	ecNameToID["sect193r2"] = Sect193r2
+	ecNameToID["sect233k1"] = Sect233k1
+	ecNameToID["sect233r1"] = Sect233r1
+	ecNameToID["sect239k1"] = Sect239k1
+	ecNameToID["sect283k1"] = Sect283k1
+	ecNameToID["sect283r1"] = Sect283r1
+	ecNameToID["sect409k1"] = Sect409k1
+	ecNameToID["sect409r1"] = Sect409r1
+	ecNameToID["sect571k1"] = Sect571k1
+	ecNameToID["sect571r1"] = Sect571r1
+	ecNameToID["secp160k1"] = Secp160k1
+	ecNameToID["secp160r1"] = Secp160r1
+	ecNameToID["secp160r2"] = Secp160r2
+	ecNameToID["secp192k1"] = Secp192k1
+	ecNameToID["secp192r1"] = Secp192r1
+	ecNameToID["secp224k1"] = Secp224k1
+	ecNameToID["secp224r1"] = Secp224r1
+	ecNameToID["secp256k1"] = Secp256k1
+	ecNameToID["secp256r1"] = Secp256r1
+	ecNameToID["secp384r1"] = Secp384r1
+	ecNameToID["secp521r1"] = Secp521r1
+	ecNameToID["brainpoolp256r1"] = BrainpoolP256r1
+	ecNameToID["brainpoolp384r1"] = BrainpoolP384r1
+	ecNameToID["brainpoolp512r1"] = BrainpoolP512r1
+}

+ 67 - 0
vendor/github.com/zmap/zcrypto/json/rsa.go

@@ -0,0 +1,67 @@
+/*
+ * ZGrab Copyright 2015 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.
+ */
+
+package json
+
+import (
+	"crypto/rsa"
+	"encoding/json"
+	"fmt"
+	"math/big"
+)
+
+// RSAPublicKey provides JSON methods for the standard rsa.PublicKey.
+type RSAPublicKey struct {
+	*rsa.PublicKey
+}
+
+type auxRSAPublicKey struct {
+	Exponent int    `json:"exponent"`
+	Modulus  []byte `json:"modulus"`
+	Length   int    `json:"length"`
+}
+
+// RSAClientParams are the TLS key exchange parameters for RSA keys.
+type RSAClientParams struct {
+	Length       uint16 `json:"length,omitempty"`
+	EncryptedPMS []byte `json:"encrypted_pre_master_secret,omitempty"`
+}
+
+// MarshalJSON implements the json.Marshal interface
+func (rp *RSAPublicKey) MarshalJSON() ([]byte, error) {
+	var aux auxRSAPublicKey
+	if rp.PublicKey != nil {
+		aux.Exponent = rp.E
+		aux.Modulus = rp.N.Bytes()
+		aux.Length = len(aux.Modulus) * 8
+	}
+	return json.Marshal(&aux)
+}
+
+// UnmarshalJSON implements the json.Unmarshal interface
+func (rp *RSAPublicKey) UnmarshalJSON(b []byte) error {
+	var aux auxRSAPublicKey
+	if err := json.Unmarshal(b, &aux); err != nil {
+		return err
+	}
+	if rp.PublicKey == nil {
+		rp.PublicKey = new(rsa.PublicKey)
+	}
+	rp.E = aux.Exponent
+	rp.N = big.NewInt(0).SetBytes(aux.Modulus)
+	if len(aux.Modulus)*8 != aux.Length {
+		return fmt.Errorf("mismatched length (got %d, field specified %d)", len(aux.Modulus), aux.Length)
+	}
+	return nil
+}

+ 77 - 0
vendor/github.com/zmap/zcrypto/util/isURL.go

@@ -0,0 +1,77 @@
+/*
+The MIT License (MIT)
+
+Copyright (c) 2014 Alex Saskevich
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+package util
+
+import (
+	"net/url"
+	"regexp"
+	"strings"
+	"unicode/utf8"
+)
+
+const (
+	maxURLRuneCount = 2083
+	minURLRuneCount = 3
+
+	IP           = `(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))`
+	URLSchema    = `((ftp|tcp|udp|wss?|https?):\/\/)`
+	URLUsername  = `(\S+(:\S*)?@)`
+	URLPath      = `((\/|\?|#)[^\s]*)`
+	URLPort      = `(:(\d{1,5}))`
+	URLIP        = `([1-9]\d?|1\d\d|2[01]\d|22[0-3])(\.(1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))`
+	URLSubdomain = `((www\.)|([a-zA-Z0-9]+([-_\.]?[a-zA-Z0-9])*[a-zA-Z0-9]\.[a-zA-Z0-9]+))`
+)
+
+var (
+	URL   = `^` + URLSchema + `?` + URLUsername + `?` + `((` + URLIP + `|(\[` + IP + `\])|(([a-zA-Z0-9]([a-zA-Z0-9-_]+)?[a-zA-Z0-9]([-\.][a-zA-Z0-9]+)*)|(` + URLSubdomain + `?))?(([a-zA-Z\x{00a1}-\x{ffff}0-9]+-?-?)*[a-zA-Z\x{00a1}-\x{ffff}0-9]+)(?:\.([a-zA-Z\x{00a1}-\x{ffff}]{1,}))?))\.?` + URLPort + `?` + URLPath + `?$`
+	rxURL = regexp.MustCompile(URL)
+)
+
+// IsURL check if the string is an URL.
+// This function is (graciously) adopted from
+// https://github.com/asaskevich/govalidator to avoid needing a full dependency on
+// `govalidator` for the one `IsURL` function.
+func IsURL(str string) bool {
+	if str == "" || utf8.RuneCountInString(str) >= maxURLRuneCount || len(str) <= minURLRuneCount || strings.HasPrefix(str, ".") {
+		return false
+	}
+	strTemp := str
+	if strings.Contains(str, ":") && !strings.Contains(str, "://") {
+		// support no indicated urlscheme but with colon for port number
+		// http:// is appended so url.Parse will succeed, strTemp used so it does not impact rxURL.MatchString
+		strTemp = "http://" + str
+	}
+	u, err := url.Parse(strTemp)
+	if err != nil {
+		return false
+	}
+	if strings.HasPrefix(u.Host, ".") {
+		return false
+	}
+	if u.Host == "" && (u.Path != "" && !strings.Contains(u.Path, ".")) {
+		return false
+	}
+	return rxURL.MatchString(str)
+}

+ 8 - 0
vendor/github.com/zmap/zcrypto/x509/README.md

@@ -0,0 +1,8 @@
+Originally based on the go/crypto/x509 standard library,
+this package has now diverged enough that it is no longer
+updated with direct correspondence to new go releases.
+
+Approximately supports all the features of
+github.com/golang/go/crypto/x509 package at:
+branch: release-branch.go1.10
+revision: dea961ebd9f871b39b3bdaab32f952037f28cd71

+ 171 - 0
vendor/github.com/zmap/zcrypto/x509/cert_pool.go

@@ -0,0 +1,171 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+	"encoding/pem"
+)
+
+// CertPool is a set of certificates.
+type CertPool struct {
+	bySubjectKeyId map[string][]int
+	byName         map[string][]int
+	bySHA256       map[string]int
+	certs          []*Certificate
+}
+
+// NewCertPool returns a new, empty CertPool.
+func NewCertPool() *CertPool {
+	return &CertPool{
+		bySubjectKeyId: make(map[string][]int),
+		byName:         make(map[string][]int),
+		bySHA256:       make(map[string]int),
+	}
+}
+
+// findVerifiedParents attempts to find certificates in s which have signed the
+// given certificate. If any candidates were rejected then errCert will be set
+// to one of them, arbitrarily, and err will contain the reason that it was
+// rejected.
+func (s *CertPool) findVerifiedParents(cert *Certificate) (parents []int, errCert *Certificate, err error) {
+	if s == nil {
+		return
+	}
+	var candidates []int
+
+	if len(cert.AuthorityKeyId) > 0 {
+		candidates, _ = s.bySubjectKeyId[string(cert.AuthorityKeyId)]
+	}
+	if len(candidates) == 0 {
+		candidates, _ = s.byName[string(cert.RawIssuer)]
+	}
+
+	for _, c := range candidates {
+		if err = cert.CheckSignatureFrom(s.certs[c]); err == nil {
+			cert.validSignature = true
+			parents = append(parents, c)
+		} else {
+			errCert = s.certs[c]
+		}
+	}
+
+	return
+}
+
+// Contains returns true if c is in s.
+func (s *CertPool) Contains(c *Certificate) bool {
+	if s == nil {
+		return false
+	}
+	_, ok := s.bySHA256[string(c.FingerprintSHA256)]
+	return ok
+}
+
+// Covers returns true if all certs in pool are in s.
+func (s *CertPool) Covers(pool *CertPool) bool {
+	if pool == nil {
+		return true
+	}
+	for _, c := range pool.certs {
+		if !s.Contains(c) {
+			return false
+		}
+	}
+	return true
+}
+
+// Certificates returns a list of parsed certificates in the pool.
+func (s *CertPool) Certificates() []*Certificate {
+	out := make([]*Certificate, 0, len(s.certs))
+	out = append(out, s.certs...)
+	return out
+}
+
+// Size returns the number of unique certificates in the CertPool.
+func (s *CertPool) Size() int {
+	if s == nil {
+		return 0
+	}
+	return len(s.certs)
+}
+
+// Sum returns the union of two certificate pools as a new certificate pool.
+func (s *CertPool) Sum(other *CertPool) (sum *CertPool) {
+	sum = NewCertPool()
+	if s != nil {
+		for _, c := range s.certs {
+			sum.AddCert(c)
+		}
+	}
+	if other != nil {
+		for _, c := range other.certs {
+			sum.AddCert(c)
+		}
+	}
+	return
+}
+
+// AddCert adds a certificate to a pool.
+func (s *CertPool) AddCert(cert *Certificate) {
+	if cert == nil {
+		panic("adding nil Certificate to CertPool")
+	}
+
+	// Check that the certificate isn't being added twice.
+	sha256fp := string(cert.FingerprintSHA256)
+	if _, ok := s.bySHA256[sha256fp]; ok {
+		return
+	}
+
+	n := len(s.certs)
+	s.certs = append(s.certs, cert)
+
+	if len(cert.SubjectKeyId) > 0 {
+		keyId := string(cert.SubjectKeyId)
+		s.bySubjectKeyId[keyId] = append(s.bySubjectKeyId[keyId], n)
+	}
+	name := string(cert.RawSubject)
+	s.byName[name] = append(s.byName[name], n)
+	s.bySHA256[sha256fp] = n
+}
+
+// AppendCertsFromPEM attempts to parse a series of PEM encoded certificates.
+// It appends any certificates found to s and reports whether any certificates
+// were successfully parsed.
+//
+// On many Linux systems, /etc/ssl/cert.pem will contain the system wide set
+// of root CAs in a format suitable for this function.
+func (s *CertPool) AppendCertsFromPEM(pemCerts []byte) (ok bool) {
+	for len(pemCerts) > 0 {
+		var block *pem.Block
+		block, pemCerts = pem.Decode(pemCerts)
+		if block == nil {
+			break
+		}
+		if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
+			continue
+		}
+
+		cert, err := ParseCertificate(block.Bytes)
+		if err != nil {
+			continue
+		}
+
+		s.AddCert(cert)
+		ok = true
+	}
+
+	return
+}
+
+// Subjects returns a list of the DER-encoded subjects of
+// all of the certificates in the pool.
+func (s *CertPool) Subjects() [][]byte {
+	res := make([][]byte, len(s.certs))
+	for i, c := range s.certs {
+		res[i] = c.RawSubject
+	}
+	return res
+}

+ 64 - 0
vendor/github.com/zmap/zcrypto/x509/certificate_type.go

@@ -0,0 +1,64 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import "encoding/json"
+
+// TODO: Automatically generate this file from a CSV
+
+// CertificateType represents whether a certificate is a root, intermediate, or
+// leaf.
+type CertificateType int
+
+// CertificateType constants. Values should not be considered significant aside
+// from CertificateTypeUnknown is the zero value.
+const (
+	CertificateTypeUnknown      CertificateType = 0
+	CertificateTypeLeaf         CertificateType = 1
+	CertificateTypeIntermediate CertificateType = 2
+	CertificateTypeRoot         CertificateType = 3
+)
+
+const (
+	certificateTypeStringLeaf         = "leaf"
+	certificateTypeStringIntermediate = "intermediate"
+	certificateTypeStringRoot         = "root"
+	certificateTypeStringUnknown      = "unknown"
+)
+
+// MarshalJSON implements the json.Marshaler interface. Any unknown integer
+// value is considered the same as CertificateTypeUnknown.
+func (t CertificateType) MarshalJSON() ([]byte, error) {
+	switch t {
+	case CertificateTypeLeaf:
+		return json.Marshal(certificateTypeStringLeaf)
+	case CertificateTypeIntermediate:
+		return json.Marshal(certificateTypeStringIntermediate)
+	case CertificateTypeRoot:
+		return json.Marshal(certificateTypeStringRoot)
+	default:
+		return json.Marshal(certificateTypeStringUnknown)
+	}
+}
+
+// UnmarshalJSON implements the json.Unmarshaler interface. Any unknown string
+// is considered the same CertificateTypeUnknown.
+func (t *CertificateType) UnmarshalJSON(b []byte) error {
+	var certificateTypeString string
+	if err := json.Unmarshal(b, &certificateTypeString); err != nil {
+		return err
+	}
+	switch certificateTypeString {
+	case certificateTypeStringLeaf:
+		*t = CertificateTypeLeaf
+	case certificateTypeStringIntermediate:
+		*t = CertificateTypeIntermediate
+	case certificateTypeStringRoot:
+		*t = CertificateTypeRoot
+	default:
+		*t = CertificateTypeUnknown
+	}
+	return nil
+}

+ 70 - 0
vendor/github.com/zmap/zcrypto/x509/chain.go

@@ -0,0 +1,70 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+	"bytes"
+	"strings"
+)
+
+// CertificateChain is a slice of certificates. The 0'th element is the leaf,
+// and the last element is a root. Successive elements have a child-parent
+// relationship.
+type CertificateChain []*Certificate
+
+// Range runs a function on each element of chain. It can modify each
+// certificate in place.
+func (chain CertificateChain) Range(f func(int, *Certificate)) {
+	for i, c := range chain {
+		f(i, c)
+	}
+}
+
+// SubjectAndKeyInChain returns true if the given SubjectAndKey is found in any
+// certificate in the chain.
+func (chain CertificateChain) SubjectAndKeyInChain(sk *SubjectAndKey) bool {
+	for _, cert := range chain {
+		if bytes.Equal(sk.RawSubject, cert.RawSubject) && bytes.Equal(sk.RawSubjectPublicKeyInfo, cert.RawSubjectPublicKeyInfo) {
+			return true
+		}
+	}
+	return false
+}
+
+// CertificateSubjectAndKeyInChain returns true if the SubjectAndKey from c is
+// found in any certificate in the chain.
+func (chain CertificateChain) CertificateSubjectAndKeyInChain(c *Certificate) bool {
+	for _, cert := range chain {
+		if bytes.Equal(c.RawSubject, cert.RawSubject) && bytes.Equal(c.RawSubjectPublicKeyInfo, cert.RawSubjectPublicKeyInfo) {
+			return true
+		}
+	}
+	return false
+}
+
+// CertificateInChain returns true if c is in the chain.
+func (chain CertificateChain) CertificateInChain(c *Certificate) bool {
+	for _, cert := range chain {
+		if bytes.Equal(c.Raw, cert.Raw) {
+			return true
+		}
+	}
+	return false
+}
+
+func (chain CertificateChain) AppendToFreshChain(c *Certificate) CertificateChain {
+	n := make([]*Certificate, len(chain)+1)
+	copy(n, chain)
+	n[len(chain)] = c
+	return n
+}
+
+func (chain CertificateChain) chainID() string {
+	var parts []string
+	for _, c := range chain {
+		parts = append(parts, string(c.FingerprintSHA256))
+	}
+	return strings.Join(parts, "")
+}

+ 168 - 0
vendor/github.com/zmap/zcrypto/x509/ct/serialization.go

@@ -0,0 +1,168 @@
+package ct
+
+// This file contains selectively chosen snippets of
+// github.com/google/certificate-transparency-go@ 5cfe585726ad9d990d4db524d6ce2567b13e2f80
+//
+// These snippets only perform deserialization for SCTs and are recreated here to prevent pulling in the whole of the ct
+// which contains yet another version of x509,asn1 and tls
+
+import (
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"io"
+)
+
+// Variable size structure prefix-header byte lengths
+const (
+	CertificateLengthBytes      = 3
+	PreCertificateLengthBytes   = 3
+	ExtensionsLengthBytes       = 2
+	CertificateChainLengthBytes = 3
+	SignatureLengthBytes        = 2
+)
+
+func writeUint(w io.Writer, value uint64, numBytes int) error {
+	buf := make([]uint8, numBytes)
+	for i := 0; i < numBytes; i++ {
+		buf[numBytes-i-1] = uint8(value & 0xff)
+		value >>= 8
+	}
+	if value != 0 {
+		return errors.New("numBytes was insufficiently large to represent value")
+	}
+	if _, err := w.Write(buf); err != nil {
+		return err
+	}
+	return nil
+}
+
+func writeVarBytes(w io.Writer, value []byte, numLenBytes int) error {
+	if err := writeUint(w, uint64(len(value)), numLenBytes); err != nil {
+		return err
+	}
+	if _, err := w.Write(value); err != nil {
+		return err
+	}
+	return nil
+}
+
+func readUint(r io.Reader, numBytes int) (uint64, error) {
+	var l uint64
+	for i := 0; i < numBytes; i++ {
+		l <<= 8
+		var t uint8
+		if err := binary.Read(r, binary.BigEndian, &t); err != nil {
+			return 0, err
+		}
+		l |= uint64(t)
+	}
+	return l, nil
+}
+
+// Reads a variable length array of bytes from |r|. |numLenBytes| specifies the
+// number of (BigEndian) prefix-bytes which contain the length of the actual
+// array data bytes that follow.
+// Allocates an array to hold the contents and returns a slice view into it if
+// the read was successful, or an error otherwise.
+func readVarBytes(r io.Reader, numLenBytes int) ([]byte, error) {
+	switch {
+	case numLenBytes > 8:
+		return nil, fmt.Errorf("numLenBytes too large (%d)", numLenBytes)
+	case numLenBytes == 0:
+		return nil, errors.New("numLenBytes should be > 0")
+	}
+	l, err := readUint(r, numLenBytes)
+	if err != nil {
+		return nil, err
+	}
+	data := make([]byte, l)
+	if n, err := io.ReadFull(r, data); err != nil {
+		if err == io.EOF || err == io.ErrUnexpectedEOF {
+			return nil, fmt.Errorf("short read: expected %d but got %d", l, n)
+		}
+		return nil, err
+	}
+	return data, nil
+}
+
+// UnmarshalDigitallySigned reconstructs a DigitallySigned structure from a Reader
+func UnmarshalDigitallySigned(r io.Reader) (*DigitallySigned, error) {
+	var h byte
+	if err := binary.Read(r, binary.BigEndian, &h); err != nil {
+		return nil, fmt.Errorf("failed to read HashAlgorithm: %v", err)
+	}
+
+	var s byte
+	if err := binary.Read(r, binary.BigEndian, &s); err != nil {
+		return nil, fmt.Errorf("failed to read SignatureAlgorithm: %v", err)
+	}
+
+	sig, err := readVarBytes(r, SignatureLengthBytes)
+	if err != nil {
+		return nil, fmt.Errorf("failed to read Signature bytes: %v", err)
+	}
+
+	return &DigitallySigned{
+		HashAlgorithm:      HashAlgorithm(h),
+		SignatureAlgorithm: SignatureAlgorithm(s),
+		Signature:          sig,
+	}, nil
+}
+
+func marshalDigitallySignedHere(ds DigitallySigned, here []byte) ([]byte, error) {
+	sigLen := len(ds.Signature)
+	dsOutLen := 2 + SignatureLengthBytes + sigLen
+	if here == nil {
+		here = make([]byte, dsOutLen)
+	}
+	if len(here) < dsOutLen {
+		return nil, ErrNotEnoughBuffer
+	}
+	here = here[0:dsOutLen]
+
+	here[0] = byte(ds.HashAlgorithm)
+	here[1] = byte(ds.SignatureAlgorithm)
+	binary.BigEndian.PutUint16(here[2:4], uint16(sigLen))
+	copy(here[4:], ds.Signature)
+
+	return here, nil
+}
+
+// MarshalDigitallySigned marshalls a DigitallySigned structure into a byte array
+func MarshalDigitallySigned(ds DigitallySigned) ([]byte, error) {
+	return marshalDigitallySignedHere(ds, nil)
+}
+
+func deserializeSCTV1(r io.Reader, sct *SignedCertificateTimestamp) error {
+	if err := binary.Read(r, binary.BigEndian, &sct.LogID); err != nil {
+		return err
+	}
+	if err := binary.Read(r, binary.BigEndian, &sct.Timestamp); err != nil {
+		return err
+	}
+	ext, err := readVarBytes(r, ExtensionsLengthBytes)
+	if err != nil {
+		return err
+	}
+	sct.Extensions = ext
+	ds, err := UnmarshalDigitallySigned(r)
+	if err != nil {
+		return err
+	}
+	sct.Signature = *ds
+	return nil
+}
+
+func DeserializeSCT(r io.Reader) (*SignedCertificateTimestamp, error) {
+	var sct SignedCertificateTimestamp
+	if err := binary.Read(r, binary.BigEndian, &sct.SCTVersion); err != nil {
+		return nil, err
+	}
+	switch sct.SCTVersion {
+	case V1:
+		return &sct, deserializeSCTV1(r, &sct)
+	default:
+		return nil, fmt.Errorf("unknown SCT version %d", sct.SCTVersion)
+	}
+}

+ 229 - 0
vendor/github.com/zmap/zcrypto/x509/ct/types.go

@@ -0,0 +1,229 @@
+package ct
+
+// This file contains selectively chosen snippets of
+// github.com/google/certificate-transparency-go@ 5cfe585726ad9d990d4db524d6ce2567b13e2f80
+//
+// These snippets only perform deserialization for SCTs and are recreated here to prevent pulling in the whole of the ct
+// which contains yet another version of x509,asn1 and tls
+
+import (
+	"bytes"
+	"crypto/sha256"
+	"encoding/base64"
+	"encoding/json"
+	"fmt"
+)
+
+// CTExtensions is a representation of the raw bytes of any CtExtension
+// structure (see section 3.2)
+type CTExtensions []byte
+
+// SHA256Hash represents the output from the SHA256 hash function.
+type SHA256Hash [sha256.Size]byte
+
+// FromBase64String populates the SHA256 struct with the contents of the base64 data passed in.
+func (s *SHA256Hash) FromBase64String(b64 string) error {
+	bs, err := base64.StdEncoding.DecodeString(b64)
+	if err != nil {
+		return fmt.Errorf("failed to unbase64 LogID: %v", err)
+	}
+	if len(bs) != sha256.Size {
+		return fmt.Errorf("invalid SHA256 length, expected 32 but got %d", len(bs))
+	}
+	copy(s[:], bs)
+	return nil
+}
+
+// Base64String returns the base64 representation of this SHA256Hash.
+func (s SHA256Hash) Base64String() string {
+	return base64.StdEncoding.EncodeToString(s[:])
+}
+
+// MarshalJSON implements the json.Marshaller interface for SHA256Hash.
+func (s SHA256Hash) MarshalJSON() ([]byte, error) {
+	return []byte(`"` + s.Base64String() + `"`), nil
+}
+
+// UnmarshalJSON implements the json.Unmarshaller interface.
+func (s *SHA256Hash) UnmarshalJSON(b []byte) error {
+	var content string
+	if err := json.Unmarshal(b, &content); err != nil {
+		return fmt.Errorf("failed to unmarshal SHA256Hash: %v", err)
+	}
+	return s.FromBase64String(content)
+}
+
+// HashAlgorithm from the DigitallySigned struct
+type HashAlgorithm byte
+
+// HashAlgorithm constants
+const (
+	None   HashAlgorithm = 0
+	MD5    HashAlgorithm = 1
+	SHA1   HashAlgorithm = 2
+	SHA224 HashAlgorithm = 3
+	SHA256 HashAlgorithm = 4
+	SHA384 HashAlgorithm = 5
+	SHA512 HashAlgorithm = 6
+)
+
+func (h HashAlgorithm) String() string {
+	switch h {
+	case None:
+		return "None"
+	case MD5:
+		return "MD5"
+	case SHA1:
+		return "SHA1"
+	case SHA224:
+		return "SHA224"
+	case SHA256:
+		return "SHA256"
+	case SHA384:
+		return "SHA384"
+	case SHA512:
+		return "SHA512"
+	default:
+		return fmt.Sprintf("UNKNOWN(%d)", h)
+	}
+}
+
+// SignatureAlgorithm from the the DigitallySigned struct
+type SignatureAlgorithm byte
+
+// SignatureAlgorithm constants
+const (
+	Anonymous SignatureAlgorithm = 0
+	RSA       SignatureAlgorithm = 1
+	DSA       SignatureAlgorithm = 2
+	ECDSA     SignatureAlgorithm = 3
+)
+
+func (s SignatureAlgorithm) String() string {
+	switch s {
+	case Anonymous:
+		return "Anonymous"
+	case RSA:
+		return "RSA"
+	case DSA:
+		return "DSA"
+	case ECDSA:
+		return "ECDSA"
+	default:
+		return fmt.Sprintf("UNKNOWN(%d)", s)
+	}
+}
+
+// DigitallySigned represents an RFC5246 DigitallySigned structure
+type DigitallySigned struct {
+	HashAlgorithm      HashAlgorithm
+	SignatureAlgorithm SignatureAlgorithm
+	Signature          []byte
+}
+
+// FromBase64String populates the DigitallySigned structure from the base64 data passed in.
+// Returns an error if the base64 data is invalid.
+func (d *DigitallySigned) FromBase64String(b64 string) error {
+	raw, err := base64.StdEncoding.DecodeString(b64)
+	if err != nil {
+		return fmt.Errorf("failed to unbase64 DigitallySigned: %v", err)
+	}
+	ds, err := UnmarshalDigitallySigned(bytes.NewReader(raw))
+	if err != nil {
+		return fmt.Errorf("failed to unmarshal DigitallySigned: %v", err)
+	}
+	*d = *ds
+	return nil
+}
+
+// Base64String returns the base64 representation of the DigitallySigned struct.
+func (d DigitallySigned) Base64String() (string, error) {
+	b, err := MarshalDigitallySigned(d)
+	if err != nil {
+		return "", err
+	}
+	return base64.StdEncoding.EncodeToString(b), nil
+}
+
+// MarshalJSON implements the json.Marshaller interface.
+func (d DigitallySigned) MarshalJSON() ([]byte, error) {
+	b64, err := d.Base64String()
+	if err != nil {
+		return []byte{}, err
+	}
+	return []byte(`"` + b64 + `"`), nil
+}
+
+// UnmarshalJSON implements the json.Unmarshaler interface.
+func (d *DigitallySigned) UnmarshalJSON(b []byte) error {
+	var content string
+	if err := json.Unmarshal(b, &content); err != nil {
+		return fmt.Errorf("failed to unmarshal DigitallySigned: %v", err)
+	}
+	return d.FromBase64String(content)
+}
+
+// Version represents the Version enum from section 3.2 of the RFC:
+// enum { v1(0), (255) } Version;
+type Version uint8
+
+func (v Version) String() string {
+	switch v {
+	case V1:
+		return "V1"
+	default:
+		return fmt.Sprintf("UnknownVersion(%d)", v)
+	}
+}
+
+// CT Version constants, see section 3.2 of the RFC.
+const (
+	V1 Version = 0
+)
+
+// SignedCertificateTimestamp represents the structure returned by the
+// add-chain and add-pre-chain methods after base64 decoding. (see RFC sections
+// 3.2 ,4.1 and 4.2)
+type SignedCertificateTimestamp struct {
+	SCTVersion Version    `json:"version"` // The version of the protocol to which the SCT conforms
+	LogID      SHA256Hash `json:"log_id"`  // the SHA-256 hash of the log's public key, calculated over
+	// the DER encoding of the key represented as SubjectPublicKeyInfo.
+	Timestamp  uint64          `json:"timestamp,omitempty"`  // Timestamp (in ms since unix epoc) at which the SCT was issued. NOTE: When this is serialized, the output is in seconds, not milliseconds.
+	Extensions CTExtensions    `json:"extensions,omitempty"` // For future extensions to the protocol
+	Signature  DigitallySigned `json:"signature"`            // The Log's signature for this SCT
+}
+
+// Copied from ct/types.go 2018/06/15 to deal with BQ timestamp overflow; output
+// is expected to be seconds, not milliseconds.
+type auxSignedCertificateTimestamp SignedCertificateTimestamp
+
+const kMaxTimestamp = 253402300799
+
+// MarshalJSON implements the JSON.Marshaller interface.
+func (sct *SignedCertificateTimestamp) MarshalJSON() ([]byte, error) {
+	aux := auxSignedCertificateTimestamp(*sct)
+	aux.Timestamp = sct.Timestamp / 1000 // convert ms to sec
+	if aux.Timestamp > kMaxTimestamp {
+		aux.Timestamp = 0
+	}
+	return json.Marshal(&aux)
+}
+
+type sctError int
+
+// Preallocate errors for performance
+var (
+	ErrInvalidVersion  error = sctError(1)
+	ErrNotEnoughBuffer error = sctError(2)
+)
+
+func (e sctError) Error() string {
+	switch e {
+	case ErrInvalidVersion:
+		return "invalid SCT version detected"
+	case ErrNotEnoughBuffer:
+		return "provided buffer was too small"
+	default:
+		return "unknown error"
+	}
+}

+ 65 - 0
vendor/github.com/zmap/zcrypto/x509/example.json

@@ -0,0 +1,65 @@
+{
+	"domain": null,
+	"certificate": {
+		"version": 3,
+		"serial_number": 123893,
+		"signature_algorithm": {
+			"id": 123,
+			"name": "SHA1"
+		},
+		"issuer": {
+			"common_name": "Starfield CA",
+			"attributes": [
+				{ "organization": "Startfield" },
+				{ "location": "Scottsdale" },
+				{ "state": "Arizona" },
+				{ "country": "US" }
+			]
+		},
+		"validity": {
+			"start": "20140102",
+			"end": "20150102",
+            "length" :8760    
+		},
+		"subject": {
+			"common_name": "*.tools.ieft.org",
+			"attributes": [
+				{ "organization_unit": "Domain Control Validated" }
+			]
+		},
+		"subject_key_info": {
+			"algorithm": {
+				"id": 234,
+				"name": "RSA"
+			},
+			"key": {
+				"modulus": "base64encodedmodulus",
+				"exponent": 65537
+			}
+		},
+		"extensions": [
+			{
+				"id": 345,
+				"name": "Certificate Basic Constraints",
+				"is_ca": false
+			},
+			{
+				"id": 456,
+				"name": "Alt Names",
+				"alt_names": [
+					"*.tools.ietf.org",
+					"tools.ietf.org"
+				]
+			}
+		]
+	},
+	"signature_algorithm": {
+		"id": 123,
+		"name": "SHA1"
+	},
+	"signature": {
+		"value": "base64encodedsignature",
+		"is_valid": true,
+		"matches_domain": null
+	}
+}

+ 679 - 0
vendor/github.com/zmap/zcrypto/x509/extended_key_usage.go

@@ -0,0 +1,679 @@
+// Created by extended_key_usage_gen; DO NOT EDIT
+
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+	"encoding/asn1"
+)
+
+const (
+	OID_EKU_APPLE_CODE_SIGNING                 = "1.2.840.113635.100.4.1"
+	OID_EKU_APPLE_CODE_SIGNING_DEVELOPMENT     = "1.2.840.113635.100.4.1.1"
+	OID_EKU_APPLE_SOFTWARE_UPDATE_SIGNING      = "1.2.840.113635.100.4.1.2"
+	OID_EKU_APPLE_CODE_SIGNING_THIRD_PARTY     = "1.2.840.113635.100.4.1.3"
+	OID_EKU_APPLE_RESOURCE_SIGNING             = "1.2.840.113635.100.4.1.4"
+	OID_EKU_APPLE_ICHAT_SIGNING                = "1.2.840.113635.100.4.2"
+	OID_EKU_APPLE_ICHAT_ENCRYPTION             = "1.2.840.113635.100.4.3"
+	OID_EKU_APPLE_SYSTEM_IDENTITY              = "1.2.840.113635.100.4.4"
+	OID_EKU_APPLE_CRYPTO_ENV                   = "1.2.840.113635.100.4.5"
+	OID_EKU_APPLE_CRYPTO_PRODUCTION_ENV        = "1.2.840.113635.100.4.5.1"
+	OID_EKU_APPLE_CRYPTO_MAINTENANCE_ENV       = "1.2.840.113635.100.4.5.2"
+	OID_EKU_APPLE_CRYPTO_TEST_ENV              = "1.2.840.113635.100.4.5.3"
+	OID_EKU_APPLE_CRYPTO_DEVELOPMENT_ENV       = "1.2.840.113635.100.4.5.4"
+	OID_EKU_APPLE_CRYPTO_QOS                   = "1.2.840.113635.100.4.6"
+	OID_EKU_APPLE_CRYPTO_TIER0_QOS             = "1.2.840.113635.100.4.6.1"
+	OID_EKU_APPLE_CRYPTO_TIER1_QOS             = "1.2.840.113635.100.4.6.2"
+	OID_EKU_APPLE_CRYPTO_TIER2_QOS             = "1.2.840.113635.100.4.6.3"
+	OID_EKU_APPLE_CRYPTO_TIER3_QOS             = "1.2.840.113635.100.4.6.4"
+	OID_EKU_MICROSOFT_CERT_TRUST_LIST_SIGNING  = "1.3.6.1.4.1.311.10.3.1"
+	OID_EKU_MICROSOFT_QUALIFIED_SUBORDINATE    = "1.3.6.1.4.1.311.10.3.10"
+	OID_EKU_MICROSOFT_KEY_RECOVERY_3           = "1.3.6.1.4.1.311.10.3.11"
+	OID_EKU_MICROSOFT_DOCUMENT_SIGNING         = "1.3.6.1.4.1.311.10.3.12"
+	OID_EKU_MICROSOFT_LIFETIME_SIGNING         = "1.3.6.1.4.1.311.10.3.13"
+	OID_EKU_MICROSOFT_MOBILE_DEVICE_SOFTWARE   = "1.3.6.1.4.1.311.10.3.14"
+	OID_EKU_MICROSOFT_SMART_DISPLAY            = "1.3.6.1.4.1.311.10.3.15"
+	OID_EKU_MICROSOFT_CSP_SIGNATURE            = "1.3.6.1.4.1.311.10.3.16"
+	OID_EKU_MICROSOFT_TIMESTAMP_SIGNING        = "1.3.6.1.4.1.311.10.3.2"
+	OID_EKU_MICROSOFT_SERVER_GATED_CRYPTO      = "1.3.6.1.4.1.311.10.3.3"
+	OID_EKU_MICROSOFT_SGC_SERIALIZED           = "1.3.6.1.4.1.311.10.3.3.1"
+	OID_EKU_MICROSOFT_ENCRYPTED_FILE_SYSTEM    = "1.3.6.1.4.1.311.10.3.4"
+	OID_EKU_MICROSOFT_EFS_RECOVERY             = "1.3.6.1.4.1.311.10.3.4.1"
+	OID_EKU_MICROSOFT_WHQL_CRYPTO              = "1.3.6.1.4.1.311.10.3.5"
+	OID_EKU_MICROSOFT_NT5_CRYPTO               = "1.3.6.1.4.1.311.10.3.6"
+	OID_EKU_MICROSOFT_OEM_WHQL_CRYPTO          = "1.3.6.1.4.1.311.10.3.7"
+	OID_EKU_MICROSOFT_EMBEDDED_NT_CRYPTO       = "1.3.6.1.4.1.311.10.3.8"
+	OID_EKU_MICROSOFT_ROOT_LIST_SIGNER         = "1.3.6.1.4.1.311.10.3.9"
+	OID_EKU_MICROSOFT_DRM                      = "1.3.6.1.4.1.311.10.5.1"
+	OID_EKU_MICROSOFT_DRM_INDIVIDUALIZATION    = "1.3.6.1.4.1.311.10.5.2"
+	OID_EKU_MICROSOFT_LICENSES                 = "1.3.6.1.4.1.311.10.5.3"
+	OID_EKU_MICROSOFT_LICENSE_SERVER           = "1.3.6.1.4.1.311.10.5.4"
+	OID_EKU_MICROSOFT_ENROLLMENT_AGENT         = "1.3.6.1.4.1.311.20.2.1"
+	OID_EKU_MICROSOFT_SMARTCARD_LOGON          = "1.3.6.1.4.1.311.20.2.2"
+	OID_EKU_MICROSOFT_CA_EXCHANGE              = "1.3.6.1.4.1.311.21.5"
+	OID_EKU_MICROSOFT_KEY_RECOVERY_21          = "1.3.6.1.4.1.311.21.6"
+	OID_EKU_MICROSOFT_SYSTEM_HEALTH            = "1.3.6.1.4.1.311.47.1.1"
+	OID_EKU_MICROSOFT_SYSTEM_HEALTH_LOOPHOLE   = "1.3.6.1.4.1.311.47.1.3"
+	OID_EKU_MICROSOFT_KERNEL_MODE_CODE_SIGNING = "1.3.6.1.4.1.311.61.1.1"
+	OID_EKU_SERVER_AUTH                        = "1.3.6.1.5.5.7.3.1"
+	OID_EKU_DVCS                               = "1.3.6.1.5.5.7.3.10"
+	OID_EKU_SBGP_CERT_AA_SERVICE_AUTH          = "1.3.6.1.5.5.7.3.11"
+	OID_EKU_EAP_OVER_PPP                       = "1.3.6.1.5.5.7.3.13"
+	OID_EKU_EAP_OVER_LAN                       = "1.3.6.1.5.5.7.3.14"
+	OID_EKU_CLIENT_AUTH                        = "1.3.6.1.5.5.7.3.2"
+	OID_EKU_CODE_SIGNING                       = "1.3.6.1.5.5.7.3.3"
+	OID_EKU_EMAIL_PROTECTION                   = "1.3.6.1.5.5.7.3.4"
+	OID_EKU_IPSEC_END_SYSTEM                   = "1.3.6.1.5.5.7.3.5"
+	OID_EKU_IPSEC_TUNNEL                       = "1.3.6.1.5.5.7.3.6"
+	OID_EKU_IPSEC_USER                         = "1.3.6.1.5.5.7.3.7"
+	OID_EKU_TIME_STAMPING                      = "1.3.6.1.5.5.7.3.8"
+	OID_EKU_OCSP_SIGNING                       = "1.3.6.1.5.5.7.3.9"
+	OID_EKU_IPSEC_INTERMEDIATE_SYSTEM_USAGE    = "1.3.6.1.5.5.8.2.2"
+	OID_EKU_NETSCAPE_SERVER_GATED_CRYPTO       = "2.16.840.1.113730.4.1"
+	OID_EKU_ANY                                = "2.5.29.37.0"
+)
+
+var (
+	oidExtKeyUsageAppleCodeSigning               = asn1.ObjectIdentifier{1, 2, 840, 113635, 100, 4, 1}
+	oidExtKeyUsageAppleCodeSigningDevelopment    = asn1.ObjectIdentifier{1, 2, 840, 113635, 100, 4, 1, 1}
+	oidExtKeyUsageAppleSoftwareUpdateSigning     = asn1.ObjectIdentifier{1, 2, 840, 113635, 100, 4, 1, 2}
+	oidExtKeyUsageAppleCodeSigningThirdParty     = asn1.ObjectIdentifier{1, 2, 840, 113635, 100, 4, 1, 3}
+	oidExtKeyUsageAppleResourceSigning           = asn1.ObjectIdentifier{1, 2, 840, 113635, 100, 4, 1, 4}
+	oidExtKeyUsageAppleIchatSigning              = asn1.ObjectIdentifier{1, 2, 840, 113635, 100, 4, 2}
+	oidExtKeyUsageAppleIchatEncryption           = asn1.ObjectIdentifier{1, 2, 840, 113635, 100, 4, 3}
+	oidExtKeyUsageAppleSystemIdentity            = asn1.ObjectIdentifier{1, 2, 840, 113635, 100, 4, 4}
+	oidExtKeyUsageAppleCryptoEnv                 = asn1.ObjectIdentifier{1, 2, 840, 113635, 100, 4, 5}
+	oidExtKeyUsageAppleCryptoProductionEnv       = asn1.ObjectIdentifier{1, 2, 840, 113635, 100, 4, 5, 1}
+	oidExtKeyUsageAppleCryptoMaintenanceEnv      = asn1.ObjectIdentifier{1, 2, 840, 113635, 100, 4, 5, 2}
+	oidExtKeyUsageAppleCryptoTestEnv             = asn1.ObjectIdentifier{1, 2, 840, 113635, 100, 4, 5, 3}
+	oidExtKeyUsageAppleCryptoDevelopmentEnv      = asn1.ObjectIdentifier{1, 2, 840, 113635, 100, 4, 5, 4}
+	oidExtKeyUsageAppleCryptoQos                 = asn1.ObjectIdentifier{1, 2, 840, 113635, 100, 4, 6}
+	oidExtKeyUsageAppleCryptoTier0Qos            = asn1.ObjectIdentifier{1, 2, 840, 113635, 100, 4, 6, 1}
+	oidExtKeyUsageAppleCryptoTier1Qos            = asn1.ObjectIdentifier{1, 2, 840, 113635, 100, 4, 6, 2}
+	oidExtKeyUsageAppleCryptoTier2Qos            = asn1.ObjectIdentifier{1, 2, 840, 113635, 100, 4, 6, 3}
+	oidExtKeyUsageAppleCryptoTier3Qos            = asn1.ObjectIdentifier{1, 2, 840, 113635, 100, 4, 6, 4}
+	oidExtKeyUsageMicrosoftCertTrustListSigning  = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 1}
+	oidExtKeyUsageMicrosoftQualifiedSubordinate  = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 10}
+	oidExtKeyUsageMicrosoftKeyRecovery3          = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 11}
+	oidExtKeyUsageMicrosoftDocumentSigning       = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 12}
+	oidExtKeyUsageMicrosoftLifetimeSigning       = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 13}
+	oidExtKeyUsageMicrosoftMobileDeviceSoftware  = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 14}
+	oidExtKeyUsageMicrosoftSmartDisplay          = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 15}
+	oidExtKeyUsageMicrosoftCspSignature          = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 16}
+	oidExtKeyUsageMicrosoftTimestampSigning      = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 2}
+	oidExtKeyUsageMicrosoftServerGatedCrypto     = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 3}
+	oidExtKeyUsageMicrosoftSgcSerialized         = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 3, 1}
+	oidExtKeyUsageMicrosoftEncryptedFileSystem   = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 4}
+	oidExtKeyUsageMicrosoftEfsRecovery           = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 4, 1}
+	oidExtKeyUsageMicrosoftWhqlCrypto            = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 5}
+	oidExtKeyUsageMicrosoftNt5Crypto             = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 6}
+	oidExtKeyUsageMicrosoftOemWhqlCrypto         = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 7}
+	oidExtKeyUsageMicrosoftEmbeddedNtCrypto      = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 8}
+	oidExtKeyUsageMicrosoftRootListSigner        = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 9}
+	oidExtKeyUsageMicrosoftDrm                   = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 5, 1}
+	oidExtKeyUsageMicrosoftDrmIndividualization  = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 5, 2}
+	oidExtKeyUsageMicrosoftLicenses              = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 5, 3}
+	oidExtKeyUsageMicrosoftLicenseServer         = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 5, 4}
+	oidExtKeyUsageMicrosoftEnrollmentAgent       = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 20, 2, 1}
+	oidExtKeyUsageMicrosoftSmartcardLogon        = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 20, 2, 2}
+	oidExtKeyUsageMicrosoftCaExchange            = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 21, 5}
+	oidExtKeyUsageMicrosoftKeyRecovery21         = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 21, 6}
+	oidExtKeyUsageMicrosoftSystemHealth          = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 47, 1, 1}
+	oidExtKeyUsageMicrosoftSystemHealthLoophole  = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 47, 1, 3}
+	oidExtKeyUsageMicrosoftKernelModeCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 61, 1, 1}
+	oidExtKeyUsageServerAuth                     = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 1}
+	oidExtKeyUsageDvcs                           = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 10}
+	oidExtKeyUsageSbgpCertAaServiceAuth          = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 11}
+	oidExtKeyUsageEapOverPpp                     = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 13}
+	oidExtKeyUsageEapOverLan                     = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 14}
+	oidExtKeyUsageClientAuth                     = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 2}
+	oidExtKeyUsageCodeSigning                    = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 3}
+	oidExtKeyUsageEmailProtection                = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 4}
+	oidExtKeyUsageIpsecEndSystem                 = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 5}
+	oidExtKeyUsageIpsecTunnel                    = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 6}
+	oidExtKeyUsageIpsecUser                      = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 7}
+	oidExtKeyUsageTimeStamping                   = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 8}
+	oidExtKeyUsageOcspSigning                    = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 9}
+	oidExtKeyUsageIpsecIntermediateSystemUsage   = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 8, 2, 2}
+	oidExtKeyUsageNetscapeServerGatedCrypto      = asn1.ObjectIdentifier{2, 16, 840, 1, 113730, 4, 1}
+	oidExtKeyUsageAny                            = asn1.ObjectIdentifier{2, 5, 29, 37, 0}
+)
+
+const (
+	ExtKeyUsageAppleCodeSigning ExtKeyUsage = iota
+	ExtKeyUsageAppleCodeSigningDevelopment
+	ExtKeyUsageAppleSoftwareUpdateSigning
+	ExtKeyUsageAppleCodeSigningThirdParty
+	ExtKeyUsageAppleResourceSigning
+	ExtKeyUsageAppleIchatSigning
+	ExtKeyUsageAppleIchatEncryption
+	ExtKeyUsageAppleSystemIdentity
+	ExtKeyUsageAppleCryptoEnv
+	ExtKeyUsageAppleCryptoProductionEnv
+	ExtKeyUsageAppleCryptoMaintenanceEnv
+	ExtKeyUsageAppleCryptoTestEnv
+	ExtKeyUsageAppleCryptoDevelopmentEnv
+	ExtKeyUsageAppleCryptoQos
+	ExtKeyUsageAppleCryptoTier0Qos
+	ExtKeyUsageAppleCryptoTier1Qos
+	ExtKeyUsageAppleCryptoTier2Qos
+	ExtKeyUsageAppleCryptoTier3Qos
+	ExtKeyUsageMicrosoftCertTrustListSigning
+	ExtKeyUsageMicrosoftQualifiedSubordinate
+	ExtKeyUsageMicrosoftKeyRecovery3
+	ExtKeyUsageMicrosoftDocumentSigning
+	ExtKeyUsageMicrosoftLifetimeSigning
+	ExtKeyUsageMicrosoftMobileDeviceSoftware
+	ExtKeyUsageMicrosoftSmartDisplay
+	ExtKeyUsageMicrosoftCspSignature
+	ExtKeyUsageMicrosoftTimestampSigning
+	ExtKeyUsageMicrosoftServerGatedCrypto
+	ExtKeyUsageMicrosoftSgcSerialized
+	ExtKeyUsageMicrosoftEncryptedFileSystem
+	ExtKeyUsageMicrosoftEfsRecovery
+	ExtKeyUsageMicrosoftWhqlCrypto
+	ExtKeyUsageMicrosoftNt5Crypto
+	ExtKeyUsageMicrosoftOemWhqlCrypto
+	ExtKeyUsageMicrosoftEmbeddedNtCrypto
+	ExtKeyUsageMicrosoftRootListSigner
+	ExtKeyUsageMicrosoftDrm
+	ExtKeyUsageMicrosoftDrmIndividualization
+	ExtKeyUsageMicrosoftLicenses
+	ExtKeyUsageMicrosoftLicenseServer
+	ExtKeyUsageMicrosoftEnrollmentAgent
+	ExtKeyUsageMicrosoftSmartcardLogon
+	ExtKeyUsageMicrosoftCaExchange
+	ExtKeyUsageMicrosoftKeyRecovery21
+	ExtKeyUsageMicrosoftSystemHealth
+	ExtKeyUsageMicrosoftSystemHealthLoophole
+	ExtKeyUsageMicrosoftKernelModeCodeSigning
+	ExtKeyUsageServerAuth
+	ExtKeyUsageDvcs
+	ExtKeyUsageSbgpCertAaServiceAuth
+	ExtKeyUsageEapOverPpp
+	ExtKeyUsageEapOverLan
+	ExtKeyUsageClientAuth
+	ExtKeyUsageCodeSigning
+	ExtKeyUsageEmailProtection
+	ExtKeyUsageIpsecEndSystem
+	ExtKeyUsageIpsecTunnel
+	ExtKeyUsageIpsecUser
+	ExtKeyUsageTimeStamping
+	ExtKeyUsageOcspSigning
+	ExtKeyUsageIpsecIntermediateSystemUsage
+	ExtKeyUsageNetscapeServerGatedCrypto
+	ExtKeyUsageAny
+)
+
+type auxExtendedKeyUsage struct {
+	AppleCodeSigning               bool     `json:"apple_code_signing,omitempty" oid:"1.2.840.113635.100.4.1"`
+	AppleCodeSigningDevelopment    bool     `json:"apple_code_signing_development,omitempty" oid:"1.2.840.113635.100.4.1.1"`
+	AppleSoftwareUpdateSigning     bool     `json:"apple_software_update_signing,omitempty" oid:"1.2.840.113635.100.4.1.2"`
+	AppleCodeSigningThirdParty     bool     `json:"apple_code_signing_third_party,omitempty" oid:"1.2.840.113635.100.4.1.3"`
+	AppleResourceSigning           bool     `json:"apple_resource_signing,omitempty" oid:"1.2.840.113635.100.4.1.4"`
+	AppleIchatSigning              bool     `json:"apple_ichat_signing,omitempty" oid:"1.2.840.113635.100.4.2"`
+	AppleIchatEncryption           bool     `json:"apple_ichat_encryption,omitempty" oid:"1.2.840.113635.100.4.3"`
+	AppleSystemIdentity            bool     `json:"apple_system_identity,omitempty" oid:"1.2.840.113635.100.4.4"`
+	AppleCryptoEnv                 bool     `json:"apple_crypto_env,omitempty" oid:"1.2.840.113635.100.4.5"`
+	AppleCryptoProductionEnv       bool     `json:"apple_crypto_production_env,omitempty" oid:"1.2.840.113635.100.4.5.1"`
+	AppleCryptoMaintenanceEnv      bool     `json:"apple_crypto_maintenance_env,omitempty" oid:"1.2.840.113635.100.4.5.2"`
+	AppleCryptoTestEnv             bool     `json:"apple_crypto_test_env,omitempty" oid:"1.2.840.113635.100.4.5.3"`
+	AppleCryptoDevelopmentEnv      bool     `json:"apple_crypto_development_env,omitempty" oid:"1.2.840.113635.100.4.5.4"`
+	AppleCryptoQos                 bool     `json:"apple_crypto_qos,omitempty" oid:"1.2.840.113635.100.4.6"`
+	AppleCryptoTier0Qos            bool     `json:"apple_crypto_tier0_qos,omitempty" oid:"1.2.840.113635.100.4.6.1"`
+	AppleCryptoTier1Qos            bool     `json:"apple_crypto_tier1_qos,omitempty" oid:"1.2.840.113635.100.4.6.2"`
+	AppleCryptoTier2Qos            bool     `json:"apple_crypto_tier2_qos,omitempty" oid:"1.2.840.113635.100.4.6.3"`
+	AppleCryptoTier3Qos            bool     `json:"apple_crypto_tier3_qos,omitempty" oid:"1.2.840.113635.100.4.6.4"`
+	MicrosoftCertTrustListSigning  bool     `json:"microsoft_cert_trust_list_signing,omitempty" oid:"1.3.6.1.4.1.311.10.3.1"`
+	MicrosoftQualifiedSubordinate  bool     `json:"microsoft_qualified_subordinate,omitempty" oid:"1.3.6.1.4.1.311.10.3.10"`
+	MicrosoftKeyRecovery3          bool     `json:"microsoft_key_recovery_3,omitempty" oid:"1.3.6.1.4.1.311.10.3.11"`
+	MicrosoftDocumentSigning       bool     `json:"microsoft_document_signing,omitempty" oid:"1.3.6.1.4.1.311.10.3.12"`
+	MicrosoftLifetimeSigning       bool     `json:"microsoft_lifetime_signing,omitempty" oid:"1.3.6.1.4.1.311.10.3.13"`
+	MicrosoftMobileDeviceSoftware  bool     `json:"microsoft_mobile_device_software,omitempty" oid:"1.3.6.1.4.1.311.10.3.14"`
+	MicrosoftSmartDisplay          bool     `json:"microsoft_smart_display,omitempty" oid:"1.3.6.1.4.1.311.10.3.15"`
+	MicrosoftCspSignature          bool     `json:"microsoft_csp_signature,omitempty" oid:"1.3.6.1.4.1.311.10.3.16"`
+	MicrosoftTimestampSigning      bool     `json:"microsoft_timestamp_signing,omitempty" oid:"1.3.6.1.4.1.311.10.3.2"`
+	MicrosoftServerGatedCrypto     bool     `json:"microsoft_server_gated_crypto,omitempty" oid:"1.3.6.1.4.1.311.10.3.3"`
+	MicrosoftSgcSerialized         bool     `json:"microsoft_sgc_serialized,omitempty" oid:"1.3.6.1.4.1.311.10.3.3.1"`
+	MicrosoftEncryptedFileSystem   bool     `json:"microsoft_encrypted_file_system,omitempty" oid:"1.3.6.1.4.1.311.10.3.4"`
+	MicrosoftEfsRecovery           bool     `json:"microsoft_efs_recovery,omitempty" oid:"1.3.6.1.4.1.311.10.3.4.1"`
+	MicrosoftWhqlCrypto            bool     `json:"microsoft_whql_crypto,omitempty" oid:"1.3.6.1.4.1.311.10.3.5"`
+	MicrosoftNt5Crypto             bool     `json:"microsoft_nt5_crypto,omitempty" oid:"1.3.6.1.4.1.311.10.3.6"`
+	MicrosoftOemWhqlCrypto         bool     `json:"microsoft_oem_whql_crypto,omitempty" oid:"1.3.6.1.4.1.311.10.3.7"`
+	MicrosoftEmbeddedNtCrypto      bool     `json:"microsoft_embedded_nt_crypto,omitempty" oid:"1.3.6.1.4.1.311.10.3.8"`
+	MicrosoftRootListSigner        bool     `json:"microsoft_root_list_signer,omitempty" oid:"1.3.6.1.4.1.311.10.3.9"`
+	MicrosoftDrm                   bool     `json:"microsoft_drm,omitempty" oid:"1.3.6.1.4.1.311.10.5.1"`
+	MicrosoftDrmIndividualization  bool     `json:"microsoft_drm_individualization,omitempty" oid:"1.3.6.1.4.1.311.10.5.2"`
+	MicrosoftLicenses              bool     `json:"microsoft_licenses,omitempty" oid:"1.3.6.1.4.1.311.10.5.3"`
+	MicrosoftLicenseServer         bool     `json:"microsoft_license_server,omitempty" oid:"1.3.6.1.4.1.311.10.5.4"`
+	MicrosoftEnrollmentAgent       bool     `json:"microsoft_enrollment_agent,omitempty" oid:"1.3.6.1.4.1.311.20.2.1"`
+	MicrosoftSmartcardLogon        bool     `json:"microsoft_smartcard_logon,omitempty" oid:"1.3.6.1.4.1.311.20.2.2"`
+	MicrosoftCaExchange            bool     `json:"microsoft_ca_exchange,omitempty" oid:"1.3.6.1.4.1.311.21.5"`
+	MicrosoftKeyRecovery21         bool     `json:"microsoft_key_recovery_21,omitempty" oid:"1.3.6.1.4.1.311.21.6"`
+	MicrosoftSystemHealth          bool     `json:"microsoft_system_health,omitempty" oid:"1.3.6.1.4.1.311.47.1.1"`
+	MicrosoftSystemHealthLoophole  bool     `json:"microsoft_system_health_loophole,omitempty" oid:"1.3.6.1.4.1.311.47.1.3"`
+	MicrosoftKernelModeCodeSigning bool     `json:"microsoft_kernel_mode_code_signing,omitempty" oid:"1.3.6.1.4.1.311.61.1.1"`
+	ServerAuth                     bool     `json:"server_auth,omitempty" oid:"1.3.6.1.5.5.7.3.1"`
+	Dvcs                           bool     `json:"dvcs,omitempty" oid:"1.3.6.1.5.5.7.3.10"`
+	SbgpCertAaServiceAuth          bool     `json:"sbgp_cert_aa_service_auth,omitempty" oid:"1.3.6.1.5.5.7.3.11"`
+	EapOverPpp                     bool     `json:"eap_over_ppp,omitempty" oid:"1.3.6.1.5.5.7.3.13"`
+	EapOverLan                     bool     `json:"eap_over_lan,omitempty" oid:"1.3.6.1.5.5.7.3.14"`
+	ClientAuth                     bool     `json:"client_auth,omitempty" oid:"1.3.6.1.5.5.7.3.2"`
+	CodeSigning                    bool     `json:"code_signing,omitempty" oid:"1.3.6.1.5.5.7.3.3"`
+	EmailProtection                bool     `json:"email_protection,omitempty" oid:"1.3.6.1.5.5.7.3.4"`
+	IpsecEndSystem                 bool     `json:"ipsec_end_system,omitempty" oid:"1.3.6.1.5.5.7.3.5"`
+	IpsecTunnel                    bool     `json:"ipsec_tunnel,omitempty" oid:"1.3.6.1.5.5.7.3.6"`
+	IpsecUser                      bool     `json:"ipsec_user,omitempty" oid:"1.3.6.1.5.5.7.3.7"`
+	TimeStamping                   bool     `json:"time_stamping,omitempty" oid:"1.3.6.1.5.5.7.3.8"`
+	OcspSigning                    bool     `json:"ocsp_signing,omitempty" oid:"1.3.6.1.5.5.7.3.9"`
+	IpsecIntermediateSystemUsage   bool     `json:"ipsec_intermediate_system_usage,omitempty" oid:"1.3.6.1.5.5.8.2.2"`
+	NetscapeServerGatedCrypto      bool     `json:"netscape_server_gated_crypto,omitempty" oid:"2.16.840.1.113730.4.1"`
+	Any                            bool     `json:"any,omitempty" oid:"2.5.29.37.0"`
+	Unknown                        []string `json:"unknown,omitempty"`
+}
+
+func (aux *auxExtendedKeyUsage) populateFromASN1(oid asn1.ObjectIdentifier) {
+	s := oid.String()
+	switch s {
+	case OID_EKU_APPLE_CODE_SIGNING:
+		aux.AppleCodeSigning = true
+	case OID_EKU_APPLE_CODE_SIGNING_DEVELOPMENT:
+		aux.AppleCodeSigningDevelopment = true
+	case OID_EKU_APPLE_SOFTWARE_UPDATE_SIGNING:
+		aux.AppleSoftwareUpdateSigning = true
+	case OID_EKU_APPLE_CODE_SIGNING_THIRD_PARTY:
+		aux.AppleCodeSigningThirdParty = true
+	case OID_EKU_APPLE_RESOURCE_SIGNING:
+		aux.AppleResourceSigning = true
+	case OID_EKU_APPLE_ICHAT_SIGNING:
+		aux.AppleIchatSigning = true
+	case OID_EKU_APPLE_ICHAT_ENCRYPTION:
+		aux.AppleIchatEncryption = true
+	case OID_EKU_APPLE_SYSTEM_IDENTITY:
+		aux.AppleSystemIdentity = true
+	case OID_EKU_APPLE_CRYPTO_ENV:
+		aux.AppleCryptoEnv = true
+	case OID_EKU_APPLE_CRYPTO_PRODUCTION_ENV:
+		aux.AppleCryptoProductionEnv = true
+	case OID_EKU_APPLE_CRYPTO_MAINTENANCE_ENV:
+		aux.AppleCryptoMaintenanceEnv = true
+	case OID_EKU_APPLE_CRYPTO_TEST_ENV:
+		aux.AppleCryptoTestEnv = true
+	case OID_EKU_APPLE_CRYPTO_DEVELOPMENT_ENV:
+		aux.AppleCryptoDevelopmentEnv = true
+	case OID_EKU_APPLE_CRYPTO_QOS:
+		aux.AppleCryptoQos = true
+	case OID_EKU_APPLE_CRYPTO_TIER0_QOS:
+		aux.AppleCryptoTier0Qos = true
+	case OID_EKU_APPLE_CRYPTO_TIER1_QOS:
+		aux.AppleCryptoTier1Qos = true
+	case OID_EKU_APPLE_CRYPTO_TIER2_QOS:
+		aux.AppleCryptoTier2Qos = true
+	case OID_EKU_APPLE_CRYPTO_TIER3_QOS:
+		aux.AppleCryptoTier3Qos = true
+	case OID_EKU_MICROSOFT_CERT_TRUST_LIST_SIGNING:
+		aux.MicrosoftCertTrustListSigning = true
+	case OID_EKU_MICROSOFT_QUALIFIED_SUBORDINATE:
+		aux.MicrosoftQualifiedSubordinate = true
+	case OID_EKU_MICROSOFT_KEY_RECOVERY_3:
+		aux.MicrosoftKeyRecovery3 = true
+	case OID_EKU_MICROSOFT_DOCUMENT_SIGNING:
+		aux.MicrosoftDocumentSigning = true
+	case OID_EKU_MICROSOFT_LIFETIME_SIGNING:
+		aux.MicrosoftLifetimeSigning = true
+	case OID_EKU_MICROSOFT_MOBILE_DEVICE_SOFTWARE:
+		aux.MicrosoftMobileDeviceSoftware = true
+	case OID_EKU_MICROSOFT_SMART_DISPLAY:
+		aux.MicrosoftSmartDisplay = true
+	case OID_EKU_MICROSOFT_CSP_SIGNATURE:
+		aux.MicrosoftCspSignature = true
+	case OID_EKU_MICROSOFT_TIMESTAMP_SIGNING:
+		aux.MicrosoftTimestampSigning = true
+	case OID_EKU_MICROSOFT_SERVER_GATED_CRYPTO:
+		aux.MicrosoftServerGatedCrypto = true
+	case OID_EKU_MICROSOFT_SGC_SERIALIZED:
+		aux.MicrosoftSgcSerialized = true
+	case OID_EKU_MICROSOFT_ENCRYPTED_FILE_SYSTEM:
+		aux.MicrosoftEncryptedFileSystem = true
+	case OID_EKU_MICROSOFT_EFS_RECOVERY:
+		aux.MicrosoftEfsRecovery = true
+	case OID_EKU_MICROSOFT_WHQL_CRYPTO:
+		aux.MicrosoftWhqlCrypto = true
+	case OID_EKU_MICROSOFT_NT5_CRYPTO:
+		aux.MicrosoftNt5Crypto = true
+	case OID_EKU_MICROSOFT_OEM_WHQL_CRYPTO:
+		aux.MicrosoftOemWhqlCrypto = true
+	case OID_EKU_MICROSOFT_EMBEDDED_NT_CRYPTO:
+		aux.MicrosoftEmbeddedNtCrypto = true
+	case OID_EKU_MICROSOFT_ROOT_LIST_SIGNER:
+		aux.MicrosoftRootListSigner = true
+	case OID_EKU_MICROSOFT_DRM:
+		aux.MicrosoftDrm = true
+	case OID_EKU_MICROSOFT_DRM_INDIVIDUALIZATION:
+		aux.MicrosoftDrmIndividualization = true
+	case OID_EKU_MICROSOFT_LICENSES:
+		aux.MicrosoftLicenses = true
+	case OID_EKU_MICROSOFT_LICENSE_SERVER:
+		aux.MicrosoftLicenseServer = true
+	case OID_EKU_MICROSOFT_ENROLLMENT_AGENT:
+		aux.MicrosoftEnrollmentAgent = true
+	case OID_EKU_MICROSOFT_SMARTCARD_LOGON:
+		aux.MicrosoftSmartcardLogon = true
+	case OID_EKU_MICROSOFT_CA_EXCHANGE:
+		aux.MicrosoftCaExchange = true
+	case OID_EKU_MICROSOFT_KEY_RECOVERY_21:
+		aux.MicrosoftKeyRecovery21 = true
+	case OID_EKU_MICROSOFT_SYSTEM_HEALTH:
+		aux.MicrosoftSystemHealth = true
+	case OID_EKU_MICROSOFT_SYSTEM_HEALTH_LOOPHOLE:
+		aux.MicrosoftSystemHealthLoophole = true
+	case OID_EKU_MICROSOFT_KERNEL_MODE_CODE_SIGNING:
+		aux.MicrosoftKernelModeCodeSigning = true
+	case OID_EKU_SERVER_AUTH:
+		aux.ServerAuth = true
+	case OID_EKU_DVCS:
+		aux.Dvcs = true
+	case OID_EKU_SBGP_CERT_AA_SERVICE_AUTH:
+		aux.SbgpCertAaServiceAuth = true
+	case OID_EKU_EAP_OVER_PPP:
+		aux.EapOverPpp = true
+	case OID_EKU_EAP_OVER_LAN:
+		aux.EapOverLan = true
+	case OID_EKU_CLIENT_AUTH:
+		aux.ClientAuth = true
+	case OID_EKU_CODE_SIGNING:
+		aux.CodeSigning = true
+	case OID_EKU_EMAIL_PROTECTION:
+		aux.EmailProtection = true
+	case OID_EKU_IPSEC_END_SYSTEM:
+		aux.IpsecEndSystem = true
+	case OID_EKU_IPSEC_TUNNEL:
+		aux.IpsecTunnel = true
+	case OID_EKU_IPSEC_USER:
+		aux.IpsecUser = true
+	case OID_EKU_TIME_STAMPING:
+		aux.TimeStamping = true
+	case OID_EKU_OCSP_SIGNING:
+		aux.OcspSigning = true
+	case OID_EKU_IPSEC_INTERMEDIATE_SYSTEM_USAGE:
+		aux.IpsecIntermediateSystemUsage = true
+	case OID_EKU_NETSCAPE_SERVER_GATED_CRYPTO:
+		aux.NetscapeServerGatedCrypto = true
+	case OID_EKU_ANY:
+		aux.Any = true
+	default:
+	}
+	return
+}
+
+func (aux *auxExtendedKeyUsage) populateFromExtKeyUsage(eku ExtKeyUsage) {
+	switch eku {
+	case ExtKeyUsageAppleCodeSigning:
+		aux.AppleCodeSigning = true
+	case ExtKeyUsageAppleCodeSigningDevelopment:
+		aux.AppleCodeSigningDevelopment = true
+	case ExtKeyUsageAppleSoftwareUpdateSigning:
+		aux.AppleSoftwareUpdateSigning = true
+	case ExtKeyUsageAppleCodeSigningThirdParty:
+		aux.AppleCodeSigningThirdParty = true
+	case ExtKeyUsageAppleResourceSigning:
+		aux.AppleResourceSigning = true
+	case ExtKeyUsageAppleIchatSigning:
+		aux.AppleIchatSigning = true
+	case ExtKeyUsageAppleIchatEncryption:
+		aux.AppleIchatEncryption = true
+	case ExtKeyUsageAppleSystemIdentity:
+		aux.AppleSystemIdentity = true
+	case ExtKeyUsageAppleCryptoEnv:
+		aux.AppleCryptoEnv = true
+	case ExtKeyUsageAppleCryptoProductionEnv:
+		aux.AppleCryptoProductionEnv = true
+	case ExtKeyUsageAppleCryptoMaintenanceEnv:
+		aux.AppleCryptoMaintenanceEnv = true
+	case ExtKeyUsageAppleCryptoTestEnv:
+		aux.AppleCryptoTestEnv = true
+	case ExtKeyUsageAppleCryptoDevelopmentEnv:
+		aux.AppleCryptoDevelopmentEnv = true
+	case ExtKeyUsageAppleCryptoQos:
+		aux.AppleCryptoQos = true
+	case ExtKeyUsageAppleCryptoTier0Qos:
+		aux.AppleCryptoTier0Qos = true
+	case ExtKeyUsageAppleCryptoTier1Qos:
+		aux.AppleCryptoTier1Qos = true
+	case ExtKeyUsageAppleCryptoTier2Qos:
+		aux.AppleCryptoTier2Qos = true
+	case ExtKeyUsageAppleCryptoTier3Qos:
+		aux.AppleCryptoTier3Qos = true
+	case ExtKeyUsageMicrosoftCertTrustListSigning:
+		aux.MicrosoftCertTrustListSigning = true
+	case ExtKeyUsageMicrosoftQualifiedSubordinate:
+		aux.MicrosoftQualifiedSubordinate = true
+	case ExtKeyUsageMicrosoftKeyRecovery3:
+		aux.MicrosoftKeyRecovery3 = true
+	case ExtKeyUsageMicrosoftDocumentSigning:
+		aux.MicrosoftDocumentSigning = true
+	case ExtKeyUsageMicrosoftLifetimeSigning:
+		aux.MicrosoftLifetimeSigning = true
+	case ExtKeyUsageMicrosoftMobileDeviceSoftware:
+		aux.MicrosoftMobileDeviceSoftware = true
+	case ExtKeyUsageMicrosoftSmartDisplay:
+		aux.MicrosoftSmartDisplay = true
+	case ExtKeyUsageMicrosoftCspSignature:
+		aux.MicrosoftCspSignature = true
+	case ExtKeyUsageMicrosoftTimestampSigning:
+		aux.MicrosoftTimestampSigning = true
+	case ExtKeyUsageMicrosoftServerGatedCrypto:
+		aux.MicrosoftServerGatedCrypto = true
+	case ExtKeyUsageMicrosoftSgcSerialized:
+		aux.MicrosoftSgcSerialized = true
+	case ExtKeyUsageMicrosoftEncryptedFileSystem:
+		aux.MicrosoftEncryptedFileSystem = true
+	case ExtKeyUsageMicrosoftEfsRecovery:
+		aux.MicrosoftEfsRecovery = true
+	case ExtKeyUsageMicrosoftWhqlCrypto:
+		aux.MicrosoftWhqlCrypto = true
+	case ExtKeyUsageMicrosoftNt5Crypto:
+		aux.MicrosoftNt5Crypto = true
+	case ExtKeyUsageMicrosoftOemWhqlCrypto:
+		aux.MicrosoftOemWhqlCrypto = true
+	case ExtKeyUsageMicrosoftEmbeddedNtCrypto:
+		aux.MicrosoftEmbeddedNtCrypto = true
+	case ExtKeyUsageMicrosoftRootListSigner:
+		aux.MicrosoftRootListSigner = true
+	case ExtKeyUsageMicrosoftDrm:
+		aux.MicrosoftDrm = true
+	case ExtKeyUsageMicrosoftDrmIndividualization:
+		aux.MicrosoftDrmIndividualization = true
+	case ExtKeyUsageMicrosoftLicenses:
+		aux.MicrosoftLicenses = true
+	case ExtKeyUsageMicrosoftLicenseServer:
+		aux.MicrosoftLicenseServer = true
+	case ExtKeyUsageMicrosoftEnrollmentAgent:
+		aux.MicrosoftEnrollmentAgent = true
+	case ExtKeyUsageMicrosoftSmartcardLogon:
+		aux.MicrosoftSmartcardLogon = true
+	case ExtKeyUsageMicrosoftCaExchange:
+		aux.MicrosoftCaExchange = true
+	case ExtKeyUsageMicrosoftKeyRecovery21:
+		aux.MicrosoftKeyRecovery21 = true
+	case ExtKeyUsageMicrosoftSystemHealth:
+		aux.MicrosoftSystemHealth = true
+	case ExtKeyUsageMicrosoftSystemHealthLoophole:
+		aux.MicrosoftSystemHealthLoophole = true
+	case ExtKeyUsageMicrosoftKernelModeCodeSigning:
+		aux.MicrosoftKernelModeCodeSigning = true
+	case ExtKeyUsageServerAuth:
+		aux.ServerAuth = true
+	case ExtKeyUsageDvcs:
+		aux.Dvcs = true
+	case ExtKeyUsageSbgpCertAaServiceAuth:
+		aux.SbgpCertAaServiceAuth = true
+	case ExtKeyUsageEapOverPpp:
+		aux.EapOverPpp = true
+	case ExtKeyUsageEapOverLan:
+		aux.EapOverLan = true
+	case ExtKeyUsageClientAuth:
+		aux.ClientAuth = true
+	case ExtKeyUsageCodeSigning:
+		aux.CodeSigning = true
+	case ExtKeyUsageEmailProtection:
+		aux.EmailProtection = true
+	case ExtKeyUsageIpsecEndSystem:
+		aux.IpsecEndSystem = true
+	case ExtKeyUsageIpsecTunnel:
+		aux.IpsecTunnel = true
+	case ExtKeyUsageIpsecUser:
+		aux.IpsecUser = true
+	case ExtKeyUsageTimeStamping:
+		aux.TimeStamping = true
+	case ExtKeyUsageOcspSigning:
+		aux.OcspSigning = true
+	case ExtKeyUsageIpsecIntermediateSystemUsage:
+		aux.IpsecIntermediateSystemUsage = true
+	case ExtKeyUsageNetscapeServerGatedCrypto:
+		aux.NetscapeServerGatedCrypto = true
+	case ExtKeyUsageAny:
+		aux.Any = true
+	default:
+	}
+	return
+}
+
+var ekuOIDs map[string]asn1.ObjectIdentifier
+
+var ekuConstants map[string]ExtKeyUsage
+
+func init() {
+	ekuOIDs = make(map[string]asn1.ObjectIdentifier)
+	ekuOIDs[OID_EKU_APPLE_CODE_SIGNING] = oidExtKeyUsageAppleCodeSigning
+	ekuOIDs[OID_EKU_APPLE_CODE_SIGNING_DEVELOPMENT] = oidExtKeyUsageAppleCodeSigningDevelopment
+	ekuOIDs[OID_EKU_APPLE_SOFTWARE_UPDATE_SIGNING] = oidExtKeyUsageAppleSoftwareUpdateSigning
+	ekuOIDs[OID_EKU_APPLE_CODE_SIGNING_THIRD_PARTY] = oidExtKeyUsageAppleCodeSigningThirdParty
+	ekuOIDs[OID_EKU_APPLE_RESOURCE_SIGNING] = oidExtKeyUsageAppleResourceSigning
+	ekuOIDs[OID_EKU_APPLE_ICHAT_SIGNING] = oidExtKeyUsageAppleIchatSigning
+	ekuOIDs[OID_EKU_APPLE_ICHAT_ENCRYPTION] = oidExtKeyUsageAppleIchatEncryption
+	ekuOIDs[OID_EKU_APPLE_SYSTEM_IDENTITY] = oidExtKeyUsageAppleSystemIdentity
+	ekuOIDs[OID_EKU_APPLE_CRYPTO_ENV] = oidExtKeyUsageAppleCryptoEnv
+	ekuOIDs[OID_EKU_APPLE_CRYPTO_PRODUCTION_ENV] = oidExtKeyUsageAppleCryptoProductionEnv
+	ekuOIDs[OID_EKU_APPLE_CRYPTO_MAINTENANCE_ENV] = oidExtKeyUsageAppleCryptoMaintenanceEnv
+	ekuOIDs[OID_EKU_APPLE_CRYPTO_TEST_ENV] = oidExtKeyUsageAppleCryptoTestEnv
+	ekuOIDs[OID_EKU_APPLE_CRYPTO_DEVELOPMENT_ENV] = oidExtKeyUsageAppleCryptoDevelopmentEnv
+	ekuOIDs[OID_EKU_APPLE_CRYPTO_QOS] = oidExtKeyUsageAppleCryptoQos
+	ekuOIDs[OID_EKU_APPLE_CRYPTO_TIER0_QOS] = oidExtKeyUsageAppleCryptoTier0Qos
+	ekuOIDs[OID_EKU_APPLE_CRYPTO_TIER1_QOS] = oidExtKeyUsageAppleCryptoTier1Qos
+	ekuOIDs[OID_EKU_APPLE_CRYPTO_TIER2_QOS] = oidExtKeyUsageAppleCryptoTier2Qos
+	ekuOIDs[OID_EKU_APPLE_CRYPTO_TIER3_QOS] = oidExtKeyUsageAppleCryptoTier3Qos
+	ekuOIDs[OID_EKU_MICROSOFT_CERT_TRUST_LIST_SIGNING] = oidExtKeyUsageMicrosoftCertTrustListSigning
+	ekuOIDs[OID_EKU_MICROSOFT_QUALIFIED_SUBORDINATE] = oidExtKeyUsageMicrosoftQualifiedSubordinate
+	ekuOIDs[OID_EKU_MICROSOFT_KEY_RECOVERY_3] = oidExtKeyUsageMicrosoftKeyRecovery3
+	ekuOIDs[OID_EKU_MICROSOFT_DOCUMENT_SIGNING] = oidExtKeyUsageMicrosoftDocumentSigning
+	ekuOIDs[OID_EKU_MICROSOFT_LIFETIME_SIGNING] = oidExtKeyUsageMicrosoftLifetimeSigning
+	ekuOIDs[OID_EKU_MICROSOFT_MOBILE_DEVICE_SOFTWARE] = oidExtKeyUsageMicrosoftMobileDeviceSoftware
+	ekuOIDs[OID_EKU_MICROSOFT_SMART_DISPLAY] = oidExtKeyUsageMicrosoftSmartDisplay
+	ekuOIDs[OID_EKU_MICROSOFT_CSP_SIGNATURE] = oidExtKeyUsageMicrosoftCspSignature
+	ekuOIDs[OID_EKU_MICROSOFT_TIMESTAMP_SIGNING] = oidExtKeyUsageMicrosoftTimestampSigning
+	ekuOIDs[OID_EKU_MICROSOFT_SERVER_GATED_CRYPTO] = oidExtKeyUsageMicrosoftServerGatedCrypto
+	ekuOIDs[OID_EKU_MICROSOFT_SGC_SERIALIZED] = oidExtKeyUsageMicrosoftSgcSerialized
+	ekuOIDs[OID_EKU_MICROSOFT_ENCRYPTED_FILE_SYSTEM] = oidExtKeyUsageMicrosoftEncryptedFileSystem
+	ekuOIDs[OID_EKU_MICROSOFT_EFS_RECOVERY] = oidExtKeyUsageMicrosoftEfsRecovery
+	ekuOIDs[OID_EKU_MICROSOFT_WHQL_CRYPTO] = oidExtKeyUsageMicrosoftWhqlCrypto
+	ekuOIDs[OID_EKU_MICROSOFT_NT5_CRYPTO] = oidExtKeyUsageMicrosoftNt5Crypto
+	ekuOIDs[OID_EKU_MICROSOFT_OEM_WHQL_CRYPTO] = oidExtKeyUsageMicrosoftOemWhqlCrypto
+	ekuOIDs[OID_EKU_MICROSOFT_EMBEDDED_NT_CRYPTO] = oidExtKeyUsageMicrosoftEmbeddedNtCrypto
+	ekuOIDs[OID_EKU_MICROSOFT_ROOT_LIST_SIGNER] = oidExtKeyUsageMicrosoftRootListSigner
+	ekuOIDs[OID_EKU_MICROSOFT_DRM] = oidExtKeyUsageMicrosoftDrm
+	ekuOIDs[OID_EKU_MICROSOFT_DRM_INDIVIDUALIZATION] = oidExtKeyUsageMicrosoftDrmIndividualization
+	ekuOIDs[OID_EKU_MICROSOFT_LICENSES] = oidExtKeyUsageMicrosoftLicenses
+	ekuOIDs[OID_EKU_MICROSOFT_LICENSE_SERVER] = oidExtKeyUsageMicrosoftLicenseServer
+	ekuOIDs[OID_EKU_MICROSOFT_ENROLLMENT_AGENT] = oidExtKeyUsageMicrosoftEnrollmentAgent
+	ekuOIDs[OID_EKU_MICROSOFT_SMARTCARD_LOGON] = oidExtKeyUsageMicrosoftSmartcardLogon
+	ekuOIDs[OID_EKU_MICROSOFT_CA_EXCHANGE] = oidExtKeyUsageMicrosoftCaExchange
+	ekuOIDs[OID_EKU_MICROSOFT_KEY_RECOVERY_21] = oidExtKeyUsageMicrosoftKeyRecovery21
+	ekuOIDs[OID_EKU_MICROSOFT_SYSTEM_HEALTH] = oidExtKeyUsageMicrosoftSystemHealth
+	ekuOIDs[OID_EKU_MICROSOFT_SYSTEM_HEALTH_LOOPHOLE] = oidExtKeyUsageMicrosoftSystemHealthLoophole
+	ekuOIDs[OID_EKU_MICROSOFT_KERNEL_MODE_CODE_SIGNING] = oidExtKeyUsageMicrosoftKernelModeCodeSigning
+	ekuOIDs[OID_EKU_SERVER_AUTH] = oidExtKeyUsageServerAuth
+	ekuOIDs[OID_EKU_DVCS] = oidExtKeyUsageDvcs
+	ekuOIDs[OID_EKU_SBGP_CERT_AA_SERVICE_AUTH] = oidExtKeyUsageSbgpCertAaServiceAuth
+	ekuOIDs[OID_EKU_EAP_OVER_PPP] = oidExtKeyUsageEapOverPpp
+	ekuOIDs[OID_EKU_EAP_OVER_LAN] = oidExtKeyUsageEapOverLan
+	ekuOIDs[OID_EKU_CLIENT_AUTH] = oidExtKeyUsageClientAuth
+	ekuOIDs[OID_EKU_CODE_SIGNING] = oidExtKeyUsageCodeSigning
+	ekuOIDs[OID_EKU_EMAIL_PROTECTION] = oidExtKeyUsageEmailProtection
+	ekuOIDs[OID_EKU_IPSEC_END_SYSTEM] = oidExtKeyUsageIpsecEndSystem
+	ekuOIDs[OID_EKU_IPSEC_TUNNEL] = oidExtKeyUsageIpsecTunnel
+	ekuOIDs[OID_EKU_IPSEC_USER] = oidExtKeyUsageIpsecUser
+	ekuOIDs[OID_EKU_TIME_STAMPING] = oidExtKeyUsageTimeStamping
+	ekuOIDs[OID_EKU_OCSP_SIGNING] = oidExtKeyUsageOcspSigning
+	ekuOIDs[OID_EKU_IPSEC_INTERMEDIATE_SYSTEM_USAGE] = oidExtKeyUsageIpsecIntermediateSystemUsage
+	ekuOIDs[OID_EKU_NETSCAPE_SERVER_GATED_CRYPTO] = oidExtKeyUsageNetscapeServerGatedCrypto
+	ekuOIDs[OID_EKU_ANY] = oidExtKeyUsageAny
+
+	ekuConstants = make(map[string]ExtKeyUsage)
+	ekuConstants[OID_EKU_APPLE_CODE_SIGNING] = ExtKeyUsageAppleCodeSigning
+	ekuConstants[OID_EKU_APPLE_CODE_SIGNING_DEVELOPMENT] = ExtKeyUsageAppleCodeSigningDevelopment
+	ekuConstants[OID_EKU_APPLE_SOFTWARE_UPDATE_SIGNING] = ExtKeyUsageAppleSoftwareUpdateSigning
+	ekuConstants[OID_EKU_APPLE_CODE_SIGNING_THIRD_PARTY] = ExtKeyUsageAppleCodeSigningThirdParty
+	ekuConstants[OID_EKU_APPLE_RESOURCE_SIGNING] = ExtKeyUsageAppleResourceSigning
+	ekuConstants[OID_EKU_APPLE_ICHAT_SIGNING] = ExtKeyUsageAppleIchatSigning
+	ekuConstants[OID_EKU_APPLE_ICHAT_ENCRYPTION] = ExtKeyUsageAppleIchatEncryption
+	ekuConstants[OID_EKU_APPLE_SYSTEM_IDENTITY] = ExtKeyUsageAppleSystemIdentity
+	ekuConstants[OID_EKU_APPLE_CRYPTO_ENV] = ExtKeyUsageAppleCryptoEnv
+	ekuConstants[OID_EKU_APPLE_CRYPTO_PRODUCTION_ENV] = ExtKeyUsageAppleCryptoProductionEnv
+	ekuConstants[OID_EKU_APPLE_CRYPTO_MAINTENANCE_ENV] = ExtKeyUsageAppleCryptoMaintenanceEnv
+	ekuConstants[OID_EKU_APPLE_CRYPTO_TEST_ENV] = ExtKeyUsageAppleCryptoTestEnv
+	ekuConstants[OID_EKU_APPLE_CRYPTO_DEVELOPMENT_ENV] = ExtKeyUsageAppleCryptoDevelopmentEnv
+	ekuConstants[OID_EKU_APPLE_CRYPTO_QOS] = ExtKeyUsageAppleCryptoQos
+	ekuConstants[OID_EKU_APPLE_CRYPTO_TIER0_QOS] = ExtKeyUsageAppleCryptoTier0Qos
+	ekuConstants[OID_EKU_APPLE_CRYPTO_TIER1_QOS] = ExtKeyUsageAppleCryptoTier1Qos
+	ekuConstants[OID_EKU_APPLE_CRYPTO_TIER2_QOS] = ExtKeyUsageAppleCryptoTier2Qos
+	ekuConstants[OID_EKU_APPLE_CRYPTO_TIER3_QOS] = ExtKeyUsageAppleCryptoTier3Qos
+	ekuConstants[OID_EKU_MICROSOFT_CERT_TRUST_LIST_SIGNING] = ExtKeyUsageMicrosoftCertTrustListSigning
+	ekuConstants[OID_EKU_MICROSOFT_QUALIFIED_SUBORDINATE] = ExtKeyUsageMicrosoftQualifiedSubordinate
+	ekuConstants[OID_EKU_MICROSOFT_KEY_RECOVERY_3] = ExtKeyUsageMicrosoftKeyRecovery3
+	ekuConstants[OID_EKU_MICROSOFT_DOCUMENT_SIGNING] = ExtKeyUsageMicrosoftDocumentSigning
+	ekuConstants[OID_EKU_MICROSOFT_LIFETIME_SIGNING] = ExtKeyUsageMicrosoftLifetimeSigning
+	ekuConstants[OID_EKU_MICROSOFT_MOBILE_DEVICE_SOFTWARE] = ExtKeyUsageMicrosoftMobileDeviceSoftware
+	ekuConstants[OID_EKU_MICROSOFT_SMART_DISPLAY] = ExtKeyUsageMicrosoftSmartDisplay
+	ekuConstants[OID_EKU_MICROSOFT_CSP_SIGNATURE] = ExtKeyUsageMicrosoftCspSignature
+	ekuConstants[OID_EKU_MICROSOFT_TIMESTAMP_SIGNING] = ExtKeyUsageMicrosoftTimestampSigning
+	ekuConstants[OID_EKU_MICROSOFT_SERVER_GATED_CRYPTO] = ExtKeyUsageMicrosoftServerGatedCrypto
+	ekuConstants[OID_EKU_MICROSOFT_SGC_SERIALIZED] = ExtKeyUsageMicrosoftSgcSerialized
+	ekuConstants[OID_EKU_MICROSOFT_ENCRYPTED_FILE_SYSTEM] = ExtKeyUsageMicrosoftEncryptedFileSystem
+	ekuConstants[OID_EKU_MICROSOFT_EFS_RECOVERY] = ExtKeyUsageMicrosoftEfsRecovery
+	ekuConstants[OID_EKU_MICROSOFT_WHQL_CRYPTO] = ExtKeyUsageMicrosoftWhqlCrypto
+	ekuConstants[OID_EKU_MICROSOFT_NT5_CRYPTO] = ExtKeyUsageMicrosoftNt5Crypto
+	ekuConstants[OID_EKU_MICROSOFT_OEM_WHQL_CRYPTO] = ExtKeyUsageMicrosoftOemWhqlCrypto
+	ekuConstants[OID_EKU_MICROSOFT_EMBEDDED_NT_CRYPTO] = ExtKeyUsageMicrosoftEmbeddedNtCrypto
+	ekuConstants[OID_EKU_MICROSOFT_ROOT_LIST_SIGNER] = ExtKeyUsageMicrosoftRootListSigner
+	ekuConstants[OID_EKU_MICROSOFT_DRM] = ExtKeyUsageMicrosoftDrm
+	ekuConstants[OID_EKU_MICROSOFT_DRM_INDIVIDUALIZATION] = ExtKeyUsageMicrosoftDrmIndividualization
+	ekuConstants[OID_EKU_MICROSOFT_LICENSES] = ExtKeyUsageMicrosoftLicenses
+	ekuConstants[OID_EKU_MICROSOFT_LICENSE_SERVER] = ExtKeyUsageMicrosoftLicenseServer
+	ekuConstants[OID_EKU_MICROSOFT_ENROLLMENT_AGENT] = ExtKeyUsageMicrosoftEnrollmentAgent
+	ekuConstants[OID_EKU_MICROSOFT_SMARTCARD_LOGON] = ExtKeyUsageMicrosoftSmartcardLogon
+	ekuConstants[OID_EKU_MICROSOFT_CA_EXCHANGE] = ExtKeyUsageMicrosoftCaExchange
+	ekuConstants[OID_EKU_MICROSOFT_KEY_RECOVERY_21] = ExtKeyUsageMicrosoftKeyRecovery21
+	ekuConstants[OID_EKU_MICROSOFT_SYSTEM_HEALTH] = ExtKeyUsageMicrosoftSystemHealth
+	ekuConstants[OID_EKU_MICROSOFT_SYSTEM_HEALTH_LOOPHOLE] = ExtKeyUsageMicrosoftSystemHealthLoophole
+	ekuConstants[OID_EKU_MICROSOFT_KERNEL_MODE_CODE_SIGNING] = ExtKeyUsageMicrosoftKernelModeCodeSigning
+	ekuConstants[OID_EKU_SERVER_AUTH] = ExtKeyUsageServerAuth
+	ekuConstants[OID_EKU_DVCS] = ExtKeyUsageDvcs
+	ekuConstants[OID_EKU_SBGP_CERT_AA_SERVICE_AUTH] = ExtKeyUsageSbgpCertAaServiceAuth
+	ekuConstants[OID_EKU_EAP_OVER_PPP] = ExtKeyUsageEapOverPpp
+	ekuConstants[OID_EKU_EAP_OVER_LAN] = ExtKeyUsageEapOverLan
+	ekuConstants[OID_EKU_CLIENT_AUTH] = ExtKeyUsageClientAuth
+	ekuConstants[OID_EKU_CODE_SIGNING] = ExtKeyUsageCodeSigning
+	ekuConstants[OID_EKU_EMAIL_PROTECTION] = ExtKeyUsageEmailProtection
+	ekuConstants[OID_EKU_IPSEC_END_SYSTEM] = ExtKeyUsageIpsecEndSystem
+	ekuConstants[OID_EKU_IPSEC_TUNNEL] = ExtKeyUsageIpsecTunnel
+	ekuConstants[OID_EKU_IPSEC_USER] = ExtKeyUsageIpsecUser
+	ekuConstants[OID_EKU_TIME_STAMPING] = ExtKeyUsageTimeStamping
+	ekuConstants[OID_EKU_OCSP_SIGNING] = ExtKeyUsageOcspSigning
+	ekuConstants[OID_EKU_IPSEC_INTERMEDIATE_SYSTEM_USAGE] = ExtKeyUsageIpsecIntermediateSystemUsage
+	ekuConstants[OID_EKU_NETSCAPE_SERVER_GATED_CRYPTO] = ExtKeyUsageNetscapeServerGatedCrypto
+	ekuConstants[OID_EKU_ANY] = ExtKeyUsageAny
+}

+ 21 - 0
vendor/github.com/zmap/zcrypto/x509/extended_key_usage_schema.sh

@@ -0,0 +1,21 @@
+#!/bin/bash
+set -e
+
+# TODO: This should really be generated by Go code as a subrecord, but
+# importing in Python is hard. This is quick and dirty.
+
+FIELDS=$(\
+	cat extended_key_usage.go |\
+	grep json |\
+	cut -d ':' -f 2 |\
+       	sed 's|,omitempty||g' |\
+	tr -d '`')
+echo "extended_key_usage = SubRecord({"
+for f in $FIELDS; do
+	if [ $f == "\"unknown\"" ]; then
+		echo "    $f: ListOf(OID())"
+	else
+		echo "    $f: Boolean(),"
+	fi
+done
+echo "})"

+ 818 - 0
vendor/github.com/zmap/zcrypto/x509/extensions.go

@@ -0,0 +1,818 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+	"encoding/asn1"
+	"encoding/hex"
+	"encoding/json"
+	"net"
+	"strconv"
+	"strings"
+
+	"github.com/zmap/zcrypto/x509/ct"
+	"github.com/zmap/zcrypto/x509/pkix"
+)
+
+var (
+	oidExtKeyUsage           = asn1.ObjectIdentifier{2, 5, 29, 15}
+	oidExtBasicConstraints   = asn1.ObjectIdentifier{2, 5, 29, 19}
+	oidExtSubjectAltName     = asn1.ObjectIdentifier{2, 5, 29, 17}
+	oidExtIssuerAltName      = asn1.ObjectIdentifier{2, 5, 29, 18}
+	oidExtNameConstraints    = asn1.ObjectIdentifier{2, 5, 29, 30}
+	oidCRLDistributionPoints = asn1.ObjectIdentifier{2, 5, 29, 31}
+	oidExtAuthKeyId          = asn1.ObjectIdentifier{2, 5, 29, 35}
+	oidExtSubjectKeyId       = asn1.ObjectIdentifier{2, 5, 29, 14}
+	oidExtExtendedKeyUsage   = asn1.ObjectIdentifier{2, 5, 29, 37}
+	oidExtCertificatePolicy  = asn1.ObjectIdentifier{2, 5, 29, 32}
+
+	oidExtAuthorityInfoAccess            = oidExtensionAuthorityInfoAccess
+	oidExtensionCTPrecertificatePoison   = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 3}
+	oidExtSignedCertificateTimestampList = oidExtensionSignedCertificateTimestampList
+
+	oidExtCABFOrganizationID = asn1.ObjectIdentifier{2, 23, 140, 3, 1}
+	oidExtQCStatements       = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 3}
+)
+
+type CertificateExtensions struct {
+	KeyUsage                       KeyUsage                         `json:"key_usage,omitempty"`
+	BasicConstraints               *BasicConstraints                `json:"basic_constraints,omitempty"`
+	SubjectAltName                 *GeneralNames                    `json:"subject_alt_name,omitempty"`
+	IssuerAltName                  *GeneralNames                    `json:"issuer_alt_name,omitempty"`
+	NameConstraints                *NameConstraints                 `json:"name_constraints,omitempty"`
+	CRLDistributionPoints          CRLDistributionPoints            `json:"crl_distribution_points,omitempty"`
+	AuthKeyID                      SubjAuthKeyId                    `json:"authority_key_id,omitempty"`
+	SubjectKeyID                   SubjAuthKeyId                    `json:"subject_key_id,omitempty"`
+	ExtendedKeyUsage               *ExtendedKeyUsageExtension       `json:"extended_key_usage,omitempty"`
+	CertificatePolicies            *CertificatePoliciesData         `json:"certificate_policies,omitempty"`
+	AuthorityInfoAccess            *AuthorityInfoAccess             `json:"authority_info_access,omitempty"`
+	IsPrecert                      IsPrecert                        `json:"ct_poison,omitempty"`
+	SignedCertificateTimestampList []*ct.SignedCertificateTimestamp `json:"signed_certificate_timestamps,omitempty"`
+	TorServiceDescriptors          []*TorServiceDescriptorHash      `json:"tor_service_descriptors,omitempty"`
+	CABFOrganizationIdentifier     *CABFOrganizationIdentifier      `json:"cabf_organization_id,omitempty"`
+	QCStatements                   *QCStatements                    `json:"qc_statements,omitempty"`
+}
+
+type UnknownCertificateExtensions []pkix.Extension
+
+type IsPrecert bool
+
+type BasicConstraints struct {
+	IsCA       bool `json:"is_ca"`
+	MaxPathLen *int `json:"max_path_len,omitempty"`
+}
+
+type NoticeReference struct {
+	Organization  string       `json:"organization,omitempty"`
+	NoticeNumbers NoticeNumber `json:"notice_numbers,omitempty"`
+}
+
+type UserNoticeData struct {
+	ExplicitText    string            `json:"explicit_text,omitempty"`
+	NoticeReference []NoticeReference `json:"notice_reference,omitempty"`
+}
+
+type CertificatePoliciesJSON struct {
+	PolicyIdentifier string           `json:"id,omitempty"`
+	CPSUri           []string         `json:"cps,omitempty"`
+	UserNotice       []UserNoticeData `json:"user_notice,omitempty"`
+}
+
+type CertificatePolicies []CertificatePoliciesJSON
+
+type CertificatePoliciesData struct {
+	PolicyIdentifiers     []asn1.ObjectIdentifier
+	QualifierId           [][]asn1.ObjectIdentifier
+	CPSUri                [][]string
+	ExplicitTexts         [][]string
+	NoticeRefOrganization [][]string
+	NoticeRefNumbers      [][]NoticeNumber
+}
+
+func (cp *CertificatePoliciesData) MarshalJSON() ([]byte, error) {
+	policies := CertificatePolicies{}
+	for idx, oid := range cp.PolicyIdentifiers {
+		cpsJSON := CertificatePoliciesJSON{}
+		cpsJSON.PolicyIdentifier = oid.String()
+		for _, uri := range cp.CPSUri[idx] {
+			cpsJSON.CPSUri = append(cpsJSON.CPSUri, uri)
+		}
+
+		for idx2, explicit_text := range cp.ExplicitTexts[idx] {
+			uNoticeData := UserNoticeData{}
+			uNoticeData.ExplicitText = explicit_text
+			noticeRef := NoticeReference{}
+			if len(cp.NoticeRefOrganization[idx]) > 0 {
+				organization := cp.NoticeRefOrganization[idx][idx2]
+				noticeRef.Organization = organization
+				noticeRef.NoticeNumbers = cp.NoticeRefNumbers[idx][idx2]
+				uNoticeData.NoticeReference = append(uNoticeData.NoticeReference, noticeRef)
+			}
+			cpsJSON.UserNotice = append(cpsJSON.UserNotice, uNoticeData)
+		}
+
+		policies = append(policies, cpsJSON)
+	}
+	return json.Marshal(policies)
+}
+
+// GeneralNames corresponds an X.509 GeneralName defined in
+// Section 4.2.1.6 of RFC 5280.
+//
+// GeneralName ::= CHOICE {
+//      otherName                 [0]  AnotherName,
+//      rfc822Name                [1]  IA5String,
+//      dNSName                   [2]  IA5String,
+//      x400Address               [3]  ORAddress,
+//      directoryName             [4]  Name,
+//      ediPartyName              [5]  EDIPartyName,
+//      uniformResourceIdentifier [6]  IA5String,
+//      iPAddress                 [7]  OCTET STRING,
+//      registeredID              [8]  OBJECT IDENTIFIER }
+type GeneralNames struct {
+	DirectoryNames []pkix.Name
+	DNSNames       []string
+	EDIPartyNames  []pkix.EDIPartyName
+	EmailAddresses []string
+	IPAddresses    []net.IP
+	OtherNames     []pkix.OtherName
+	RegisteredIDs  []asn1.ObjectIdentifier
+	URIs           []string
+}
+
+type jsonGeneralNames struct {
+	DirectoryNames []pkix.Name         `json:"directory_names,omitempty"`
+	DNSNames       []string            `json:"dns_names,omitempty"`
+	EDIPartyNames  []pkix.EDIPartyName `json:"edi_party_names,omitempty"`
+	EmailAddresses []string            `json:"email_addresses,omitempty"`
+	IPAddresses    []net.IP            `json:"ip_addresses,omitempty"`
+	OtherNames     []pkix.OtherName    `json:"other_names,omitempty"`
+	RegisteredIDs  []string            `json:"registered_ids,omitempty"`
+	URIs           []string            `json:"uniform_resource_identifiers,omitempty"`
+}
+
+func (gn *GeneralNames) MarshalJSON() ([]byte, error) {
+	jsan := jsonGeneralNames{
+		DirectoryNames: gn.DirectoryNames,
+		DNSNames:       gn.DNSNames,
+		EDIPartyNames:  gn.EDIPartyNames,
+		EmailAddresses: gn.EmailAddresses,
+		IPAddresses:    gn.IPAddresses,
+		OtherNames:     gn.OtherNames,
+		RegisteredIDs:  make([]string, 0, len(gn.RegisteredIDs)),
+		URIs:           gn.URIs,
+	}
+	for _, id := range gn.RegisteredIDs {
+		jsan.RegisteredIDs = append(jsan.RegisteredIDs, id.String())
+	}
+	return json.Marshal(jsan)
+}
+
+func (gn *GeneralNames) UnmarshalJSON(b []byte) error {
+	var jsan jsonGeneralNames
+	err := json.Unmarshal(b, &jsan)
+	if err != nil {
+		return err
+	}
+
+	gn.DirectoryNames = jsan.DirectoryNames
+	gn.DNSNames = jsan.DNSNames
+	gn.EDIPartyNames = jsan.EDIPartyNames
+	gn.EmailAddresses = jsan.EmailAddresses
+	gn.IPAddresses = jsan.IPAddresses
+	gn.OtherNames = jsan.OtherNames
+	gn.RegisteredIDs = make([]asn1.ObjectIdentifier, len(jsan.RegisteredIDs))
+	gn.URIs = jsan.URIs
+
+	for i, rID := range jsan.RegisteredIDs {
+		arcs := strings.Split(rID, ".")
+		oid := make(asn1.ObjectIdentifier, len(arcs))
+
+		for j, s := range arcs {
+			tmp, err := strconv.ParseInt(s, 10, 32)
+			if err != nil {
+				return err
+			}
+			oid[j] = int(tmp)
+		}
+		gn.RegisteredIDs[i] = oid
+	}
+	return nil
+}
+
+// TODO: Handle excluded names
+
+type NameConstraints struct {
+	Critical bool `json:"critical"`
+
+	PermittedDNSNames       []GeneralSubtreeString
+	PermittedEmailAddresses []GeneralSubtreeString
+	PermittedURIs           []GeneralSubtreeString
+	PermittedIPAddresses    []GeneralSubtreeIP
+	PermittedDirectoryNames []GeneralSubtreeName
+	PermittedEdiPartyNames  []GeneralSubtreeEdi
+	PermittedRegisteredIDs  []GeneralSubtreeOid
+
+	ExcludedEmailAddresses []GeneralSubtreeString
+	ExcludedDNSNames       []GeneralSubtreeString
+	ExcludedURIs           []GeneralSubtreeString
+	ExcludedIPAddresses    []GeneralSubtreeIP
+	ExcludedDirectoryNames []GeneralSubtreeName
+	ExcludedEdiPartyNames  []GeneralSubtreeEdi
+	ExcludedRegisteredIDs  []GeneralSubtreeOid
+}
+
+type NameConstraintsJSON struct {
+	Critical bool `json:"critical"`
+
+	PermittedDNSNames       []string            `json:"permitted_names,omitempty"`
+	PermittedEmailAddresses []string            `json:"permitted_email_addresses,omitempty"`
+	PermittedURIs           []string            `json:"permitted_uris,omitempty"`
+	PermittedIPAddresses    []GeneralSubtreeIP  `json:"permitted_ip_addresses,omitempty"`
+	PermittedDirectoryNames []pkix.Name         `json:"permitted_directory_names,omitempty"`
+	PermittedEdiPartyNames  []pkix.EDIPartyName `json:"permitted_edi_party_names,omitempty"`
+	PermittedRegisteredIDs  []string            `json:"permitted_registred_id,omitempty"`
+
+	ExcludedDNSNames       []string            `json:"excluded_names,omitempty"`
+	ExcludedEmailAddresses []string            `json:"excluded_email_addresses,omitempty"`
+	ExcludedURIs           []string            `json:"excluded_uris,omitempty"`
+	ExcludedIPAddresses    []GeneralSubtreeIP  `json:"excluded_ip_addresses,omitempty"`
+	ExcludedDirectoryNames []pkix.Name         `json:"excluded_directory_names,omitempty"`
+	ExcludedEdiPartyNames  []pkix.EDIPartyName `json:"excluded_edi_party_names,omitempty"`
+	ExcludedRegisteredIDs  []string            `json:"excluded_registred_id,omitempty"`
+}
+
+func (nc *NameConstraints) UnmarshalJSON(b []byte) error {
+	var ncJson NameConstraintsJSON
+	err := json.Unmarshal(b, &ncJson)
+	if err != nil {
+		return err
+	}
+	for _, dns := range ncJson.PermittedDNSNames {
+		nc.PermittedDNSNames = append(nc.PermittedDNSNames, GeneralSubtreeString{Data: dns})
+	}
+	for _, email := range ncJson.PermittedEmailAddresses {
+		nc.PermittedEmailAddresses = append(nc.PermittedEmailAddresses, GeneralSubtreeString{Data: email})
+	}
+	for _, uri := range ncJson.PermittedURIs {
+		nc.PermittedURIs = append(nc.PermittedURIs, GeneralSubtreeString{Data: uri})
+	}
+	for _, constraint := range ncJson.PermittedIPAddresses {
+		nc.PermittedIPAddresses = append(nc.PermittedIPAddresses, constraint)
+	}
+	for _, directory := range ncJson.PermittedDirectoryNames {
+		nc.PermittedDirectoryNames = append(nc.PermittedDirectoryNames, GeneralSubtreeName{Data: directory})
+	}
+	for _, edi := range ncJson.PermittedEdiPartyNames {
+		nc.PermittedEdiPartyNames = append(nc.PermittedEdiPartyNames, GeneralSubtreeEdi{Data: edi})
+	}
+	for _, id := range ncJson.PermittedRegisteredIDs {
+		arcs := strings.Split(id, ".")
+		oid := make(asn1.ObjectIdentifier, len(arcs))
+
+		for j, s := range arcs {
+			tmp, err := strconv.ParseInt(s, 10, 32)
+			if err != nil {
+				return err
+			}
+			oid[j] = int(tmp)
+		}
+		nc.PermittedRegisteredIDs = append(nc.PermittedRegisteredIDs, GeneralSubtreeOid{Data: oid})
+	}
+
+	for _, dns := range ncJson.ExcludedDNSNames {
+		nc.ExcludedDNSNames = append(nc.ExcludedDNSNames, GeneralSubtreeString{Data: dns})
+	}
+	for _, email := range ncJson.ExcludedEmailAddresses {
+		nc.ExcludedEmailAddresses = append(nc.ExcludedEmailAddresses, GeneralSubtreeString{Data: email})
+	}
+	for _, uri := range ncJson.ExcludedURIs {
+		nc.ExcludedURIs = append(nc.ExcludedURIs, GeneralSubtreeString{Data: uri})
+	}
+	for _, constraint := range ncJson.ExcludedIPAddresses {
+		nc.ExcludedIPAddresses = append(nc.ExcludedIPAddresses, constraint)
+	}
+	for _, directory := range ncJson.ExcludedDirectoryNames {
+		nc.ExcludedDirectoryNames = append(nc.ExcludedDirectoryNames, GeneralSubtreeName{Data: directory})
+	}
+	for _, edi := range ncJson.ExcludedEdiPartyNames {
+		nc.ExcludedEdiPartyNames = append(nc.ExcludedEdiPartyNames, GeneralSubtreeEdi{Data: edi})
+	}
+	for _, id := range ncJson.ExcludedRegisteredIDs {
+		arcs := strings.Split(id, ".")
+		oid := make(asn1.ObjectIdentifier, len(arcs))
+
+		for j, s := range arcs {
+			tmp, err := strconv.ParseInt(s, 10, 32)
+			if err != nil {
+				return err
+			}
+			oid[j] = int(tmp)
+		}
+		nc.ExcludedRegisteredIDs = append(nc.ExcludedRegisteredIDs, GeneralSubtreeOid{Data: oid})
+	}
+	return nil
+}
+
+func (nc NameConstraints) MarshalJSON() ([]byte, error) {
+	var out NameConstraintsJSON
+	for _, dns := range nc.PermittedDNSNames {
+		out.PermittedDNSNames = append(out.PermittedDNSNames, dns.Data)
+	}
+	for _, email := range nc.PermittedEmailAddresses {
+		out.PermittedEmailAddresses = append(out.PermittedEmailAddresses, email.Data)
+	}
+	for _, uri := range nc.PermittedURIs {
+		out.PermittedURIs = append(out.PermittedURIs, uri.Data)
+	}
+	out.PermittedIPAddresses = nc.PermittedIPAddresses
+	for _, directory := range nc.PermittedDirectoryNames {
+		out.PermittedDirectoryNames = append(out.PermittedDirectoryNames, directory.Data)
+	}
+	for _, edi := range nc.PermittedEdiPartyNames {
+		out.PermittedEdiPartyNames = append(out.PermittedEdiPartyNames, edi.Data)
+	}
+	for _, id := range nc.PermittedRegisteredIDs {
+		out.PermittedRegisteredIDs = append(out.PermittedRegisteredIDs, id.Data.String())
+	}
+
+	for _, dns := range nc.ExcludedDNSNames {
+		out.ExcludedDNSNames = append(out.ExcludedDNSNames, dns.Data)
+	}
+	for _, email := range nc.ExcludedEmailAddresses {
+		out.ExcludedEmailAddresses = append(out.ExcludedEmailAddresses, email.Data)
+	}
+	for _, uri := range nc.ExcludedURIs {
+		out.ExcludedURIs = append(out.ExcludedURIs, uri.Data)
+	}
+	for _, ip := range nc.ExcludedIPAddresses {
+		out.ExcludedIPAddresses = append(out.ExcludedIPAddresses, ip)
+	}
+	for _, directory := range nc.ExcludedDirectoryNames {
+		out.ExcludedDirectoryNames = append(out.ExcludedDirectoryNames, directory.Data)
+	}
+	for _, edi := range nc.ExcludedEdiPartyNames {
+		out.ExcludedEdiPartyNames = append(out.ExcludedEdiPartyNames, edi.Data)
+	}
+	for _, id := range nc.ExcludedRegisteredIDs {
+		out.ExcludedRegisteredIDs = append(out.ExcludedRegisteredIDs, id.Data.String())
+	}
+	return json.Marshal(out)
+}
+
+type CRLDistributionPoints []string
+
+type SubjAuthKeyId []byte
+
+func (kid SubjAuthKeyId) MarshalJSON() ([]byte, error) {
+	enc := hex.EncodeToString(kid)
+	return json.Marshal(enc)
+}
+
+type ExtendedKeyUsage []ExtKeyUsage
+
+type ExtendedKeyUsageExtension struct {
+	Known   ExtendedKeyUsage
+	Unknown []asn1.ObjectIdentifier
+}
+
+// MarshalJSON implements the json.Marshal interface. The output is a struct of
+// bools, with an additional `Value` field containing the actual OIDs.
+func (e *ExtendedKeyUsageExtension) MarshalJSON() ([]byte, error) {
+	aux := new(auxExtendedKeyUsage)
+	for _, e := range e.Known {
+		aux.populateFromExtKeyUsage(e)
+	}
+	for _, oid := range e.Unknown {
+		aux.Unknown = append(aux.Unknown, oid.String())
+	}
+	return json.Marshal(aux)
+}
+
+func (e *ExtendedKeyUsageExtension) UnmarshalJSON(b []byte) error {
+	aux := new(auxExtendedKeyUsage)
+	if err := json.Unmarshal(b, aux); err != nil {
+		return err
+	}
+	// TODO: Generate the reverse functions.
+	return nil
+}
+
+//go:generate go run extended_key_usage_gen.go
+
+// The string functions for CertValidationLevel are auto-generated via
+// `go generate <full_path_to_x509_package>` or running `go generate` in the package directory
+//go:generate stringer -type=CertValidationLevel -output=generated_certvalidationlevel_string.go
+type CertValidationLevel int
+
+const (
+	UnknownValidationLevel CertValidationLevel = 0
+	DV                     CertValidationLevel = 1
+	OV                     CertValidationLevel = 2
+	EV                     CertValidationLevel = 3
+)
+
+func (c *CertValidationLevel) MarshalJSON() ([]byte, error) {
+	if *c == UnknownValidationLevel || *c < 0 || *c > EV {
+		return json.Marshal("unknown")
+	}
+	return json.Marshal(c.String())
+}
+
+// TODO: All of validation-level maps should be auto-generated from
+// https://github.com/zmap/constants.
+
+// ExtendedValidationOIDs contains the UNION of Chromium
+// (https://chromium.googlesource.com/chromium/src/net/+/master/cert/ev_root_ca_metadata.cc)
+// and Firefox
+// (http://hg.mozilla.org/mozilla-central/file/tip/security/certverifier/ExtendedValidation.cpp)
+// EV OID lists
+var ExtendedValidationOIDs = map[string]interface{}{
+	// CA/Browser Forum EV OID standard
+	// https://cabforum.org/object-registry/
+	"2.23.140.1.1": nil,
+	// CA/Browser Forum EV Code Signing
+	"2.23.140.1.3": nil,
+	// CA/Browser Forum .onion EV Certs
+	"2.23.140.1.31": nil,
+	// AC Camerfirma S.A. Chambers of Commerce Root - 2008
+	// https://www.camerfirma.com
+	// AC Camerfirma uses the last two arcs to track how the private key
+	// is managed - the effective verification policy is the same.
+	"1.3.6.1.4.1.17326.10.14.2.1.2": nil,
+	"1.3.6.1.4.1.17326.10.14.2.2.2": nil,
+	// AC Camerfirma S.A. Global Chambersign Root - 2008
+	// https://server2.camerfirma.com:8082
+	// AC Camerfirma uses the last two arcs to track how the private key
+	// is managed - the effective verification policy is the same.
+	"1.3.6.1.4.1.17326.10.8.12.1.2": nil,
+	"1.3.6.1.4.1.17326.10.8.12.2.2": nil,
+	// Actalis Authentication Root CA
+	// https://ssltest-a.actalis.it:8443
+	"1.3.159.1.17.1": nil,
+	// AffirmTrust Commercial
+	// https://commercial.affirmtrust.com/
+	"1.3.6.1.4.1.34697.2.1": nil,
+	// AffirmTrust Networking
+	// https://networking.affirmtrust.com:4431
+	"1.3.6.1.4.1.34697.2.2": nil,
+	// AffirmTrust Premium
+	// https://premium.affirmtrust.com:4432/
+	"1.3.6.1.4.1.34697.2.3": nil,
+	// AffirmTrust Premium ECC
+	// https://premiumecc.affirmtrust.com:4433/
+	"1.3.6.1.4.1.34697.2.4": nil,
+	// Autoridad de Certificacion Firmaprofesional CIF A62634068
+	// https://publifirma.firmaprofesional.com/
+	"1.3.6.1.4.1.13177.10.1.3.10": nil,
+	// Buypass Class 3 CA 1
+	// https://valid.evident.ca13.ssl.buypass.no/
+	"2.16.578.1.26.1.3.3": nil,
+	// Certification Authority of WoSign
+	// CA 沃通根证书
+	// https://root2evtest.wosign.com/
+	"1.3.6.1.4.1.36305.2": nil,
+	// CertPlus Class 2 Primary CA (KEYNECTIS)
+	// https://www.keynectis.com/
+	"1.3.6.1.4.1.22234.2.5.2.3.1": nil,
+	// Certum Trusted Network CA
+	// https://juice.certum.pl/
+	"1.2.616.1.113527.2.5.1.1": nil,
+	// China Internet Network Information Center EV Certificates Root
+	// https://evdemo.cnnic.cn/
+	"1.3.6.1.4.1.29836.1.10": nil,
+	// COMODO Certification Authority & USERTrust RSA Certification Authority & UTN-USERFirst-Hardware & AddTrust External CA Root
+	// https://secure.comodo.com/
+	// https://usertrustrsacertificationauthority-ev.comodoca.com/
+	// https://addtrustexternalcaroot-ev.comodoca.com
+	"1.3.6.1.4.1.6449.1.2.1.5.1": nil,
+	// Cybertrust Global Root & GTE CyberTrust Global Root & Baltimore CyberTrust Root
+	// https://evup.cybertrust.ne.jp/ctj-ev-upgrader/evseal.gif
+	// https://www.cybertrust.ne.jp/
+	// https://secure.omniroot.com/repository/
+	"1.3.6.1.4.1.6334.1.100.1": nil,
+	// DigiCert High Assurance EV Root CA
+	// https://www.digicert.com
+	"2.16.840.1.114412.2.1": nil,
+	// D-TRUST Root Class 3 CA 2 EV 2009
+	// https://certdemo-ev-valid.ssl.d-trust.net/
+	"1.3.6.1.4.1.4788.2.202.1": nil,
+	// Entrust.net Secure Server Certification Authority
+	// https://www.entrust.net/
+	"2.16.840.1.114028.10.1.2": nil,
+	// E-Tugra Certification Authority
+	// https://sslev.e-tugra.com.tr
+	"2.16.792.3.0.4.1.1.4": nil,
+	// GeoTrust Primary Certification Authority
+	// https://www.geotrust.com/
+	"1.3.6.1.4.1.14370.1.6": nil,
+	// GlobalSign Root CA - R2
+	// https://www.globalsign.com/
+	"1.3.6.1.4.1.4146.1.1": nil,
+	// Go Daddy Class 2 Certification Authority & Go Daddy Root Certificate Authority - G2
+	// https://www.godaddy.com/
+	// https://valid.gdig2.catest.godaddy.com/
+	"2.16.840.1.114413.1.7.23.3": nil,
+	// Izenpe.com - SHA256 root
+	// The first OID is for businesses and the second for government entities.
+	// These are the test sites, respectively:
+	// https://servicios.izenpe.com
+	// https://servicios1.izenpe.com
+	// Windows XP finds this, SHA1, root instead. The policy OIDs are the same
+	// as for the SHA256 root, above.
+	"1.3.6.1.4.1.14777.6.1.1": nil,
+	"1.3.6.1.4.1.14777.6.1.2": nil,
+	// Network Solutions Certificate Authority
+	// https://www.networksolutions.com/website-packages/index.jsp
+	"1.3.6.1.4.1.782.1.2.1.8.1": nil,
+	// QuoVadis Root CA 2
+	// https://www.quovadis.bm/
+	"1.3.6.1.4.1.8024.0.2.100.1.2": nil,
+	// SecureTrust CA, SecureTrust Corporation
+	// https://www.securetrust.com
+	// https://www.trustwave.com/
+	"2.16.840.1.114404.1.1.2.4.1": nil,
+	// Security Communication RootCA1
+	// https://www.secomtrust.net/contact/form.html
+	"1.2.392.200091.100.721.1": nil,
+	// Staat der Nederlanden EV Root CA
+	// https://pkioevssl-v.quovadisglobal.com/
+	"2.16.528.1.1003.1.2.7": nil,
+	// StartCom Certification Authority
+	// https://www.startssl.com/
+	"1.3.6.1.4.1.23223.1.1.1": nil,
+	// Starfield Class 2 Certification Authority
+	// https://www.starfieldtech.com/
+	"2.16.840.1.114414.1.7.23.3": nil,
+	// Starfield Services Root Certificate Authority - G2
+	// https://valid.sfsg2.catest.starfieldtech.com/
+	"2.16.840.1.114414.1.7.24.3": nil,
+	// SwissSign Gold CA - G2
+	// https://testevg2.swisssign.net/
+	"2.16.756.1.89.1.2.1.1": nil,
+	// Swisscom Root EV CA 2
+	// https://test-quarz-ev-ca-2.pre.swissdigicert.ch
+	"2.16.756.1.83.21.0": nil,
+	// thawte Primary Root CA
+	// https://www.thawte.com/
+	"2.16.840.1.113733.1.7.48.1": nil,
+	// TWCA Global Root CA
+	// https://evssldemo3.twca.com.tw/index.html
+	"1.3.6.1.4.1.40869.1.1.22.3": nil,
+	// T-TeleSec GlobalRoot Class 3
+	// http://www.telesec.de/ / https://root-class3.test.telesec.de/
+	"1.3.6.1.4.1.7879.13.24.1": nil,
+	// VeriSign Class 3 Public Primary Certification Authority - G5
+	// https://www.verisign.com/
+	"2.16.840.1.113733.1.7.23.6": nil,
+	// Wells Fargo WellsSecure Public Root Certificate Authority
+	// https://nerys.wellsfargo.com/test.html
+	"2.16.840.1.114171.500.9": nil,
+	// CN=CFCA EV ROOT,O=China Financial Certification Authority,C=CN
+	// https://www.cfca.com.cn/
+	"2.16.156.112554.3": nil,
+	// CN=OISTE WISeKey Global Root GB CA,OU=OISTE Foundation Endorsed,O=WISeKey,C=CH
+	// https://www.wisekey.com/repository/cacertificates/
+	"2.16.756.5.14.7.4.8": nil,
+	// CN=TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı H6,O=TÜRKTRUST Bilgi İletişim ve Bilişim Güvenliği Hizmetleri A...,L=Ankara,C=TR
+	// https://www.turktrust.com.tr/
+	"2.16.792.3.0.3.1.1.5": nil,
+}
+
+// OrganizationValidationOIDs contains CA specific OV OIDs from
+// https://cabforum.org/object-registry/
+var OrganizationValidationOIDs = map[string]interface{}{
+	// CA/Browser Forum OV OID standard
+	// https://cabforum.org/object-registry/
+	"2.23.140.1.2.2": nil,
+	// CA/Browser Forum individually validated
+	"2.23.140.1.2.3": nil,
+	// Digicert
+	"2.16.840.1.114412.1.1": nil,
+	// D-Trust
+	"1.3.6.1.4.1.4788.2.200.1": nil,
+	// GoDaddy
+	"2.16.840.1.114413.1.7.23.2": nil,
+	// Logius
+	"2.16.528.1.1003.1.2.5.6": nil,
+	// QuoVadis
+	"1.3.6.1.4.1.8024.0.2.100.1.1": nil,
+	// Starfield
+	"2.16.840.1.114414.1.7.23.2": nil,
+	// TurkTrust
+	"2.16.792.3.0.3.1.1.2": nil,
+}
+
+// DomainValidationOIDs contain OIDs that identify DV certs.
+var DomainValidationOIDs = map[string]interface{}{
+	// Globalsign
+	"1.3.6.1.4.1.4146.1.10.10": nil,
+	// Let's Encrypt
+	"1.3.6.1.4.1.44947.1.1.1": nil,
+	// Comodo (eNom)
+	"1.3.6.1.4.1.6449.1.2.2.10": nil,
+	// Comodo (WoTrust)
+	"1.3.6.1.4.1.6449.1.2.2.15": nil,
+	// Comodo (RBC SOFT)
+	"1.3.6.1.4.1.6449.1.2.2.16": nil,
+	// Comodo (RegisterFly)
+	"1.3.6.1.4.1.6449.1.2.2.17": nil,
+	// Comodo (Central Security Patrols)
+	"1.3.6.1.4.1.6449.1.2.2.18": nil,
+	// Comodo (eBiz Networks)
+	"1.3.6.1.4.1.6449.1.2.2.19": nil,
+	// Comodo (OptimumSSL)
+	"1.3.6.1.4.1.6449.1.2.2.21": nil,
+	// Comodo (WoSign)
+	"1.3.6.1.4.1.6449.1.2.2.22": nil,
+	// Comodo (Register.com)
+	"1.3.6.1.4.1.6449.1.2.2.24": nil,
+	// Comodo (The Code Project)
+	"1.3.6.1.4.1.6449.1.2.2.25": nil,
+	// Comodo (Gandi)
+	"1.3.6.1.4.1.6449.1.2.2.26": nil,
+	// Comodo (GlobeSSL)
+	"1.3.6.1.4.1.6449.1.2.2.27": nil,
+	// Comodo (DreamHost)
+	"1.3.6.1.4.1.6449.1.2.2.28": nil,
+	// Comodo (TERENA)
+	"1.3.6.1.4.1.6449.1.2.2.29": nil,
+	// Comodo (GlobalSSL)
+	"1.3.6.1.4.1.6449.1.2.2.31": nil,
+	// Comodo (IceWarp)
+	"1.3.6.1.4.1.6449.1.2.2.35": nil,
+	// Comodo (Dotname Korea)
+	"1.3.6.1.4.1.6449.1.2.2.37": nil,
+	// Comodo (TrustSign)
+	"1.3.6.1.4.1.6449.1.2.2.38": nil,
+	// Comodo (Formidable)
+	"1.3.6.1.4.1.6449.1.2.2.39": nil,
+	// Comodo (SSL Blindado)
+	"1.3.6.1.4.1.6449.1.2.2.40": nil,
+	// Comodo (Dreamscape Networks)
+	"1.3.6.1.4.1.6449.1.2.2.41": nil,
+	// Comodo (K Software)
+	"1.3.6.1.4.1.6449.1.2.2.42": nil,
+	// Comodo (FBS)
+	"1.3.6.1.4.1.6449.1.2.2.44": nil,
+	// Comodo (ReliaSite)
+	"1.3.6.1.4.1.6449.1.2.2.45": nil,
+	// Comodo (CertAssure)
+	"1.3.6.1.4.1.6449.1.2.2.47": nil,
+	// Comodo (TrustAsia)
+	"1.3.6.1.4.1.6449.1.2.2.49": nil,
+	// Comodo (SecureCore)
+	"1.3.6.1.4.1.6449.1.2.2.50": nil,
+	// Comodo (Western Digital)
+	"1.3.6.1.4.1.6449.1.2.2.51": nil,
+	// Comodo (cPanel)
+	"1.3.6.1.4.1.6449.1.2.2.52": nil,
+	// Comodo (BlackCert)
+	"1.3.6.1.4.1.6449.1.2.2.53": nil,
+	// Comodo (KeyNet Systems)
+	"1.3.6.1.4.1.6449.1.2.2.54": nil,
+	// Comodo
+	"1.3.6.1.4.1.6449.1.2.2.7": nil,
+	// Comodo (CSC)
+	"1.3.6.1.4.1.6449.1.2.2.8": nil,
+	// Digicert
+	"2.16.840.1.114412.1.2": nil,
+	// GoDaddy
+	"2.16.840.1.114413.1.7.23.1": nil,
+	// Starfield
+	"2.16.840.1.114414.1.7.23.1": nil,
+	// CA/B Forum
+	"2.23.140.1.2.1": nil,
+}
+
+// TODO pull out other types
+type AuthorityInfoAccess struct {
+	OCSPServer            []string `json:"ocsp_urls,omitempty"`
+	IssuingCertificateURL []string `json:"issuer_urls,omitempty"`
+}
+
+/*
+    id-CABFOrganizationIdentifier OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) international-organizations(23) ca-browser-forum(140) certificate-extensions(3) cabf-organization-identifier(1) }
+
+    ext-CABFOrganizationIdentifier EXTENSION ::= { SYNTAX CABFOrganizationIdentifier IDENTIFIED BY id-CABFOrganizationIdentifier }
+
+    CABFOrganizationIdentifier ::= SEQUENCE {
+
+        registrationSchemeIdentifier   PrintableString (SIZE(3)),
+
+        registrationCountry            PrintableString (SIZE(2)),
+
+        registrationStateOrProvince    [0] IMPLICIT PrintableString OPTIONAL (SIZE(0..128)),
+
+        registrationReference          UTF8String
+
+	}
+*/
+type CABFOrganizationIDASN struct {
+	RegistrationSchemeIdentifier string `asn1:"printable"`
+	RegistrationCountry          string `asn1:"printable"`
+	RegistrationStateOrProvince  string `asn1:"printable,optional,tag:0"`
+	RegistrationReference        string `asn1:"utf8"`
+}
+
+type CABFOrganizationIdentifier struct {
+	Scheme    string `json:"scheme,omitempty"`
+	Country   string `json:"country,omitempty"`
+	State     string `json:"state,omitempty"`
+	Reference string `json:"reference,omitempty"`
+}
+
+func (c *Certificate) jsonifyExtensions() (*CertificateExtensions, UnknownCertificateExtensions) {
+	exts := new(CertificateExtensions)
+	unk := make([]pkix.Extension, 0, 2)
+	for _, e := range c.Extensions {
+		if e.Id.Equal(oidExtKeyUsage) {
+			exts.KeyUsage = c.KeyUsage
+		} else if e.Id.Equal(oidExtBasicConstraints) {
+			exts.BasicConstraints = new(BasicConstraints)
+			exts.BasicConstraints.IsCA = c.IsCA
+			if c.MaxPathLen > 0 || c.MaxPathLenZero {
+				exts.BasicConstraints.MaxPathLen = new(int)
+				*exts.BasicConstraints.MaxPathLen = c.MaxPathLen
+			}
+		} else if e.Id.Equal(oidExtSubjectAltName) {
+			exts.SubjectAltName = new(GeneralNames)
+			exts.SubjectAltName.DirectoryNames = c.DirectoryNames
+			exts.SubjectAltName.DNSNames = c.DNSNames
+			exts.SubjectAltName.EDIPartyNames = c.EDIPartyNames
+			exts.SubjectAltName.EmailAddresses = c.EmailAddresses
+			exts.SubjectAltName.IPAddresses = c.IPAddresses
+			exts.SubjectAltName.OtherNames = c.OtherNames
+			exts.SubjectAltName.RegisteredIDs = c.RegisteredIDs
+			exts.SubjectAltName.URIs = c.URIs
+		} else if e.Id.Equal(oidExtIssuerAltName) {
+			exts.IssuerAltName = new(GeneralNames)
+			exts.IssuerAltName.DirectoryNames = c.IANDirectoryNames
+			exts.IssuerAltName.DNSNames = c.IANDNSNames
+			exts.IssuerAltName.EDIPartyNames = c.IANEDIPartyNames
+			exts.IssuerAltName.EmailAddresses = c.IANEmailAddresses
+			exts.IssuerAltName.IPAddresses = c.IANIPAddresses
+			exts.IssuerAltName.OtherNames = c.IANOtherNames
+			exts.IssuerAltName.RegisteredIDs = c.IANRegisteredIDs
+			exts.IssuerAltName.URIs = c.IANURIs
+		} else if e.Id.Equal(oidExtNameConstraints) {
+			exts.NameConstraints = new(NameConstraints)
+			exts.NameConstraints.Critical = c.NameConstraintsCritical
+
+			exts.NameConstraints.PermittedDNSNames = c.PermittedDNSNames
+			exts.NameConstraints.PermittedEmailAddresses = c.PermittedEmailAddresses
+			exts.NameConstraints.PermittedURIs = c.PermittedURIs
+			exts.NameConstraints.PermittedIPAddresses = c.PermittedIPAddresses
+			exts.NameConstraints.PermittedDirectoryNames = c.PermittedDirectoryNames
+			exts.NameConstraints.PermittedEdiPartyNames = c.PermittedEdiPartyNames
+			exts.NameConstraints.PermittedRegisteredIDs = c.PermittedRegisteredIDs
+
+			exts.NameConstraints.ExcludedEmailAddresses = c.ExcludedEmailAddresses
+			exts.NameConstraints.ExcludedDNSNames = c.ExcludedDNSNames
+			exts.NameConstraints.ExcludedURIs = c.ExcludedURIs
+			exts.NameConstraints.ExcludedIPAddresses = c.ExcludedIPAddresses
+			exts.NameConstraints.ExcludedDirectoryNames = c.ExcludedDirectoryNames
+			exts.NameConstraints.ExcludedEdiPartyNames = c.ExcludedEdiPartyNames
+			exts.NameConstraints.ExcludedRegisteredIDs = c.ExcludedRegisteredIDs
+		} else if e.Id.Equal(oidCRLDistributionPoints) {
+			exts.CRLDistributionPoints = c.CRLDistributionPoints
+		} else if e.Id.Equal(oidExtAuthKeyId) {
+			exts.AuthKeyID = c.AuthorityKeyId
+		} else if e.Id.Equal(oidExtExtendedKeyUsage) {
+			exts.ExtendedKeyUsage = new(ExtendedKeyUsageExtension)
+			exts.ExtendedKeyUsage.Known = c.ExtKeyUsage
+			exts.ExtendedKeyUsage.Unknown = c.UnknownExtKeyUsage
+		} else if e.Id.Equal(oidExtCertificatePolicy) {
+			exts.CertificatePolicies = new(CertificatePoliciesData)
+			exts.CertificatePolicies.PolicyIdentifiers = c.PolicyIdentifiers
+			exts.CertificatePolicies.NoticeRefNumbers = c.NoticeRefNumbers
+			exts.CertificatePolicies.NoticeRefOrganization = c.ParsedNoticeRefOrganization
+			exts.CertificatePolicies.ExplicitTexts = c.ParsedExplicitTexts
+			exts.CertificatePolicies.QualifierId = c.QualifierId
+			exts.CertificatePolicies.CPSUri = c.CPSuri
+
+		} else if e.Id.Equal(oidExtAuthorityInfoAccess) {
+			exts.AuthorityInfoAccess = new(AuthorityInfoAccess)
+			exts.AuthorityInfoAccess.OCSPServer = c.OCSPServer
+			exts.AuthorityInfoAccess.IssuingCertificateURL = c.IssuingCertificateURL
+		} else if e.Id.Equal(oidExtSubjectKeyId) {
+			exts.SubjectKeyID = c.SubjectKeyId
+		} else if e.Id.Equal(oidExtSignedCertificateTimestampList) {
+			exts.SignedCertificateTimestampList = c.SignedCertificateTimestampList
+		} else if e.Id.Equal(oidExtensionCTPrecertificatePoison) {
+			exts.IsPrecert = true
+		} else if e.Id.Equal(oidBRTorServiceDescriptor) {
+			exts.TorServiceDescriptors = c.TorServiceDescriptors
+		} else if e.Id.Equal(oidExtCABFOrganizationID) {
+			exts.CABFOrganizationIdentifier = c.CABFOrganizationIdentifier
+		} else if e.Id.Equal(oidExtQCStatements) {
+			exts.QCStatements = c.QCStatements
+		} else {
+			// Unknown extension
+			unk = append(unk, e)
+		}
+	}
+	return exts, unk
+}

+ 61 - 0
vendor/github.com/zmap/zcrypto/x509/fingerprint.go

@@ -0,0 +1,61 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+	"bytes"
+	"crypto/md5"
+	"crypto/sha1"
+	"crypto/sha256"
+	"crypto/sha512"
+	"encoding/hex"
+	"encoding/json"
+)
+
+// CertificateFingerprint represents a digest/fingerprint of some data. It can
+// easily be encoded to hex and JSON (as a hex string).
+type CertificateFingerprint []byte
+
+// MD5Fingerprint creates a fingerprint of data using the MD5 hash algorithm.
+func MD5Fingerprint(data []byte) CertificateFingerprint {
+	sum := md5.Sum(data)
+	return sum[:]
+}
+
+// SHA1Fingerprint creates a fingerprint of data using the SHA1 hash algorithm.
+func SHA1Fingerprint(data []byte) CertificateFingerprint {
+	sum := sha1.Sum(data)
+	return sum[:]
+}
+
+// SHA256Fingerprint creates a fingerprint of data using the SHA256 hash
+// algorithm.
+func SHA256Fingerprint(data []byte) CertificateFingerprint {
+	sum := sha256.Sum256(data)
+	return sum[:]
+}
+
+// SHA512Fingerprint creates a fingerprint of data using the SHA256 hash
+// algorithm.
+func SHA512Fingerprint(data []byte) CertificateFingerprint {
+	sum := sha512.Sum512(data)
+	return sum[:]
+}
+
+// Equal returns true if the fingerprints are bytewise-equal.
+func (f CertificateFingerprint) Equal(other CertificateFingerprint) bool {
+	return bytes.Equal(f, other)
+}
+
+// Hex returns the given fingerprint encoded as a hex string.
+func (f CertificateFingerprint) Hex() string {
+	return hex.EncodeToString(f)
+}
+
+// MarshalJSON implements the json.Marshaler interface, and marshals the
+// fingerprint as a hex string.
+func (f *CertificateFingerprint) MarshalJSON() ([]byte, error) {
+	return json.Marshal(f.Hex())
+}

+ 16 - 0
vendor/github.com/zmap/zcrypto/x509/generated_certvalidationlevel_string.go

@@ -0,0 +1,16 @@
+// Code generated by "stringer -type=CertValidationLevel -output=generated_certvalidationlevel_string.go"; DO NOT EDIT.
+
+package x509
+
+import "strconv"
+
+const _CertValidationLevel_name = "UnknownValidationLevelDVOVEV"
+
+var _CertValidationLevel_index = [...]uint8{0, 22, 24, 26, 28}
+
+func (i CertValidationLevel) String() string {
+	if i < 0 || i >= CertValidationLevel(len(_CertValidationLevel_index)-1) {
+		return "CertValidationLevel(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+	return _CertValidationLevel_name[_CertValidationLevel_index[i]:_CertValidationLevel_index[i+1]]
+}

+ 652 - 0
vendor/github.com/zmap/zcrypto/x509/json.go

@@ -0,0 +1,652 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+	"crypto/ecdsa"
+	"crypto/rsa"
+	"encoding/asn1"
+	"encoding/json"
+	"errors"
+	"net"
+	"sort"
+
+	"github.com/zmap/zcrypto/dsa"
+
+	"strings"
+	"time"
+
+	jsonKeys "github.com/zmap/zcrypto/json"
+	"github.com/zmap/zcrypto/util"
+	"github.com/zmap/zcrypto/x509/pkix"
+)
+
+var kMinTime, kMaxTime time.Time
+
+func init() {
+	var err error
+	kMinTime, err = time.Parse(time.RFC3339, "1970-01-01T00:00:00Z")
+	if err != nil {
+		panic(err)
+	}
+	kMaxTime, err = time.Parse(time.RFC3339, "9999-12-31T23:59:59Z")
+	if err != nil {
+		panic(err)
+	}
+}
+
+type auxKeyUsage struct {
+	DigitalSignature  bool   `json:"digital_signature,omitempty"`
+	ContentCommitment bool   `json:"content_commitment,omitempty"`
+	KeyEncipherment   bool   `json:"key_encipherment,omitempty"`
+	DataEncipherment  bool   `json:"data_encipherment,omitempty"`
+	KeyAgreement      bool   `json:"key_agreement,omitempty"`
+	CertificateSign   bool   `json:"certificate_sign,omitempty"`
+	CRLSign           bool   `json:"crl_sign,omitempty"`
+	EncipherOnly      bool   `json:"encipher_only,omitempty"`
+	DecipherOnly      bool   `json:"decipher_only,omitempty"`
+	Value             uint32 `json:"value"`
+}
+
+// MarshalJSON implements the json.Marshaler interface
+func (k KeyUsage) MarshalJSON() ([]byte, error) {
+	var enc auxKeyUsage
+	enc.Value = uint32(k)
+	if k&KeyUsageDigitalSignature > 0 {
+		enc.DigitalSignature = true
+	}
+	if k&KeyUsageContentCommitment > 0 {
+		enc.ContentCommitment = true
+	}
+	if k&KeyUsageKeyEncipherment > 0 {
+		enc.KeyEncipherment = true
+	}
+	if k&KeyUsageDataEncipherment > 0 {
+		enc.DataEncipherment = true
+	}
+	if k&KeyUsageKeyAgreement > 0 {
+		enc.KeyAgreement = true
+	}
+	if k&KeyUsageCertSign > 0 {
+		enc.CertificateSign = true
+	}
+	if k&KeyUsageCRLSign > 0 {
+		enc.CRLSign = true
+	}
+	if k&KeyUsageEncipherOnly > 0 {
+		enc.EncipherOnly = true
+	}
+	if k&KeyUsageDecipherOnly > 0 {
+		enc.DecipherOnly = true
+	}
+	return json.Marshal(&enc)
+}
+
+// UnmarshalJSON implements the json.Unmarshler interface
+func (k *KeyUsage) UnmarshalJSON(b []byte) error {
+	var aux auxKeyUsage
+	if err := json.Unmarshal(b, &aux); err != nil {
+		return err
+	}
+	// TODO: validate the flags match
+	v := int(aux.Value)
+	*k = KeyUsage(v)
+	return nil
+}
+
+// JSONSignatureAlgorithm is the intermediate type
+// used when marshaling a PublicKeyAlgorithm out to JSON.
+type JSONSignatureAlgorithm struct {
+	Name string      `json:"name,omitempty"`
+	OID  pkix.AuxOID `json:"oid"`
+}
+
+// MarshalJSON implements the json.Marshaler interface
+// MAY NOT PRESERVE ORIGINAL OID FROM CERTIFICATE -
+// CONSIDER USING jsonifySignatureAlgorithm INSTEAD!
+func (s *SignatureAlgorithm) MarshalJSON() ([]byte, error) {
+	aux := JSONSignatureAlgorithm{
+		Name: s.String(),
+	}
+	for _, val := range signatureAlgorithmDetails {
+		if val.algo == *s {
+			aux.OID = make([]int, len(val.oid))
+			for idx := range val.oid {
+				aux.OID[idx] = val.oid[idx]
+			}
+		}
+	}
+	return json.Marshal(&aux)
+}
+
+// UnmarshalJSON implements the json.Unmarshler interface
+func (s *SignatureAlgorithm) UnmarshalJSON(b []byte) error {
+	var aux JSONSignatureAlgorithm
+	if err := json.Unmarshal(b, &aux); err != nil {
+		return err
+	}
+	*s = UnknownSignatureAlgorithm
+	oid := asn1.ObjectIdentifier(aux.OID.AsSlice())
+	if oid.Equal(oidSignatureRSAPSS) {
+		pssAlgs := []SignatureAlgorithm{SHA256WithRSAPSS, SHA384WithRSAPSS, SHA512WithRSAPSS}
+		for _, alg := range pssAlgs {
+			if strings.Compare(alg.String(), aux.Name) == 0 {
+				*s = alg
+				break
+			}
+		}
+	} else {
+		for _, val := range signatureAlgorithmDetails {
+			if val.oid.Equal(oid) {
+				*s = val.algo
+				break
+			}
+		}
+	}
+	return nil
+}
+
+// jsonifySignatureAlgorithm gathers the necessary fields in a Certificate
+// into a JSONSignatureAlgorithm, which can then use the default
+// JSON marhsalers and unmarshalers. THIS FUNCTION IS PREFERED OVER
+// THE CUSTOM JSON MARSHALER PRESENTED ABOVE FOR SIGNATUREALGORITHM
+// BECAUSE THIS METHOD PRESERVES THE OID ORIGINALLY IN THE CERTIFICATE!
+// This reason also explains why we need this function -
+// the OID is unfortunately stored outside the scope of a
+// SignatureAlgorithm struct and cannot be recovered without access to the
+// entire Certificate if we do not know the signature algorithm.
+func (c *Certificate) jsonifySignatureAlgorithm() JSONSignatureAlgorithm {
+	aux := JSONSignatureAlgorithm{}
+	if c.SignatureAlgorithm == 0 {
+		aux.Name = "unknown_algorithm"
+	} else {
+		aux.Name = c.SignatureAlgorithm.String()
+	}
+	aux.OID = make([]int, len(c.SignatureAlgorithmOID))
+	for idx := range c.SignatureAlgorithmOID {
+		aux.OID[idx] = c.SignatureAlgorithmOID[idx]
+	}
+	return aux
+}
+
+type auxPublicKeyAlgorithm struct {
+	Name string       `json:"name,omitempty"`
+	OID  *pkix.AuxOID `json:"oid,omitempty"`
+}
+
+var publicKeyNameToAlgorithm = map[string]PublicKeyAlgorithm{
+	"RSA":   RSA,
+	"DSA":   DSA,
+	"ECDSA": ECDSA,
+}
+
+// MarshalJSON implements the json.Marshaler interface
+func (p *PublicKeyAlgorithm) MarshalJSON() ([]byte, error) {
+	aux := auxPublicKeyAlgorithm{
+		Name: p.String(),
+	}
+	return json.Marshal(&aux)
+}
+
+// UnmarshalJSON implements the json.Unmarshaler interface
+func (p *PublicKeyAlgorithm) UnmarshalJSON(b []byte) error {
+	var aux auxPublicKeyAlgorithm
+	if err := json.Unmarshal(b, &aux); err != nil {
+		return err
+	}
+	*p = publicKeyNameToAlgorithm[aux.Name]
+	return nil
+}
+
+func clampTime(t time.Time) time.Time {
+	if t.Before(kMinTime) {
+		return kMinTime
+	}
+	if t.After(kMaxTime) {
+		return kMaxTime
+	}
+	return t
+}
+
+type auxValidity struct {
+	Start          string `json:"start"`
+	End            string `json:"end"`
+	ValidityPeriod int    `json:"length"`
+}
+
+func (v *validity) MarshalJSON() ([]byte, error) {
+	aux := auxValidity{
+		Start:          clampTime(v.NotBefore.UTC()).Format(time.RFC3339),
+		End:            clampTime(v.NotAfter.UTC()).Format(time.RFC3339),
+		ValidityPeriod: int(v.NotAfter.Sub(v.NotBefore).Seconds()),
+	}
+	return json.Marshal(&aux)
+}
+
+func (v *validity) UnmarshalJSON(b []byte) error {
+	var aux auxValidity
+	if err := json.Unmarshal(b, &aux); err != nil {
+		return err
+	}
+	var err error
+	if v.NotBefore, err = time.Parse(time.RFC3339, aux.Start); err != nil {
+		return err
+	}
+	if v.NotAfter, err = time.Parse(time.RFC3339, aux.End); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// ECDSAPublicKeyJSON - used to condense several fields from a
+// ECDSA public key into one field for use in JSONCertificate.
+// Uses default JSON marshal and unmarshal methods
+type ECDSAPublicKeyJSON struct {
+	B      []byte `json:"b"`
+	Curve  string `json:"curve"`
+	Gx     []byte `json:"gx"`
+	Gy     []byte `json:"gy"`
+	Length int    `json:"length"`
+	N      []byte `json:"n"`
+	P      []byte `json:"p"`
+	Pub    []byte `json:"pub,omitempty"`
+	X      []byte `json:"x"`
+	Y      []byte `json:"y"`
+}
+
+// DSAPublicKeyJSON - used to condense several fields from a
+// DSA public key into one field for use in JSONCertificate.
+// Uses default JSON marshal and unmarshal methods
+type DSAPublicKeyJSON struct {
+	G []byte `json:"g"`
+	P []byte `json:"p"`
+	Q []byte `json:"q"`
+	Y []byte `json:"y"`
+}
+
+// GetDSAPublicKeyJSON - get the DSAPublicKeyJSON for the given standard DSA PublicKey.
+func GetDSAPublicKeyJSON(key *dsa.PublicKey) *DSAPublicKeyJSON {
+	return &DSAPublicKeyJSON{
+		P: key.P.Bytes(),
+		Q: key.Q.Bytes(),
+		G: key.G.Bytes(),
+		Y: key.Y.Bytes(),
+	}
+}
+
+// GetRSAPublicKeyJSON - get the jsonKeys.RSAPublicKey for the given standard RSA PublicKey.
+func GetRSAPublicKeyJSON(key *rsa.PublicKey) *jsonKeys.RSAPublicKey {
+	rsaKey := new(jsonKeys.RSAPublicKey)
+	rsaKey.PublicKey = key
+	return rsaKey
+}
+
+// GetECDSAPublicKeyJSON - get the GetECDSAPublicKeyJSON for the given standard ECDSA PublicKey.
+func GetECDSAPublicKeyJSON(key *ecdsa.PublicKey) *ECDSAPublicKeyJSON {
+	params := key.Params()
+	return &ECDSAPublicKeyJSON{
+		P:      params.P.Bytes(),
+		N:      params.N.Bytes(),
+		B:      params.B.Bytes(),
+		Gx:     params.Gx.Bytes(),
+		Gy:     params.Gy.Bytes(),
+		X:      key.X.Bytes(),
+		Y:      key.Y.Bytes(),
+		Curve:  key.Curve.Params().Name,
+		Length: key.Curve.Params().BitSize,
+	}
+}
+
+// GetAugmentedECDSAPublicKeyJSON - get the GetECDSAPublicKeyJSON for the given "augmented"
+// ECDSA PublicKey.
+func GetAugmentedECDSAPublicKeyJSON(key *AugmentedECDSA) *ECDSAPublicKeyJSON {
+	params := key.Pub.Params()
+	return &ECDSAPublicKeyJSON{
+		P:      params.P.Bytes(),
+		N:      params.N.Bytes(),
+		B:      params.B.Bytes(),
+		Gx:     params.Gx.Bytes(),
+		Gy:     params.Gy.Bytes(),
+		X:      key.Pub.X.Bytes(),
+		Y:      key.Pub.Y.Bytes(),
+		Curve:  key.Pub.Curve.Params().Name,
+		Length: key.Pub.Curve.Params().BitSize,
+		Pub:    key.Raw.Bytes,
+	}
+}
+
+// jsonifySubjectKey - Convert public key data in a Certificate
+// into json output format for JSONCertificate
+func (c *Certificate) jsonifySubjectKey() JSONSubjectKeyInfo {
+	j := JSONSubjectKeyInfo{
+		KeyAlgorithm:    c.PublicKeyAlgorithm,
+		SPKIFingerprint: c.SPKIFingerprint,
+	}
+
+	switch key := c.PublicKey.(type) {
+	case *rsa.PublicKey:
+		rsaKey := new(jsonKeys.RSAPublicKey)
+		rsaKey.PublicKey = key
+		j.RSAPublicKey = rsaKey
+	case *dsa.PublicKey:
+		j.DSAPublicKey = &DSAPublicKeyJSON{
+			P: key.P.Bytes(),
+			Q: key.Q.Bytes(),
+			G: key.G.Bytes(),
+			Y: key.Y.Bytes(),
+		}
+	case *ecdsa.PublicKey:
+		params := key.Params()
+		j.ECDSAPublicKey = &ECDSAPublicKeyJSON{
+			P:      params.P.Bytes(),
+			N:      params.N.Bytes(),
+			B:      params.B.Bytes(),
+			Gx:     params.Gx.Bytes(),
+			Gy:     params.Gy.Bytes(),
+			X:      key.X.Bytes(),
+			Y:      key.Y.Bytes(),
+			Curve:  key.Curve.Params().Name,
+			Length: key.Curve.Params().BitSize,
+		}
+	case *AugmentedECDSA:
+		params := key.Pub.Params()
+		j.ECDSAPublicKey = &ECDSAPublicKeyJSON{
+			P:      params.P.Bytes(),
+			N:      params.N.Bytes(),
+			B:      params.B.Bytes(),
+			Gx:     params.Gx.Bytes(),
+			Gy:     params.Gy.Bytes(),
+			X:      key.Pub.X.Bytes(),
+			Y:      key.Pub.Y.Bytes(),
+			Curve:  key.Pub.Curve.Params().Name,
+			Length: key.Pub.Curve.Params().BitSize,
+			Pub:    key.Raw.Bytes,
+		}
+	}
+	return j
+}
+
+// JSONSubjectKeyInfo - used to condense several fields from x509.Certificate
+// related to the subject public key into one field within JSONCertificate
+// Unfortunately, this struct cannot have its own Marshal method since it
+// needs information from multiple fields in x509.Certificate
+type JSONSubjectKeyInfo struct {
+	KeyAlgorithm    PublicKeyAlgorithm     `json:"key_algorithm"`
+	RSAPublicKey    *jsonKeys.RSAPublicKey `json:"rsa_public_key,omitempty"`
+	DSAPublicKey    *DSAPublicKeyJSON      `json:"dsa_public_key,omitempty"`
+	ECDSAPublicKey  *ECDSAPublicKeyJSON    `json:"ecdsa_public_key,omitempty"`
+	SPKIFingerprint CertificateFingerprint `json:"fingerprint_sha256"`
+}
+
+// JSONSignature - used to condense several fields from x509.Certificate
+// related to the signature into one field within JSONCertificate
+// Unfortunately, this struct cannot have its own Marshal method since it
+// needs information from multiple fields in x509.Certificate
+type JSONSignature struct {
+	SignatureAlgorithm JSONSignatureAlgorithm `json:"signature_algorithm"`
+	Value              []byte                 `json:"value"`
+	Valid              bool                   `json:"valid"`
+	SelfSigned         bool                   `json:"self_signed"`
+}
+
+// JSONValidity - used to condense several fields related
+// to validity in x509.Certificate into one field within JSONCertificate
+// Unfortunately, this struct cannot have its own Marshal method since it
+// needs information from multiple fields in x509.Certificate
+type JSONValidity struct {
+	validity
+	ValidityPeriod int
+}
+
+// JSONCertificate - used to condense data from x509.Certificate when marhsaling
+// into JSON. This struct has a distinct and independent layout from
+// x509.Certificate, mostly for condensing data across repetitive
+// fields and making it more presentable.
+type JSONCertificate struct {
+	Version                   int                          `json:"version"`
+	SerialNumber              string                       `json:"serial_number"`
+	SignatureAlgorithm        JSONSignatureAlgorithm       `json:"signature_algorithm"`
+	Issuer                    pkix.Name                    `json:"issuer"`
+	IssuerDN                  string                       `json:"issuer_dn,omitempty"`
+	Validity                  JSONValidity                 `json:"validity"`
+	Subject                   pkix.Name                    `json:"subject"`
+	SubjectDN                 string                       `json:"subject_dn,omitempty"`
+	SubjectKeyInfo            JSONSubjectKeyInfo           `json:"subject_key_info"`
+	Extensions                *CertificateExtensions       `json:"extensions,omitempty"`
+	UnknownExtensions         UnknownCertificateExtensions `json:"unknown_extensions,omitempty"`
+	Signature                 JSONSignature                `json:"signature"`
+	FingerprintMD5            CertificateFingerprint       `json:"fingerprint_md5"`
+	FingerprintSHA1           CertificateFingerprint       `json:"fingerprint_sha1"`
+	FingerprintSHA256         CertificateFingerprint       `json:"fingerprint_sha256"`
+	FingerprintNoCT           CertificateFingerprint       `json:"tbs_noct_fingerprint"`
+	SPKISubjectFingerprint    CertificateFingerprint       `json:"spki_subject_fingerprint"`
+	TBSCertificateFingerprint CertificateFingerprint       `json:"tbs_fingerprint"`
+	ValidationLevel           CertValidationLevel          `json:"validation_level"`
+	Names                     []string                     `json:"names,omitempty"`
+	Redacted                  bool                         `json:"redacted"`
+}
+
+// CollectAllNames - Collect and validate all DNS / URI / IP Address names for a given certificate
+func (c *Certificate) CollectAllNames() []string {
+	var names []string
+
+	if isValidName(c.Subject.CommonName) {
+		names = append(names, c.Subject.CommonName)
+	}
+
+	for _, name := range c.DNSNames {
+		if isValidName(name) {
+			names = append(names, name)
+		} else if !strings.Contains(name, ".") { //just a TLD
+			names = append(names, name)
+		}
+
+	}
+
+	for _, name := range c.URIs {
+		if util.IsURL(name) {
+			names = append(names, name)
+		}
+	}
+
+	for _, name := range c.IPAddresses {
+		str := name.String()
+		if util.IsURL(str) {
+			names = append(names, str)
+		}
+	}
+
+	return purgeNameDuplicates(names)
+}
+
+func (c *Certificate) MarshalJSON() ([]byte, error) {
+	// Fill out the certificate
+	jc := new(JSONCertificate)
+	jc.Version = c.Version
+	jc.SerialNumber = c.SerialNumber.String()
+	jc.Issuer = c.Issuer
+	jc.IssuerDN = c.Issuer.String()
+
+	jc.Validity.NotBefore = c.NotBefore
+	jc.Validity.NotAfter = c.NotAfter
+	jc.Validity.ValidityPeriod = c.ValidityPeriod
+	jc.Subject = c.Subject
+	jc.SubjectDN = c.Subject.String()
+	jc.Names = c.CollectAllNames()
+	jc.Redacted = false
+	for _, name := range jc.Names {
+		if strings.HasPrefix(name, "?") {
+			jc.Redacted = true
+		}
+	}
+
+	jc.SubjectKeyInfo = c.jsonifySubjectKey()
+	jc.Extensions, jc.UnknownExtensions = c.jsonifyExtensions()
+
+	// TODO: Handle the fact this might not match
+	jc.SignatureAlgorithm = c.jsonifySignatureAlgorithm()
+	jc.Signature.SignatureAlgorithm = jc.SignatureAlgorithm
+	jc.Signature.Value = c.Signature
+	jc.Signature.Valid = c.validSignature
+	jc.Signature.SelfSigned = c.SelfSigned
+	if c.SelfSigned {
+		jc.Signature.Valid = true
+	}
+	jc.FingerprintMD5 = c.FingerprintMD5
+	jc.FingerprintSHA1 = c.FingerprintSHA1
+	jc.FingerprintSHA256 = c.FingerprintSHA256
+	jc.FingerprintNoCT = c.FingerprintNoCT
+	jc.SPKISubjectFingerprint = c.SPKISubjectFingerprint
+	jc.TBSCertificateFingerprint = c.TBSCertificateFingerprint
+	jc.ValidationLevel = c.ValidationLevel
+
+	return json.Marshal(jc)
+}
+
+// UnmarshalJSON - intentionally implimented to always error,
+// as this method should not be used. The MarshalJSON method
+// on Certificate condenses data in a way that is not recoverable.
+// Use the x509.ParseCertificate function instead or
+// JSONCertificateWithRaw Marshal method
+func (jc *JSONCertificate) UnmarshalJSON(b []byte) error {
+	return errors.New("Do not unmarshal cert JSON directly, use JSONCertificateWithRaw or x509.ParseCertificate function")
+}
+
+// UnmarshalJSON - intentionally implimented to always error,
+// as this method should not be used. The MarshalJSON method
+// on Certificate condenses data in a way that is not recoverable.
+// Use the x509.ParseCertificate function instead or
+// JSONCertificateWithRaw Marshal method
+func (c *Certificate) UnmarshalJSON(b []byte) error {
+	return errors.New("Do not unmarshal cert JSON directly, use JSONCertificateWithRaw or x509.ParseCertificate function")
+}
+
+// JSONCertificateWithRaw - intermediate struct for unmarshaling json
+// of a certificate - the raw is require since the
+// MarshalJSON method on Certificate condenses data in a way that
+// makes extraction to the original in Unmarshal impossible.
+// The JSON output of Marshal is not even used to construct
+// a certificate, all we need is raw
+type JSONCertificateWithRaw struct {
+	Raw []byte `json:"raw,omitempty"`
+}
+
+// ParseRaw - for converting the intermediate object
+// JSONCertificateWithRaw into a parsed Certificate
+// see description of JSONCertificateWithRaw for
+// why this is used instead of UnmarshalJSON methods
+func (c *JSONCertificateWithRaw) ParseRaw() (*Certificate, error) {
+	return ParseCertificate(c.Raw)
+}
+
+func purgeNameDuplicates(names []string) (out []string) {
+	hashset := make(map[string]bool, len(names))
+	for _, name := range names {
+		if _, inc := hashset[name]; !inc {
+			hashset[name] = true
+		}
+	}
+
+	out = make([]string, 0, len(hashset))
+	for key := range hashset {
+		out = append(out, key)
+	}
+
+	sort.Strings(out) // must sort to ensure output is deterministic!
+	return
+}
+
+func isValidName(name string) (ret bool) {
+
+	// Check for wildcards and redacts, ignore malformed urls
+	if strings.HasPrefix(name, "?.") || strings.HasPrefix(name, "*.") {
+		ret = isValidName(name[2:])
+	} else {
+		ret = util.IsURL(name)
+	}
+	return
+}
+
+func orMask(ip net.IP, mask net.IPMask) net.IP {
+	if len(ip) == 0 || len(mask) == 0 {
+		return nil
+	}
+	if len(ip) != net.IPv4len && len(ip) != net.IPv6len {
+		return nil
+	}
+	if len(ip) != len(mask) {
+		return nil
+	}
+	out := make([]byte, len(ip))
+	for idx := range ip {
+		out[idx] = ip[idx] | mask[idx]
+	}
+	return out
+}
+
+func invertMask(mask net.IPMask) net.IPMask {
+	if mask == nil {
+		return nil
+	}
+	out := make([]byte, len(mask))
+	for idx := range mask {
+		out[idx] = ^mask[idx]
+	}
+	return out
+}
+
+type auxGeneralSubtreeIP struct {
+	CIDR  string `json:"cidr,omitempty"`
+	Begin string `json:"begin,omitempty"`
+	End   string `json:"end,omitempty"`
+	Mask  string `json:"mask,omitempty"`
+}
+
+func (g *GeneralSubtreeIP) MarshalJSON() ([]byte, error) {
+	aux := auxGeneralSubtreeIP{}
+	aux.CIDR = g.Data.String()
+	// Check to see if the subnet is valid. An invalid subnet will return 0,0
+	// from Size(). If the subnet is invalid, only output the CIDR.
+	ones, bits := g.Data.Mask.Size()
+	if ones == 0 && bits == 0 {
+		return json.Marshal(&aux)
+	}
+	// The first IP in the range should be `ip & mask`.
+	begin := g.Data.IP.Mask(g.Data.Mask)
+	if begin != nil {
+		aux.Begin = begin.String()
+	}
+	// The last IP (inclusive) is `ip & (^mask)`.
+	inverseMask := invertMask(g.Data.Mask)
+	end := orMask(g.Data.IP, inverseMask)
+	if end != nil {
+		aux.End = end.String()
+	}
+	// Output the mask as an IP, but enforce it can be formatted correctly.
+	// net.IP.String() only works on byte arrays of the correct length.
+	maskLen := len(g.Data.Mask)
+	if maskLen == net.IPv4len || maskLen == net.IPv6len {
+		maskAsIP := net.IP(g.Data.Mask)
+		aux.Mask = maskAsIP.String()
+	}
+	return json.Marshal(&aux)
+}
+
+func (g *GeneralSubtreeIP) UnmarshalJSON(b []byte) error {
+	aux := auxGeneralSubtreeIP{}
+	if err := json.Unmarshal(b, &aux); err != nil {
+		return err
+	}
+	ip, ipNet, err := net.ParseCIDR(aux.CIDR)
+	if err != nil {
+		return err
+	}
+	g.Data.IP = ip
+	g.Data.Mask = ipNet.Mask
+	g.Min = 0
+	g.Max = 0
+	return nil
+}

+ 30 - 0
vendor/github.com/zmap/zcrypto/x509/names.go

@@ -0,0 +1,30 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+func (p PublicKeyAlgorithm) String() string {
+	if p >= total_key_algorithms || p < 0 {
+		p = UnknownPublicKeyAlgorithm
+	}
+	return keyAlgorithmNames[p]
+}
+
+func (c *Certificate) SignatureAlgorithmName() string {
+	switch c.SignatureAlgorithm {
+	case UnknownSignatureAlgorithm:
+		return c.SignatureAlgorithmOID.String()
+	default:
+		return c.SignatureAlgorithm.String()
+	}
+}
+
+func (c *Certificate) PublicKeyAlgorithmName() string {
+	switch c.PublicKeyAlgorithm {
+	case UnknownPublicKeyAlgorithm:
+		return c.PublicKeyAlgorithmOID.String()
+	default:
+		return c.PublicKeyAlgorithm.String()
+	}
+}

+ 240 - 0
vendor/github.com/zmap/zcrypto/x509/pem_decrypt.go

@@ -0,0 +1,240 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+// RFC 1423 describes the encryption of PEM blocks. The algorithm used to
+// generate a key from the password was derived by looking at the OpenSSL
+// implementation.
+
+import (
+	"crypto/aes"
+	"crypto/cipher"
+	"crypto/des"
+	"crypto/md5"
+	"encoding/hex"
+	"encoding/pem"
+	"errors"
+	"io"
+	"strings"
+)
+
+type PEMCipher int
+
+// Possible values for the EncryptPEMBlock encryption algorithm.
+const (
+	_ PEMCipher = iota
+	PEMCipherDES
+	PEMCipher3DES
+	PEMCipherAES128
+	PEMCipherAES192
+	PEMCipherAES256
+)
+
+// rfc1423Algo holds a method for enciphering a PEM block.
+type rfc1423Algo struct {
+	cipher     PEMCipher
+	name       string
+	cipherFunc func(key []byte) (cipher.Block, error)
+	keySize    int
+	blockSize  int
+}
+
+// rfc1423Algos holds a slice of the possible ways to encrypt a PEM
+// block. The ivSize numbers were taken from the OpenSSL source.
+var rfc1423Algos = []rfc1423Algo{{
+	cipher:     PEMCipherDES,
+	name:       "DES-CBC",
+	cipherFunc: des.NewCipher,
+	keySize:    8,
+	blockSize:  des.BlockSize,
+}, {
+	cipher:     PEMCipher3DES,
+	name:       "DES-EDE3-CBC",
+	cipherFunc: des.NewTripleDESCipher,
+	keySize:    24,
+	blockSize:  des.BlockSize,
+}, {
+	cipher:     PEMCipherAES128,
+	name:       "AES-128-CBC",
+	cipherFunc: aes.NewCipher,
+	keySize:    16,
+	blockSize:  aes.BlockSize,
+}, {
+	cipher:     PEMCipherAES192,
+	name:       "AES-192-CBC",
+	cipherFunc: aes.NewCipher,
+	keySize:    24,
+	blockSize:  aes.BlockSize,
+}, {
+	cipher:     PEMCipherAES256,
+	name:       "AES-256-CBC",
+	cipherFunc: aes.NewCipher,
+	keySize:    32,
+	blockSize:  aes.BlockSize,
+},
+}
+
+// deriveKey uses a key derivation function to stretch the password into a key
+// with the number of bits our cipher requires. This algorithm was derived from
+// the OpenSSL source.
+func (c rfc1423Algo) deriveKey(password, salt []byte) []byte {
+	hash := md5.New()
+	out := make([]byte, c.keySize)
+	var digest []byte
+
+	for i := 0; i < len(out); i += len(digest) {
+		hash.Reset()
+		hash.Write(digest)
+		hash.Write(password)
+		hash.Write(salt)
+		digest = hash.Sum(digest[:0])
+		copy(out[i:], digest)
+	}
+	return out
+}
+
+// IsEncryptedPEMBlock returns if the PEM block is password encrypted.
+func IsEncryptedPEMBlock(b *pem.Block) bool {
+	_, ok := b.Headers["DEK-Info"]
+	return ok
+}
+
+// IncorrectPasswordError is returned when an incorrect password is detected.
+var IncorrectPasswordError = errors.New("x509: decryption password incorrect")
+
+// DecryptPEMBlock takes a password encrypted PEM block and the password used to
+// encrypt it and returns a slice of decrypted DER encoded bytes. It inspects
+// the DEK-Info header to determine the algorithm used for decryption. If no
+// DEK-Info header is present, an error is returned. If an incorrect password
+// is detected an IncorrectPasswordError is returned. Because of deficiencies
+// in the encrypted-PEM format, it's not always possible to detect an incorrect
+// password. In these cases no error will be returned but the decrypted DER
+// bytes will be random noise.
+func DecryptPEMBlock(b *pem.Block, password []byte) ([]byte, error) {
+	dek, ok := b.Headers["DEK-Info"]
+	if !ok {
+		return nil, errors.New("x509: no DEK-Info header in block")
+	}
+
+	idx := strings.Index(dek, ",")
+	if idx == -1 {
+		return nil, errors.New("x509: malformed DEK-Info header")
+	}
+
+	mode, hexIV := dek[:idx], dek[idx+1:]
+	ciph := cipherByName(mode)
+	if ciph == nil {
+		return nil, errors.New("x509: unknown encryption mode")
+	}
+	iv, err := hex.DecodeString(hexIV)
+	if err != nil {
+		return nil, err
+	}
+	if len(iv) != ciph.blockSize {
+		return nil, errors.New("x509: incorrect IV size")
+	}
+
+	// Based on the OpenSSL implementation. The salt is the first 8 bytes
+	// of the initialization vector.
+	key := ciph.deriveKey(password, iv[:8])
+	block, err := ciph.cipherFunc(key)
+	if err != nil {
+		return nil, err
+	}
+
+	if len(b.Bytes)%block.BlockSize() != 0 {
+		return nil, errors.New("x509: encrypted PEM data is not a multiple of the block size")
+	}
+
+	data := make([]byte, len(b.Bytes))
+	dec := cipher.NewCBCDecrypter(block, iv)
+	dec.CryptBlocks(data, b.Bytes)
+
+	// Blocks are padded using a scheme where the last n bytes of padding are all
+	// equal to n. It can pad from 1 to blocksize bytes inclusive. See RFC 1423.
+	// For example:
+	//	[x y z 2 2]
+	//	[x y 7 7 7 7 7 7 7]
+	// If we detect a bad padding, we assume it is an invalid password.
+	dlen := len(data)
+	if dlen == 0 || dlen%ciph.blockSize != 0 {
+		return nil, errors.New("x509: invalid padding")
+	}
+	last := int(data[dlen-1])
+	if dlen < last {
+		return nil, IncorrectPasswordError
+	}
+	if last == 0 || last > ciph.blockSize {
+		return nil, IncorrectPasswordError
+	}
+	for _, val := range data[dlen-last:] {
+		if int(val) != last {
+			return nil, IncorrectPasswordError
+		}
+	}
+	return data[:dlen-last], nil
+}
+
+// EncryptPEMBlock returns a PEM block of the specified type holding the
+// given DER-encoded data encrypted with the specified algorithm and
+// password.
+func EncryptPEMBlock(rand io.Reader, blockType string, data, password []byte, alg PEMCipher) (*pem.Block, error) {
+	ciph := cipherByKey(alg)
+	if ciph == nil {
+		return nil, errors.New("x509: unknown encryption mode")
+	}
+	iv := make([]byte, ciph.blockSize)
+	if _, err := io.ReadFull(rand, iv); err != nil {
+		return nil, errors.New("x509: cannot generate IV: " + err.Error())
+	}
+	// The salt is the first 8 bytes of the initialization vector,
+	// matching the key derivation in DecryptPEMBlock.
+	key := ciph.deriveKey(password, iv[:8])
+	block, err := ciph.cipherFunc(key)
+	if err != nil {
+		return nil, err
+	}
+	enc := cipher.NewCBCEncrypter(block, iv)
+	pad := ciph.blockSize - len(data)%ciph.blockSize
+	encrypted := make([]byte, len(data), len(data)+pad)
+	// We could save this copy by encrypting all the whole blocks in
+	// the data separately, but it doesn't seem worth the additional
+	// code.
+	copy(encrypted, data)
+	// See RFC 1423, section 1.1
+	for i := 0; i < pad; i++ {
+		encrypted = append(encrypted, byte(pad))
+	}
+	enc.CryptBlocks(encrypted, encrypted)
+
+	return &pem.Block{
+		Type: blockType,
+		Headers: map[string]string{
+			"Proc-Type": "4,ENCRYPTED",
+			"DEK-Info":  ciph.name + "," + hex.EncodeToString(iv),
+		},
+		Bytes: encrypted,
+	}, nil
+}
+
+func cipherByName(name string) *rfc1423Algo {
+	for i := range rfc1423Algos {
+		alg := &rfc1423Algos[i]
+		if alg.name == name {
+			return alg
+		}
+	}
+	return nil
+}
+
+func cipherByKey(key PEMCipher) *rfc1423Algo {
+	for i := range rfc1423Algos {
+		alg := &rfc1423Algos[i]
+		if alg.cipher == key {
+			return alg
+		}
+	}
+	return nil
+}

+ 121 - 0
vendor/github.com/zmap/zcrypto/x509/pkcs1.go

@@ -0,0 +1,121 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+	"crypto/rsa"
+	"encoding/asn1"
+	"errors"
+	"math/big"
+)
+
+// pkcs1PrivateKey is a structure which mirrors the PKCS#1 ASN.1 for an RSA private key.
+type pkcs1PrivateKey struct {
+	Version int
+	N       *big.Int
+	E       int
+	D       *big.Int
+	P       *big.Int
+	Q       *big.Int
+	// We ignore these values, if present, because rsa will calculate them.
+	Dp   *big.Int `asn1:"optional"`
+	Dq   *big.Int `asn1:"optional"`
+	Qinv *big.Int `asn1:"optional"`
+
+	AdditionalPrimes []pkcs1AdditionalRSAPrime `asn1:"optional,omitempty"`
+}
+
+type pkcs1AdditionalRSAPrime struct {
+	Prime *big.Int
+
+	// We ignore these values because rsa will calculate them.
+	Exp   *big.Int
+	Coeff *big.Int
+}
+
+// pkcs1PublicKey reflects the ASN.1 structure of a PKCS#1 public key.
+type pkcs1PublicKey struct {
+	N *big.Int
+	E int
+}
+
+// ParsePKCS1PrivateKey returns an RSA private key from its ASN.1 PKCS#1 DER encoded form.
+func ParsePKCS1PrivateKey(der []byte) (*rsa.PrivateKey, error) {
+	var priv pkcs1PrivateKey
+	rest, err := asn1.Unmarshal(der, &priv)
+	if len(rest) > 0 {
+		return nil, asn1.SyntaxError{Msg: "trailing data"}
+	}
+	if err != nil {
+		return nil, err
+	}
+
+	if priv.Version > 1 {
+		return nil, errors.New("x509: unsupported private key version")
+	}
+
+	if priv.N.Sign() <= 0 || priv.D.Sign() <= 0 || priv.P.Sign() <= 0 || priv.Q.Sign() <= 0 {
+		return nil, errors.New("x509: private key contains zero or negative value")
+	}
+
+	key := new(rsa.PrivateKey)
+	key.PublicKey = rsa.PublicKey{
+		E: priv.E,
+		N: priv.N,
+	}
+
+	key.D = priv.D
+	key.Primes = make([]*big.Int, 2+len(priv.AdditionalPrimes))
+	key.Primes[0] = priv.P
+	key.Primes[1] = priv.Q
+	for i, a := range priv.AdditionalPrimes {
+		if a.Prime.Sign() <= 0 {
+			return nil, errors.New("x509: private key contains zero or negative prime")
+		}
+		key.Primes[i+2] = a.Prime
+		// We ignore the other two values because rsa will calculate
+		// them as needed.
+	}
+
+	err = key.Validate()
+	if err != nil {
+		return nil, err
+	}
+	key.Precompute()
+
+	return key, nil
+}
+
+// MarshalPKCS1PrivateKey converts a private key to ASN.1 DER encoded form.
+func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte {
+	key.Precompute()
+
+	version := 0
+	if len(key.Primes) > 2 {
+		version = 1
+	}
+
+	priv := pkcs1PrivateKey{
+		Version: version,
+		N:       key.N,
+		E:       key.PublicKey.E,
+		D:       key.D,
+		P:       key.Primes[0],
+		Q:       key.Primes[1],
+		Dp:      key.Precomputed.Dp,
+		Dq:      key.Precomputed.Dq,
+		Qinv:    key.Precomputed.Qinv,
+	}
+
+	priv.AdditionalPrimes = make([]pkcs1AdditionalRSAPrime, len(key.Precomputed.CRTValues))
+	for i, values := range key.Precomputed.CRTValues {
+		priv.AdditionalPrimes[i].Prime = key.Primes[2+i]
+		priv.AdditionalPrimes[i].Exp = values.Exp
+		priv.AdditionalPrimes[i].Coeff = values.Coeff
+	}
+
+	b, _ := asn1.Marshal(priv)
+	return b
+}

+ 54 - 0
vendor/github.com/zmap/zcrypto/x509/pkcs8.go

@@ -0,0 +1,54 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+	"encoding/asn1"
+	"errors"
+	"fmt"
+	"github.com/zmap/zcrypto/x509/pkix"
+)
+
+// pkcs8 reflects an ASN.1, PKCS#8 PrivateKey. See
+// ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-8/pkcs-8v1_2.asn
+// and RFC 5208.
+type pkcs8 struct {
+	Version    int
+	Algo       pkix.AlgorithmIdentifier
+	PrivateKey []byte
+	// optional attributes omitted.
+}
+
+// ParsePKCS8PrivateKey parses an unencrypted, PKCS#8 private key.
+// See RFC 5208.
+func ParsePKCS8PrivateKey(der []byte) (key interface{}, err error) {
+	var privKey pkcs8
+	if _, err := asn1.Unmarshal(der, &privKey); err != nil {
+		return nil, err
+	}
+	switch {
+	case privKey.Algo.Algorithm.Equal(oidPublicKeyRSA):
+		key, err = ParsePKCS1PrivateKey(privKey.PrivateKey)
+		if err != nil {
+			return nil, errors.New("x509: failed to parse RSA private key embedded in PKCS#8: " + err.Error())
+		}
+		return key, nil
+
+	case privKey.Algo.Algorithm.Equal(oidPublicKeyECDSA):
+		bytes := privKey.Algo.Parameters.FullBytes
+		namedCurveOID := new(asn1.ObjectIdentifier)
+		if _, err := asn1.Unmarshal(bytes, namedCurveOID); err != nil {
+			namedCurveOID = nil
+		}
+		key, err = parseECPrivateKey(namedCurveOID, privKey.PrivateKey)
+		if err != nil {
+			return nil, errors.New("x509: failed to parse EC private key embedded in PKCS#8: " + err.Error())
+		}
+		return key, nil
+
+	default:
+		return nil, fmt.Errorf("x509: PKCS#8 wrapping contained private key with unknown algorithm: %v", privKey.Algo.Algorithm)
+	}
+}

+ 279 - 0
vendor/github.com/zmap/zcrypto/x509/pkix/json.go

@@ -0,0 +1,279 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkix
+
+import (
+	"encoding/asn1"
+	"encoding/json"
+	"errors"
+	"strconv"
+	"strings"
+)
+
+type auxAttributeTypeAndValue struct {
+	Type  string `json:"type,omitempty"`
+	Value string `json:"value,omitempty"`
+}
+
+// MarshalJSON implements the json.Marshaler interface.
+func (a *AttributeTypeAndValue) MarshalJSON() ([]byte, error) {
+	aux := auxAttributeTypeAndValue{}
+	aux.Type = a.Type.String()
+	if s, ok := a.Value.(string); ok {
+		aux.Value = s
+	}
+	return json.Marshal(&aux)
+}
+
+// UnmarshalJSON implements the json.Unmarshaler interface.
+func (a *AttributeTypeAndValue) UnmarshalJSON(b []byte) error {
+	aux := auxAttributeTypeAndValue{}
+	if err := json.Unmarshal(b, &aux); err != nil {
+		return err
+	}
+	a.Type = nil
+	if len(aux.Type) > 0 {
+		parts := strings.Split(aux.Type, ".")
+		for _, part := range parts {
+			i, err := strconv.Atoi(part)
+			if err != nil {
+				return err
+			}
+			a.Type = append(a.Type, i)
+		}
+	}
+	a.Value = aux.Value
+	return nil
+}
+
+type auxOtherName struct {
+	ID    string `json:"id,omitempty"`
+	Value []byte `json:"value,omitempty"`
+}
+
+// MarshalJSON implements the json.Marshaler interface.
+func (o *OtherName) MarshalJSON() ([]byte, error) {
+	aux := auxOtherName{
+		ID:    o.TypeID.String(),
+		Value: o.Value.Bytes,
+	}
+	return json.Marshal(&aux)
+}
+
+// UnmarshalJSON implements the json.Unmarshaler interface.
+func (o *OtherName) UnmarshalJSON(b []byte) (err error) {
+	aux := auxOtherName{}
+	if err = json.Unmarshal(b, &aux); err != nil {
+		return
+	}
+
+	// Turn dot-notation back into an OID
+	if len(aux.ID) == 0 {
+		return errors.New("empty type ID")
+	}
+	parts := strings.Split(aux.ID, ".")
+	o.TypeID = nil
+	for _, part := range parts {
+		i, err := strconv.Atoi(part)
+		if err != nil {
+			return err
+		}
+		o.TypeID = append(o.TypeID, i)
+	}
+
+	// Build the ASN.1 value
+	o.Value = asn1.RawValue{
+		Tag:        0,
+		Class:      asn1.ClassContextSpecific,
+		IsCompound: true,
+		Bytes:      aux.Value,
+	}
+	o.Value.FullBytes, err = asn1.Marshal(o.Value)
+	return
+}
+
+type auxExtension struct {
+	ID       string `json:"id,omitempty"`
+	Critical bool   `json:"critical"`
+	Value    []byte `json:"value,omitempty"`
+}
+
+// MarshalJSON implements the json.Marshaler interface.
+func (ext *Extension) MarshalJSON() ([]byte, error) {
+	aux := auxExtension{
+		ID:       ext.Id.String(),
+		Critical: ext.Critical,
+		Value:    ext.Value,
+	}
+	return json.Marshal(&aux)
+}
+
+// UnmarshalJSON implements the json.Unmarshaler interface.
+func (ext *Extension) UnmarshalJSON(b []byte) (err error) {
+	aux := auxExtension{}
+	if err = json.Unmarshal(b, &aux); err != nil {
+		return
+	}
+
+	parts := strings.Split(aux.ID, ".")
+	for _, part := range parts {
+		i, err := strconv.Atoi(part)
+		if err != nil {
+			return err
+		}
+		ext.Id = append(ext.Id, i)
+	}
+	ext.Critical = aux.Critical
+	ext.Value = aux.Value
+	return
+}
+
+type auxName struct {
+	CommonName         []string `json:"common_name,omitempty"`
+	SerialNumber       []string `json:"serial_number,omitempty"`
+	Country            []string `json:"country,omitempty"`
+	Locality           []string `json:"locality,omitempty"`
+	Province           []string `json:"province,omitempty"`
+	StreetAddress      []string `json:"street_address,omitempty"`
+	Organization       []string `json:"organization,omitempty"`
+	OrganizationalUnit []string `json:"organizational_unit,omitempty"`
+	PostalCode         []string `json:"postal_code,omitempty"`
+	DomainComponent    []string `json:"domain_component,omitempty"`
+	EmailAddress       []string `json:"email_address,omitempty"`
+	GivenName          []string `json:"given_name,omitempty"`
+	Surname            []string `json:"surname,omitempty"`
+	// EV
+	JurisdictionCountry  []string `json:"jurisdiction_country,omitempty"`
+	JurisdictionLocality []string `json:"jurisdiction_locality,omitempty"`
+	JurisdictionProvince []string `json:"jurisdiction_province,omitempty"`
+
+	// QWACS
+	OrganizationID []string `json:"organization_id,omitempty"`
+
+	UnknownAttributes []AttributeTypeAndValue `json:"-"`
+}
+
+// MarshalJSON implements the json.Marshaler interface.
+func (n *Name) MarshalJSON() ([]byte, error) {
+	aux := auxName{}
+	attrs := n.ToRDNSequence()
+	for _, attrSet := range attrs {
+		for _, a := range attrSet {
+			s, ok := a.Value.(string)
+			if !ok {
+				continue
+			}
+			if a.Type.Equal(oidCommonName) {
+				aux.CommonName = append(aux.CommonName, s)
+			} else if a.Type.Equal(oidSurname) {
+				aux.Surname = append(aux.Surname, s)
+			} else if a.Type.Equal(oidSerialNumber) {
+				aux.SerialNumber = append(aux.SerialNumber, s)
+			} else if a.Type.Equal(oidCountry) {
+				aux.Country = append(aux.Country, s)
+			} else if a.Type.Equal(oidLocality) {
+				aux.Locality = append(aux.Locality, s)
+			} else if a.Type.Equal(oidProvince) {
+				aux.Province = append(aux.Province, s)
+			} else if a.Type.Equal(oidStreetAddress) {
+				aux.StreetAddress = append(aux.StreetAddress, s)
+			} else if a.Type.Equal(oidOrganization) {
+				aux.Organization = append(aux.Organization, s)
+			} else if a.Type.Equal(oidGivenName) {
+				aux.GivenName = append(aux.GivenName, s)
+			} else if a.Type.Equal(oidOrganizationalUnit) {
+				aux.OrganizationalUnit = append(aux.OrganizationalUnit, s)
+			} else if a.Type.Equal(oidPostalCode) {
+				aux.PostalCode = append(aux.PostalCode, s)
+			} else if a.Type.Equal(oidDomainComponent) {
+				aux.DomainComponent = append(aux.DomainComponent, s)
+			} else if a.Type.Equal(oidDNEmailAddress) {
+				aux.EmailAddress = append(aux.EmailAddress, s)
+				// EV
+			} else if a.Type.Equal(oidJurisdictionCountry) {
+				aux.JurisdictionCountry = append(aux.JurisdictionCountry, s)
+			} else if a.Type.Equal(oidJurisdictionLocality) {
+				aux.JurisdictionLocality = append(aux.JurisdictionLocality, s)
+			} else if a.Type.Equal(oidJurisdictionProvince) {
+				aux.JurisdictionProvince = append(aux.JurisdictionProvince, s)
+			} else if a.Type.Equal(oidOrganizationID) {
+				aux.OrganizationID = append(aux.OrganizationID, s)
+			} else {
+				aux.UnknownAttributes = append(aux.UnknownAttributes, a)
+			}
+		}
+	}
+	return json.Marshal(&aux)
+}
+
+func appendATV(names []AttributeTypeAndValue, fieldVals []string, asn1Id asn1.ObjectIdentifier) []AttributeTypeAndValue {
+	if len(fieldVals) == 0 {
+		return names
+	}
+
+	for _, val := range fieldVals {
+		names = append(names, AttributeTypeAndValue{Type: asn1Id, Value: val})
+	}
+
+	return names
+}
+
+// UnmarshalJSON implements the json.Unmarshaler interface.
+func (n *Name) UnmarshalJSON(b []byte) error {
+	aux := auxName{}
+	if err := json.Unmarshal(b, &aux); err != nil {
+		return err
+	}
+
+	// Populate Names as []AttributeTypeAndValue
+	n.Names = appendATV(n.Names, aux.Country, oidCountry)
+	n.Names = appendATV(n.Names, aux.Organization, oidOrganization)
+	n.Names = appendATV(n.Names, aux.OrganizationalUnit, oidOrganizationalUnit)
+	n.Names = appendATV(n.Names, aux.Locality, oidLocality)
+	n.Names = appendATV(n.Names, aux.Province, oidProvince)
+	n.Names = appendATV(n.Names, aux.StreetAddress, oidStreetAddress)
+	n.Names = appendATV(n.Names, aux.PostalCode, oidPostalCode)
+	n.Names = appendATV(n.Names, aux.DomainComponent, oidDomainComponent)
+	n.Names = appendATV(n.Names, aux.EmailAddress, oidDNEmailAddress)
+	// EV
+	n.Names = appendATV(n.Names, aux.JurisdictionCountry, oidJurisdictionCountry)
+	n.Names = appendATV(n.Names, aux.JurisdictionLocality, oidJurisdictionLocality)
+	n.Names = appendATV(n.Names, aux.JurisdictionProvince, oidJurisdictionProvince)
+
+	n.Names = appendATV(n.Names, aux.CommonName, oidCommonName)
+	n.Names = appendATV(n.Names, aux.SerialNumber, oidSerialNumber)
+
+	// Populate specific fields as []string
+	n.Country = aux.Country
+	n.Organization = aux.Organization
+	n.OrganizationalUnit = aux.OrganizationalUnit
+	n.Locality = aux.Locality
+	n.Province = aux.Province
+	n.StreetAddress = aux.StreetAddress
+	n.PostalCode = aux.PostalCode
+	n.DomainComponent = aux.DomainComponent
+	// EV
+	n.JurisdictionCountry = aux.JurisdictionCountry
+	n.JurisdictionLocality = aux.JurisdictionLocality
+	n.JurisdictionProvince = aux.JurisdictionProvince
+
+	// CommonName and SerialNumber are not arrays.
+	if len(aux.CommonName) > 0 {
+		n.CommonName = aux.CommonName[0]
+	}
+	if len(aux.SerialNumber) > 0 {
+		n.SerialNumber = aux.SerialNumber[0]
+	}
+
+	// Add "extra" commonNames and serialNumbers to ExtraNames.
+	if len(aux.CommonName) > 1 {
+		n.ExtraNames = appendATV(n.ExtraNames, aux.CommonName[1:], oidCommonName)
+	}
+	if len(aux.SerialNumber) > 1 {
+		n.ExtraNames = appendATV(n.ExtraNames, aux.SerialNumber[1:], oidSerialNumber)
+	}
+
+	return nil
+}

+ 74 - 0
vendor/github.com/zmap/zcrypto/x509/pkix/oid.go

@@ -0,0 +1,74 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkix
+
+import (
+	"encoding/asn1"
+	"encoding/json"
+	"fmt"
+	"strconv"
+	"strings"
+)
+
+// AuxOID behaves similar to asn1.ObjectIdentifier, except encodes to JSON as a
+// string in dot notation. It is a type synonym for []int, and can be converted
+// to an asn1.ObjectIdentifier by going through []int and back.
+type AuxOID []int
+
+// AsSlice returns a slice over the inner-representation
+func (aux *AuxOID) AsSlice() []int {
+	return *aux
+}
+
+// CopyAsSlice returns a copy of the inter-representation as a slice
+func (aux *AuxOID) CopyAsSlice() []int {
+	out := make([]int, len(*aux))
+	copy(out, *aux)
+	return out
+}
+
+// Equal tests (deep) equality of two AuxOIDs
+func (aux *AuxOID) Equal(other *AuxOID) bool {
+	var a []int = *aux
+	var b []int = *other
+	if len(a) != len(b) {
+		return false
+	}
+	for idx := range a {
+		if a[idx] != b[idx] {
+			return false
+		}
+	}
+	return true
+}
+
+// MarshalJSON implements the json.Marshaler interface
+func (aux *AuxOID) MarshalJSON() ([]byte, error) {
+	var oid asn1.ObjectIdentifier
+	oid = []int(*aux)
+	return json.Marshal(oid.String())
+}
+
+// UnmarshalJSON implements the json.Unmarshaler interface
+func (aux *AuxOID) UnmarshalJSON(b []byte) error {
+	var s string
+	if err := json.Unmarshal(b, &s); err != nil {
+		return err
+	}
+	parts := strings.Split(s, ".")
+	if len(parts) < 1 {
+		return fmt.Errorf("Invalid OID string %s", s)
+	}
+	slice := make([]int, len(parts))
+	for idx := range parts {
+		n, err := strconv.Atoi(parts[idx])
+		if err != nil || n < 0 {
+			return fmt.Errorf("Invalid OID integer %s", parts[idx])
+		}
+		slice[idx] = n
+	}
+	*aux = slice
+	return nil
+}

+ 1014 - 0
vendor/github.com/zmap/zcrypto/x509/pkix/oid_names.go

@@ -0,0 +1,1014 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkix
+
+// OIDName stores the short and long version of the name of an IANA-assigned OID
+type OIDName struct {
+	ShortName string `json:"short_name"`
+	LongName  string `json:"long_name"`
+}
+
+var oidDotNotationToNames map[string]OIDName
+
+func init() {
+	oidDotNotationToNames = make(map[string]OIDName, 1024)
+
+	oidDotNotationToNames["0.0"] = OIDName{ShortName: "UNDEF", LongName: "undefined"}
+	oidDotNotationToNames["1.2.840.113549"] = OIDName{ShortName: "rsadsi", LongName: "RSA Data Security"}
+	oidDotNotationToNames["1.2.840.113549.1"] = OIDName{ShortName: "pkcs", LongName: "RSA Data Security"}
+	oidDotNotationToNames["1.2.840.113549.2.2"] = OIDName{ShortName: "MD2", LongName: "md2"}
+	oidDotNotationToNames["1.2.840.113549.2.5"] = OIDName{ShortName: "MD5", LongName: "md5"}
+	oidDotNotationToNames["1.2.840.113549.3.4"] = OIDName{ShortName: "RC4", LongName: "rc4"}
+	oidDotNotationToNames["1.2.840.113549.1.1.1"] = OIDName{ShortName: "rsaEncryption", LongName: "rsaEncryption"}
+	oidDotNotationToNames["1.2.840.113549.1.1.2"] = OIDName{ShortName: "RSA-MD2", LongName: "md2WithRSAEncryption"}
+	oidDotNotationToNames["1.2.840.113549.1.1.4"] = OIDName{ShortName: "RSA-MD5", LongName: "md5WithRSAEncryption"}
+	oidDotNotationToNames["1.2.840.113549.1.5.1"] = OIDName{ShortName: "PBE-MD2-DES", LongName: "pbeWithMD2AndDES-CBC"}
+	oidDotNotationToNames["1.2.840.113549.1.5.3"] = OIDName{ShortName: "PBE-MD5-DES", LongName: "pbeWithMD5AndDES-CBC"}
+	oidDotNotationToNames["2.5"] = OIDName{ShortName: "X500", LongName: "directory services (X.500)"}
+	oidDotNotationToNames["2.5.4"] = OIDName{ShortName: "X509", LongName: "X509"}
+	oidDotNotationToNames["2.5.4.3"] = OIDName{ShortName: "CN", LongName: "commonName"}
+	oidDotNotationToNames["2.5.4.6"] = OIDName{ShortName: "C", LongName: "countryName"}
+	oidDotNotationToNames["2.5.4.7"] = OIDName{ShortName: "L", LongName: "localityName"}
+	oidDotNotationToNames["2.5.4.8"] = OIDName{ShortName: "ST", LongName: "stateOrProvinceName"}
+	oidDotNotationToNames["2.5.4.10"] = OIDName{ShortName: "O", LongName: "organizationName"}
+	oidDotNotationToNames["2.5.4.11"] = OIDName{ShortName: "OU", LongName: "organizationalUnitName"}
+	oidDotNotationToNames["2.5.4.97"] = OIDName{ShortName: "organizationIdentifier", LongName: "organizationIdentifier"}
+	oidDotNotationToNames["2.5.8.1.1"] = OIDName{ShortName: "RSA", LongName: "rsa"}
+	oidDotNotationToNames["1.2.840.113549.1.7"] = OIDName{ShortName: "pkcs7", LongName: "pkcs7"}
+	oidDotNotationToNames["1.2.840.113549.1.7.1"] = OIDName{ShortName: "pkcs7-data", LongName: "pkcs7-data"}
+	oidDotNotationToNames["1.2.840.113549.1.7.2"] = OIDName{ShortName: "pkcs7-signedData", LongName: "pkcs7-signedData"}
+	oidDotNotationToNames["1.2.840.113549.1.7.3"] = OIDName{ShortName: "pkcs7-envelopedData", LongName: "pkcs7-envelopedData"}
+	oidDotNotationToNames["1.2.840.113549.1.7.4"] = OIDName{ShortName: "pkcs7-signedAndEnvelopedData", LongName: "pkcs7-signedAndEnvelopedData"}
+	oidDotNotationToNames["1.2.840.113549.1.7.5"] = OIDName{ShortName: "pkcs7-digestData", LongName: "pkcs7-digestData"}
+	oidDotNotationToNames["1.2.840.113549.1.7.6"] = OIDName{ShortName: "pkcs7-encryptedData", LongName: "pkcs7-encryptedData"}
+	oidDotNotationToNames["1.2.840.113549.1.3"] = OIDName{ShortName: "pkcs3", LongName: "pkcs3"}
+	oidDotNotationToNames["1.2.840.113549.1.3.1"] = OIDName{ShortName: "dhKeyAgreement", LongName: "dhKeyAgreement"}
+	oidDotNotationToNames["1.3.14.3.2.6"] = OIDName{ShortName: "DES-ECB", LongName: "des-ecb"}
+	oidDotNotationToNames["1.3.14.3.2.9"] = OIDName{ShortName: "DES-CFB", LongName: "des-cfb"}
+	oidDotNotationToNames["1.3.14.3.2.7"] = OIDName{ShortName: "DES-CBC", LongName: "des-cbc"}
+	oidDotNotationToNames["1.3.14.3.2.17"] = OIDName{ShortName: "DES-EDE", LongName: "des-ede"}
+	oidDotNotationToNames["1.3.6.1.4.1.188.7.1.1.2"] = OIDName{ShortName: "IDEA-CBC", LongName: "idea-cbc"}
+	oidDotNotationToNames["1.2.840.113549.3.2"] = OIDName{ShortName: "RC2-CBC", LongName: "rc2-cbc"}
+	oidDotNotationToNames["1.3.14.3.2.18"] = OIDName{ShortName: "SHA", LongName: "sha"}
+	oidDotNotationToNames["1.3.14.3.2.15"] = OIDName{ShortName: "RSA-SHA", LongName: "shaWithRSAEncryption"}
+	oidDotNotationToNames["1.2.840.113549.3.7"] = OIDName{ShortName: "DES-EDE3-CBC", LongName: "des-ede3-cbc"}
+	oidDotNotationToNames["1.3.14.3.2.8"] = OIDName{ShortName: "DES-OFB", LongName: "des-ofb"}
+	oidDotNotationToNames["1.2.840.113549.1.9"] = OIDName{ShortName: "pkcs9", LongName: "pkcs9"}
+	oidDotNotationToNames["1.2.840.113549.1.9.1"] = OIDName{ShortName: "emailAddress", LongName: "emailAddress"}
+	oidDotNotationToNames["1.2.840.113549.1.9.2"] = OIDName{ShortName: "unstructuredName", LongName: "unstructuredName"}
+	oidDotNotationToNames["1.2.840.113549.1.9.3"] = OIDName{ShortName: "contentType", LongName: "contentType"}
+	oidDotNotationToNames["1.2.840.113549.1.9.4"] = OIDName{ShortName: "messageDigest", LongName: "messageDigest"}
+	oidDotNotationToNames["1.2.840.113549.1.9.5"] = OIDName{ShortName: "signingTime", LongName: "signingTime"}
+	oidDotNotationToNames["1.2.840.113549.1.9.6"] = OIDName{ShortName: "countersignature", LongName: "countersignature"}
+	oidDotNotationToNames["1.2.840.113549.1.9.7"] = OIDName{ShortName: "challengePassword", LongName: "challengePassword"}
+	oidDotNotationToNames["1.2.840.113549.1.9.8"] = OIDName{ShortName: "unstructuredAddress", LongName: "unstructuredAddress"}
+	oidDotNotationToNames["1.2.840.113549.1.9.9"] = OIDName{ShortName: "extendedCertificateAttributes", LongName: "extendedCertificateAttributes"}
+	oidDotNotationToNames["2.16.840.1.113730"] = OIDName{ShortName: "Netscape", LongName: "Netscape Communications Corp."}
+	oidDotNotationToNames["2.16.840.1.113730.1"] = OIDName{ShortName: "nsCertExt", LongName: "Netscape Certificate Extension"}
+	oidDotNotationToNames["2.16.840.1.113730.2"] = OIDName{ShortName: "nsDataType", LongName: "Netscape Data Type"}
+	oidDotNotationToNames["1.3.14.3.2.26"] = OIDName{ShortName: "SHA1", LongName: "sha1"}
+	oidDotNotationToNames["1.2.840.113549.1.1.5"] = OIDName{ShortName: "RSA-SHA1", LongName: "sha1WithRSAEncryption"}
+	oidDotNotationToNames["1.3.14.3.2.13"] = OIDName{ShortName: "DSA-SHA", LongName: "dsaWithSHA"}
+	oidDotNotationToNames["1.3.14.3.2.12"] = OIDName{ShortName: "DSA-old", LongName: "dsaEncryption-old"}
+	oidDotNotationToNames["1.2.840.113549.1.5.11"] = OIDName{ShortName: "PBE-SHA1-RC2-64", LongName: "pbeWithSHA1AndRC2-CBC"}
+	oidDotNotationToNames["1.2.840.113549.1.5.12"] = OIDName{ShortName: "PBKDF2", LongName: "PBKDF2"}
+	oidDotNotationToNames["1.3.14.3.2.27"] = OIDName{ShortName: "DSA-SHA1-old", LongName: "dsaWithSHA1-old"}
+	oidDotNotationToNames["2.16.840.1.113730.1.1"] = OIDName{ShortName: "nsCertType", LongName: "Netscape Cert Type"}
+	oidDotNotationToNames["2.16.840.1.113730.1.2"] = OIDName{ShortName: "nsBaseUrl", LongName: "Netscape Base Url"}
+	oidDotNotationToNames["2.16.840.1.113730.1.3"] = OIDName{ShortName: "nsRevocationUrl", LongName: "Netscape Revocation Url"}
+	oidDotNotationToNames["2.16.840.1.113730.1.4"] = OIDName{ShortName: "nsCaRevocationUrl", LongName: "Netscape CA Revocation Url"}
+	oidDotNotationToNames["2.16.840.1.113730.1.7"] = OIDName{ShortName: "nsRenewalUrl", LongName: "Netscape Renewal Url"}
+	oidDotNotationToNames["2.16.840.1.113730.1.8"] = OIDName{ShortName: "nsCaPolicyUrl", LongName: "Netscape CA Policy Url"}
+	oidDotNotationToNames["2.16.840.1.113730.1.12"] = OIDName{ShortName: "nsSslServerName", LongName: "Netscape SSL Server Name"}
+	oidDotNotationToNames["2.16.840.1.113730.1.13"] = OIDName{ShortName: "nsComment", LongName: "Netscape Comment"}
+	oidDotNotationToNames["2.16.840.1.113730.2.5"] = OIDName{ShortName: "nsCertSequence", LongName: "Netscape Certificate Sequence"}
+	oidDotNotationToNames["2.5.29"] = OIDName{ShortName: "id-ce", LongName: "id-ce"}
+	oidDotNotationToNames["2.5.29.14"] = OIDName{ShortName: "subjectKeyIdentifier", LongName: "X509v3 Subject Key Identifier"}
+	oidDotNotationToNames["2.5.29.15"] = OIDName{ShortName: "keyUsage", LongName: "X509v3 Key Usage"}
+	oidDotNotationToNames["2.5.29.16"] = OIDName{ShortName: "privateKeyUsagePeriod", LongName: "X509v3 Private Key Usage Period"}
+	oidDotNotationToNames["2.5.29.17"] = OIDName{ShortName: "subjectAltName", LongName: "X509v3 Subject Alternative Name"}
+	oidDotNotationToNames["2.5.29.18"] = OIDName{ShortName: "issuerAltName", LongName: "X509v3 Issuer Alternative Name"}
+	oidDotNotationToNames["2.5.29.19"] = OIDName{ShortName: "basicConstraints", LongName: "X509v3 Basic Constraints"}
+	oidDotNotationToNames["2.5.29.20"] = OIDName{ShortName: "crlNumber", LongName: "X509v3 CRL Number"}
+	oidDotNotationToNames["2.5.29.32"] = OIDName{ShortName: "certificatePolicies", LongName: "X509v3 Certificate Policies"}
+	oidDotNotationToNames["2.5.29.35"] = OIDName{ShortName: "authorityKeyIdentifier", LongName: "X509v3 Authority Key Identifier"}
+	oidDotNotationToNames["1.3.6.1.4.1.3029.1.2"] = OIDName{ShortName: "BF-CBC", LongName: "bf-cbc"}
+	oidDotNotationToNames["2.5.8.3.101"] = OIDName{ShortName: "MDC2", LongName: "mdc2"}
+	oidDotNotationToNames["2.5.8.3.100"] = OIDName{ShortName: "RSA-MDC2", LongName: "mdc2WithRSA"}
+	oidDotNotationToNames["2.5.4.42"] = OIDName{ShortName: "GN", LongName: "givenName"}
+	oidDotNotationToNames["2.5.4.4"] = OIDName{ShortName: "SN", LongName: "surname"}
+	oidDotNotationToNames["2.5.4.43"] = OIDName{ShortName: "initials", LongName: "initials"}
+	oidDotNotationToNames["2.5.29.31"] = OIDName{ShortName: "crlDistributionPoints", LongName: "X509v3 CRL Distribution Points"}
+	oidDotNotationToNames["1.3.14.3.2.3"] = OIDName{ShortName: "RSA-NP-MD5", LongName: "md5WithRSA"}
+	oidDotNotationToNames["2.5.4.5"] = OIDName{ShortName: "serialNumber", LongName: "serialNumber"}
+	oidDotNotationToNames["2.5.4.12"] = OIDName{ShortName: "title", LongName: "title"}
+	oidDotNotationToNames["2.5.4.13"] = OIDName{ShortName: "description", LongName: "description"}
+	oidDotNotationToNames["1.2.840.113533.7.66.10"] = OIDName{ShortName: "CAST5-CBC", LongName: "cast5-cbc"}
+	oidDotNotationToNames["1.2.840.113533.7.66.12"] = OIDName{ShortName: "pbeWithMD5AndCast5CBC", LongName: "pbeWithMD5AndCast5CBC"}
+	oidDotNotationToNames["1.2.840.10040.4.3"] = OIDName{ShortName: "DSA-SHA1", LongName: "dsaWithSHA1"}
+	oidDotNotationToNames["1.3.14.3.2.29"] = OIDName{ShortName: "RSA-SHA1-2", LongName: "sha1WithRSA"}
+	oidDotNotationToNames["1.2.840.10040.4.1"] = OIDName{ShortName: "DSA", LongName: "dsaEncryption"}
+	oidDotNotationToNames["1.3.36.3.2.1"] = OIDName{ShortName: "RIPEMD160", LongName: "ripemd160"}
+	oidDotNotationToNames["1.3.36.3.3.1.2"] = OIDName{ShortName: "RSA-RIPEMD160", LongName: "ripemd160WithRSA"}
+	oidDotNotationToNames["1.2.840.113549.3.8"] = OIDName{ShortName: "RC5-CBC", LongName: "rc5-cbc"}
+	oidDotNotationToNames["1.1.1.1.666.1"] = OIDName{ShortName: "RLE", LongName: "run length compression"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.3.8"] = OIDName{ShortName: "ZLIB", LongName: "zlib compression"}
+	oidDotNotationToNames["2.5.29.37"] = OIDName{ShortName: "extendedKeyUsage", LongName: "X509v3 Extended Key Usage"}
+	oidDotNotationToNames["1.3.6.1.5.5.7"] = OIDName{ShortName: "PKIX", LongName: "PKIX"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.3"] = OIDName{ShortName: "id-kp", LongName: "id-kp"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.3.1"] = OIDName{ShortName: "serverAuth", LongName: "TLS Web Server Authentication"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.3.2"] = OIDName{ShortName: "clientAuth", LongName: "TLS Web Client Authentication"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.3.3"] = OIDName{ShortName: "codeSigning", LongName: "Code Signing"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.3.4"] = OIDName{ShortName: "emailProtection", LongName: "E-mail Protection"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.3.8"] = OIDName{ShortName: "timeStamping", LongName: "Time Stamping"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.2.1.21"] = OIDName{ShortName: "msCodeInd", LongName: "Microsoft Individual Code Signing"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.2.1.22"] = OIDName{ShortName: "msCodeCom", LongName: "Microsoft Commercial Code Signing"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.3.1"] = OIDName{ShortName: "msCTLSign", LongName: "Microsoft Trust List Signing"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.3.3"] = OIDName{ShortName: "msSGC", LongName: "Microsoft Server Gated Crypto"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.3.4"] = OIDName{ShortName: "msEFS", LongName: "Microsoft Encrypted File System"}
+	oidDotNotationToNames["2.16.840.1.113730.4.1"] = OIDName{ShortName: "nsSGC", LongName: "Netscape Server Gated Crypto"}
+	oidDotNotationToNames["2.5.29.27"] = OIDName{ShortName: "deltaCRL", LongName: "X509v3 Delta CRL Indicator"}
+	oidDotNotationToNames["2.5.29.21"] = OIDName{ShortName: "CRLReason", LongName: "X509v3 CRL Reason Code"}
+	oidDotNotationToNames["2.5.29.24"] = OIDName{ShortName: "invalidityDate", LongName: "Invalidity Date"}
+	oidDotNotationToNames["1.3.101.1.4.1"] = OIDName{ShortName: "SXNetID", LongName: "Strong Extranet ID"}
+	oidDotNotationToNames["1.2.840.113549.1.12.1.1"] = OIDName{ShortName: "PBE-SHA1-RC4-128", LongName: "pbeWithSHA1And128BitRC4"}
+	oidDotNotationToNames["1.2.840.113549.1.12.1.2"] = OIDName{ShortName: "PBE-SHA1-RC4-40", LongName: "pbeWithSHA1And40BitRC4"}
+	oidDotNotationToNames["1.2.840.113549.1.12.1.3"] = OIDName{ShortName: "PBE-SHA1-3DES", LongName: "pbeWithSHA1And3-KeyTripleDES-CBC"}
+	oidDotNotationToNames["1.2.840.113549.1.12.1.4"] = OIDName{ShortName: "PBE-SHA1-2DES", LongName: "pbeWithSHA1And2-KeyTripleDES-CBC"}
+	oidDotNotationToNames["1.2.840.113549.1.12.1.5"] = OIDName{ShortName: "PBE-SHA1-RC2-128", LongName: "pbeWithSHA1And128BitRC2-CBC"}
+	oidDotNotationToNames["1.2.840.113549.1.12.1.6"] = OIDName{ShortName: "PBE-SHA1-RC2-40", LongName: "pbeWithSHA1And40BitRC2-CBC"}
+	oidDotNotationToNames["1.2.840.113549.1.12.10.1.1"] = OIDName{ShortName: "keyBag", LongName: "keyBag"}
+	oidDotNotationToNames["1.2.840.113549.1.12.10.1.2"] = OIDName{ShortName: "pkcs8ShroudedKeyBag", LongName: "pkcs8ShroudedKeyBag"}
+	oidDotNotationToNames["1.2.840.113549.1.12.10.1.3"] = OIDName{ShortName: "certBag", LongName: "certBag"}
+	oidDotNotationToNames["1.2.840.113549.1.12.10.1.4"] = OIDName{ShortName: "crlBag", LongName: "crlBag"}
+	oidDotNotationToNames["1.2.840.113549.1.12.10.1.5"] = OIDName{ShortName: "secretBag", LongName: "secretBag"}
+	oidDotNotationToNames["1.2.840.113549.1.12.10.1.6"] = OIDName{ShortName: "safeContentsBag", LongName: "safeContentsBag"}
+	oidDotNotationToNames["1.2.840.113549.1.9.20"] = OIDName{ShortName: "friendlyName", LongName: "friendlyName"}
+	oidDotNotationToNames["1.2.840.113549.1.9.21"] = OIDName{ShortName: "localKeyID", LongName: "localKeyID"}
+	oidDotNotationToNames["1.2.840.113549.1.9.22.1"] = OIDName{ShortName: "x509Certificate", LongName: "x509Certificate"}
+	oidDotNotationToNames["1.2.840.113549.1.9.22.2"] = OIDName{ShortName: "sdsiCertificate", LongName: "sdsiCertificate"}
+	oidDotNotationToNames["1.2.840.113549.1.9.23.1"] = OIDName{ShortName: "x509Crl", LongName: "x509Crl"}
+	oidDotNotationToNames["1.2.840.113549.1.5.13"] = OIDName{ShortName: "PBES2", LongName: "PBES2"}
+	oidDotNotationToNames["1.2.840.113549.1.5.14"] = OIDName{ShortName: "PBMAC1", LongName: "PBMAC1"}
+	oidDotNotationToNames["1.2.840.113549.2.7"] = OIDName{ShortName: "hmacWithSHA1", LongName: "hmacWithSHA1"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.2.1"] = OIDName{ShortName: "id-qt-cps", LongName: "Policy Qualifier CPS"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.2.2"] = OIDName{ShortName: "id-qt-unotice", LongName: "Policy Qualifier User Notice"}
+	oidDotNotationToNames["1.2.840.113549.1.9.15"] = OIDName{ShortName: "SMIME-CAPS", LongName: "S/MIME Capabilities"}
+	oidDotNotationToNames["1.2.840.113549.1.5.4"] = OIDName{ShortName: "PBE-MD2-RC2-64", LongName: "pbeWithMD2AndRC2-CBC"}
+	oidDotNotationToNames["1.2.840.113549.1.5.6"] = OIDName{ShortName: "PBE-MD5-RC2-64", LongName: "pbeWithMD5AndRC2-CBC"}
+	oidDotNotationToNames["1.2.840.113549.1.5.10"] = OIDName{ShortName: "PBE-SHA1-DES", LongName: "pbeWithSHA1AndDES-CBC"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.2.1.14"] = OIDName{ShortName: "msExtReq", LongName: "Microsoft Extension Request"}
+	oidDotNotationToNames["1.2.840.113549.1.9.14"] = OIDName{ShortName: "extReq", LongName: "Extension Request"}
+	oidDotNotationToNames["2.5.4.41"] = OIDName{ShortName: "name", LongName: "name"}
+	oidDotNotationToNames["2.5.4.46"] = OIDName{ShortName: "dnQualifier", LongName: "dnQualifier"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.1"] = OIDName{ShortName: "id-pe", LongName: "id-pe"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.48"] = OIDName{ShortName: "id-ad", LongName: "id-ad"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.1.1"] = OIDName{ShortName: "authorityInfoAccess", LongName: "Authority Information Access"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.48.1"] = OIDName{ShortName: "OCSP", LongName: "OCSP"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.48.2"] = OIDName{ShortName: "caIssuers", LongName: "CA Issuers"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.3.9"] = OIDName{ShortName: "OCSPSigning", LongName: "OCSP Signing"}
+	oidDotNotationToNames["1.0"] = OIDName{ShortName: "ISO", LongName: "iso"}
+	oidDotNotationToNames["1.2"] = OIDName{ShortName: "member-body", LongName: "ISO Member Body"}
+	oidDotNotationToNames["1.2.840"] = OIDName{ShortName: "ISO-US", LongName: "ISO US Member Body"}
+	oidDotNotationToNames["1.2.840.10040"] = OIDName{ShortName: "X9-57", LongName: "X9.57"}
+	oidDotNotationToNames["1.2.840.10040.4"] = OIDName{ShortName: "X9cm", LongName: "X9.57 CM ?"}
+	oidDotNotationToNames["1.2.840.113549.1.1"] = OIDName{ShortName: "pkcs1", LongName: "pkcs1"}
+	oidDotNotationToNames["1.2.840.113549.1.5"] = OIDName{ShortName: "pkcs5", LongName: "pkcs5"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16"] = OIDName{ShortName: "SMIME", LongName: "S/MIME"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.0"] = OIDName{ShortName: "id-smime-mod", LongName: "id-smime-mod"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.1"] = OIDName{ShortName: "id-smime-ct", LongName: "id-smime-ct"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.2"] = OIDName{ShortName: "id-smime-aa", LongName: "id-smime-aa"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.3"] = OIDName{ShortName: "id-smime-alg", LongName: "id-smime-alg"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.4"] = OIDName{ShortName: "id-smime-cd", LongName: "id-smime-cd"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.5"] = OIDName{ShortName: "id-smime-spq", LongName: "id-smime-spq"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.6"] = OIDName{ShortName: "id-smime-cti", LongName: "id-smime-cti"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.0.1"] = OIDName{ShortName: "id-smime-mod-cms", LongName: "id-smime-mod-cms"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.0.2"] = OIDName{ShortName: "id-smime-mod-ess", LongName: "id-smime-mod-ess"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.0.3"] = OIDName{ShortName: "id-smime-mod-oid", LongName: "id-smime-mod-oid"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.0.4"] = OIDName{ShortName: "id-smime-mod-msg-v3", LongName: "id-smime-mod-msg-v3"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.0.5"] = OIDName{ShortName: "id-smime-mod-ets-eSignature-88", LongName: "id-smime-mod-ets-eSignature-88"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.0.6"] = OIDName{ShortName: "id-smime-mod-ets-eSignature-97", LongName: "id-smime-mod-ets-eSignature-97"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.0.7"] = OIDName{ShortName: "id-smime-mod-ets-eSigPolicy-88", LongName: "id-smime-mod-ets-eSigPolicy-88"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.0.8"] = OIDName{ShortName: "id-smime-mod-ets-eSigPolicy-97", LongName: "id-smime-mod-ets-eSigPolicy-97"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.1.1"] = OIDName{ShortName: "id-smime-ct-receipt", LongName: "id-smime-ct-receipt"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.1.2"] = OIDName{ShortName: "id-smime-ct-authData", LongName: "id-smime-ct-authData"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.1.3"] = OIDName{ShortName: "id-smime-ct-publishCert", LongName: "id-smime-ct-publishCert"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.1.4"] = OIDName{ShortName: "id-smime-ct-TSTInfo", LongName: "id-smime-ct-TSTInfo"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.1.5"] = OIDName{ShortName: "id-smime-ct-TDTInfo", LongName: "id-smime-ct-TDTInfo"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.1.6"] = OIDName{ShortName: "id-smime-ct-contentInfo", LongName: "id-smime-ct-contentInfo"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.1.7"] = OIDName{ShortName: "id-smime-ct-DVCSRequestData", LongName: "id-smime-ct-DVCSRequestData"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.1.8"] = OIDName{ShortName: "id-smime-ct-DVCSResponseData", LongName: "id-smime-ct-DVCSResponseData"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.2.1"] = OIDName{ShortName: "id-smime-aa-receiptRequest", LongName: "id-smime-aa-receiptRequest"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.2.2"] = OIDName{ShortName: "id-smime-aa-securityLabel", LongName: "id-smime-aa-securityLabel"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.2.3"] = OIDName{ShortName: "id-smime-aa-mlExpandHistory", LongName: "id-smime-aa-mlExpandHistory"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.2.4"] = OIDName{ShortName: "id-smime-aa-contentHint", LongName: "id-smime-aa-contentHint"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.2.5"] = OIDName{ShortName: "id-smime-aa-msgSigDigest", LongName: "id-smime-aa-msgSigDigest"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.2.6"] = OIDName{ShortName: "id-smime-aa-encapContentType", LongName: "id-smime-aa-encapContentType"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.2.7"] = OIDName{ShortName: "id-smime-aa-contentIdentifier", LongName: "id-smime-aa-contentIdentifier"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.2.8"] = OIDName{ShortName: "id-smime-aa-macValue", LongName: "id-smime-aa-macValue"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.2.9"] = OIDName{ShortName: "id-smime-aa-equivalentLabels", LongName: "id-smime-aa-equivalentLabels"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.2.10"] = OIDName{ShortName: "id-smime-aa-contentReference", LongName: "id-smime-aa-contentReference"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.2.11"] = OIDName{ShortName: "id-smime-aa-encrypKeyPref", LongName: "id-smime-aa-encrypKeyPref"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.2.12"] = OIDName{ShortName: "id-smime-aa-signingCertificate", LongName: "id-smime-aa-signingCertificate"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.2.13"] = OIDName{ShortName: "id-smime-aa-smimeEncryptCerts", LongName: "id-smime-aa-smimeEncryptCerts"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.2.14"] = OIDName{ShortName: "id-smime-aa-timeStampToken", LongName: "id-smime-aa-timeStampToken"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.2.15"] = OIDName{ShortName: "id-smime-aa-ets-sigPolicyId", LongName: "id-smime-aa-ets-sigPolicyId"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.2.16"] = OIDName{ShortName: "id-smime-aa-ets-commitmentType", LongName: "id-smime-aa-ets-commitmentType"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.2.17"] = OIDName{ShortName: "id-smime-aa-ets-signerLocation", LongName: "id-smime-aa-ets-signerLocation"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.2.18"] = OIDName{ShortName: "id-smime-aa-ets-signerAttr", LongName: "id-smime-aa-ets-signerAttr"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.2.19"] = OIDName{ShortName: "id-smime-aa-ets-otherSigCert", LongName: "id-smime-aa-ets-otherSigCert"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.2.20"] = OIDName{ShortName: "id-smime-aa-ets-contentTimestamp", LongName: "id-smime-aa-ets-contentTimestamp"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.2.21"] = OIDName{ShortName: "id-smime-aa-ets-CertificateRefs", LongName: "id-smime-aa-ets-CertificateRefs"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.2.22"] = OIDName{ShortName: "id-smime-aa-ets-RevocationRefs", LongName: "id-smime-aa-ets-RevocationRefs"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.2.23"] = OIDName{ShortName: "id-smime-aa-ets-certValues", LongName: "id-smime-aa-ets-certValues"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.2.24"] = OIDName{ShortName: "id-smime-aa-ets-revocationValues", LongName: "id-smime-aa-ets-revocationValues"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.2.25"] = OIDName{ShortName: "id-smime-aa-ets-escTimeStamp", LongName: "id-smime-aa-ets-escTimeStamp"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.2.26"] = OIDName{ShortName: "id-smime-aa-ets-certCRLTimestamp", LongName: "id-smime-aa-ets-certCRLTimestamp"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.2.27"] = OIDName{ShortName: "id-smime-aa-ets-archiveTimeStamp", LongName: "id-smime-aa-ets-archiveTimeStamp"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.2.28"] = OIDName{ShortName: "id-smime-aa-signatureType", LongName: "id-smime-aa-signatureType"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.2.29"] = OIDName{ShortName: "id-smime-aa-dvcs-dvc", LongName: "id-smime-aa-dvcs-dvc"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.3.1"] = OIDName{ShortName: "id-smime-alg-ESDHwith3DES", LongName: "id-smime-alg-ESDHwith3DES"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.3.2"] = OIDName{ShortName: "id-smime-alg-ESDHwithRC2", LongName: "id-smime-alg-ESDHwithRC2"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.3.3"] = OIDName{ShortName: "id-smime-alg-3DESwrap", LongName: "id-smime-alg-3DESwrap"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.3.4"] = OIDName{ShortName: "id-smime-alg-RC2wrap", LongName: "id-smime-alg-RC2wrap"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.3.5"] = OIDName{ShortName: "id-smime-alg-ESDH", LongName: "id-smime-alg-ESDH"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.3.6"] = OIDName{ShortName: "id-smime-alg-CMS3DESwrap", LongName: "id-smime-alg-CMS3DESwrap"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.3.7"] = OIDName{ShortName: "id-smime-alg-CMSRC2wrap", LongName: "id-smime-alg-CMSRC2wrap"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.4.1"] = OIDName{ShortName: "id-smime-cd-ldap", LongName: "id-smime-cd-ldap"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.5.1"] = OIDName{ShortName: "id-smime-spq-ets-sqt-uri", LongName: "id-smime-spq-ets-sqt-uri"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.5.2"] = OIDName{ShortName: "id-smime-spq-ets-sqt-unotice", LongName: "id-smime-spq-ets-sqt-unotice"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.6.1"] = OIDName{ShortName: "id-smime-cti-ets-proofOfOrigin", LongName: "id-smime-cti-ets-proofOfOrigin"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.6.2"] = OIDName{ShortName: "id-smime-cti-ets-proofOfReceipt", LongName: "id-smime-cti-ets-proofOfReceipt"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.6.3"] = OIDName{ShortName: "id-smime-cti-ets-proofOfDelivery", LongName: "id-smime-cti-ets-proofOfDelivery"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.6.4"] = OIDName{ShortName: "id-smime-cti-ets-proofOfSender", LongName: "id-smime-cti-ets-proofOfSender"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.6.5"] = OIDName{ShortName: "id-smime-cti-ets-proofOfApproval", LongName: "id-smime-cti-ets-proofOfApproval"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.6.6"] = OIDName{ShortName: "id-smime-cti-ets-proofOfCreation", LongName: "id-smime-cti-ets-proofOfCreation"}
+	oidDotNotationToNames["1.2.840.113549.2.4"] = OIDName{ShortName: "MD4", LongName: "md4"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.0"] = OIDName{ShortName: "id-pkix-mod", LongName: "id-pkix-mod"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.2"] = OIDName{ShortName: "id-qt", LongName: "id-qt"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.4"] = OIDName{ShortName: "id-it", LongName: "id-it"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.5"] = OIDName{ShortName: "id-pkip", LongName: "id-pkip"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.6"] = OIDName{ShortName: "id-alg", LongName: "id-alg"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.7"] = OIDName{ShortName: "id-cmc", LongName: "id-cmc"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.8"] = OIDName{ShortName: "id-on", LongName: "id-on"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.9"] = OIDName{ShortName: "id-pda", LongName: "id-pda"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.10"] = OIDName{ShortName: "id-aca", LongName: "id-aca"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.11"] = OIDName{ShortName: "id-qcs", LongName: "id-qcs"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.12"] = OIDName{ShortName: "id-cct", LongName: "id-cct"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.0.1"] = OIDName{ShortName: "id-pkix1-explicit-88", LongName: "id-pkix1-explicit-88"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.0.2"] = OIDName{ShortName: "id-pkix1-implicit-88", LongName: "id-pkix1-implicit-88"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.0.3"] = OIDName{ShortName: "id-pkix1-explicit-93", LongName: "id-pkix1-explicit-93"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.0.4"] = OIDName{ShortName: "id-pkix1-implicit-93", LongName: "id-pkix1-implicit-93"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.0.5"] = OIDName{ShortName: "id-mod-crmf", LongName: "id-mod-crmf"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.0.6"] = OIDName{ShortName: "id-mod-cmc", LongName: "id-mod-cmc"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.0.7"] = OIDName{ShortName: "id-mod-kea-profile-88", LongName: "id-mod-kea-profile-88"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.0.8"] = OIDName{ShortName: "id-mod-kea-profile-93", LongName: "id-mod-kea-profile-93"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.0.9"] = OIDName{ShortName: "id-mod-cmp", LongName: "id-mod-cmp"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.0.10"] = OIDName{ShortName: "id-mod-qualified-cert-88", LongName: "id-mod-qualified-cert-88"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.0.11"] = OIDName{ShortName: "id-mod-qualified-cert-93", LongName: "id-mod-qualified-cert-93"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.0.12"] = OIDName{ShortName: "id-mod-attribute-cert", LongName: "id-mod-attribute-cert"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.0.13"] = OIDName{ShortName: "id-mod-timestamp-protocol", LongName: "id-mod-timestamp-protocol"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.0.14"] = OIDName{ShortName: "id-mod-ocsp", LongName: "id-mod-ocsp"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.0.15"] = OIDName{ShortName: "id-mod-dvcs", LongName: "id-mod-dvcs"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.0.16"] = OIDName{ShortName: "id-mod-cmp2000", LongName: "id-mod-cmp2000"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.1.2"] = OIDName{ShortName: "biometricInfo", LongName: "Biometric Info"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.1.3"] = OIDName{ShortName: "qcStatements", LongName: "qcStatements"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.1.4"] = OIDName{ShortName: "ac-auditEntity", LongName: "ac-auditEntity"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.1.5"] = OIDName{ShortName: "ac-targeting", LongName: "ac-targeting"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.1.6"] = OIDName{ShortName: "aaControls", LongName: "aaControls"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.1.7"] = OIDName{ShortName: "sbgp-ipAddrBlock", LongName: "sbgp-ipAddrBlock"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.1.8"] = OIDName{ShortName: "sbgp-autonomousSysNum", LongName: "sbgp-autonomousSysNum"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.1.9"] = OIDName{ShortName: "sbgp-routerIdentifier", LongName: "sbgp-routerIdentifier"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.2.3"] = OIDName{ShortName: "textNotice", LongName: "textNotice"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.3.5"] = OIDName{ShortName: "ipsecEndSystem", LongName: "IPSec End System"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.3.6"] = OIDName{ShortName: "ipsecTunnel", LongName: "IPSec Tunnel"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.3.7"] = OIDName{ShortName: "ipsecUser", LongName: "IPSec User"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.3.10"] = OIDName{ShortName: "DVCS", LongName: "dvcs"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.4.1"] = OIDName{ShortName: "id-it-caProtEncCert", LongName: "id-it-caProtEncCert"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.4.2"] = OIDName{ShortName: "id-it-signKeyPairTypes", LongName: "id-it-signKeyPairTypes"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.4.3"] = OIDName{ShortName: "id-it-encKeyPairTypes", LongName: "id-it-encKeyPairTypes"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.4.4"] = OIDName{ShortName: "id-it-preferredSymmAlg", LongName: "id-it-preferredSymmAlg"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.4.5"] = OIDName{ShortName: "id-it-caKeyUpdateInfo", LongName: "id-it-caKeyUpdateInfo"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.4.6"] = OIDName{ShortName: "id-it-currentCRL", LongName: "id-it-currentCRL"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.4.7"] = OIDName{ShortName: "id-it-unsupportedOIDs", LongName: "id-it-unsupportedOIDs"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.4.8"] = OIDName{ShortName: "id-it-subscriptionRequest", LongName: "id-it-subscriptionRequest"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.4.9"] = OIDName{ShortName: "id-it-subscriptionResponse", LongName: "id-it-subscriptionResponse"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.4.10"] = OIDName{ShortName: "id-it-keyPairParamReq", LongName: "id-it-keyPairParamReq"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.4.11"] = OIDName{ShortName: "id-it-keyPairParamRep", LongName: "id-it-keyPairParamRep"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.4.12"] = OIDName{ShortName: "id-it-revPassphrase", LongName: "id-it-revPassphrase"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.4.13"] = OIDName{ShortName: "id-it-implicitConfirm", LongName: "id-it-implicitConfirm"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.4.14"] = OIDName{ShortName: "id-it-confirmWaitTime", LongName: "id-it-confirmWaitTime"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.4.15"] = OIDName{ShortName: "id-it-origPKIMessage", LongName: "id-it-origPKIMessage"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.5.1"] = OIDName{ShortName: "id-regCtrl", LongName: "id-regCtrl"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.5.2"] = OIDName{ShortName: "id-regInfo", LongName: "id-regInfo"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.5.1.1"] = OIDName{ShortName: "id-regCtrl-regToken", LongName: "id-regCtrl-regToken"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.5.1.2"] = OIDName{ShortName: "id-regCtrl-authenticator", LongName: "id-regCtrl-authenticator"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.5.1.3"] = OIDName{ShortName: "id-regCtrl-pkiPublicationInfo", LongName: "id-regCtrl-pkiPublicationInfo"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.5.1.4"] = OIDName{ShortName: "id-regCtrl-pkiArchiveOptions", LongName: "id-regCtrl-pkiArchiveOptions"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.5.1.5"] = OIDName{ShortName: "id-regCtrl-oldCertID", LongName: "id-regCtrl-oldCertID"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.5.1.6"] = OIDName{ShortName: "id-regCtrl-protocolEncrKey", LongName: "id-regCtrl-protocolEncrKey"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.5.2.1"] = OIDName{ShortName: "id-regInfo-utf8Pairs", LongName: "id-regInfo-utf8Pairs"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.5.2.2"] = OIDName{ShortName: "id-regInfo-certReq", LongName: "id-regInfo-certReq"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.6.1"] = OIDName{ShortName: "id-alg-des40", LongName: "id-alg-des40"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.6.2"] = OIDName{ShortName: "id-alg-noSignature", LongName: "id-alg-noSignature"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.6.3"] = OIDName{ShortName: "id-alg-dh-sig-hmac-sha1", LongName: "id-alg-dh-sig-hmac-sha1"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.6.4"] = OIDName{ShortName: "id-alg-dh-pop", LongName: "id-alg-dh-pop"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.7.1"] = OIDName{ShortName: "id-cmc-statusInfo", LongName: "id-cmc-statusInfo"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.7.2"] = OIDName{ShortName: "id-cmc-identification", LongName: "id-cmc-identification"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.7.3"] = OIDName{ShortName: "id-cmc-identityProof", LongName: "id-cmc-identityProof"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.7.4"] = OIDName{ShortName: "id-cmc-dataReturn", LongName: "id-cmc-dataReturn"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.7.5"] = OIDName{ShortName: "id-cmc-transactionId", LongName: "id-cmc-transactionId"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.7.6"] = OIDName{ShortName: "id-cmc-senderNonce", LongName: "id-cmc-senderNonce"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.7.7"] = OIDName{ShortName: "id-cmc-recipientNonce", LongName: "id-cmc-recipientNonce"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.7.8"] = OIDName{ShortName: "id-cmc-addExtensions", LongName: "id-cmc-addExtensions"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.7.9"] = OIDName{ShortName: "id-cmc-encryptedPOP", LongName: "id-cmc-encryptedPOP"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.7.10"] = OIDName{ShortName: "id-cmc-decryptedPOP", LongName: "id-cmc-decryptedPOP"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.7.11"] = OIDName{ShortName: "id-cmc-lraPOPWitness", LongName: "id-cmc-lraPOPWitness"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.7.15"] = OIDName{ShortName: "id-cmc-getCert", LongName: "id-cmc-getCert"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.7.16"] = OIDName{ShortName: "id-cmc-getCRL", LongName: "id-cmc-getCRL"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.7.17"] = OIDName{ShortName: "id-cmc-revokeRequest", LongName: "id-cmc-revokeRequest"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.7.18"] = OIDName{ShortName: "id-cmc-regInfo", LongName: "id-cmc-regInfo"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.7.19"] = OIDName{ShortName: "id-cmc-responseInfo", LongName: "id-cmc-responseInfo"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.7.21"] = OIDName{ShortName: "id-cmc-queryPending", LongName: "id-cmc-queryPending"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.7.22"] = OIDName{ShortName: "id-cmc-popLinkRandom", LongName: "id-cmc-popLinkRandom"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.7.23"] = OIDName{ShortName: "id-cmc-popLinkWitness", LongName: "id-cmc-popLinkWitness"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.7.24"] = OIDName{ShortName: "id-cmc-confirmCertAcceptance", LongName: "id-cmc-confirmCertAcceptance"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.8.1"] = OIDName{ShortName: "id-on-personalData", LongName: "id-on-personalData"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.9.1"] = OIDName{ShortName: "id-pda-dateOfBirth", LongName: "id-pda-dateOfBirth"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.9.2"] = OIDName{ShortName: "id-pda-placeOfBirth", LongName: "id-pda-placeOfBirth"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.9.3"] = OIDName{ShortName: "id-pda-gender", LongName: "id-pda-gender"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.9.4"] = OIDName{ShortName: "id-pda-countryOfCitizenship", LongName: "id-pda-countryOfCitizenship"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.9.5"] = OIDName{ShortName: "id-pda-countryOfResidence", LongName: "id-pda-countryOfResidence"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.10.1"] = OIDName{ShortName: "id-aca-authenticationInfo", LongName: "id-aca-authenticationInfo"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.10.2"] = OIDName{ShortName: "id-aca-accessIdentity", LongName: "id-aca-accessIdentity"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.10.3"] = OIDName{ShortName: "id-aca-chargingIdentity", LongName: "id-aca-chargingIdentity"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.10.4"] = OIDName{ShortName: "id-aca-group", LongName: "id-aca-group"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.10.5"] = OIDName{ShortName: "id-aca-role", LongName: "id-aca-role"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.11.1"] = OIDName{ShortName: "id-qcs-pkixQCSyntax-v1", LongName: "id-qcs-pkixQCSyntax-v1"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.12.1"] = OIDName{ShortName: "id-cct-crs", LongName: "id-cct-crs"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.12.2"] = OIDName{ShortName: "id-cct-PKIData", LongName: "id-cct-PKIData"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.12.3"] = OIDName{ShortName: "id-cct-PKIResponse", LongName: "id-cct-PKIResponse"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.48.3"] = OIDName{ShortName: "ad_timestamping", LongName: "AD Time Stamping"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.48.4"] = OIDName{ShortName: "AD_DVCS", LongName: "ad dvcs"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.48.1.1"] = OIDName{ShortName: "basicOCSPResponse", LongName: "Basic OCSP Response"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.48.1.2"] = OIDName{ShortName: "Nonce", LongName: "OCSP Nonce"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.48.1.3"] = OIDName{ShortName: "CrlID", LongName: "OCSP CRL ID"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.48.1.4"] = OIDName{ShortName: "acceptableResponses", LongName: "Acceptable OCSP Responses"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.48.1.5"] = OIDName{ShortName: "noCheck", LongName: "OCSP No Check"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.48.1.6"] = OIDName{ShortName: "archiveCutoff", LongName: "OCSP Archive Cutoff"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.48.1.7"] = OIDName{ShortName: "serviceLocator", LongName: "OCSP Service Locator"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.48.1.8"] = OIDName{ShortName: "extendedStatus", LongName: "Extended OCSP Status"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.48.1.9"] = OIDName{ShortName: "valid", LongName: "valid"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.48.1.10"] = OIDName{ShortName: "path", LongName: "path"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.48.1.11"] = OIDName{ShortName: "trustRoot", LongName: "Trust Root"}
+	oidDotNotationToNames["1.3.14.3.2"] = OIDName{ShortName: "algorithm", LongName: "algorithm"}
+	oidDotNotationToNames["1.3.14.3.2.11"] = OIDName{ShortName: "rsaSignature", LongName: "rsaSignature"}
+	oidDotNotationToNames["2.5.8"] = OIDName{ShortName: "X500algorithms", LongName: "directory services - algorithms"}
+	oidDotNotationToNames["1.3"] = OIDName{ShortName: "ORG", LongName: "org"}
+	oidDotNotationToNames["1.3.6"] = OIDName{ShortName: "DOD", LongName: "dod"}
+	oidDotNotationToNames["1.3.6.1"] = OIDName{ShortName: "IANA", LongName: "iana"}
+	oidDotNotationToNames["1.3.6.1.1"] = OIDName{ShortName: "directory", LongName: "Directory"}
+	oidDotNotationToNames["1.3.6.1.2"] = OIDName{ShortName: "mgmt", LongName: "Management"}
+	oidDotNotationToNames["1.3.6.1.3"] = OIDName{ShortName: "experimental", LongName: "Experimental"}
+	oidDotNotationToNames["1.3.6.1.4"] = OIDName{ShortName: "private", LongName: "Private"}
+	oidDotNotationToNames["1.3.6.1.5"] = OIDName{ShortName: "security", LongName: "Security"}
+	oidDotNotationToNames["1.3.6.1.6"] = OIDName{ShortName: "snmpv2", LongName: "SNMPv2"}
+	oidDotNotationToNames["1.3.6.1.7"] = OIDName{ShortName: "Mail", LongName: "Mail"}
+	oidDotNotationToNames["1.3.6.1.4.1"] = OIDName{ShortName: "enterprises", LongName: "Enterprises"}
+	oidDotNotationToNames["1.3.6.1.4.1.1466.344"] = OIDName{ShortName: "dcobject", LongName: "dcObject"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.25"] = OIDName{ShortName: "DC", LongName: "domainComponent"}
+	oidDotNotationToNames["0.9.2342.19200300.100.4.13"] = OIDName{ShortName: "domain", LongName: "Domain"}
+	oidDotNotationToNames["0.0"] = OIDName{ShortName: "NULL", LongName: "NULL"}
+	oidDotNotationToNames["2.5.1.5"] = OIDName{ShortName: "selected-attribute-types", LongName: "Selected Attribute Types"}
+	oidDotNotationToNames["2.5.1.5.55"] = OIDName{ShortName: "clearance", LongName: "clearance"}
+	oidDotNotationToNames["1.2.840.113549.1.1.3"] = OIDName{ShortName: "RSA-MD4", LongName: "md4WithRSAEncryption"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.1.10"] = OIDName{ShortName: "ac-proxying", LongName: "ac-proxying"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.1.11"] = OIDName{ShortName: "subjectInfoAccess", LongName: "Subject Information Access"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.10.6"] = OIDName{ShortName: "id-aca-encAttrs", LongName: "id-aca-encAttrs"}
+	oidDotNotationToNames["2.5.4.72"] = OIDName{ShortName: "role", LongName: "role"}
+	oidDotNotationToNames["2.5.29.36"] = OIDName{ShortName: "policyConstraints", LongName: "X509v3 Policy Constraints"}
+	oidDotNotationToNames["2.5.29.55"] = OIDName{ShortName: "targetInformation", LongName: "X509v3 AC Targeting"}
+	oidDotNotationToNames["2.5.29.56"] = OIDName{ShortName: "noRevAvail", LongName: "X509v3 No Revocation Available"}
+	oidDotNotationToNames["0.0"] = OIDName{ShortName: "NULL", LongName: "NULL"}
+	oidDotNotationToNames["1.2.840.10045"] = OIDName{ShortName: "ansi-X9-62", LongName: "ANSI X9.62"}
+	oidDotNotationToNames["1.2.840.10045.1.1"] = OIDName{ShortName: "prime-field", LongName: "prime-field"}
+	oidDotNotationToNames["1.2.840.10045.1.2"] = OIDName{ShortName: "characteristic-two-field", LongName: "characteristic-two-field"}
+	oidDotNotationToNames["1.2.840.10045.2.1"] = OIDName{ShortName: "id-ecPublicKey", LongName: "id-ecPublicKey"}
+	oidDotNotationToNames["1.2.840.10045.3.1.1"] = OIDName{ShortName: "prime192v1", LongName: "prime192v1"}
+	oidDotNotationToNames["1.2.840.10045.3.1.2"] = OIDName{ShortName: "prime192v2", LongName: "prime192v2"}
+	oidDotNotationToNames["1.2.840.10045.3.1.3"] = OIDName{ShortName: "prime192v3", LongName: "prime192v3"}
+	oidDotNotationToNames["1.2.840.10045.3.1.4"] = OIDName{ShortName: "prime239v1", LongName: "prime239v1"}
+	oidDotNotationToNames["1.2.840.10045.3.1.5"] = OIDName{ShortName: "prime239v2", LongName: "prime239v2"}
+	oidDotNotationToNames["1.2.840.10045.3.1.6"] = OIDName{ShortName: "prime239v3", LongName: "prime239v3"}
+	oidDotNotationToNames["1.2.840.10045.3.1.7"] = OIDName{ShortName: "prime256v1", LongName: "prime256v1"}
+	oidDotNotationToNames["1.2.840.10045.4.1"] = OIDName{ShortName: "ecdsa-with-SHA1", LongName: "ecdsa-with-SHA1"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.17.1"] = OIDName{ShortName: "CSPName", LongName: "Microsoft CSP Name"}
+	oidDotNotationToNames["2.16.840.1.101.3.4.1.1"] = OIDName{ShortName: "AES-128-ECB", LongName: "aes-128-ecb"}
+	oidDotNotationToNames["2.16.840.1.101.3.4.1.2"] = OIDName{ShortName: "AES-128-CBC", LongName: "aes-128-cbc"}
+	oidDotNotationToNames["2.16.840.1.101.3.4.1.3"] = OIDName{ShortName: "AES-128-OFB", LongName: "aes-128-ofb"}
+	oidDotNotationToNames["2.16.840.1.101.3.4.1.4"] = OIDName{ShortName: "AES-128-CFB", LongName: "aes-128-cfb"}
+	oidDotNotationToNames["2.16.840.1.101.3.4.1.21"] = OIDName{ShortName: "AES-192-ECB", LongName: "aes-192-ecb"}
+	oidDotNotationToNames["2.16.840.1.101.3.4.1.22"] = OIDName{ShortName: "AES-192-CBC", LongName: "aes-192-cbc"}
+	oidDotNotationToNames["2.16.840.1.101.3.4.1.23"] = OIDName{ShortName: "AES-192-OFB", LongName: "aes-192-ofb"}
+	oidDotNotationToNames["2.16.840.1.101.3.4.1.24"] = OIDName{ShortName: "AES-192-CFB", LongName: "aes-192-cfb"}
+	oidDotNotationToNames["2.16.840.1.101.3.4.1.41"] = OIDName{ShortName: "AES-256-ECB", LongName: "aes-256-ecb"}
+	oidDotNotationToNames["2.16.840.1.101.3.4.1.42"] = OIDName{ShortName: "AES-256-CBC", LongName: "aes-256-cbc"}
+	oidDotNotationToNames["2.16.840.1.101.3.4.1.43"] = OIDName{ShortName: "AES-256-OFB", LongName: "aes-256-ofb"}
+	oidDotNotationToNames["2.16.840.1.101.3.4.1.44"] = OIDName{ShortName: "AES-256-CFB", LongName: "aes-256-cfb"}
+	oidDotNotationToNames["2.5.29.23"] = OIDName{ShortName: "holdInstructionCode", LongName: "Hold Instruction Code"}
+	oidDotNotationToNames["1.2.840.10040.2.1"] = OIDName{ShortName: "holdInstructionNone", LongName: "Hold Instruction None"}
+	oidDotNotationToNames["1.2.840.10040.2.2"] = OIDName{ShortName: "holdInstructionCallIssuer", LongName: "Hold Instruction Call Issuer"}
+	oidDotNotationToNames["1.2.840.10040.2.3"] = OIDName{ShortName: "holdInstructionReject", LongName: "Hold Instruction Reject"}
+	oidDotNotationToNames["0.9"] = OIDName{ShortName: "data", LongName: "data"}
+	oidDotNotationToNames["0.9.2342"] = OIDName{ShortName: "pss", LongName: "pss"}
+	oidDotNotationToNames["0.9.2342.19200300"] = OIDName{ShortName: "ucl", LongName: "ucl"}
+	oidDotNotationToNames["0.9.2342.19200300.100"] = OIDName{ShortName: "pilot", LongName: "pilot"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1"] = OIDName{ShortName: "pilotAttributeType", LongName: "pilotAttributeType"}
+	oidDotNotationToNames["0.9.2342.19200300.100.3"] = OIDName{ShortName: "pilotAttributeSyntax", LongName: "pilotAttributeSyntax"}
+	oidDotNotationToNames["0.9.2342.19200300.100.4"] = OIDName{ShortName: "pilotObjectClass", LongName: "pilotObjectClass"}
+	oidDotNotationToNames["0.9.2342.19200300.100.10"] = OIDName{ShortName: "pilotGroups", LongName: "pilotGroups"}
+	oidDotNotationToNames["0.9.2342.19200300.100.3.4"] = OIDName{ShortName: "iA5StringSyntax", LongName: "iA5StringSyntax"}
+	oidDotNotationToNames["0.9.2342.19200300.100.3.5"] = OIDName{ShortName: "caseIgnoreIA5StringSyntax", LongName: "caseIgnoreIA5StringSyntax"}
+	oidDotNotationToNames["0.9.2342.19200300.100.4.3"] = OIDName{ShortName: "pilotObject", LongName: "pilotObject"}
+	oidDotNotationToNames["0.9.2342.19200300.100.4.4"] = OIDName{ShortName: "pilotPerson", LongName: "pilotPerson"}
+	oidDotNotationToNames["0.9.2342.19200300.100.4.5"] = OIDName{ShortName: "account", LongName: "account"}
+	oidDotNotationToNames["0.9.2342.19200300.100.4.6"] = OIDName{ShortName: "document", LongName: "document"}
+	oidDotNotationToNames["0.9.2342.19200300.100.4.7"] = OIDName{ShortName: "room", LongName: "room"}
+	oidDotNotationToNames["0.9.2342.19200300.100.4.9"] = OIDName{ShortName: "documentSeries", LongName: "documentSeries"}
+	oidDotNotationToNames["0.9.2342.19200300.100.4.14"] = OIDName{ShortName: "rFC822localPart", LongName: "rFC822localPart"}
+	oidDotNotationToNames["0.9.2342.19200300.100.4.15"] = OIDName{ShortName: "dNSDomain", LongName: "dNSDomain"}
+	oidDotNotationToNames["0.9.2342.19200300.100.4.17"] = OIDName{ShortName: "domainRelatedObject", LongName: "domainRelatedObject"}
+	oidDotNotationToNames["0.9.2342.19200300.100.4.18"] = OIDName{ShortName: "friendlyCountry", LongName: "friendlyCountry"}
+	oidDotNotationToNames["0.9.2342.19200300.100.4.19"] = OIDName{ShortName: "simpleSecurityObject", LongName: "simpleSecurityObject"}
+	oidDotNotationToNames["0.9.2342.19200300.100.4.20"] = OIDName{ShortName: "pilotOrganization", LongName: "pilotOrganization"}
+	oidDotNotationToNames["0.9.2342.19200300.100.4.21"] = OIDName{ShortName: "pilotDSA", LongName: "pilotDSA"}
+	oidDotNotationToNames["0.9.2342.19200300.100.4.22"] = OIDName{ShortName: "qualityLabelledData", LongName: "qualityLabelledData"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.1"] = OIDName{ShortName: "UID", LongName: "userId"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.2"] = OIDName{ShortName: "textEncodedORAddress", LongName: "textEncodedORAddress"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.3"] = OIDName{ShortName: "mail", LongName: "rfc822Mailbox"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.4"] = OIDName{ShortName: "info", LongName: "info"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.5"] = OIDName{ShortName: "favouriteDrink", LongName: "favouriteDrink"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.6"] = OIDName{ShortName: "roomNumber", LongName: "roomNumber"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.7"] = OIDName{ShortName: "photo", LongName: "photo"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.8"] = OIDName{ShortName: "userClass", LongName: "userClass"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.9"] = OIDName{ShortName: "host", LongName: "host"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.10"] = OIDName{ShortName: "manager", LongName: "manager"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.11"] = OIDName{ShortName: "documentIdentifier", LongName: "documentIdentifier"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.12"] = OIDName{ShortName: "documentTitle", LongName: "documentTitle"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.13"] = OIDName{ShortName: "documentVersion", LongName: "documentVersion"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.14"] = OIDName{ShortName: "documentAuthor", LongName: "documentAuthor"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.15"] = OIDName{ShortName: "documentLocation", LongName: "documentLocation"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.20"] = OIDName{ShortName: "homeTelephoneNumber", LongName: "homeTelephoneNumber"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.21"] = OIDName{ShortName: "secretary", LongName: "secretary"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.22"] = OIDName{ShortName: "otherMailbox", LongName: "otherMailbox"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.23"] = OIDName{ShortName: "lastModifiedTime", LongName: "lastModifiedTime"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.24"] = OIDName{ShortName: "lastModifiedBy", LongName: "lastModifiedBy"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.26"] = OIDName{ShortName: "aRecord", LongName: "aRecord"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.27"] = OIDName{ShortName: "pilotAttributeType27", LongName: "pilotAttributeType27"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.28"] = OIDName{ShortName: "mXRecord", LongName: "mXRecord"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.29"] = OIDName{ShortName: "nSRecord", LongName: "nSRecord"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.30"] = OIDName{ShortName: "sOARecord", LongName: "sOARecord"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.31"] = OIDName{ShortName: "cNAMERecord", LongName: "cNAMERecord"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.37"] = OIDName{ShortName: "associatedDomain", LongName: "associatedDomain"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.38"] = OIDName{ShortName: "associatedName", LongName: "associatedName"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.39"] = OIDName{ShortName: "homePostalAddress", LongName: "homePostalAddress"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.40"] = OIDName{ShortName: "personalTitle", LongName: "personalTitle"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.41"] = OIDName{ShortName: "mobileTelephoneNumber", LongName: "mobileTelephoneNumber"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.42"] = OIDName{ShortName: "pagerTelephoneNumber", LongName: "pagerTelephoneNumber"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.43"] = OIDName{ShortName: "friendlyCountryName", LongName: "friendlyCountryName"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.45"] = OIDName{ShortName: "organizationalStatus", LongName: "organizationalStatus"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.46"] = OIDName{ShortName: "janetMailbox", LongName: "janetMailbox"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.47"] = OIDName{ShortName: "mailPreferenceOption", LongName: "mailPreferenceOption"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.48"] = OIDName{ShortName: "buildingName", LongName: "buildingName"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.49"] = OIDName{ShortName: "dSAQuality", LongName: "dSAQuality"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.50"] = OIDName{ShortName: "singleLevelQuality", LongName: "singleLevelQuality"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.51"] = OIDName{ShortName: "subtreeMinimumQuality", LongName: "subtreeMinimumQuality"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.52"] = OIDName{ShortName: "subtreeMaximumQuality", LongName: "subtreeMaximumQuality"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.53"] = OIDName{ShortName: "personalSignature", LongName: "personalSignature"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.54"] = OIDName{ShortName: "dITRedirect", LongName: "dITRedirect"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.55"] = OIDName{ShortName: "audio", LongName: "audio"}
+	oidDotNotationToNames["0.9.2342.19200300.100.1.56"] = OIDName{ShortName: "documentPublisher", LongName: "documentPublisher"}
+	oidDotNotationToNames["2.5.4.45"] = OIDName{ShortName: "x500UniqueIdentifier", LongName: "x500UniqueIdentifier"}
+	oidDotNotationToNames["1.3.6.1.7.1"] = OIDName{ShortName: "mime-mhs", LongName: "MIME MHS"}
+	oidDotNotationToNames["1.3.6.1.7.1.1"] = OIDName{ShortName: "mime-mhs-headings", LongName: "mime-mhs-headings"}
+	oidDotNotationToNames["1.3.6.1.7.1.2"] = OIDName{ShortName: "mime-mhs-bodies", LongName: "mime-mhs-bodies"}
+	oidDotNotationToNames["1.3.6.1.7.1.1.1"] = OIDName{ShortName: "id-hex-partial-message", LongName: "id-hex-partial-message"}
+	oidDotNotationToNames["1.3.6.1.7.1.1.2"] = OIDName{ShortName: "id-hex-multipart-message", LongName: "id-hex-multipart-message"}
+	oidDotNotationToNames["2.5.4.44"] = OIDName{ShortName: "generationQualifier", LongName: "generationQualifier"}
+	oidDotNotationToNames["2.5.4.65"] = OIDName{ShortName: "pseudonym", LongName: "pseudonym"}
+	oidDotNotationToNames["2.23.42"] = OIDName{ShortName: "id-set", LongName: "Secure Electronic Transactions"}
+	oidDotNotationToNames["2.23.42.0"] = OIDName{ShortName: "set-ctype", LongName: "content types"}
+	oidDotNotationToNames["2.23.42.1"] = OIDName{ShortName: "set-msgExt", LongName: "message extensions"}
+	oidDotNotationToNames["2.23.42.3"] = OIDName{ShortName: "set-attr", LongName: "set-attr"}
+	oidDotNotationToNames["2.23.42.5"] = OIDName{ShortName: "set-policy", LongName: "set-policy"}
+	oidDotNotationToNames["2.23.42.7"] = OIDName{ShortName: "set-certExt", LongName: "certificate extensions"}
+	oidDotNotationToNames["2.23.42.8"] = OIDName{ShortName: "set-brand", LongName: "set-brand"}
+	oidDotNotationToNames["2.23.42.0.0"] = OIDName{ShortName: "setct-PANData", LongName: "setct-PANData"}
+	oidDotNotationToNames["2.23.42.0.1"] = OIDName{ShortName: "setct-PANToken", LongName: "setct-PANToken"}
+	oidDotNotationToNames["2.23.42.0.2"] = OIDName{ShortName: "setct-PANOnly", LongName: "setct-PANOnly"}
+	oidDotNotationToNames["2.23.42.0.3"] = OIDName{ShortName: "setct-OIData", LongName: "setct-OIData"}
+	oidDotNotationToNames["2.23.42.0.4"] = OIDName{ShortName: "setct-PI", LongName: "setct-PI"}
+	oidDotNotationToNames["2.23.42.0.5"] = OIDName{ShortName: "setct-PIData", LongName: "setct-PIData"}
+	oidDotNotationToNames["2.23.42.0.6"] = OIDName{ShortName: "setct-PIDataUnsigned", LongName: "setct-PIDataUnsigned"}
+	oidDotNotationToNames["2.23.42.0.7"] = OIDName{ShortName: "setct-HODInput", LongName: "setct-HODInput"}
+	oidDotNotationToNames["2.23.42.0.8"] = OIDName{ShortName: "setct-AuthResBaggage", LongName: "setct-AuthResBaggage"}
+	oidDotNotationToNames["2.23.42.0.9"] = OIDName{ShortName: "setct-AuthRevReqBaggage", LongName: "setct-AuthRevReqBaggage"}
+	oidDotNotationToNames["2.23.42.0.10"] = OIDName{ShortName: "setct-AuthRevResBaggage", LongName: "setct-AuthRevResBaggage"}
+	oidDotNotationToNames["2.23.42.0.11"] = OIDName{ShortName: "setct-CapTokenSeq", LongName: "setct-CapTokenSeq"}
+	oidDotNotationToNames["2.23.42.0.12"] = OIDName{ShortName: "setct-PInitResData", LongName: "setct-PInitResData"}
+	oidDotNotationToNames["2.23.42.0.13"] = OIDName{ShortName: "setct-PI-TBS", LongName: "setct-PI-TBS"}
+	oidDotNotationToNames["2.23.42.0.14"] = OIDName{ShortName: "setct-PResData", LongName: "setct-PResData"}
+	oidDotNotationToNames["2.23.42.0.16"] = OIDName{ShortName: "setct-AuthReqTBS", LongName: "setct-AuthReqTBS"}
+	oidDotNotationToNames["2.23.42.0.17"] = OIDName{ShortName: "setct-AuthResTBS", LongName: "setct-AuthResTBS"}
+	oidDotNotationToNames["2.23.42.0.18"] = OIDName{ShortName: "setct-AuthResTBSX", LongName: "setct-AuthResTBSX"}
+	oidDotNotationToNames["2.23.42.0.19"] = OIDName{ShortName: "setct-AuthTokenTBS", LongName: "setct-AuthTokenTBS"}
+	oidDotNotationToNames["2.23.42.0.20"] = OIDName{ShortName: "setct-CapTokenData", LongName: "setct-CapTokenData"}
+	oidDotNotationToNames["2.23.42.0.21"] = OIDName{ShortName: "setct-CapTokenTBS", LongName: "setct-CapTokenTBS"}
+	oidDotNotationToNames["2.23.42.0.22"] = OIDName{ShortName: "setct-AcqCardCodeMsg", LongName: "setct-AcqCardCodeMsg"}
+	oidDotNotationToNames["2.23.42.0.23"] = OIDName{ShortName: "setct-AuthRevReqTBS", LongName: "setct-AuthRevReqTBS"}
+	oidDotNotationToNames["2.23.42.0.24"] = OIDName{ShortName: "setct-AuthRevResData", LongName: "setct-AuthRevResData"}
+	oidDotNotationToNames["2.23.42.0.25"] = OIDName{ShortName: "setct-AuthRevResTBS", LongName: "setct-AuthRevResTBS"}
+	oidDotNotationToNames["2.23.42.0.26"] = OIDName{ShortName: "setct-CapReqTBS", LongName: "setct-CapReqTBS"}
+	oidDotNotationToNames["2.23.42.0.27"] = OIDName{ShortName: "setct-CapReqTBSX", LongName: "setct-CapReqTBSX"}
+	oidDotNotationToNames["2.23.42.0.28"] = OIDName{ShortName: "setct-CapResData", LongName: "setct-CapResData"}
+	oidDotNotationToNames["2.23.42.0.29"] = OIDName{ShortName: "setct-CapRevReqTBS", LongName: "setct-CapRevReqTBS"}
+	oidDotNotationToNames["2.23.42.0.30"] = OIDName{ShortName: "setct-CapRevReqTBSX", LongName: "setct-CapRevReqTBSX"}
+	oidDotNotationToNames["2.23.42.0.31"] = OIDName{ShortName: "setct-CapRevResData", LongName: "setct-CapRevResData"}
+	oidDotNotationToNames["2.23.42.0.32"] = OIDName{ShortName: "setct-CredReqTBS", LongName: "setct-CredReqTBS"}
+	oidDotNotationToNames["2.23.42.0.33"] = OIDName{ShortName: "setct-CredReqTBSX", LongName: "setct-CredReqTBSX"}
+	oidDotNotationToNames["2.23.42.0.34"] = OIDName{ShortName: "setct-CredResData", LongName: "setct-CredResData"}
+	oidDotNotationToNames["2.23.42.0.35"] = OIDName{ShortName: "setct-CredRevReqTBS", LongName: "setct-CredRevReqTBS"}
+	oidDotNotationToNames["2.23.42.0.36"] = OIDName{ShortName: "setct-CredRevReqTBSX", LongName: "setct-CredRevReqTBSX"}
+	oidDotNotationToNames["2.23.42.0.37"] = OIDName{ShortName: "setct-CredRevResData", LongName: "setct-CredRevResData"}
+	oidDotNotationToNames["2.23.42.0.38"] = OIDName{ShortName: "setct-PCertReqData", LongName: "setct-PCertReqData"}
+	oidDotNotationToNames["2.23.42.0.39"] = OIDName{ShortName: "setct-PCertResTBS", LongName: "setct-PCertResTBS"}
+	oidDotNotationToNames["2.23.42.0.40"] = OIDName{ShortName: "setct-BatchAdminReqData", LongName: "setct-BatchAdminReqData"}
+	oidDotNotationToNames["2.23.42.0.41"] = OIDName{ShortName: "setct-BatchAdminResData", LongName: "setct-BatchAdminResData"}
+	oidDotNotationToNames["2.23.42.0.42"] = OIDName{ShortName: "setct-CardCInitResTBS", LongName: "setct-CardCInitResTBS"}
+	oidDotNotationToNames["2.23.42.0.43"] = OIDName{ShortName: "setct-MeAqCInitResTBS", LongName: "setct-MeAqCInitResTBS"}
+	oidDotNotationToNames["2.23.42.0.44"] = OIDName{ShortName: "setct-RegFormResTBS", LongName: "setct-RegFormResTBS"}
+	oidDotNotationToNames["2.23.42.0.45"] = OIDName{ShortName: "setct-CertReqData", LongName: "setct-CertReqData"}
+	oidDotNotationToNames["2.23.42.0.46"] = OIDName{ShortName: "setct-CertReqTBS", LongName: "setct-CertReqTBS"}
+	oidDotNotationToNames["2.23.42.0.47"] = OIDName{ShortName: "setct-CertResData", LongName: "setct-CertResData"}
+	oidDotNotationToNames["2.23.42.0.48"] = OIDName{ShortName: "setct-CertInqReqTBS", LongName: "setct-CertInqReqTBS"}
+	oidDotNotationToNames["2.23.42.0.49"] = OIDName{ShortName: "setct-ErrorTBS", LongName: "setct-ErrorTBS"}
+	oidDotNotationToNames["2.23.42.0.50"] = OIDName{ShortName: "setct-PIDualSignedTBE", LongName: "setct-PIDualSignedTBE"}
+	oidDotNotationToNames["2.23.42.0.51"] = OIDName{ShortName: "setct-PIUnsignedTBE", LongName: "setct-PIUnsignedTBE"}
+	oidDotNotationToNames["2.23.42.0.52"] = OIDName{ShortName: "setct-AuthReqTBE", LongName: "setct-AuthReqTBE"}
+	oidDotNotationToNames["2.23.42.0.53"] = OIDName{ShortName: "setct-AuthResTBE", LongName: "setct-AuthResTBE"}
+	oidDotNotationToNames["2.23.42.0.54"] = OIDName{ShortName: "setct-AuthResTBEX", LongName: "setct-AuthResTBEX"}
+	oidDotNotationToNames["2.23.42.0.55"] = OIDName{ShortName: "setct-AuthTokenTBE", LongName: "setct-AuthTokenTBE"}
+	oidDotNotationToNames["2.23.42.0.56"] = OIDName{ShortName: "setct-CapTokenTBE", LongName: "setct-CapTokenTBE"}
+	oidDotNotationToNames["2.23.42.0.57"] = OIDName{ShortName: "setct-CapTokenTBEX", LongName: "setct-CapTokenTBEX"}
+	oidDotNotationToNames["2.23.42.0.58"] = OIDName{ShortName: "setct-AcqCardCodeMsgTBE", LongName: "setct-AcqCardCodeMsgTBE"}
+	oidDotNotationToNames["2.23.42.0.59"] = OIDName{ShortName: "setct-AuthRevReqTBE", LongName: "setct-AuthRevReqTBE"}
+	oidDotNotationToNames["2.23.42.0.60"] = OIDName{ShortName: "setct-AuthRevResTBE", LongName: "setct-AuthRevResTBE"}
+	oidDotNotationToNames["2.23.42.0.61"] = OIDName{ShortName: "setct-AuthRevResTBEB", LongName: "setct-AuthRevResTBEB"}
+	oidDotNotationToNames["2.23.42.0.62"] = OIDName{ShortName: "setct-CapReqTBE", LongName: "setct-CapReqTBE"}
+	oidDotNotationToNames["2.23.42.0.63"] = OIDName{ShortName: "setct-CapReqTBEX", LongName: "setct-CapReqTBEX"}
+	oidDotNotationToNames["2.23.42.0.64"] = OIDName{ShortName: "setct-CapResTBE", LongName: "setct-CapResTBE"}
+	oidDotNotationToNames["2.23.42.0.65"] = OIDName{ShortName: "setct-CapRevReqTBE", LongName: "setct-CapRevReqTBE"}
+	oidDotNotationToNames["2.23.42.0.66"] = OIDName{ShortName: "setct-CapRevReqTBEX", LongName: "setct-CapRevReqTBEX"}
+	oidDotNotationToNames["2.23.42.0.67"] = OIDName{ShortName: "setct-CapRevResTBE", LongName: "setct-CapRevResTBE"}
+	oidDotNotationToNames["2.23.42.0.68"] = OIDName{ShortName: "setct-CredReqTBE", LongName: "setct-CredReqTBE"}
+	oidDotNotationToNames["2.23.42.0.69"] = OIDName{ShortName: "setct-CredReqTBEX", LongName: "setct-CredReqTBEX"}
+	oidDotNotationToNames["2.23.42.0.70"] = OIDName{ShortName: "setct-CredResTBE", LongName: "setct-CredResTBE"}
+	oidDotNotationToNames["2.23.42.0.71"] = OIDName{ShortName: "setct-CredRevReqTBE", LongName: "setct-CredRevReqTBE"}
+	oidDotNotationToNames["2.23.42.0.72"] = OIDName{ShortName: "setct-CredRevReqTBEX", LongName: "setct-CredRevReqTBEX"}
+	oidDotNotationToNames["2.23.42.0.73"] = OIDName{ShortName: "setct-CredRevResTBE", LongName: "setct-CredRevResTBE"}
+	oidDotNotationToNames["2.23.42.0.74"] = OIDName{ShortName: "setct-BatchAdminReqTBE", LongName: "setct-BatchAdminReqTBE"}
+	oidDotNotationToNames["2.23.42.0.75"] = OIDName{ShortName: "setct-BatchAdminResTBE", LongName: "setct-BatchAdminResTBE"}
+	oidDotNotationToNames["2.23.42.0.76"] = OIDName{ShortName: "setct-RegFormReqTBE", LongName: "setct-RegFormReqTBE"}
+	oidDotNotationToNames["2.23.42.0.77"] = OIDName{ShortName: "setct-CertReqTBE", LongName: "setct-CertReqTBE"}
+	oidDotNotationToNames["2.23.42.0.78"] = OIDName{ShortName: "setct-CertReqTBEX", LongName: "setct-CertReqTBEX"}
+	oidDotNotationToNames["2.23.42.0.79"] = OIDName{ShortName: "setct-CertResTBE", LongName: "setct-CertResTBE"}
+	oidDotNotationToNames["2.23.42.0.80"] = OIDName{ShortName: "setct-CRLNotificationTBS", LongName: "setct-CRLNotificationTBS"}
+	oidDotNotationToNames["2.23.42.0.81"] = OIDName{ShortName: "setct-CRLNotificationResTBS", LongName: "setct-CRLNotificationResTBS"}
+	oidDotNotationToNames["2.23.42.0.82"] = OIDName{ShortName: "setct-BCIDistributionTBS", LongName: "setct-BCIDistributionTBS"}
+	oidDotNotationToNames["2.23.42.1.1"] = OIDName{ShortName: "setext-genCrypt", LongName: "generic cryptogram"}
+	oidDotNotationToNames["2.23.42.1.3"] = OIDName{ShortName: "setext-miAuth", LongName: "merchant initiated auth"}
+	oidDotNotationToNames["2.23.42.1.4"] = OIDName{ShortName: "setext-pinSecure", LongName: "setext-pinSecure"}
+	oidDotNotationToNames["2.23.42.1.5"] = OIDName{ShortName: "setext-pinAny", LongName: "setext-pinAny"}
+	oidDotNotationToNames["2.23.42.1.7"] = OIDName{ShortName: "setext-track2", LongName: "setext-track2"}
+	oidDotNotationToNames["2.23.42.1.8"] = OIDName{ShortName: "setext-cv", LongName: "additional verification"}
+	oidDotNotationToNames["2.23.42.5.0"] = OIDName{ShortName: "set-policy-root", LongName: "set-policy-root"}
+	oidDotNotationToNames["2.23.42.7.0"] = OIDName{ShortName: "setCext-hashedRoot", LongName: "setCext-hashedRoot"}
+	oidDotNotationToNames["2.23.42.7.1"] = OIDName{ShortName: "setCext-certType", LongName: "setCext-certType"}
+	oidDotNotationToNames["2.23.42.7.2"] = OIDName{ShortName: "setCext-merchData", LongName: "setCext-merchData"}
+	oidDotNotationToNames["2.23.42.7.3"] = OIDName{ShortName: "setCext-cCertRequired", LongName: "setCext-cCertRequired"}
+	oidDotNotationToNames["2.23.42.7.4"] = OIDName{ShortName: "setCext-tunneling", LongName: "setCext-tunneling"}
+	oidDotNotationToNames["2.23.42.7.5"] = OIDName{ShortName: "setCext-setExt", LongName: "setCext-setExt"}
+	oidDotNotationToNames["2.23.42.7.6"] = OIDName{ShortName: "setCext-setQualf", LongName: "setCext-setQualf"}
+	oidDotNotationToNames["2.23.42.7.7"] = OIDName{ShortName: "setCext-PGWYcapabilities", LongName: "setCext-PGWYcapabilities"}
+	oidDotNotationToNames["2.23.42.7.8"] = OIDName{ShortName: "setCext-TokenIdentifier", LongName: "setCext-TokenIdentifier"}
+	oidDotNotationToNames["2.23.42.7.9"] = OIDName{ShortName: "setCext-Track2Data", LongName: "setCext-Track2Data"}
+	oidDotNotationToNames["2.23.42.7.10"] = OIDName{ShortName: "setCext-TokenType", LongName: "setCext-TokenType"}
+	oidDotNotationToNames["2.23.42.7.11"] = OIDName{ShortName: "setCext-IssuerCapabilities", LongName: "setCext-IssuerCapabilities"}
+	oidDotNotationToNames["2.23.42.3.0"] = OIDName{ShortName: "setAttr-Cert", LongName: "setAttr-Cert"}
+	oidDotNotationToNames["2.23.42.3.1"] = OIDName{ShortName: "setAttr-PGWYcap", LongName: "payment gateway capabilities"}
+	oidDotNotationToNames["2.23.42.3.2"] = OIDName{ShortName: "setAttr-TokenType", LongName: "setAttr-TokenType"}
+	oidDotNotationToNames["2.23.42.3.3"] = OIDName{ShortName: "setAttr-IssCap", LongName: "issuer capabilities"}
+	oidDotNotationToNames["2.23.42.3.0.0"] = OIDName{ShortName: "set-rootKeyThumb", LongName: "set-rootKeyThumb"}
+	oidDotNotationToNames["2.23.42.3.0.1"] = OIDName{ShortName: "set-addPolicy", LongName: "set-addPolicy"}
+	oidDotNotationToNames["2.23.42.3.2.1"] = OIDName{ShortName: "setAttr-Token-EMV", LongName: "setAttr-Token-EMV"}
+	oidDotNotationToNames["2.23.42.3.2.2"] = OIDName{ShortName: "setAttr-Token-B0Prime", LongName: "setAttr-Token-B0Prime"}
+	oidDotNotationToNames["2.23.42.3.3.3"] = OIDName{ShortName: "setAttr-IssCap-CVM", LongName: "setAttr-IssCap-CVM"}
+	oidDotNotationToNames["2.23.42.3.3.4"] = OIDName{ShortName: "setAttr-IssCap-T2", LongName: "setAttr-IssCap-T2"}
+	oidDotNotationToNames["2.23.42.3.3.5"] = OIDName{ShortName: "setAttr-IssCap-Sig", LongName: "setAttr-IssCap-Sig"}
+	oidDotNotationToNames["2.23.42.3.3.3.1"] = OIDName{ShortName: "setAttr-GenCryptgrm", LongName: "generate cryptogram"}
+	oidDotNotationToNames["2.23.42.3.3.4.1"] = OIDName{ShortName: "setAttr-T2Enc", LongName: "encrypted track 2"}
+	oidDotNotationToNames["2.23.42.3.3.4.2"] = OIDName{ShortName: "setAttr-T2cleartxt", LongName: "cleartext track 2"}
+	oidDotNotationToNames["2.23.42.3.3.5.1"] = OIDName{ShortName: "setAttr-TokICCsig", LongName: "ICC or token signature"}
+	oidDotNotationToNames["2.23.42.3.3.5.2"] = OIDName{ShortName: "setAttr-SecDevSig", LongName: "secure device signature"}
+	oidDotNotationToNames["2.23.42.8.1"] = OIDName{ShortName: "set-brand-IATA-ATA", LongName: "set-brand-IATA-ATA"}
+	oidDotNotationToNames["2.23.42.8.30"] = OIDName{ShortName: "set-brand-Diners", LongName: "set-brand-Diners"}
+	oidDotNotationToNames["2.23.42.8.34"] = OIDName{ShortName: "set-brand-AmericanExpress", LongName: "set-brand-AmericanExpress"}
+	oidDotNotationToNames["2.23.42.8.35"] = OIDName{ShortName: "set-brand-JCB", LongName: "set-brand-JCB"}
+	oidDotNotationToNames["2.23.42.8.4"] = OIDName{ShortName: "set-brand-Visa", LongName: "set-brand-Visa"}
+	oidDotNotationToNames["2.23.42.8.5"] = OIDName{ShortName: "set-brand-MasterCard", LongName: "set-brand-MasterCard"}
+	oidDotNotationToNames["2.23.42.8.6011"] = OIDName{ShortName: "set-brand-Novus", LongName: "set-brand-Novus"}
+	oidDotNotationToNames["1.2.840.113549.3.10"] = OIDName{ShortName: "DES-CDMF", LongName: "des-cdmf"}
+	oidDotNotationToNames["1.2.840.113549.1.1.6"] = OIDName{ShortName: "rsaOAEPEncryptionSET", LongName: "rsaOAEPEncryptionSET"}
+	oidDotNotationToNames["0.0"] = OIDName{ShortName: "ITU-T", LongName: "itu-t"}
+	oidDotNotationToNames["2.0"] = OIDName{ShortName: "JOINT-ISO-ITU-T", LongName: "joint-iso-itu-t"}
+	oidDotNotationToNames["2.23"] = OIDName{ShortName: "international-organizations", LongName: "International Organizations"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.20.2.2"] = OIDName{ShortName: "msSmartcardLogin", LongName: "Microsoft Smartcardlogin"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.20.2.3"] = OIDName{ShortName: "msUPN", LongName: "Microsoft Universal Principal Name"}
+	oidDotNotationToNames["2.5.4.9"] = OIDName{ShortName: "street", LongName: "streetAddress"}
+	oidDotNotationToNames["2.5.4.17"] = OIDName{ShortName: "postalCode", LongName: "postalCode"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.21"] = OIDName{ShortName: "id-ppl", LongName: "id-ppl"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.1.14"] = OIDName{ShortName: "proxyCertInfo", LongName: "Proxy Certificate Information"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.21.0"] = OIDName{ShortName: "id-ppl-anyLanguage", LongName: "Any language"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.21.1"] = OIDName{ShortName: "id-ppl-inheritAll", LongName: "Inherit all"}
+	oidDotNotationToNames["2.5.29.30"] = OIDName{ShortName: "nameConstraints", LongName: "X509v3 Name Constraints"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.21.2"] = OIDName{ShortName: "id-ppl-independent", LongName: "Independent"}
+	oidDotNotationToNames["1.2.840.113549.1.1.11"] = OIDName{ShortName: "RSA-SHA256", LongName: "sha256WithRSAEncryption"}
+	oidDotNotationToNames["1.2.840.113549.1.1.12"] = OIDName{ShortName: "RSA-SHA384", LongName: "sha384WithRSAEncryption"}
+	oidDotNotationToNames["1.2.840.113549.1.1.13"] = OIDName{ShortName: "RSA-SHA512", LongName: "sha512WithRSAEncryption"}
+	oidDotNotationToNames["1.2.840.113549.1.1.14"] = OIDName{ShortName: "RSA-SHA224", LongName: "sha224WithRSAEncryption"}
+	oidDotNotationToNames["2.16.840.1.101.3.4.2.1"] = OIDName{ShortName: "SHA256", LongName: "sha256"}
+	oidDotNotationToNames["2.16.840.1.101.3.4.2.2"] = OIDName{ShortName: "SHA384", LongName: "sha384"}
+	oidDotNotationToNames["2.16.840.1.101.3.4.2.3"] = OIDName{ShortName: "SHA512", LongName: "sha512"}
+	oidDotNotationToNames["2.16.840.1.101.3.4.2.4"] = OIDName{ShortName: "SHA224", LongName: "sha224"}
+	oidDotNotationToNames["1.3"] = OIDName{ShortName: "identified-organization", LongName: "identified-organization"}
+	oidDotNotationToNames["1.3.132"] = OIDName{ShortName: "certicom-arc", LongName: "certicom-arc"}
+	oidDotNotationToNames["2.23.43"] = OIDName{ShortName: "wap", LongName: "wap"}
+	oidDotNotationToNames["2.23.43.1"] = OIDName{ShortName: "wap-wsg", LongName: "wap-wsg"}
+	oidDotNotationToNames["1.2.840.10045.1.2.3"] = OIDName{ShortName: "id-characteristic-two-basis", LongName: "id-characteristic-two-basis"}
+	oidDotNotationToNames["1.2.840.10045.1.2.3.1"] = OIDName{ShortName: "onBasis", LongName: "onBasis"}
+	oidDotNotationToNames["1.2.840.10045.1.2.3.2"] = OIDName{ShortName: "tpBasis", LongName: "tpBasis"}
+	oidDotNotationToNames["1.2.840.10045.1.2.3.3"] = OIDName{ShortName: "ppBasis", LongName: "ppBasis"}
+	oidDotNotationToNames["1.2.840.10045.3.0.1"] = OIDName{ShortName: "c2pnb163v1", LongName: "c2pnb163v1"}
+	oidDotNotationToNames["1.2.840.10045.3.0.2"] = OIDName{ShortName: "c2pnb163v2", LongName: "c2pnb163v2"}
+	oidDotNotationToNames["1.2.840.10045.3.0.3"] = OIDName{ShortName: "c2pnb163v3", LongName: "c2pnb163v3"}
+	oidDotNotationToNames["1.2.840.10045.3.0.4"] = OIDName{ShortName: "c2pnb176v1", LongName: "c2pnb176v1"}
+	oidDotNotationToNames["1.2.840.10045.3.0.5"] = OIDName{ShortName: "c2tnb191v1", LongName: "c2tnb191v1"}
+	oidDotNotationToNames["1.2.840.10045.3.0.6"] = OIDName{ShortName: "c2tnb191v2", LongName: "c2tnb191v2"}
+	oidDotNotationToNames["1.2.840.10045.3.0.7"] = OIDName{ShortName: "c2tnb191v3", LongName: "c2tnb191v3"}
+	oidDotNotationToNames["1.2.840.10045.3.0.8"] = OIDName{ShortName: "c2onb191v4", LongName: "c2onb191v4"}
+	oidDotNotationToNames["1.2.840.10045.3.0.9"] = OIDName{ShortName: "c2onb191v5", LongName: "c2onb191v5"}
+	oidDotNotationToNames["1.2.840.10045.3.0.10"] = OIDName{ShortName: "c2pnb208w1", LongName: "c2pnb208w1"}
+	oidDotNotationToNames["1.2.840.10045.3.0.11"] = OIDName{ShortName: "c2tnb239v1", LongName: "c2tnb239v1"}
+	oidDotNotationToNames["1.2.840.10045.3.0.12"] = OIDName{ShortName: "c2tnb239v2", LongName: "c2tnb239v2"}
+	oidDotNotationToNames["1.2.840.10045.3.0.13"] = OIDName{ShortName: "c2tnb239v3", LongName: "c2tnb239v3"}
+	oidDotNotationToNames["1.2.840.10045.3.0.14"] = OIDName{ShortName: "c2onb239v4", LongName: "c2onb239v4"}
+	oidDotNotationToNames["1.2.840.10045.3.0.15"] = OIDName{ShortName: "c2onb239v5", LongName: "c2onb239v5"}
+	oidDotNotationToNames["1.2.840.10045.3.0.16"] = OIDName{ShortName: "c2pnb272w1", LongName: "c2pnb272w1"}
+	oidDotNotationToNames["1.2.840.10045.3.0.17"] = OIDName{ShortName: "c2pnb304w1", LongName: "c2pnb304w1"}
+	oidDotNotationToNames["1.2.840.10045.3.0.18"] = OIDName{ShortName: "c2tnb359v1", LongName: "c2tnb359v1"}
+	oidDotNotationToNames["1.2.840.10045.3.0.19"] = OIDName{ShortName: "c2pnb368w1", LongName: "c2pnb368w1"}
+	oidDotNotationToNames["1.2.840.10045.3.0.20"] = OIDName{ShortName: "c2tnb431r1", LongName: "c2tnb431r1"}
+	oidDotNotationToNames["1.3.132.0.6"] = OIDName{ShortName: "secp112r1", LongName: "secp112r1"}
+	oidDotNotationToNames["1.3.132.0.7"] = OIDName{ShortName: "secp112r2", LongName: "secp112r2"}
+	oidDotNotationToNames["1.3.132.0.28"] = OIDName{ShortName: "secp128r1", LongName: "secp128r1"}
+	oidDotNotationToNames["1.3.132.0.29"] = OIDName{ShortName: "secp128r2", LongName: "secp128r2"}
+	oidDotNotationToNames["1.3.132.0.9"] = OIDName{ShortName: "secp160k1", LongName: "secp160k1"}
+	oidDotNotationToNames["1.3.132.0.8"] = OIDName{ShortName: "secp160r1", LongName: "secp160r1"}
+	oidDotNotationToNames["1.3.132.0.30"] = OIDName{ShortName: "secp160r2", LongName: "secp160r2"}
+	oidDotNotationToNames["1.3.132.0.31"] = OIDName{ShortName: "secp192k1", LongName: "secp192k1"}
+	oidDotNotationToNames["1.3.132.0.32"] = OIDName{ShortName: "secp224k1", LongName: "secp224k1"}
+	oidDotNotationToNames["1.3.132.0.33"] = OIDName{ShortName: "secp224r1", LongName: "secp224r1"}
+	oidDotNotationToNames["1.3.132.0.10"] = OIDName{ShortName: "secp256k1", LongName: "secp256k1"}
+	oidDotNotationToNames["1.3.132.0.34"] = OIDName{ShortName: "secp384r1", LongName: "secp384r1"}
+	oidDotNotationToNames["1.3.132.0.35"] = OIDName{ShortName: "secp521r1", LongName: "secp521r1"}
+	oidDotNotationToNames["1.3.132.0.4"] = OIDName{ShortName: "sect113r1", LongName: "sect113r1"}
+	oidDotNotationToNames["1.3.132.0.5"] = OIDName{ShortName: "sect113r2", LongName: "sect113r2"}
+	oidDotNotationToNames["1.3.132.0.22"] = OIDName{ShortName: "sect131r1", LongName: "sect131r1"}
+	oidDotNotationToNames["1.3.132.0.23"] = OIDName{ShortName: "sect131r2", LongName: "sect131r2"}
+	oidDotNotationToNames["1.3.132.0.1"] = OIDName{ShortName: "sect163k1", LongName: "sect163k1"}
+	oidDotNotationToNames["1.3.132.0.2"] = OIDName{ShortName: "sect163r1", LongName: "sect163r1"}
+	oidDotNotationToNames["1.3.132.0.15"] = OIDName{ShortName: "sect163r2", LongName: "sect163r2"}
+	oidDotNotationToNames["1.3.132.0.24"] = OIDName{ShortName: "sect193r1", LongName: "sect193r1"}
+	oidDotNotationToNames["1.3.132.0.25"] = OIDName{ShortName: "sect193r2", LongName: "sect193r2"}
+	oidDotNotationToNames["1.3.132.0.26"] = OIDName{ShortName: "sect233k1", LongName: "sect233k1"}
+	oidDotNotationToNames["1.3.132.0.27"] = OIDName{ShortName: "sect233r1", LongName: "sect233r1"}
+	oidDotNotationToNames["1.3.132.0.3"] = OIDName{ShortName: "sect239k1", LongName: "sect239k1"}
+	oidDotNotationToNames["1.3.132.0.16"] = OIDName{ShortName: "sect283k1", LongName: "sect283k1"}
+	oidDotNotationToNames["1.3.132.0.17"] = OIDName{ShortName: "sect283r1", LongName: "sect283r1"}
+	oidDotNotationToNames["1.3.132.0.36"] = OIDName{ShortName: "sect409k1", LongName: "sect409k1"}
+	oidDotNotationToNames["1.3.132.0.37"] = OIDName{ShortName: "sect409r1", LongName: "sect409r1"}
+	oidDotNotationToNames["1.3.132.0.38"] = OIDName{ShortName: "sect571k1", LongName: "sect571k1"}
+	oidDotNotationToNames["1.3.132.0.39"] = OIDName{ShortName: "sect571r1", LongName: "sect571r1"}
+	oidDotNotationToNames["2.23.43.1.4.1"] = OIDName{ShortName: "wap-wsg-idm-ecid-wtls1", LongName: "wap-wsg-idm-ecid-wtls1"}
+	oidDotNotationToNames["2.23.43.1.4.3"] = OIDName{ShortName: "wap-wsg-idm-ecid-wtls3", LongName: "wap-wsg-idm-ecid-wtls3"}
+	oidDotNotationToNames["2.23.43.1.4.4"] = OIDName{ShortName: "wap-wsg-idm-ecid-wtls4", LongName: "wap-wsg-idm-ecid-wtls4"}
+	oidDotNotationToNames["2.23.43.1.4.5"] = OIDName{ShortName: "wap-wsg-idm-ecid-wtls5", LongName: "wap-wsg-idm-ecid-wtls5"}
+	oidDotNotationToNames["2.23.43.1.4.6"] = OIDName{ShortName: "wap-wsg-idm-ecid-wtls6", LongName: "wap-wsg-idm-ecid-wtls6"}
+	oidDotNotationToNames["2.23.43.1.4.7"] = OIDName{ShortName: "wap-wsg-idm-ecid-wtls7", LongName: "wap-wsg-idm-ecid-wtls7"}
+	oidDotNotationToNames["2.23.43.1.4.8"] = OIDName{ShortName: "wap-wsg-idm-ecid-wtls8", LongName: "wap-wsg-idm-ecid-wtls8"}
+	oidDotNotationToNames["2.23.43.1.4.9"] = OIDName{ShortName: "wap-wsg-idm-ecid-wtls9", LongName: "wap-wsg-idm-ecid-wtls9"}
+	oidDotNotationToNames["2.23.43.1.4.10"] = OIDName{ShortName: "wap-wsg-idm-ecid-wtls10", LongName: "wap-wsg-idm-ecid-wtls10"}
+	oidDotNotationToNames["2.23.43.1.4.11"] = OIDName{ShortName: "wap-wsg-idm-ecid-wtls11", LongName: "wap-wsg-idm-ecid-wtls11"}
+	oidDotNotationToNames["2.23.43.1.4.12"] = OIDName{ShortName: "wap-wsg-idm-ecid-wtls12", LongName: "wap-wsg-idm-ecid-wtls12"}
+	oidDotNotationToNames["2.5.29.32.0"] = OIDName{ShortName: "anyPolicy", LongName: "X509v3 Any Policy"}
+	oidDotNotationToNames["2.5.29.33"] = OIDName{ShortName: "policyMappings", LongName: "X509v3 Policy Mappings"}
+	oidDotNotationToNames["2.5.29.54"] = OIDName{ShortName: "inhibitAnyPolicy", LongName: "X509v3 Inhibit Any Policy"}
+	oidDotNotationToNames["1.2.392.200011.61.1.1.1.2"] = OIDName{ShortName: "CAMELLIA-128-CBC", LongName: "camellia-128-cbc"}
+	oidDotNotationToNames["1.2.392.200011.61.1.1.1.3"] = OIDName{ShortName: "CAMELLIA-192-CBC", LongName: "camellia-192-cbc"}
+	oidDotNotationToNames["1.2.392.200011.61.1.1.1.4"] = OIDName{ShortName: "CAMELLIA-256-CBC", LongName: "camellia-256-cbc"}
+	oidDotNotationToNames["0.3.4401.5.3.1.9.1"] = OIDName{ShortName: "CAMELLIA-128-ECB", LongName: "camellia-128-ecb"}
+	oidDotNotationToNames["0.3.4401.5.3.1.9.21"] = OIDName{ShortName: "CAMELLIA-192-ECB", LongName: "camellia-192-ecb"}
+	oidDotNotationToNames["0.3.4401.5.3.1.9.41"] = OIDName{ShortName: "CAMELLIA-256-ECB", LongName: "camellia-256-ecb"}
+	oidDotNotationToNames["0.3.4401.5.3.1.9.4"] = OIDName{ShortName: "CAMELLIA-128-CFB", LongName: "camellia-128-cfb"}
+	oidDotNotationToNames["0.3.4401.5.3.1.9.24"] = OIDName{ShortName: "CAMELLIA-192-CFB", LongName: "camellia-192-cfb"}
+	oidDotNotationToNames["0.3.4401.5.3.1.9.44"] = OIDName{ShortName: "CAMELLIA-256-CFB", LongName: "camellia-256-cfb"}
+	oidDotNotationToNames["0.3.4401.5.3.1.9.3"] = OIDName{ShortName: "CAMELLIA-128-OFB", LongName: "camellia-128-ofb"}
+	oidDotNotationToNames["0.3.4401.5.3.1.9.23"] = OIDName{ShortName: "CAMELLIA-192-OFB", LongName: "camellia-192-ofb"}
+	oidDotNotationToNames["0.3.4401.5.3.1.9.43"] = OIDName{ShortName: "CAMELLIA-256-OFB", LongName: "camellia-256-ofb"}
+	oidDotNotationToNames["2.5.29.9"] = OIDName{ShortName: "subjectDirectoryAttributes", LongName: "X509v3 Subject Directory Attributes"}
+	oidDotNotationToNames["2.5.29.28"] = OIDName{ShortName: "issuingDistributionPoint", LongName: "X509v3 Issuing Distrubution Point"}
+	oidDotNotationToNames["2.5.29.29"] = OIDName{ShortName: "certificateIssuer", LongName: "X509v3 Certificate Issuer"}
+	oidDotNotationToNames["1.2.410.200004"] = OIDName{ShortName: "KISA", LongName: "kisa"}
+	oidDotNotationToNames["1.2.410.200004.1.3"] = OIDName{ShortName: "SEED-ECB", LongName: "seed-ecb"}
+	oidDotNotationToNames["1.2.410.200004.1.4"] = OIDName{ShortName: "SEED-CBC", LongName: "seed-cbc"}
+	oidDotNotationToNames["1.2.410.200004.1.6"] = OIDName{ShortName: "SEED-OFB", LongName: "seed-ofb"}
+	oidDotNotationToNames["1.2.410.200004.1.5"] = OIDName{ShortName: "SEED-CFB", LongName: "seed-cfb"}
+	oidDotNotationToNames["1.3.6.1.5.5.8.1.1"] = OIDName{ShortName: "HMAC-MD5", LongName: "hmac-md5"}
+	oidDotNotationToNames["1.3.6.1.5.5.8.1.2"] = OIDName{ShortName: "HMAC-SHA1", LongName: "hmac-sha1"}
+	oidDotNotationToNames["1.2.840.113533.7.66.13"] = OIDName{ShortName: "id-PasswordBasedMAC", LongName: "password based MAC"}
+	oidDotNotationToNames["1.2.840.113533.7.66.30"] = OIDName{ShortName: "id-DHBasedMac", LongName: "Diffie-Hellman based MAC"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.4.16"] = OIDName{ShortName: "id-it-suppLangTags", LongName: "id-it-suppLangTags"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.48.5"] = OIDName{ShortName: "caRepository", LongName: "CA Repository"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.1.9"] = OIDName{ShortName: "id-smime-ct-compressedData", LongName: "id-smime-ct-compressedData"}
+	oidDotNotationToNames["1.2.840.113549.1.9.16.1.27"] = OIDName{ShortName: "id-ct-asciiTextWithCRLF", LongName: "id-ct-asciiTextWithCRLF"}
+	oidDotNotationToNames["2.16.840.1.101.3.4.1.5"] = OIDName{ShortName: "id-aes128-wrap", LongName: "id-aes128-wrap"}
+	oidDotNotationToNames["2.16.840.1.101.3.4.1.25"] = OIDName{ShortName: "id-aes192-wrap", LongName: "id-aes192-wrap"}
+	oidDotNotationToNames["2.16.840.1.101.3.4.1.45"] = OIDName{ShortName: "id-aes256-wrap", LongName: "id-aes256-wrap"}
+	oidDotNotationToNames["1.2.840.10045.4.2"] = OIDName{ShortName: "ecdsa-with-Recommended", LongName: "ecdsa-with-Recommended"}
+	oidDotNotationToNames["1.2.840.10045.4.3"] = OIDName{ShortName: "ecdsa-with-Specified", LongName: "ecdsa-with-Specified"}
+	oidDotNotationToNames["1.2.840.10045.4.3.1"] = OIDName{ShortName: "ecdsa-with-SHA224", LongName: "ecdsa-with-SHA224"}
+	oidDotNotationToNames["1.2.840.10045.4.3.2"] = OIDName{ShortName: "ecdsa-with-SHA256", LongName: "ecdsa-with-SHA256"}
+	oidDotNotationToNames["1.2.840.10045.4.3.3"] = OIDName{ShortName: "ecdsa-with-SHA384", LongName: "ecdsa-with-SHA384"}
+	oidDotNotationToNames["1.2.840.10045.4.3.4"] = OIDName{ShortName: "ecdsa-with-SHA512", LongName: "ecdsa-with-SHA512"}
+	oidDotNotationToNames["1.2.840.113549.2.6"] = OIDName{ShortName: "hmacWithMD5", LongName: "hmacWithMD5"}
+	oidDotNotationToNames["1.2.840.113549.2.8"] = OIDName{ShortName: "hmacWithSHA224", LongName: "hmacWithSHA224"}
+	oidDotNotationToNames["1.2.840.113549.2.9"] = OIDName{ShortName: "hmacWithSHA256", LongName: "hmacWithSHA256"}
+	oidDotNotationToNames["1.2.840.113549.2.10"] = OIDName{ShortName: "hmacWithSHA384", LongName: "hmacWithSHA384"}
+	oidDotNotationToNames["1.2.840.113549.2.11"] = OIDName{ShortName: "hmacWithSHA512", LongName: "hmacWithSHA512"}
+	oidDotNotationToNames["2.16.840.1.101.3.4.3.1"] = OIDName{ShortName: "dsa_with_SHA224", LongName: "dsa_with_SHA224"}
+	oidDotNotationToNames["2.16.840.1.101.3.4.3.2"] = OIDName{ShortName: "dsa_with_SHA256", LongName: "dsa_with_SHA256"}
+	oidDotNotationToNames["1.0.10118.3.0.55"] = OIDName{ShortName: "whirlpool", LongName: "whirlpool"}
+	oidDotNotationToNames["1.2.643.2.2"] = OIDName{ShortName: "cryptopro", LongName: "cryptopro"}
+	oidDotNotationToNames["1.2.643.2.9"] = OIDName{ShortName: "cryptocom", LongName: "cryptocom"}
+	oidDotNotationToNames["1.2.643.2.2.3"] = OIDName{ShortName: "id-GostR3411-94-with-GostR3410-2001", LongName: "GOST R 34.11-94 with GOST R 34.10-2001"}
+	oidDotNotationToNames["1.2.643.2.2.4"] = OIDName{ShortName: "id-GostR3411-94-with-GostR3410-94", LongName: "GOST R 34.11-94 with GOST R 34.10-94"}
+	oidDotNotationToNames["1.2.643.2.2.9"] = OIDName{ShortName: "md_gost94", LongName: "GOST R 34.11-94"}
+	oidDotNotationToNames["1.2.643.2.2.10"] = OIDName{ShortName: "id-HMACGostR3411-94", LongName: "HMAC GOST 34.11-94"}
+	oidDotNotationToNames["1.2.643.2.2.19"] = OIDName{ShortName: "gost2001", LongName: "GOST R 34.10-2001"}
+	oidDotNotationToNames["1.2.643.2.2.20"] = OIDName{ShortName: "gost94", LongName: "GOST R 34.10-94"}
+	oidDotNotationToNames["1.2.643.2.2.21"] = OIDName{ShortName: "gost89", LongName: "GOST 28147-89"}
+	oidDotNotationToNames["1.2.643.2.2.22"] = OIDName{ShortName: "gost-mac", LongName: "GOST 28147-89 MAC"}
+	oidDotNotationToNames["1.2.643.2.2.23"] = OIDName{ShortName: "prf-gostr3411-94", LongName: "GOST R 34.11-94 PRF"}
+	oidDotNotationToNames["1.2.643.2.2.98"] = OIDName{ShortName: "id-GostR3410-2001DH", LongName: "GOST R 34.10-2001 DH"}
+	oidDotNotationToNames["1.2.643.2.2.99"] = OIDName{ShortName: "id-GostR3410-94DH", LongName: "GOST R 34.10-94 DH"}
+	oidDotNotationToNames["1.2.643.2.2.14.1"] = OIDName{ShortName: "id-Gost28147-89-CryptoPro-KeyMeshing", LongName: "id-Gost28147-89-CryptoPro-KeyMeshing"}
+	oidDotNotationToNames["1.2.643.2.2.14.0"] = OIDName{ShortName: "id-Gost28147-89-None-KeyMeshing", LongName: "id-Gost28147-89-None-KeyMeshing"}
+	oidDotNotationToNames["1.2.643.2.2.30.0"] = OIDName{ShortName: "id-GostR3411-94-TestParamSet", LongName: "id-GostR3411-94-TestParamSet"}
+	oidDotNotationToNames["1.2.643.2.2.30.1"] = OIDName{ShortName: "id-GostR3411-94-CryptoProParamSet", LongName: "id-GostR3411-94-CryptoProParamSet"}
+	oidDotNotationToNames["1.2.643.2.2.31.0"] = OIDName{ShortName: "id-Gost28147-89-TestParamSet", LongName: "id-Gost28147-89-TestParamSet"}
+	oidDotNotationToNames["1.2.643.2.2.31.1"] = OIDName{ShortName: "id-Gost28147-89-CryptoPro-A-ParamSet", LongName: "id-Gost28147-89-CryptoPro-A-ParamSet"}
+	oidDotNotationToNames["1.2.643.2.2.31.2"] = OIDName{ShortName: "id-Gost28147-89-CryptoPro-B-ParamSet", LongName: "id-Gost28147-89-CryptoPro-B-ParamSet"}
+	oidDotNotationToNames["1.2.643.2.2.31.3"] = OIDName{ShortName: "id-Gost28147-89-CryptoPro-C-ParamSet", LongName: "id-Gost28147-89-CryptoPro-C-ParamSet"}
+	oidDotNotationToNames["1.2.643.2.2.31.4"] = OIDName{ShortName: "id-Gost28147-89-CryptoPro-D-ParamSet", LongName: "id-Gost28147-89-CryptoPro-D-ParamSet"}
+	oidDotNotationToNames["1.2.643.2.2.31.5"] = OIDName{ShortName: "id-Gost28147-89-CryptoPro-Oscar-1-1-ParamSet", LongName: "id-Gost28147-89-CryptoPro-Oscar-1-1-ParamSet"}
+	oidDotNotationToNames["1.2.643.2.2.31.6"] = OIDName{ShortName: "id-Gost28147-89-CryptoPro-Oscar-1-0-ParamSet", LongName: "id-Gost28147-89-CryptoPro-Oscar-1-0-ParamSet"}
+	oidDotNotationToNames["1.2.643.2.2.31.7"] = OIDName{ShortName: "id-Gost28147-89-CryptoPro-RIC-1-ParamSet", LongName: "id-Gost28147-89-CryptoPro-RIC-1-ParamSet"}
+	oidDotNotationToNames["1.2.643.2.2.32.0"] = OIDName{ShortName: "id-GostR3410-94-TestParamSet", LongName: "id-GostR3410-94-TestParamSet"}
+	oidDotNotationToNames["1.2.643.2.2.32.2"] = OIDName{ShortName: "id-GostR3410-94-CryptoPro-A-ParamSet", LongName: "id-GostR3410-94-CryptoPro-A-ParamSet"}
+	oidDotNotationToNames["1.2.643.2.2.32.3"] = OIDName{ShortName: "id-GostR3410-94-CryptoPro-B-ParamSet", LongName: "id-GostR3410-94-CryptoPro-B-ParamSet"}
+	oidDotNotationToNames["1.2.643.2.2.32.4"] = OIDName{ShortName: "id-GostR3410-94-CryptoPro-C-ParamSet", LongName: "id-GostR3410-94-CryptoPro-C-ParamSet"}
+	oidDotNotationToNames["1.2.643.2.2.32.5"] = OIDName{ShortName: "id-GostR3410-94-CryptoPro-D-ParamSet", LongName: "id-GostR3410-94-CryptoPro-D-ParamSet"}
+	oidDotNotationToNames["1.2.643.2.2.33.1"] = OIDName{ShortName: "id-GostR3410-94-CryptoPro-XchA-ParamSet", LongName: "id-GostR3410-94-CryptoPro-XchA-ParamSet"}
+	oidDotNotationToNames["1.2.643.2.2.33.2"] = OIDName{ShortName: "id-GostR3410-94-CryptoPro-XchB-ParamSet", LongName: "id-GostR3410-94-CryptoPro-XchB-ParamSet"}
+	oidDotNotationToNames["1.2.643.2.2.33.3"] = OIDName{ShortName: "id-GostR3410-94-CryptoPro-XchC-ParamSet", LongName: "id-GostR3410-94-CryptoPro-XchC-ParamSet"}
+	oidDotNotationToNames["1.2.643.2.2.35.0"] = OIDName{ShortName: "id-GostR3410-2001-TestParamSet", LongName: "id-GostR3410-2001-TestParamSet"}
+	oidDotNotationToNames["1.2.643.2.2.35.1"] = OIDName{ShortName: "id-GostR3410-2001-CryptoPro-A-ParamSet", LongName: "id-GostR3410-2001-CryptoPro-A-ParamSet"}
+	oidDotNotationToNames["1.2.643.2.2.35.2"] = OIDName{ShortName: "id-GostR3410-2001-CryptoPro-B-ParamSet", LongName: "id-GostR3410-2001-CryptoPro-B-ParamSet"}
+	oidDotNotationToNames["1.2.643.2.2.35.3"] = OIDName{ShortName: "id-GostR3410-2001-CryptoPro-C-ParamSet", LongName: "id-GostR3410-2001-CryptoPro-C-ParamSet"}
+	oidDotNotationToNames["1.2.643.2.2.36.0"] = OIDName{ShortName: "id-GostR3410-2001-CryptoPro-XchA-ParamSet", LongName: "id-GostR3410-2001-CryptoPro-XchA-ParamSet"}
+	oidDotNotationToNames["1.2.643.2.2.36.1"] = OIDName{ShortName: "id-GostR3410-2001-CryptoPro-XchB-ParamSet", LongName: "id-GostR3410-2001-CryptoPro-XchB-ParamSet"}
+	oidDotNotationToNames["1.2.643.2.2.20.1"] = OIDName{ShortName: "id-GostR3410-94-a", LongName: "id-GostR3410-94-a"}
+	oidDotNotationToNames["1.2.643.2.2.20.2"] = OIDName{ShortName: "id-GostR3410-94-aBis", LongName: "id-GostR3410-94-aBis"}
+	oidDotNotationToNames["1.2.643.2.2.20.3"] = OIDName{ShortName: "id-GostR3410-94-b", LongName: "id-GostR3410-94-b"}
+	oidDotNotationToNames["1.2.643.2.2.20.4"] = OIDName{ShortName: "id-GostR3410-94-bBis", LongName: "id-GostR3410-94-bBis"}
+	oidDotNotationToNames["1.2.643.2.9.1.6.1"] = OIDName{ShortName: "id-Gost28147-89-cc", LongName: "GOST 28147-89 Cryptocom ParamSet"}
+	oidDotNotationToNames["1.2.643.2.9.1.5.3"] = OIDName{ShortName: "gost94cc", LongName: "GOST 34.10-94 Cryptocom"}
+	oidDotNotationToNames["1.2.643.2.9.1.5.4"] = OIDName{ShortName: "gost2001cc", LongName: "GOST 34.10-2001 Cryptocom"}
+	oidDotNotationToNames["1.2.643.2.9.1.3.3"] = OIDName{ShortName: "id-GostR3411-94-with-GostR3410-94-cc", LongName: "GOST R 34.11-94 with GOST R 34.10-94 Cryptocom"}
+	oidDotNotationToNames["1.2.643.2.9.1.3.4"] = OIDName{ShortName: "id-GostR3411-94-with-GostR3410-2001-cc", LongName: "GOST R 34.11-94 with GOST R 34.10-2001 Cryptocom"}
+	oidDotNotationToNames["1.2.643.2.9.1.8.1"] = OIDName{ShortName: "id-GostR3410-2001-ParamSet-cc", LongName: "GOST R 3410-2001 Parameter Set Cryptocom"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.17.2"] = OIDName{ShortName: "LocalKeySet", LongName: "Microsoft Local Key set"}
+	oidDotNotationToNames["2.5.29.46"] = OIDName{ShortName: "freshestCRL", LongName: "X509v3 Freshest CRL"}
+	oidDotNotationToNames["1.3.6.1.5.5.7.8.3"] = OIDName{ShortName: "id-on-permanentIdentifier", LongName: "Permanent Identifier"}
+	oidDotNotationToNames["2.5.4.14"] = OIDName{ShortName: "searchGuide", LongName: "searchGuide"}
+	oidDotNotationToNames["2.5.4.15"] = OIDName{ShortName: "businessCategory", LongName: "businessCategory"}
+	oidDotNotationToNames["2.5.4.16"] = OIDName{ShortName: "postalAddress", LongName: "postalAddress"}
+	oidDotNotationToNames["2.5.4.18"] = OIDName{ShortName: "postOfficeBox", LongName: "postOfficeBox"}
+	oidDotNotationToNames["2.5.4.19"] = OIDName{ShortName: "physicalDeliveryOfficeName", LongName: "physicalDeliveryOfficeName"}
+	oidDotNotationToNames["2.5.4.20"] = OIDName{ShortName: "telephoneNumber", LongName: "telephoneNumber"}
+	oidDotNotationToNames["2.5.4.21"] = OIDName{ShortName: "telexNumber", LongName: "telexNumber"}
+	oidDotNotationToNames["2.5.4.22"] = OIDName{ShortName: "teletexTerminalIdentifier", LongName: "teletexTerminalIdentifier"}
+	oidDotNotationToNames["2.5.4.23"] = OIDName{ShortName: "facsimileTelephoneNumber", LongName: "facsimileTelephoneNumber"}
+	oidDotNotationToNames["2.5.4.24"] = OIDName{ShortName: "x121Address", LongName: "x121Address"}
+	oidDotNotationToNames["2.5.4.25"] = OIDName{ShortName: "internationaliSDNNumber", LongName: "internationaliSDNNumber"}
+	oidDotNotationToNames["2.5.4.26"] = OIDName{ShortName: "registeredAddress", LongName: "registeredAddress"}
+	oidDotNotationToNames["2.5.4.27"] = OIDName{ShortName: "destinationIndicator", LongName: "destinationIndicator"}
+	oidDotNotationToNames["2.5.4.28"] = OIDName{ShortName: "preferredDeliveryMethod", LongName: "preferredDeliveryMethod"}
+	oidDotNotationToNames["2.5.4.29"] = OIDName{ShortName: "presentationAddress", LongName: "presentationAddress"}
+	oidDotNotationToNames["2.5.4.30"] = OIDName{ShortName: "supportedApplicationContext", LongName: "supportedApplicationContext"}
+	oidDotNotationToNames["2.5.4.31"] = OIDName{ShortName: "member", LongName: "member"}
+	oidDotNotationToNames["2.5.4.32"] = OIDName{ShortName: "owner", LongName: "owner"}
+	oidDotNotationToNames["2.5.4.33"] = OIDName{ShortName: "roleOccupant", LongName: "roleOccupant"}
+	oidDotNotationToNames["2.5.4.34"] = OIDName{ShortName: "seeAlso", LongName: "seeAlso"}
+	oidDotNotationToNames["2.5.4.35"] = OIDName{ShortName: "userPassword", LongName: "userPassword"}
+	oidDotNotationToNames["2.5.4.36"] = OIDName{ShortName: "userCertificate", LongName: "userCertificate"}
+	oidDotNotationToNames["2.5.4.37"] = OIDName{ShortName: "cACertificate", LongName: "cACertificate"}
+	oidDotNotationToNames["2.5.4.38"] = OIDName{ShortName: "authorityRevocationList", LongName: "authorityRevocationList"}
+	oidDotNotationToNames["2.5.4.39"] = OIDName{ShortName: "certificateRevocationList", LongName: "certificateRevocationList"}
+	oidDotNotationToNames["2.5.4.40"] = OIDName{ShortName: "crossCertificatePair", LongName: "crossCertificatePair"}
+	oidDotNotationToNames["2.5.4.47"] = OIDName{ShortName: "enhancedSearchGuide", LongName: "enhancedSearchGuide"}
+	oidDotNotationToNames["2.5.4.48"] = OIDName{ShortName: "protocolInformation", LongName: "protocolInformation"}
+	oidDotNotationToNames["2.5.4.49"] = OIDName{ShortName: "distinguishedName", LongName: "distinguishedName"}
+	oidDotNotationToNames["2.5.4.50"] = OIDName{ShortName: "uniqueMember", LongName: "uniqueMember"}
+	oidDotNotationToNames["2.5.4.51"] = OIDName{ShortName: "houseIdentifier", LongName: "houseIdentifier"}
+	oidDotNotationToNames["2.5.4.52"] = OIDName{ShortName: "supportedAlgorithms", LongName: "supportedAlgorithms"}
+	oidDotNotationToNames["2.5.4.53"] = OIDName{ShortName: "deltaRevocationList", LongName: "deltaRevocationList"}
+	oidDotNotationToNames["2.5.4.54"] = OIDName{ShortName: "dmdName", LongName: "dmdName"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.17.1"] = OIDName{ShortName: "MS_LOCAL_MACHINE_KEYSET", LongName: "MS_LOCAL_MACHINE_KEYSET"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.4.1"] = OIDName{ShortName: "MS_YESNO_TRUST_ATTR", LongName: "MS_YESNO_TRUST_ATTR"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.13.2.1"] = OIDName{ShortName: "MS_ENROLLMENT_NAME_VALUE_PAIR", LongName: "MS_ENROLLMENT_NAME_VALUE_PAIR"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.13.2.3"] = OIDName{ShortName: "MS_OS_VERSION", LongName: "MS_OS_VERSION"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.13.2.2"] = OIDName{ShortName: "MS_ENROLLMENT_CSP_PROVIDER", LongName: "MS_ENROLLMENT_CSP_PROVIDER"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.12.1.2"] = OIDName{ShortName: "MS_CATALOG_LIST_MEMBER", LongName: "MS_CATALOG_LIST_MEMBER"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.11"] = OIDName{ShortName: "MS_CERT_PROP_ID_PREFIX", LongName: "MS_CERT_PROP_ID_PREFIX"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.13.1"] = OIDName{ShortName: "MS_RENEWAL_CERTIFICATE", LongName: "MS_RENEWAL_CERTIFICATE"}
+	oidDotNotationToNames["1.3.6.1.4.1.311"] = OIDName{ShortName: "MS_OID", LongName: "MS_OID"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.2.1.30"] = OIDName{ShortName: "MS_SPC_SIPINFO_OBJID", LongName: "MS_SPC_SIPINFO_OBJID"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.88.3"] = OIDName{ShortName: "MS_CAPICOM_ENCRYPTED_DATA", LongName: "MS_CAPICOM_ENCRYPTED_DATA"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.88.2"] = OIDName{ShortName: "MS_CAPICOM_ATTRIBUTE", LongName: "MS_CAPICOM_ATTRIBUTE"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.88.1"] = OIDName{ShortName: "MS_CAPICOM_VERSION", LongName: "MS_CAPICOM_VERSION"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.6.2"] = OIDName{ShortName: "MS_LICENSE_SERVER", LongName: "MS_LICENSE_SERVER"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.10.1"] = OIDName{ShortName: "MS_CMC_ADD_ATTRIBUTES", LongName: "MS_CMC_ADD_ATTRIBUTES"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.3.2.1"] = OIDName{ShortName: "MS_SPC_TIME_STAMP_REQUEST_OBJID", LongName: "MS_SPC_TIME_STAMP_REQUEST_OBJID"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.12.1"] = OIDName{ShortName: "MS_ANY_APPLICATION_POLICY", LongName: "MS_ANY_APPLICATION_POLICY"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.44.0.4"] = OIDName{ShortName: "MS_PEERNET_CERT_VERSION", LongName: "MS_PEERNET_CERT_VERSION"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.21.19"] = OIDName{ShortName: "MS_DS_EMAIL_REPLICATION", LongName: "MS_DS_EMAIL_REPLICATION"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.21.16"] = OIDName{ShortName: "MS_ARCHIVED_KEY_CERT_HASH", LongName: "MS_ARCHIVED_KEY_CERT_HASH"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.21.17"] = OIDName{ShortName: "MS_ISSUED_CERT_HASH", LongName: "MS_ISSUED_CERT_HASH"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.21.14"] = OIDName{ShortName: "MS_CRL_SELF_CDP", LongName: "MS_CRL_SELF_CDP"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.21.15"] = OIDName{ShortName: "MS_REQUIRE_CERT_CHAIN_POLICY", LongName: "MS_REQUIRE_CERT_CHAIN_POLICY"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.21.12"] = OIDName{ShortName: "MS_APPLICATION_POLICY_CONSTRAINTS", LongName: "MS_APPLICATION_POLICY_CONSTRAINTS"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.21.13"] = OIDName{ShortName: "MS_ARCHIVED_KEY_ATTR", LongName: "MS_ARCHIVED_KEY_ATTR"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.21.10"] = OIDName{ShortName: "MS_APPLICATION_CERT_POLICIES", LongName: "MS_APPLICATION_CERT_POLICIES"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.21.11"] = OIDName{ShortName: "MS_APPLICATION_POLICY_MAPPINGS", LongName: "MS_APPLICATION_POLICY_MAPPINGS"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.44"] = OIDName{ShortName: "MS_Peer_Networking", LongName: "MS_Peer_Networking"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.12.2.1"] = OIDName{ShortName: "MS_CAT_NAMEVALUE_OBJID", LongName: "MS_CAT_NAMEVALUE_OBJID"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.5.1"] = OIDName{ShortName: "MS_DRM", LongName: "MS_DRM"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.43"] = OIDName{ShortName: "MS_WWOps_BizExt", LongName: "MS_WWOps_BizExt"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.5.2"] = OIDName{ShortName: "MS_DRM_INDIVIDUALIZATION", LongName: "MS_DRM_INDIVIDUALIZATION"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.3.13"] = OIDName{ShortName: "MS_KP_LIFETIME_SIGNING", LongName: "MS_KP_LIFETIME_SIGNING"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.3.12"] = OIDName{ShortName: "MS_KP_DOCUMENT_SIGNING", LongName: "MS_KP_DOCUMENT_SIGNING"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.3.11"] = OIDName{ShortName: "MS_KP_KEY_RECOVERY", LongName: "MS_KP_KEY_RECOVERY"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.3.10"] = OIDName{ShortName: "MS_KP_QUALIFIED_SUBORDINATION", LongName: "MS_KP_QUALIFIED_SUBORDINATION"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.18.1"] = OIDName{ShortName: "MS_PKIX_LICENSE_INFO", LongName: "MS_PKIX_LICENSE_INFO"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.18.2"] = OIDName{ShortName: "MS_PKIX_MANUFACTURER", LongName: "MS_PKIX_MANUFACTURER"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.18.3"] = OIDName{ShortName: "MS_PKIX_MANUFACTURER_MS_SPECIFIC", LongName: "MS_PKIX_MANUFACTURER_MS_SPECIFIC"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.18.4"] = OIDName{ShortName: "MS_PKIX_HYDRA_CERT_VERSION", LongName: "MS_PKIX_HYDRA_CERT_VERSION"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.18.5"] = OIDName{ShortName: "MS_PKIX_LICENSED_PRODUCT_INFO", LongName: "MS_PKIX_LICENSED_PRODUCT_INFO"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.18.6"] = OIDName{ShortName: "MS_PKIX_MS_LICENSE_SERVER_INFO", LongName: "MS_PKIX_MS_LICENSE_SERVER_INFO"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.18.7"] = OIDName{ShortName: "MS_PKIS_PRODUCT_SPECIFIC_OID", LongName: "MS_PKIS_PRODUCT_SPECIFIC_OID"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.21.22"] = OIDName{ShortName: "MS_CERTSRV_CROSSCA_VERSION", LongName: "MS_CERTSRV_CROSSCA_VERSION"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.21.21"] = OIDName{ShortName: "MS_ENCRYPTED_KEY_HASH", LongName: "MS_ENCRYPTED_KEY_HASH"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.21.20"] = OIDName{ShortName: "MS_REQUEST_CLIENT_INFO", LongName: "MS_REQUEST_CLIENT_INFO"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.20.3"] = OIDName{ShortName: "MS_CERT_MANIFOLD", LongName: "MS_CERT_MANIFOLD"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.1.1"] = OIDName{ShortName: "MS_SORTED_CTL", LongName: "MS_SORTED_CTL"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.44.1.3"] = OIDName{ShortName: "MS_PEERNET_PNRP_PAYLOAD", LongName: "MS_PEERNET_PNRP_PAYLOAD"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.7.1"] = OIDName{ShortName: "MS_KEYID_RDN", LongName: "MS_KEYID_RDN"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.44.1.1"] = OIDName{ShortName: "MS_PEERNET_PNRP_ADDRESS", LongName: "MS_PEERNET_PNRP_ADDRESS"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.21.8"] = OIDName{ShortName: "MS_ENTERPRISE_OID_ROOT", LongName: "MS_ENTERPRISE_OID_ROOT"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.44.1.4"] = OIDName{ShortName: "MS_PEERNET_PNRP_ID", LongName: "MS_PEERNET_PNRP_ID"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.44.3.1"] = OIDName{ShortName: "MS_PEERNET_GROUPING_PEERNAME", LongName: "MS_PEERNET_GROUPING_PEERNAME"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.12"] = OIDName{ShortName: "MS_CryptUI", LongName: "MS_CryptUI"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.10"] = OIDName{ShortName: "MS_CMC_OIDs", LongName: "MS_CMC_OIDs"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.11"] = OIDName{ShortName: "MS_certificate_property_OIDs", LongName: "MS_certificate_property_OIDs"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.2.1.4"] = OIDName{ShortName: "MS_SPC_INDIRECT_DATA_OBJID", LongName: "MS_SPC_INDIRECT_DATA_OBJID"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.2.2"] = OIDName{ShortName: "MS_CTL_for_Software_Publishers_Trusted_CAs", LongName: "MS_CTL_for_Software_Publishers_Trusted_CAs"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.44.3.5"] = OIDName{ShortName: "MS_PEERNET_GROUPING_CLASSIFIERS", LongName: "MS_PEERNET_GROUPING_CLASSIFIERS"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.2"] = OIDName{ShortName: "MS_Authenticode", LongName: "MS_Authenticode"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.3"] = OIDName{ShortName: "MS_Time_Stamping", LongName: "MS_Time_Stamping"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.21.7"] = OIDName{ShortName: "MS_CERTIFICATE_TEMPLATE", LongName: "MS_CERTIFICATE_TEMPLATE"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.4"] = OIDName{ShortName: "MS_Permissions", LongName: "MS_Permissions"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.30"] = OIDName{ShortName: "MS_IIS", LongName: "MS_IIS"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.19"] = OIDName{ShortName: "MS_ISPU_Test", LongName: "MS_ISPU_Test"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.3.7"] = OIDName{ShortName: "MS_OEM_WHQL_CRYPTO", LongName: "MS_OEM_WHQL_CRYPTO"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.3.6"] = OIDName{ShortName: "MS_NT5_CRYPTO", LongName: "MS_NT5_CRYPTO"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.3.5"] = OIDName{ShortName: "MS_WHQL_CRYPTO", LongName: "MS_WHQL_CRYPTO"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.3.4"] = OIDName{ShortName: "MS_EFS_CRYPTO", LongName: "MS_EFS_CRYPTO"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.20.2.3"] = OIDName{ShortName: "MS_NT_PRINCIPAL_NAME", LongName: "MS_NT_PRINCIPAL_NAME"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.20.2.2"] = OIDName{ShortName: "MS_KP_SMARTCARD_LOGON", LongName: "MS_KP_SMARTCARD_LOGON"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.20.2.1"] = OIDName{ShortName: "MS_ENROLLMENT_AGENT", LongName: "MS_ENROLLMENT_AGENT"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.3.9"] = OIDName{ShortName: "MS_ROOT_LIST_SIGNER", LongName: "MS_ROOT_LIST_SIGNER"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.3.8"] = OIDName{ShortName: "MS_EMBEDDED_NT_CRYPTO", LongName: "MS_EMBEDDED_NT_CRYPTO"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.18.8"] = OIDName{ShortName: "MS_PKIS_TLSERVER_SPK_OID", LongName: "MS_PKIS_TLSERVER_SPK_OID"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.2.2.2"] = OIDName{ShortName: "MS_TRUSTED_CLIENT_AUTH_CA_LIST", LongName: "MS_TRUSTED_CLIENT_AUTH_CA_LIST"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.2.2.3"] = OIDName{ShortName: "MS_TRUSTED_SERVER_AUTH_CA_LIST", LongName: "MS_TRUSTED_SERVER_AUTH_CA_LIST"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.12.1.1"] = OIDName{ShortName: "MS_CATALOG_LIST", LongName: "MS_CATALOG_LIST"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.2.2.1"] = OIDName{ShortName: "MS_TRUSTED_CODESIGNING_CA_LIST", LongName: "MS_TRUSTED_CODESIGNING_CA_LIST"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.45"] = OIDName{ShortName: "MS_Mobile_Devices_Code_Signing", LongName: "MS_Mobile_Devices_Code_Signing"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.30.1"] = OIDName{ShortName: "MS_IIS_VIRTUAL_SERVER", LongName: "MS_IIS_VIRTUAL_SERVER"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.3.14"] = OIDName{ShortName: "MS_KP_MOBILE_DEVICE_SOFTWARE", LongName: "MS_KP_MOBILE_DEVICE_SOFTWARE"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.8.1"] = OIDName{ShortName: "MS_REMOVE_CERTIFICATE", LongName: "MS_REMOVE_CERTIFICATE"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.42"] = OIDName{ShortName: "MS_Corporate_PKI_(ITG)", LongName: "MS_Corporate_PKI_(ITG)"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.2.1.26"] = OIDName{ShortName: "MS_SPC_MINIMAL_CRITERIA_OBJID", LongName: "MS_SPC_MINIMAL_CRITERIA_OBJID"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.44.3.2"] = OIDName{ShortName: "MS_PEERNET_GROUPING_FLAGS", LongName: "MS_PEERNET_GROUPING_FLAGS"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.44.3.3"] = OIDName{ShortName: "MS_PEERNET_GROUPING_ROLES", LongName: "MS_PEERNET_GROUPING_ROLES"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.41"] = OIDName{ShortName: "MS_Licensing_and_Registration", LongName: "MS_Licensing_and_Registration"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.20"] = OIDName{ShortName: "MS_Enrollment_Infrastructure", LongName: "MS_Enrollment_Infrastructure"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.40"] = OIDName{ShortName: "MS_Fonts", LongName: "MS_Fonts"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.21"] = OIDName{ShortName: "MS_CertSrv_Infrastructure", LongName: "MS_CertSrv_Infrastructure"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.3.3.1"] = OIDName{ShortName: "MS_SERIALIZED", LongName: "MS_SERIALIZED"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.12.2.2"] = OIDName{ShortName: "MS_CAT_MEMBERINFO_OBJID", LongName: "MS_CAT_MEMBERINFO_OBJID"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.25"] = OIDName{ShortName: "MS_Directory_Service", LongName: "MS_Directory_Service"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.44.0.3"] = OIDName{ShortName: "MS_PEERNET_CLASSIFIER", LongName: "MS_PEERNET_CLASSIFIER"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.44.0.1"] = OIDName{ShortName: "MS_PEERNET_CERT_TYPE", LongName: "MS_PEERNET_CERT_TYPE"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.44.1"] = OIDName{ShortName: "MS_PEERNET_PNRP", LongName: "MS_PEERNET_PNRP"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.88.3.1"] = OIDName{ShortName: "MS_CAPICOM_ENCRYPTED_CONTENT", LongName: "MS_CAPICOM_ENCRYPTED_CONTENT"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.44.0.2"] = OIDName{ShortName: "MS_PEERNET_PEERNAME", LongName: "MS_PEERNET_PEERNAME"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.44.3"] = OIDName{ShortName: "MS_PEERNET_GROUPING", LongName: "MS_PEERNET_GROUPING"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.44.1.2"] = OIDName{ShortName: "MS_PEERNET_PNRP_FLAGS", LongName: "MS_PEERNET_PNRP_FLAGS"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.15"] = OIDName{ShortName: "MS_Java", LongName: "MS_Java"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.16"] = OIDName{ShortName: "MS_Outlook/Exchange", LongName: "MS_Outlook/Exchange"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.17"] = OIDName{ShortName: "MS_PKCS12_attributes", LongName: "MS_PKCS12_attributes"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10"] = OIDName{ShortName: "MS_Crypto_2.0", LongName: "MS_Crypto_2.0"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.21.9"] = OIDName{ShortName: "MS_RDN_DUMMY_SIGNER", LongName: "MS_RDN_DUMMY_SIGNER"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.12"] = OIDName{ShortName: "MS_Catalog", LongName: "MS_Catalog"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.13"] = OIDName{ShortName: "MS_PKCS10_OIDs", LongName: "MS_PKCS10_OIDs"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.21.4"] = OIDName{ShortName: "MS_CRL_NEXT_PUBLISH", LongName: "MS_CRL_NEXT_PUBLISH"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.21.5"] = OIDName{ShortName: "MS_KP_CA_EXCHANGE", LongName: "MS_KP_CA_EXCHANGE"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.21.6"] = OIDName{ShortName: "MS_KP_KEY_RECOVERY_AGENT", LongName: "MS_KP_KEY_RECOVERY_AGENT"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.6.1"] = OIDName{ShortName: "MS_LICENSES", LongName: "MS_LICENSES"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.18"] = OIDName{ShortName: "MS_Hydra", LongName: "MS_Hydra"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.21.1"] = OIDName{ShortName: "MS_CERTSRV_CA_VERSION", LongName: "MS_CERTSRV_CA_VERSION"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.21.2"] = OIDName{ShortName: "MS_CERTSRV_PREVIOUS_CERT_HASH", LongName: "MS_CERTSRV_PREVIOUS_CERT_HASH"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.21.3"] = OIDName{ShortName: "MS_CRL_VIRTUAL_BASE", LongName: "MS_CRL_VIRTUAL_BASE"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.31.1"] = OIDName{ShortName: "MS_PRODUCT_UPDATE", LongName: "MS_PRODUCT_UPDATE"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.16.4"] = OIDName{ShortName: "MS_MICROSOFT_Encryption_Key_Preference", LongName: "MS_MICROSOFT_Encryption_Key_Preference"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.44.2"] = OIDName{ShortName: "MS_PEERNET_IDENTITY", LongName: "MS_PEERNET_IDENTITY"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.88"] = OIDName{ShortName: "MS_CAPICOM", LongName: "MS_CAPICOM"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.9.1"] = OIDName{ShortName: "MS_CROSS_CERT_DIST_POINTS", LongName: "MS_CROSS_CERT_DIST_POINTS"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.2.1.19"] = OIDName{ShortName: "MS_SPC_STRUCTURED_STORAGE_DATA_OBJID", LongName: "MS_SPC_STRUCTURED_STORAGE_DATA_OBJID"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.2.1.18"] = OIDName{ShortName: "MS_SPC_RAW_FILE_DATA_OBJID", LongName: "MS_SPC_RAW_FILE_DATA_OBJID"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.2.1.25"] = OIDName{ShortName: "MS_SPC_GLUE_RDN_OBJID", LongName: "MS_SPC_GLUE_RDN_OBJID"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.2.1.11"] = OIDName{ShortName: "MS_SPC_STATEMENT_TYPE_OBJID", LongName: "MS_SPC_STATEMENT_TYPE_OBJID"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.2.1.10"] = OIDName{ShortName: "MS_SPC_SP_AGENCY_INFO_OBJID", LongName: "MS_SPC_SP_AGENCY_INFO_OBJID"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.3.4.1"] = OIDName{ShortName: "MS_EFS_RECOVERY", LongName: "MS_EFS_RECOVERY"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.2.1.12"] = OIDName{ShortName: "MS_SPC_SP_OPUS_INFO_OBJID", LongName: "MS_SPC_SP_OPUS_INFO_OBJID"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.2.1.15"] = OIDName{ShortName: "MS_SPC_PE_IMAGE_DATA_OBJID", LongName: "MS_SPC_PE_IMAGE_DATA_OBJID"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.2.1.14"] = OIDName{ShortName: "MS_SPC_CERT_EXTENSIONS_OBJID", LongName: "MS_SPC_CERT_EXTENSIONS_OBJID"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.25.1"] = OIDName{ShortName: "MS_NTDS_REPLICATION", LongName: "MS_NTDS_REPLICATION"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.2.1.27"] = OIDName{ShortName: "MS_SPC_FINANCIAL_CRITERIA_OBJID", LongName: "MS_SPC_FINANCIAL_CRITERIA_OBJID"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.3.3"] = OIDName{ShortName: "MS_SERVER_GATED_CRYPTO", LongName: "MS_SERVER_GATED_CRYPTO"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.11.1"] = OIDName{ShortName: "MS_CERT_PROP_ID_PREFIX", LongName: "MS_CERT_PROP_ID_PREFIX"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.3.2"] = OIDName{ShortName: "MS_KP_TIME_STAMP_SIGNING", LongName: "MS_KP_TIME_STAMP_SIGNING"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.3.1"] = OIDName{ShortName: "MS_KP_CTL_USAGE_SIGNING", LongName: "MS_KP_CTL_USAGE_SIGNING"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.31"] = OIDName{ShortName: "MS_Windows_updates_and_service_packs", LongName: "MS_Windows_updates_and_service_packs"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.88.2.1"] = OIDName{ShortName: "MS_CAPICOM_DOCUMENT_NAME", LongName: "MS_CAPICOM_DOCUMENT_NAME"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.88.2.2"] = OIDName{ShortName: "MS_CAPICOM_DOCUMENT_DESCRIPTION", LongName: "MS_CAPICOM_DOCUMENT_DESCRIPTION"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.44.2.2"] = OIDName{ShortName: "MS_PEERNET_IDENTITY_FLAGS", LongName: "MS_PEERNET_IDENTITY_FLAGS"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.20.1"] = OIDName{ShortName: "MS_AUTO_ENROLL_CTL_USAGE", LongName: "MS_AUTO_ENROLL_CTL_USAGE"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.1"] = OIDName{ShortName: "MS_CTL", LongName: "MS_CTL"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.2"] = OIDName{ShortName: "MS_NEXT_UPDATE_LOCATION", LongName: "MS_NEXT_UPDATE_LOCATION"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.20.2"] = OIDName{ShortName: "MS_ENROLL_CERTTYPE_EXTENSION", LongName: "MS_ENROLL_CERTTYPE_EXTENSION"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.2.1.20"] = OIDName{ShortName: "MS_SPC_JAVA_CLASS_DATA_OBJID", LongName: "MS_SPC_JAVA_CLASS_DATA_OBJID"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.2.1.21"] = OIDName{ShortName: "MS_SPC_INDIVIDUAL_SP_KEY_PURPOSE_OBJID", LongName: "MS_SPC_INDIVIDUAL_SP_KEY_PURPOSE_OBJID"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.2.1.22"] = OIDName{ShortName: "MS_SPC_COMMERCIAL_SP_KEY_PURPOSE_OBJID", LongName: "MS_SPC_COMMERCIAL_SP_KEY_PURPOSE_OBJID"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.10.7"] = OIDName{ShortName: "MS_MICROSOFT_RDN_PREFIX", LongName: "MS_MICROSOFT_RDN_PREFIX"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.2.1.28"] = OIDName{ShortName: "MS_SPC_LINK_OBJID", LongName: "MS_SPC_LINK_OBJID"}
+	// EV Certificates
+	oidDotNotationToNames["1.3.6.1.4.1.311.60.2.1.1"] = OIDName{ShortName: "jurisdictionLocality", LongName: "jurisdictionLocalityName"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.60.2.1.2"] = OIDName{ShortName: "jurisdictionStateOrProvince", LongName: "jurisdictionStateOrProvinceName"}
+	oidDotNotationToNames["1.3.6.1.4.1.311.60.2.1.3"] = OIDName{ShortName: "jurisdictionCountry", LongName: "jurisdictionCountryName"}
+
+}

+ 299 - 0
vendor/github.com/zmap/zcrypto/x509/pkix/pkix.go

@@ -0,0 +1,299 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package pkix contains shared, low level structures used for ASN.1 parsing
+// and serialization of X.509 certificates, CRL and OCSP.
+package pkix
+
+import (
+	"encoding/asn1"
+	"math/big"
+	"strings"
+	"time"
+)
+
+// AlgorithmIdentifier represents the ASN.1 structure of the same name. See RFC
+// 5280, section 4.1.1.2.
+type AlgorithmIdentifier struct {
+	Algorithm  asn1.ObjectIdentifier
+	Parameters asn1.RawValue `asn1:"optional"`
+}
+
+type RDNSequence []RelativeDistinguishedNameSET
+
+type RelativeDistinguishedNameSET []AttributeTypeAndValue
+
+// AttributeTypeAndValue mirrors the ASN.1 structure of the same name in
+// http://tools.ietf.org/html/rfc5280#section-4.1.2.4
+type AttributeTypeAndValue struct {
+	Type  asn1.ObjectIdentifier `json:"type"`
+	Value interface{}           `json:"value"`
+}
+
+// AttributeTypeAndValueSET represents a set of ASN.1 sequences of
+// AttributeTypeAndValue sequences from RFC 2986 (PKCS #10).
+type AttributeTypeAndValueSET struct {
+	Type  asn1.ObjectIdentifier
+	Value [][]AttributeTypeAndValue `asn1:"set"`
+}
+
+// Extension represents the ASN.1 structure of the same name. See RFC
+// 5280, section 4.2.
+type Extension struct {
+	Id       asn1.ObjectIdentifier
+	Critical bool `asn1:"optional"`
+	Value    []byte
+}
+
+// Name represents an X.509 distinguished name. This only includes the common
+// elements of a DN.  Additional elements in the name are ignored.
+type Name struct {
+	Country, Organization, OrganizationalUnit  []string
+	Locality, Province                         []string
+	StreetAddress, PostalCode, DomainComponent []string
+	EmailAddress                               []string
+	SerialNumber, CommonName                   string
+	SerialNumbers, CommonNames                 []string
+	GivenName, Surname                         []string
+	OrganizationIDs                            []string
+	// EV Components
+	JurisdictionLocality, JurisdictionProvince, JurisdictionCountry []string
+
+	Names      []AttributeTypeAndValue
+	ExtraNames []AttributeTypeAndValue
+
+	// OriginalRDNS is saved if the name is populated using FillFromRDNSequence.
+	// Additionally, if OriginalRDNS is non-nil, the String and ToRDNSequence
+	// methods will simply use this.
+	OriginalRDNS RDNSequence
+}
+
+// FillFromRDNSequence populates n based on the AttributeTypeAndValueSETs in the
+// RDNSequence. It save the sequence as OriginalRDNS.
+func (n *Name) FillFromRDNSequence(rdns *RDNSequence) {
+	n.OriginalRDNS = *rdns
+	for _, rdn := range *rdns {
+		if len(rdn) == 0 {
+			continue
+		}
+		atv := rdn[0]
+		n.Names = append(n.Names, atv)
+		value, ok := atv.Value.(string)
+		if !ok {
+			continue
+		}
+
+		t := atv.Type
+		if len(t) == 4 && t[0] == 2 && t[1] == 5 && t[2] == 4 {
+			switch t[3] {
+			case 3:
+				n.CommonName = value
+				n.CommonNames = append(n.CommonNames, value)
+			case 4:
+				n.Surname = append(n.Surname, value)
+			case 5:
+				n.SerialNumber = value
+				n.SerialNumbers = append(n.SerialNumbers, value)
+			case 6:
+				n.Country = append(n.Country, value)
+			case 7:
+				n.Locality = append(n.Locality, value)
+			case 8:
+				n.Province = append(n.Province, value)
+			case 9:
+				n.StreetAddress = append(n.StreetAddress, value)
+			case 10:
+				n.Organization = append(n.Organization, value)
+			case 11:
+				n.OrganizationalUnit = append(n.OrganizationalUnit, value)
+			case 17:
+				n.PostalCode = append(n.PostalCode, value)
+			case 42:
+				n.GivenName = append(n.GivenName, value)
+			case 97:
+				n.OrganizationIDs = append(n.OrganizationIDs, value)
+			}
+		} else if t.Equal(oidDomainComponent) {
+			n.DomainComponent = append(n.DomainComponent, value)
+		} else if t.Equal(oidDNEmailAddress) {
+			// Deprecated, see RFC 5280 Section 4.1.2.6
+			n.EmailAddress = append(n.EmailAddress, value)
+		} else if t.Equal(oidJurisdictionLocality) {
+			n.JurisdictionLocality = append(n.JurisdictionLocality, value)
+		} else if t.Equal(oidJurisdictionProvince) {
+			n.JurisdictionProvince = append(n.JurisdictionProvince, value)
+		} else if t.Equal(oidJurisdictionCountry) {
+			n.JurisdictionCountry = append(n.JurisdictionCountry, value)
+		}
+	}
+}
+
+var (
+	oidCountry            = []int{2, 5, 4, 6}
+	oidOrganization       = []int{2, 5, 4, 10}
+	oidOrganizationalUnit = []int{2, 5, 4, 11}
+	oidCommonName         = []int{2, 5, 4, 3}
+	oidSurname            = []int{2, 5, 4, 4}
+	oidSerialNumber       = []int{2, 5, 4, 5}
+	oidLocality           = []int{2, 5, 4, 7}
+	oidProvince           = []int{2, 5, 4, 8}
+	oidStreetAddress      = []int{2, 5, 4, 9}
+	oidPostalCode         = []int{2, 5, 4, 17}
+	oidGivenName          = []int{2, 5, 4, 42}
+	oidDomainComponent    = []int{0, 9, 2342, 19200300, 100, 1, 25}
+	oidDNEmailAddress     = []int{1, 2, 840, 113549, 1, 9, 1}
+	// EV
+	oidJurisdictionLocality = []int{1, 3, 6, 1, 4, 1, 311, 60, 2, 1, 1}
+	oidJurisdictionProvince = []int{1, 3, 6, 1, 4, 1, 311, 60, 2, 1, 2}
+	oidJurisdictionCountry  = []int{1, 3, 6, 1, 4, 1, 311, 60, 2, 1, 3}
+	// QWACS
+	oidOrganizationID = []int{2, 5, 4, 97}
+)
+
+// appendRDNs appends a relativeDistinguishedNameSET to the given RDNSequence
+// and returns the new value. The relativeDistinguishedNameSET contains an
+// attributeTypeAndValue for each of the given values. See RFC 5280, A.1, and
+// search for AttributeTypeAndValue.
+func (n Name) appendRDNs(in RDNSequence, values []string, oid asn1.ObjectIdentifier) RDNSequence {
+	// NOTE: stdlib prevents adding if the oid is already present in n.ExtraNames
+	//if len(values) == 0 || oidInAttributeTypeAndValue(oid, n.ExtraNames) {
+	if len(values) == 0 {
+		return in
+	}
+
+	s := make([]AttributeTypeAndValue, len(values))
+	for i, value := range values {
+		s[i].Type = oid
+		s[i].Value = value
+	}
+
+	return append(in, s)
+}
+
+// String returns an RDNSequence as comma seperated list of
+// AttributeTypeAndValues in canonical form.
+func (seq RDNSequence) String() string {
+	out := make([]string, 0, len(seq))
+	// An RDNSequence is effectively an [][]AttributeTypeAndValue
+	for _, atvSet := range seq {
+		for _, atv := range atvSet {
+			// Convert each individual AttributeTypeAndValue to X=Y
+			attrParts := make([]string, 0, 2)
+			oidString := atv.Type.String()
+			oidName, ok := oidDotNotationToNames[oidString]
+			if ok {
+				attrParts = append(attrParts, oidName.ShortName)
+			} else {
+				attrParts = append(attrParts, oidString)
+			}
+			switch value := atv.Value.(type) {
+			case string:
+				attrParts = append(attrParts, value)
+			case []byte:
+				attrParts = append(attrParts, string(value))
+			default:
+				continue
+			}
+			attrString := strings.Join(attrParts, "=")
+			out = append(out, attrString)
+		}
+	}
+	return strings.Join(out, ", ")
+}
+
+// ToRDNSequence returns OriginalRDNS is populated. Otherwise, it builds an
+// RDNSequence in canonical order.
+func (n Name) ToRDNSequence() (ret RDNSequence) {
+	if n.OriginalRDNS != nil {
+		return n.OriginalRDNS
+	}
+	if len(n.CommonName) > 0 {
+		ret = n.appendRDNs(ret, []string{n.CommonName}, oidCommonName)
+	}
+	ret = n.appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit)
+	ret = n.appendRDNs(ret, n.Organization, oidOrganization)
+	ret = n.appendRDNs(ret, n.StreetAddress, oidStreetAddress)
+	ret = n.appendRDNs(ret, n.Locality, oidLocality)
+	ret = n.appendRDNs(ret, n.Province, oidProvince)
+	ret = n.appendRDNs(ret, n.PostalCode, oidPostalCode)
+	ret = n.appendRDNs(ret, n.Country, oidCountry)
+	ret = n.appendRDNs(ret, n.DomainComponent, oidDomainComponent)
+	// EV Components
+	ret = n.appendRDNs(ret, n.JurisdictionLocality, oidJurisdictionLocality)
+	ret = n.appendRDNs(ret, n.JurisdictionProvince, oidJurisdictionProvince)
+	ret = n.appendRDNs(ret, n.JurisdictionCountry, oidJurisdictionCountry)
+	// QWACS
+	ret = n.appendRDNs(ret, n.OrganizationIDs, oidOrganizationID)
+	if len(n.SerialNumber) > 0 {
+		ret = n.appendRDNs(ret, []string{n.SerialNumber}, oidSerialNumber)
+	}
+	ret = append(ret, n.ExtraNames)
+	return ret
+}
+
+// oidInAttributeTypeAndValue returns whether a type with the given OID exists
+// in atv.
+func oidInAttributeTypeAndValue(oid asn1.ObjectIdentifier, atv []AttributeTypeAndValue) bool {
+	for _, a := range atv {
+		if a.Type.Equal(oid) {
+			return true
+		}
+	}
+	return false
+}
+
+// CertificateList represents the ASN.1 structure of the same name. See RFC
+// 5280, section 5.1. Use Certificate.CheckCRLSignature to verify the
+// signature.
+type CertificateList struct {
+	TBSCertList        TBSCertificateList
+	SignatureAlgorithm AlgorithmIdentifier
+	SignatureValue     asn1.BitString
+}
+
+// HasExpired reports whether now is past the expiry time of certList.
+func (certList *CertificateList) HasExpired(now time.Time) bool {
+	return now.After(certList.TBSCertList.NextUpdate)
+}
+
+// String returns a canonical representation of a DistinguishedName
+func (n *Name) String() string {
+	seq := n.ToRDNSequence()
+	return seq.String()
+}
+
+// OtherName represents the ASN.1 structure of the same name. See RFC
+// 5280, section 4.2.1.6.
+type OtherName struct {
+	TypeID asn1.ObjectIdentifier
+	Value  asn1.RawValue `asn1:"explicit"`
+}
+
+// EDIPartyName represents the ASN.1 structure of the same name. See RFC
+// 5280, section 4.2.1.6.
+type EDIPartyName struct {
+	NameAssigner string `asn1:"tag:0,optional,explicit" json:"name_assigner,omitempty"`
+	PartyName    string `asn1:"tag:1,explicit" json:"party_name"`
+}
+
+// TBSCertificateList represents the ASN.1 structure of the same name. See RFC
+// 5280, section 5.1.
+type TBSCertificateList struct {
+	Raw                 asn1.RawContent
+	Version             int `asn1:"optional,default:0"`
+	Signature           AlgorithmIdentifier
+	Issuer              RDNSequence
+	ThisUpdate          time.Time
+	NextUpdate          time.Time            `asn1:"optional"`
+	RevokedCertificates []RevokedCertificate `asn1:"optional"`
+	Extensions          []Extension          `asn1:"tag:0,optional,explicit"`
+}
+
+// RevokedCertificate represents the ASN.1 structure of the same name. See RFC
+// 5280, section 5.1.
+type RevokedCertificate struct {
+	SerialNumber   *big.Int
+	RevocationTime time.Time
+	Extensions     []Extension `asn1:"optional"`
+}

+ 173 - 0
vendor/github.com/zmap/zcrypto/x509/qc_statements.go

@@ -0,0 +1,173 @@
+package x509
+
+import (
+	"encoding/asn1"
+	"encoding/json"
+	"errors"
+)
+
+type QCStatementASN struct {
+	StatementID   asn1.ObjectIdentifier
+	StatementInfo asn1.RawValue `asn1:"optional"`
+}
+
+func (s *QCStatementASN) MarshalJSON() ([]byte, error) {
+	aux := struct {
+		ID    string `json:"id,omitempty"`
+		Value []byte `json:"value,omitempty"`
+	}{
+		ID:    s.StatementID.String(),
+		Value: s.StatementInfo.Bytes,
+	}
+	return json.Marshal(&aux)
+}
+
+type QCStatementsASN struct {
+	QCStatements []QCStatementASN
+}
+
+// ETSI OIDS from https://www.etsi.org/deliver/etsi_en/319400_319499/31941205/02.02.03_20/en_31941205v020203a.pdf
+var (
+	oidEtsiQcsQcCompliance      = asn1.ObjectIdentifier{0, 4, 0, 1862, 1, 1}
+	oidEtsiQcsQcLimitValue      = asn1.ObjectIdentifier{0, 4, 0, 1862, 1, 2}
+	oidEtsiQcsQcRetentionPeriod = asn1.ObjectIdentifier{0, 4, 0, 1862, 1, 3}
+	oidEtsiQcsQcSSCD            = asn1.ObjectIdentifier{0, 4, 0, 1862, 1, 4}
+	oidEtsiQcsQcEuPDS           = asn1.ObjectIdentifier{0, 4, 0, 1862, 1, 5}
+	oidEtsiQcsQcType            = asn1.ObjectIdentifier{0, 4, 0, 1862, 1, 6}
+	oidEtsiQcsQcCCLegislation   = asn1.ObjectIdentifier{0, 4, 0, 1862, 1, 7}
+	oidEtsiQcsQctEsign          = asn1.ObjectIdentifier{0, 4, 0, 1862, 1, 6, 1}
+	oidEtsiQcsQctEseal          = asn1.ObjectIdentifier{0, 4, 0, 1862, 1, 6, 2}
+	oidEtsiQcsQctWeb            = asn1.ObjectIdentifier{0, 4, 0, 1862, 1, 6, 3}
+)
+
+type QCStatements struct {
+	StatementIDs     []string            `json:"ids,omitempty"`
+	ParsedStatements *ParsedQCStatements `json:"parsed,omitempty"`
+}
+
+type ParsedQCStatements struct {
+	ETSICompliance  []bool          `json:"etsi_compliance,omitempty"`
+	SSCD            []bool          `json:"sscd,omitempty"`
+	Types           []QCType        `json:"types,omitempty"`
+	Limit           []MonetaryValue `json:"limit,omitempty"`
+	PDSLocations    []PDSLocations  `json:"pds_locations,omitempty"`
+	RetentionPeriod []int           `json:"retention_period,omitempty"`
+	Legislation     []QCLegistation `json:"legislation,omitempty"`
+}
+
+type MonetaryValue struct {
+	Currency       string `json:"currency,omitempty"`
+	CurrencyNumber int    `json:"currency_number,omitempty"`
+	Amount         int    `json:"amount,omitempty"`
+	Exponent       int    `json:"exponent,omitempty"`
+}
+
+type monetaryValueASNString struct {
+	Currency string `asn1:"printable"`
+	Amount   int
+	Exponent int
+}
+
+type monetaryValueASNNumber struct {
+	Currency int
+	Amount   int
+	Exponent int
+}
+
+type PDSLocations struct {
+	Locations []PDSLocation `json:"locations,omitempty"`
+}
+
+type PDSLocation struct {
+	URL      string `json:"url,omitempty" asn1:"ia5"`
+	Language string `json:"language,omitempty" asn1:"printable"`
+}
+
+type QCType struct {
+	TypeIdentifiers []asn1.ObjectIdentifier
+}
+
+type QCLegistation struct {
+	CountryCodes []string `json:"country_codes,omitempty"`
+}
+
+func (qt *QCType) MarshalJSON() ([]byte, error) {
+	aux := struct {
+		Types []string `json:"ids,omitempty"`
+	}{
+		Types: make([]string, len(qt.TypeIdentifiers)),
+	}
+	for idx := range qt.TypeIdentifiers {
+		aux.Types[idx] = qt.TypeIdentifiers[idx].String()
+	}
+	return json.Marshal(&aux)
+}
+
+func (q *QCStatements) Parse(in *QCStatementsASN) error {
+	q.StatementIDs = make([]string, len(in.QCStatements))
+	known := ParsedQCStatements{}
+	for i, s := range in.QCStatements {
+		val := in.QCStatements[i].StatementInfo.FullBytes
+		q.StatementIDs[i] = s.StatementID.String()
+		if s.StatementID.Equal(oidEtsiQcsQcCompliance) {
+			known.ETSICompliance = append(known.ETSICompliance, true)
+			if val != nil {
+				return errors.New("EtsiQcsQcCompliance QCStatement must not contain a statementInfo")
+			}
+		} else if s.StatementID.Equal(oidEtsiQcsQcLimitValue) {
+			// TODO
+			mvs := monetaryValueASNString{}
+			mvn := monetaryValueASNNumber{}
+			out := MonetaryValue{}
+			if _, err := asn1.Unmarshal(val, &mvs); err == nil {
+				out.Currency = mvs.Currency
+				out.Amount = mvs.Amount
+				out.Exponent = mvs.Exponent
+			} else if _, err := asn1.Unmarshal(val, &mvn); err == nil {
+				out.CurrencyNumber = mvn.Currency
+				out.Amount = mvn.Amount
+				out.Exponent = mvn.Exponent
+			} else {
+				return err
+			}
+			known.Limit = append(known.Limit, out)
+		} else if s.StatementID.Equal(oidEtsiQcsQcRetentionPeriod) {
+			var retentionPeriod int
+			if _, err := asn1.Unmarshal(val, &retentionPeriod); err != nil {
+				return err
+			}
+			known.RetentionPeriod = append(known.RetentionPeriod, retentionPeriod)
+		} else if s.StatementID.Equal(oidEtsiQcsQcSSCD) {
+			known.SSCD = append(known.SSCD, true)
+			if val != nil {
+				return errors.New("EtsiQcsQcSSCD QCStatement must not contain a statementInfo")
+			}
+		} else if s.StatementID.Equal(oidEtsiQcsQcEuPDS) {
+			locations := make([]PDSLocation, 0)
+			if _, err := asn1.Unmarshal(val, &locations); err != nil {
+				return err
+			}
+			known.PDSLocations = append(known.PDSLocations, PDSLocations{
+				Locations: locations,
+			})
+		} else if s.StatementID.Equal(oidEtsiQcsQcType) {
+			typeIds := make([]asn1.ObjectIdentifier, 0)
+			if _, err := asn1.Unmarshal(val, &typeIds); err != nil {
+				return err
+			}
+			known.Types = append(known.Types, QCType{
+				TypeIdentifiers: typeIds,
+			})
+		} else if s.StatementID.Equal(oidEtsiQcsQcCCLegislation) {
+			countryCodes := make([]string, 0)
+			if _, err := asn1.Unmarshal(val, &countryCodes); err != nil {
+				return err
+			}
+			known.Legislation = append(known.Legislation, QCLegistation{
+				CountryCodes: countryCodes,
+			})
+		}
+	}
+	q.ParsedStatements = &known
+	return nil
+}

+ 105 - 0
vendor/github.com/zmap/zcrypto/x509/sec1.go

@@ -0,0 +1,105 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+	"crypto/ecdsa"
+	"crypto/elliptic"
+	"encoding/asn1"
+	"errors"
+	"fmt"
+	"math/big"
+)
+
+const ecPrivKeyVersion = 1
+
+// ecPrivateKey reflects an ASN.1 Elliptic Curve Private Key Structure.
+// References:
+//   RFC 5915
+//   SEC1 - http://www.secg.org/sec1-v2.pdf
+// Per RFC 5915 the NamedCurveOID is marked as ASN.1 OPTIONAL, however in
+// most cases it is not.
+type ecPrivateKey struct {
+	Version       int
+	PrivateKey    []byte
+	NamedCurveOID asn1.ObjectIdentifier `asn1:"optional,explicit,tag:0"`
+	PublicKey     asn1.BitString        `asn1:"optional,explicit,tag:1"`
+}
+
+// ParseECPrivateKey parses an ASN.1 Elliptic Curve Private Key Structure.
+func ParseECPrivateKey(der []byte) (*ecdsa.PrivateKey, error) {
+	return parseECPrivateKey(nil, der)
+}
+
+// MarshalECPrivateKey marshals an EC private key into ASN.1, DER format.
+func MarshalECPrivateKey(key *ecdsa.PrivateKey) ([]byte, error) {
+	oid, ok := oidFromNamedCurve(key.Curve)
+	if !ok {
+		return nil, errors.New("x509: unknown elliptic curve")
+	}
+
+	privateKeyBytes := key.D.Bytes()
+	paddedPrivateKey := make([]byte, (key.Curve.Params().N.BitLen()+7)/8)
+	copy(paddedPrivateKey[len(paddedPrivateKey)-len(privateKeyBytes):], privateKeyBytes)
+
+	return asn1.Marshal(ecPrivateKey{
+		Version:       1,
+		PrivateKey:    paddedPrivateKey,
+		NamedCurveOID: oid,
+		PublicKey:     asn1.BitString{Bytes: elliptic.Marshal(key.Curve, key.X, key.Y)},
+	})
+}
+
+// parseECPrivateKey parses an ASN.1 Elliptic Curve Private Key Structure.
+// The OID for the named curve may be provided from another source (such as
+// the PKCS8 container) - if it is provided then use this instead of the OID
+// that may exist in the EC private key structure.
+func parseECPrivateKey(namedCurveOID *asn1.ObjectIdentifier, der []byte) (key *ecdsa.PrivateKey, err error) {
+	var privKey ecPrivateKey
+	if _, err := asn1.Unmarshal(der, &privKey); err != nil {
+		return nil, errors.New("x509: failed to parse EC private key: " + err.Error())
+	}
+	if privKey.Version != ecPrivKeyVersion {
+		return nil, fmt.Errorf("x509: unknown EC private key version %d", privKey.Version)
+	}
+
+	var curve elliptic.Curve
+	if namedCurveOID != nil {
+		curve = namedCurveFromOID(*namedCurveOID)
+	} else {
+		curve = namedCurveFromOID(privKey.NamedCurveOID)
+	}
+	if curve == nil {
+		return nil, errors.New("x509: unknown elliptic curve")
+	}
+
+	k := new(big.Int).SetBytes(privKey.PrivateKey)
+	curveOrder := curve.Params().N
+	if k.Cmp(curveOrder) >= 0 {
+		return nil, errors.New("x509: invalid elliptic curve private key value")
+	}
+	priv := new(ecdsa.PrivateKey)
+	priv.Curve = curve
+	priv.D = k
+
+	privateKey := make([]byte, (curveOrder.BitLen()+7)/8)
+
+	// Some private keys have leading zero padding. This is invalid
+	// according to [SEC1], but this code will ignore it.
+	for len(privKey.PrivateKey) > len(privateKey) {
+		if privKey.PrivateKey[0] != 0 {
+			return nil, errors.New("x509: invalid private key length")
+		}
+		privKey.PrivateKey = privKey.PrivateKey[1:]
+	}
+
+	// Some private keys remove all leading zeros, this is also invalid
+	// according to [SEC1] but since OpenSSL used to do this, we ignore
+	// this too.
+	copy(privateKey[len(privateKey)-len(privKey.PrivateKey):], privKey.PrivateKey)
+	priv.X, priv.Y = curve.ScalarBaseMult(privateKey)
+
+	return priv, nil
+}

+ 158 - 0
vendor/github.com/zmap/zcrypto/x509/tor_service_descriptor.go

@@ -0,0 +1,158 @@
+package x509
+
+import (
+	"encoding/asn1"
+	"github.com/zmap/zcrypto/x509/pkix"
+)
+
+var (
+	// oidBRTorServiceDescriptor is the assigned OID for the CAB Forum Tor Service
+	// Descriptor Hash extension (see EV Guidelines Appendix F)
+	oidBRTorServiceDescriptor = asn1.ObjectIdentifier{2, 23, 140, 1, 31}
+)
+
+// TorServiceDescriptorHash is a structure corrsponding to the
+// TorServiceDescriptorHash SEQUENCE described in Appendix F ("Issuance of
+// Certificates for .onion Domain Names").
+//
+// Each TorServiceDescriptorHash holds an onion URI (a utf8 string with the
+// .onion address that was validated), a hash algorithm name (computed based on
+// the pkix.AlgorithmIdentifier in the TorServiceDescriptorHash), the hash bytes
+// (computed over the DER encoding of the ASN.1 SubjectPublicKey of the .onion
+// service), and the number of bits in the hash bytes.
+type TorServiceDescriptorHash struct {
+	Onion         string                   `json:"onion"`
+	Algorithm     pkix.AlgorithmIdentifier `json:"-"`
+	AlgorithmName string                   `json:"algorithm_name"`
+	Hash          CertificateFingerprint   `json:"hash"`
+	HashBits      int                      `json:"hash_bits"`
+}
+
+// parseTorServiceDescriptorSyntax parses the given pkix.Extension (assumed to
+// have OID == oidBRTorServiceDescriptor) and returns a slice of parsed
+// TorServiceDescriptorHash objects, or an error. An error will be returned if
+// there are any structural errors related to the ASN.1 content (wrong tags,
+// trailing data, missing fields, etc).
+func parseTorServiceDescriptorSyntax(ext pkix.Extension) ([]*TorServiceDescriptorHash, error) {
+	// TorServiceDescriptorSyntax ::=
+	//    SEQUENCE ( 1..MAX ) of TorServiceDescriptorHash
+	var seq asn1.RawValue
+	rest, err := asn1.Unmarshal(ext.Value, &seq)
+	if err != nil {
+		return nil, asn1.SyntaxError{
+			Msg: "unable to unmarshal outer TorServiceDescriptor SEQUENCE",
+		}
+	}
+	if len(rest) != 0 {
+		return nil, asn1.SyntaxError{
+			Msg: "trailing data after outer TorServiceDescriptor SEQUENCE",
+		}
+	}
+	if seq.Tag != asn1.TagSequence || seq.Class != asn1.ClassUniversal || !seq.IsCompound {
+		return nil, asn1.SyntaxError{
+			Msg: "invalid outer TorServiceDescriptor SEQUENCE",
+		}
+	}
+
+	var descriptors []*TorServiceDescriptorHash
+	rest = seq.Bytes
+	for len(rest) > 0 {
+		var descriptor *TorServiceDescriptorHash
+		descriptor, rest, err = parseTorServiceDescriptorHash(rest)
+		if err != nil {
+			return nil, err
+		}
+		descriptors = append(descriptors, descriptor)
+	}
+	return descriptors, nil
+}
+
+// parseTorServiceDescriptorHash unmarshals a SEQUENCE from the provided data
+// and parses a TorServiceDescriptorHash using the data contained in the
+// sequence. The TorServiceDescriptorHash object and the remaining data are
+// returned if no error occurs.
+func parseTorServiceDescriptorHash(data []byte) (*TorServiceDescriptorHash, []byte, error) {
+	// TorServiceDescriptorHash:: = SEQUENCE {
+	//   onionURI UTF8String
+	//   algorithm AlgorithmIdentifier
+	//   subjectPublicKeyHash BIT STRING
+	// }
+	var outerSeq asn1.RawValue
+	var err error
+	data, err = asn1.Unmarshal(data, &outerSeq)
+	if err != nil {
+		return nil, data, asn1.SyntaxError{
+			Msg: "error unmarshaling TorServiceDescriptorHash SEQUENCE",
+		}
+	}
+	if outerSeq.Tag != asn1.TagSequence ||
+		outerSeq.Class != asn1.ClassUniversal ||
+		!outerSeq.IsCompound {
+		return nil, data, asn1.SyntaxError{
+			Msg: "TorServiceDescriptorHash missing compound SEQUENCE tag",
+		}
+	}
+	fieldData := outerSeq.Bytes
+
+	// Unmarshal and verify the structure of the onionURI UTF8String field.
+	var rawOnionURI asn1.RawValue
+	fieldData, err = asn1.Unmarshal(fieldData, &rawOnionURI)
+	if err != nil {
+		return nil, data, asn1.SyntaxError{
+			Msg: "error unmarshaling TorServiceDescriptorHash onionURI",
+		}
+	}
+	if rawOnionURI.Tag != asn1.TagUTF8String ||
+		rawOnionURI.Class != asn1.ClassUniversal ||
+		rawOnionURI.IsCompound {
+		return nil, data, asn1.SyntaxError{
+			Msg: "TorServiceDescriptorHash missing non-compound UTF8String tag",
+		}
+	}
+
+	// Unmarshal and verify the structure of the algorithm UTF8String field.
+	var algorithm pkix.AlgorithmIdentifier
+	fieldData, err = asn1.Unmarshal(fieldData, &algorithm)
+	if err != nil {
+		return nil, nil, asn1.SyntaxError{
+			Msg: "error unmarshaling TorServiceDescriptorHash algorithm",
+		}
+	}
+
+	var algorithmName string
+	if algorithm.Algorithm.Equal(oidSHA256) {
+		algorithmName = "SHA256"
+	} else if algorithm.Algorithm.Equal(oidSHA384) {
+		algorithmName = "SHA384"
+	} else if algorithm.Algorithm.Equal(oidSHA512) {
+		algorithmName = "SHA512"
+	} else {
+		algorithmName = "Unknown"
+	}
+
+	// Unmarshal and verify the structure of the Subject Public Key Hash BitString
+	// field.
+	var spkh asn1.BitString
+	fieldData, err = asn1.Unmarshal(fieldData, &spkh)
+	if err != nil {
+		return nil, data, asn1.SyntaxError{
+			Msg: "error unmarshaling TorServiceDescriptorHash Hash",
+		}
+	}
+
+	// There should be no trailing data after the TorServiceDescriptorHash
+	// SEQUENCE.
+	if len(fieldData) > 0 {
+		return nil, data, asn1.SyntaxError{
+			Msg: "trailing data after TorServiceDescriptorHash",
+		}
+	}
+
+	return &TorServiceDescriptorHash{
+		Onion:         string(rawOnionURI.Bytes),
+		Algorithm:     algorithm,
+		AlgorithmName: algorithmName,
+		HashBits:      spkh.BitLength,
+		Hash:          CertificateFingerprint(spkh.Bytes),
+	}, data, nil
+}

+ 60 - 0
vendor/github.com/zmap/zcrypto/x509/validation.go

@@ -0,0 +1,60 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import "time"
+
+// Validation stores different validation levels for a given certificate
+type Validation struct {
+	BrowserTrusted bool   `json:"browser_trusted"`
+	BrowserError   string `json:"browser_error,omitempty"`
+	MatchesDomain  bool   `json:"matches_domain,omitempty"`
+	Domain         string `json:"-"`
+}
+
+// ValidateWithStupidDetail fills out a Validation struct given a leaf
+// certificate and intermediates / roots. If opts.DNSName is set, then it will
+// also check if the domain matches.
+//
+// Deprecated: Use verifier.Verify() instead.
+func (c *Certificate) ValidateWithStupidDetail(opts VerifyOptions) (chains []CertificateChain, validation *Validation, err error) {
+
+	// Manually set the time, so that all verifies we do get the same time
+	if opts.CurrentTime.IsZero() {
+		opts.CurrentTime = time.Now()
+	}
+
+	// XXX: Don't pass a KeyUsage to the Verify API
+	opts.KeyUsages = nil
+	domain := opts.DNSName
+	opts.DNSName = ""
+
+	out := new(Validation)
+	out.Domain = domain
+
+	if chains, _, _, err = c.Verify(opts); err != nil {
+		out.BrowserError = err.Error()
+	} else {
+		out.BrowserTrusted = true
+	}
+
+	if domain != "" {
+		nameErr := c.VerifyHostname(domain)
+		if nameErr != nil {
+			out.MatchesDomain = false
+		} else {
+			out.MatchesDomain = true
+		}
+
+		// Make sure we return an error if either chain building or hostname
+		// verification fails.
+		if err == nil && nameErr != nil {
+			err = nameErr
+		}
+	}
+	validation = out
+
+	return
+}

+ 635 - 0
vendor/github.com/zmap/zcrypto/x509/verify.go

@@ -0,0 +1,635 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+	"errors"
+	"fmt"
+	"net"
+	"strings"
+	"time"
+	"unicode/utf8"
+)
+
+type InvalidReason int
+
+const (
+	// NotAuthorizedToSign results when a certificate is signed by another
+	// which isn't marked as a CA certificate.
+	NotAuthorizedToSign InvalidReason = iota
+
+	// Expired results when a certificate has expired, based on the time
+	// given in the VerifyOptions.
+	Expired
+
+	// CANotAuthorizedForThisName results when an intermediate or root
+	// certificate has a name constraint which doesn't include the name
+	// being checked.
+	CANotAuthorizedForThisName
+
+	// CANotAuthorizedForThisEmail results when an intermediate or root
+	// certificate has a name constraint which doesn't include the email
+	// being checked.
+	CANotAuthorizedForThisEmail
+
+	// CANotAuthorizedForThisIP results when an intermediate or root
+	// certificate has a name constraint which doesn't include the IP
+	// being checked.
+	CANotAuthorizedForThisIP
+
+	// CANotAuthorizedForThisDirectory results when an intermediate or root
+	// certificate has a name constraint which doesn't include the directory
+	// being checked.
+	CANotAuthorizedForThisDirectory
+
+	// TooManyIntermediates results when a path length constraint is
+	// violated.
+	TooManyIntermediates
+
+	// IncompatibleUsage results when the certificate's key usage indicates
+	// that it may only be used for a different purpose.
+	IncompatibleUsage
+
+	// NameMismatch results when the subject name of a parent certificate
+	// does not match the issuer name in the child.
+	NameMismatch
+
+	// NeverValid results when the certificate could never have been valid due to
+	// some date-related issue, e.g. NotBefore > NotAfter.
+	NeverValid
+
+	// IsSelfSigned results when the certificate is self-signed and not a trusted
+	// root.
+	IsSelfSigned
+)
+
+// CertificateInvalidError results when an odd error occurs. Users of this
+// library probably want to handle all these errors uniformly.
+type CertificateInvalidError struct {
+	Cert   *Certificate
+	Reason InvalidReason
+}
+
+func (e CertificateInvalidError) Error() string {
+	switch e.Reason {
+	case NotAuthorizedToSign:
+		return "x509: certificate is not authorized to sign other certificates"
+	case Expired:
+		return "x509: certificate has expired or is not yet valid"
+	case CANotAuthorizedForThisName:
+		return "x509: a root or intermediate certificate is not authorized to sign in this domain"
+	case CANotAuthorizedForThisEmail:
+		return "x509: a root or intermediate certificate is not authorized to sign this email address"
+	case CANotAuthorizedForThisIP:
+		return "x509: a root or intermediate certificate is not authorized to sign this IP address"
+	case CANotAuthorizedForThisDirectory:
+		return "x509: a root or intermediate certificate is not authorized to sign in this directory"
+	case TooManyIntermediates:
+		return "x509: too many intermediates for path length constraint"
+	case IncompatibleUsage:
+		return "x509: certificate specifies an incompatible key usage"
+	case NameMismatch:
+		return "x509: issuer name does not match subject from issuing certificate"
+	case NeverValid:
+		return "x509: certificate will never be valid"
+	}
+	return "x509: unknown error"
+}
+
+// HostnameError results when the set of authorized names doesn't match the
+// requested name.
+type HostnameError struct {
+	Certificate *Certificate
+	Host        string
+}
+
+func (h HostnameError) Error() string {
+	c := h.Certificate
+
+	var valid string
+	if ip := net.ParseIP(h.Host); ip != nil {
+		// Trying to validate an IP
+		if len(c.IPAddresses) == 0 {
+			return "x509: cannot validate certificate for " + h.Host + " because it doesn't contain any IP SANs"
+		}
+		for _, san := range c.IPAddresses {
+			if len(valid) > 0 {
+				valid += ", "
+			}
+			valid += san.String()
+		}
+	} else {
+		if c.hasSANExtension() {
+			valid = strings.Join(c.DNSNames, ", ")
+		} else {
+			valid = c.Subject.CommonName
+		}
+	}
+
+	if len(valid) == 0 {
+		return "x509: certificate is not valid for any names, but wanted to match " + h.Host
+	}
+	return "x509: certificate is valid for " + valid + ", not " + h.Host
+}
+
+// UnknownAuthorityError results when the certificate issuer is unknown
+type UnknownAuthorityError struct {
+	Cert *Certificate
+	// hintErr contains an error that may be helpful in determining why an
+	// authority wasn't found.
+	hintErr error
+	// hintCert contains a possible authority certificate that was rejected
+	// because of the error in hintErr.
+	hintCert *Certificate
+}
+
+func (e UnknownAuthorityError) Error() string {
+	s := "x509: certificate signed by unknown authority"
+	if e.hintErr != nil {
+		certName := e.hintCert.Subject.CommonName
+		if len(certName) == 0 {
+			if len(e.hintCert.Subject.Organization) > 0 {
+				certName = e.hintCert.Subject.Organization[0]
+			} else {
+				certName = "serial:" + e.hintCert.SerialNumber.String()
+			}
+		}
+		s += fmt.Sprintf(" (possibly because of %q while trying to verify candidate authority certificate %q)", e.hintErr, certName)
+	}
+	return s
+}
+
+// SystemRootsError results when we fail to load the system root certificates.
+type SystemRootsError struct {
+	Err error
+}
+
+func (se SystemRootsError) Error() string {
+	msg := "x509: failed to load system roots and no roots provided"
+	if se.Err != nil {
+		return msg + "; " + se.Err.Error()
+	}
+	return msg
+}
+
+// errNotParsed is returned when a certificate without ASN.1 contents is
+// verified. Platform-specific verification needs the ASN.1 contents.
+var errNotParsed = errors.New("x509: missing ASN.1 contents; use ParseCertificate")
+
+const maxIntermediateCount = 10
+
+// VerifyOptions contains parameters for Certificate.Verify. It's a structure
+// because other PKIX verification APIs have ended up needing many options.
+type VerifyOptions struct {
+	DNSName      string
+	EmailAddress string
+	IPAddress    net.IP
+
+	Intermediates *CertPool
+	Roots         *CertPool // if nil, the system roots are used
+	CurrentTime   time.Time // if zero, the current time is used
+	// KeyUsage specifies which Extended Key Usage values are acceptable.
+	// An empty list means ExtKeyUsageServerAuth. Key usage is considered a
+	// constraint down the chain which mirrors Windows CryptoAPI behaviour,
+	// but not the spec. To accept any key usage, include ExtKeyUsageAny.
+	KeyUsages []ExtKeyUsage
+}
+
+const (
+	leafCertificate = iota
+	intermediateCertificate
+	rootCertificate
+)
+
+func matchNameConstraint(domain, constraint string) bool {
+	// The meaning of zero length constraints is not specified, but this
+	// code follows NSS and accepts them as matching everything.
+	if len(constraint) == 0 {
+		return true
+	}
+
+	if len(domain) < len(constraint) {
+		return false
+	}
+
+	prefixLen := len(domain) - len(constraint)
+	if !strings.EqualFold(domain[prefixLen:], constraint) {
+		return false
+	}
+
+	if prefixLen == 0 {
+		return true
+	}
+
+	isSubdomain := domain[prefixLen-1] == '.'
+	constraintHasLeadingDot := constraint[0] == '.'
+	return isSubdomain != constraintHasLeadingDot
+}
+
+// NOTE: the stdlib function does many more checks and is preferable. For backwards compatibility using this version
+
+// isValid performs validity checks on the c. It will never return a
+// date-related error.
+func (c *Certificate) isValid(certType CertificateType, currentChain CertificateChain) error {
+
+	// KeyUsage status flags are ignored. From Engineering Security, Peter
+	// Gutmann: A European government CA marked its signing certificates as
+	// being valid for encryption only, but no-one noticed. Another
+	// European CA marked its signature keys as not being valid for
+	// signatures. A different CA marked its own trusted root certificate
+	// as being invalid for certificate signing.  Another national CA
+	// distributed a certificate to be used to encrypt data for the
+	// country’s tax authority that was marked as only being usable for
+	// digital signatures but not for encryption. Yet another CA reversed
+	// the order of the bit flags in the keyUsage due to confusion over
+	// encoding endianness, essentially setting a random keyUsage in
+	// certificates that it issued. Another CA created a self-invalidating
+	// certificate by adding a certificate policy statement stipulating
+	// that the certificate had to be used strictly as specified in the
+	// keyUsage, and a keyUsage containing a flag indicating that the RSA
+	// encryption key could only be used for Diffie-Hellman key agreement.
+
+	if certType == CertificateTypeIntermediate && (!c.BasicConstraintsValid || !c.IsCA) {
+		return CertificateInvalidError{c, NotAuthorizedToSign}
+	}
+
+	if c.BasicConstraintsValid && c.MaxPathLen >= 0 {
+		numIntermediates := len(currentChain) - 1
+		if numIntermediates > c.MaxPathLen {
+			return CertificateInvalidError{c, TooManyIntermediates}
+		}
+	}
+
+	if len(currentChain) > maxIntermediateCount {
+		return CertificateInvalidError{c, TooManyIntermediates}
+	}
+
+	return nil
+}
+
+// Verify attempts to verify c by building one or more chains from c to a
+// certificate in opts.Roots, using certificates in opts.Intermediates if
+// needed. If successful, it returns one or more chains where the first
+// element of the chain is c and the last element is from opts.Roots.
+//
+// If opts.Roots is nil and system roots are unavailable the returned error
+// will be of type SystemRootsError.
+//
+// WARNING: this doesn't do any revocation checking.
+func (c *Certificate) Verify(opts VerifyOptions) (current, expired, never []CertificateChain, err error) {
+
+	if opts.Roots == nil {
+		err = SystemRootsError{}
+		return
+	}
+
+	err = c.isValid(CertificateTypeLeaf, nil)
+	if err != nil {
+		return
+	}
+
+	candidateChains, err := c.buildChains(make(map[int][]CertificateChain), []*Certificate{c}, &opts)
+	if err != nil {
+		return
+	}
+
+	keyUsages := opts.KeyUsages
+	if len(keyUsages) == 0 {
+		keyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth}
+	}
+
+	// If any key usage is acceptable then we're done.
+	hasKeyUsageAny := false
+	for _, usage := range keyUsages {
+		if usage == ExtKeyUsageAny {
+			hasKeyUsageAny = true
+			break
+		}
+	}
+
+	var chains []CertificateChain
+	if hasKeyUsageAny {
+		chains = candidateChains
+	} else {
+		for _, candidate := range candidateChains {
+			if checkChainForKeyUsage(candidate, keyUsages) {
+				chains = append(chains, candidate)
+			}
+		}
+	}
+
+	if len(chains) == 0 {
+		err = CertificateInvalidError{c, IncompatibleUsage}
+		return
+	}
+
+	current, expired, never = FilterByDate(chains, opts.CurrentTime)
+	if len(current) == 0 {
+		if len(expired) > 0 {
+			err = CertificateInvalidError{c, Expired}
+		} else if len(never) > 0 {
+			err = CertificateInvalidError{c, NeverValid}
+		}
+		return
+	}
+
+	if len(opts.DNSName) > 0 {
+		err = c.VerifyHostname(opts.DNSName)
+		if err != nil {
+			return
+		}
+	}
+	return
+}
+
+func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate {
+	n := make([]*Certificate, len(chain)+1)
+	copy(n, chain)
+	n[len(chain)] = cert
+	return n
+}
+
+// buildChains returns all chains of length < maxIntermediateCount. Chains begin
+// the certificate being validated (chain[0] = c), and end at a root. It
+// enforces that all intermediates can sign certificates, and checks signatures.
+// It does not enforce expiration.
+func (c *Certificate) buildChains(cache map[int][]CertificateChain, currentChain CertificateChain, opts *VerifyOptions) (chains []CertificateChain, err error) {
+
+	// If the certificate being validated is a root, add the chain of length one
+	// containing just the root. Only do this on the first call to buildChains,
+	// when the len(currentChain) = 1.
+	if len(currentChain) == 1 && opts.Roots.Contains(c) {
+		chains = append(chains, CertificateChain{c})
+	}
+
+	if len(chains) == 0 && c.SelfSigned {
+		err = CertificateInvalidError{c, IsSelfSigned}
+	}
+
+	// Find roots that signed c and have matching SKID/AKID and Subject/Issuer.
+	possibleRoots, failedRoot, rootErr := opts.Roots.findVerifiedParents(c)
+
+	// If any roots are parents of c, create new chain for each one of them.
+	for _, rootNum := range possibleRoots {
+		root := opts.Roots.certs[rootNum]
+		err = root.isValid(CertificateTypeRoot, currentChain)
+		if err != nil {
+			continue
+		}
+		if !currentChain.CertificateInChain(root) {
+			chains = append(chains, currentChain.AppendToFreshChain(root))
+		}
+	}
+
+	// The root chains of length N+1 are now "done". Now we'll look for any
+	// intermediates that issue this certificate, meaning that any chain to a root
+	// through these intermediates is at least length N+2.
+	possibleIntermediates, failedIntermediate, intermediateErr := opts.Intermediates.findVerifiedParents(c)
+
+	for _, intermediateNum := range possibleIntermediates {
+		intermediate := opts.Intermediates.certs[intermediateNum]
+		if opts.Roots.Contains(intermediate) {
+			continue
+		}
+		if currentChain.CertificateSubjectAndKeyInChain(intermediate) {
+			continue
+		}
+		err = intermediate.isValid(CertificateTypeIntermediate, currentChain)
+		if err != nil {
+			continue
+		}
+
+		// We don't want to add any certificate to chains that doesn't somehow get
+		// to a root. We don't know if all chains through the intermediates will end
+		// at a root, so we slice off the back half of the chain and try to build
+		// that part separately.
+		childChains, ok := cache[intermediateNum]
+		if !ok {
+			childChains, err = intermediate.buildChains(cache, currentChain.AppendToFreshChain(intermediate), opts)
+			cache[intermediateNum] = childChains
+		}
+		chains = append(chains, childChains...)
+	}
+
+	if len(chains) > 0 {
+		err = nil
+	}
+
+	if len(chains) == 0 && err == nil {
+		hintErr := rootErr
+		hintCert := failedRoot
+		if hintErr == nil {
+			hintErr = intermediateErr
+			hintCert = failedIntermediate
+		}
+		err = UnknownAuthorityError{c, hintErr, hintCert}
+	}
+
+	return
+}
+
+func matchHostnames(pattern, host string) bool {
+	host = strings.TrimSuffix(host, ".")
+	pattern = strings.TrimSuffix(pattern, ".")
+
+	if len(pattern) == 0 || len(host) == 0 {
+		return false
+	}
+
+	patternParts := strings.Split(pattern, ".")
+	hostParts := strings.Split(host, ".")
+
+	if len(patternParts) != len(hostParts) {
+		return false
+	}
+
+	for i, patternPart := range patternParts {
+		if /*i == 0 &&*/ patternPart == "*" {
+			continue
+		}
+		if patternPart != hostParts[i] {
+			return false
+		}
+	}
+
+	return true
+}
+
+// toLowerCaseASCII returns a lower-case version of in. See RFC 6125 6.4.1. We use
+// an explicitly ASCII function to avoid any sharp corners resulting from
+// performing Unicode operations on DNS labels.
+func toLowerCaseASCII(in string) string {
+	// If the string is already lower-case then there's nothing to do.
+	isAlreadyLowerCase := true
+	for _, c := range in {
+		if c == utf8.RuneError {
+			// If we get a UTF-8 error then there might be
+			// upper-case ASCII bytes in the invalid sequence.
+			isAlreadyLowerCase = false
+			break
+		}
+		if 'A' <= c && c <= 'Z' {
+			isAlreadyLowerCase = false
+			break
+		}
+	}
+
+	if isAlreadyLowerCase {
+		return in
+	}
+
+	out := []byte(in)
+	for i, c := range out {
+		if 'A' <= c && c <= 'Z' {
+			out[i] += 'a' - 'A'
+		}
+	}
+	return string(out)
+}
+
+// VerifyHostname returns nil if c is a valid certificate for the named host.
+// Otherwise it returns an error describing the mismatch.
+func (c *Certificate) VerifyHostname(h string) error {
+	// IP addresses may be written in [ ].
+	candidateIP := h
+	if len(h) >= 3 && h[0] == '[' && h[len(h)-1] == ']' {
+		candidateIP = h[1 : len(h)-1]
+	}
+	if ip := net.ParseIP(candidateIP); ip != nil {
+		// We only match IP addresses against IP SANs.
+		// https://tools.ietf.org/html/rfc6125#appendix-B.2
+		for _, candidate := range c.IPAddresses {
+			if ip.Equal(candidate) {
+				return nil
+			}
+		}
+		return HostnameError{c, candidateIP}
+	}
+
+	lowered := toLowerCaseASCII(h)
+
+	if c.hasSANExtension() {
+		for _, match := range c.DNSNames {
+			if matchHostnames(toLowerCaseASCII(match), lowered) {
+				return nil
+			}
+		}
+		// If Subject Alt Name is given, we ignore the common name.
+	} else if matchHostnames(toLowerCaseASCII(c.Subject.CommonName), lowered) {
+		return nil
+	}
+
+	return HostnameError{c, h}
+}
+
+func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool {
+	usages := make([]ExtKeyUsage, len(keyUsages))
+	copy(usages, keyUsages)
+
+	if len(chain) == 0 {
+		return false
+	}
+
+	usagesRemaining := len(usages)
+
+	// We walk down the list and cross out any usages that aren't supported
+	// by each certificate. If we cross out all the usages, then the chain
+	// is unacceptable.
+
+NextCert:
+	for i := len(chain) - 1; i >= 0; i-- {
+		cert := chain[i]
+		if len(cert.ExtKeyUsage) == 0 && len(cert.UnknownExtKeyUsage) == 0 {
+			// The certificate doesn't have any extended key usage specified.
+			continue
+		}
+
+		for _, usage := range cert.ExtKeyUsage {
+			if usage == ExtKeyUsageAny {
+				// The certificate is explicitly good for any usage.
+				continue NextCert
+			}
+		}
+
+		const invalidUsage ExtKeyUsage = -1
+
+	NextRequestedUsage:
+		for i, requestedUsage := range usages {
+			if requestedUsage == invalidUsage {
+				continue
+			}
+
+			for _, usage := range cert.ExtKeyUsage {
+				if requestedUsage == usage {
+					continue NextRequestedUsage
+				} else if requestedUsage == ExtKeyUsageServerAuth &&
+					(usage == ExtKeyUsageNetscapeServerGatedCrypto ||
+						usage == ExtKeyUsageMicrosoftServerGatedCrypto) {
+					// In order to support COMODO
+					// certificate chains, we have to
+					// accept Netscape or Microsoft SGC
+					// usages as equal to ServerAuth.
+					continue NextRequestedUsage
+				}
+			}
+
+			usages[i] = invalidUsage
+			usagesRemaining--
+			if usagesRemaining == 0 {
+				return false
+			}
+		}
+	}
+
+	return true
+}
+
+// earlier returns the earlier of a and b
+func earlier(a, b time.Time) time.Time {
+	if a.Before(b) {
+		return a
+	}
+	return b
+}
+
+// later returns the later of a and b
+func later(a, b time.Time) time.Time {
+	if a.After(b) {
+		return a
+	}
+	return b
+}
+
+// check expirations divides chains into a set of disjoint chains, containing
+// current chains valid now, expired chains that were valid at some point, and
+// the set of chains that were never valid.
+func FilterByDate(chains []CertificateChain, now time.Time) (current, expired, never []CertificateChain) {
+	for _, chain := range chains {
+		if len(chain) == 0 {
+			continue
+		}
+		leaf := chain[0]
+		lowerBound := leaf.NotBefore
+		upperBound := leaf.NotAfter
+		for _, c := range chain[1:] {
+			lowerBound = later(lowerBound, c.NotBefore)
+			upperBound = earlier(upperBound, c.NotAfter)
+		}
+		valid := lowerBound.Before(now) && upperBound.After(now)
+		wasValid := lowerBound.Before(upperBound)
+		if valid && !wasValid {
+			// Math/logic tells us this is impossible.
+			panic("valid && !wasValid should not be possible")
+		}
+		if valid {
+			current = append(current, chain)
+		} else if wasValid {
+			expired = append(expired, chain)
+		} else {
+			never = append(never, chain)
+		}
+	}
+	return
+}

+ 3042 - 0
vendor/github.com/zmap/zcrypto/x509/x509.go

@@ -0,0 +1,3042 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package x509 parses X.509-encoded keys and certificates.
+//
+// Originally based on the go/crypto/x509 standard library,
+// this package has now diverged enough that it is no longer
+// updated with direct correspondence to new go releases.
+
+package x509
+
+import (
+	// all of the hash libraries need to be imported for side-effects,
+	// so that crypto.RegisterHash is called
+	_ "crypto/md5"
+	"crypto/sha256"
+	_ "crypto/sha512"
+	"io"
+	"strings"
+
+	"bytes"
+	"crypto"
+	"crypto/ecdsa"
+	"crypto/elliptic"
+	"crypto/rsa"
+	_ "crypto/sha1"
+	_ "crypto/sha256"
+	_ "crypto/sha512"
+	"encoding/asn1"
+	"encoding/pem"
+	"errors"
+	"fmt"
+	"math/big"
+	"net"
+	"strconv"
+	"time"
+
+	"github.com/zmap/zcrypto/dsa"
+
+	"github.com/weppos/publicsuffix-go/publicsuffix"
+	"github.com/zmap/zcrypto/x509/ct"
+	"github.com/zmap/zcrypto/x509/pkix"
+	"golang.org/x/crypto/ed25519"
+)
+
+// pkixPublicKey reflects a PKIX public key structure. See SubjectPublicKeyInfo
+// in RFC 3280.
+type pkixPublicKey struct {
+	Algo      pkix.AlgorithmIdentifier
+	BitString asn1.BitString
+}
+
+// ParsePKIXPublicKey parses a DER encoded public key. These values are
+// typically found in PEM blocks with "BEGIN PUBLIC KEY".
+//
+// Supported key types include RSA, DSA, and ECDSA. Unknown key
+// types result in an error.
+//
+// On success, pub will be of type *rsa.PublicKey, *dsa.PublicKey,
+// or *ecdsa.PublicKey.
+func ParsePKIXPublicKey(derBytes []byte) (pub interface{}, err error) {
+	var pki publicKeyInfo
+	if rest, err := asn1.Unmarshal(derBytes, &pki); err != nil {
+		return nil, err
+	} else if len(rest) != 0 {
+		return nil, errors.New("x509: trailing data after ASN.1 of public-key")
+	}
+	algo := getPublicKeyAlgorithmFromOID(pki.Algorithm.Algorithm)
+	if algo == UnknownPublicKeyAlgorithm {
+		return nil, errors.New("x509: unknown public key algorithm")
+	}
+	return parsePublicKey(algo, &pki)
+}
+
+func marshalPublicKey(pub interface{}) (publicKeyBytes []byte, publicKeyAlgorithm pkix.AlgorithmIdentifier, err error) {
+	switch pub := pub.(type) {
+	case *rsa.PublicKey:
+		publicKeyBytes, err = asn1.Marshal(pkcs1PublicKey{
+			N: pub.N,
+			E: pub.E,
+		})
+		if err != nil {
+			return nil, pkix.AlgorithmIdentifier{}, err
+		}
+		publicKeyAlgorithm.Algorithm = oidPublicKeyRSA
+		// This is a NULL parameters value which is required by
+		// https://tools.ietf.org/html/rfc3279#section-2.3.1.
+		publicKeyAlgorithm.Parameters = asn1.NullRawValue
+	case *ecdsa.PublicKey:
+		publicKeyBytes = elliptic.Marshal(pub.Curve, pub.X, pub.Y)
+		oid, ok := oidFromNamedCurve(pub.Curve)
+		if !ok {
+			return nil, pkix.AlgorithmIdentifier{}, errors.New("x509: unsupported elliptic curve")
+		}
+		publicKeyAlgorithm.Algorithm = oidPublicKeyECDSA
+		var paramBytes []byte
+		paramBytes, err = asn1.Marshal(oid)
+		if err != nil {
+			return
+		}
+		publicKeyAlgorithm.Parameters.FullBytes = paramBytes
+	case *AugmentedECDSA:
+		return marshalPublicKey(pub.Pub)
+	case ed25519.PublicKey:
+		publicKeyAlgorithm.Algorithm = oidKeyEd25519
+		return []byte(pub), publicKeyAlgorithm, nil
+	case X25519PublicKey:
+		publicKeyAlgorithm.Algorithm = oidKeyX25519
+		return []byte(pub), publicKeyAlgorithm, nil
+	default:
+		return nil, pkix.AlgorithmIdentifier{}, errors.New("x509: only RSA, ECDSA, ed25519, or X25519 public keys supported")
+	}
+
+	return publicKeyBytes, publicKeyAlgorithm, nil
+}
+
+// MarshalPKIXPublicKey serialises a public key to DER-encoded PKIX format.
+func MarshalPKIXPublicKey(pub interface{}) ([]byte, error) {
+	var publicKeyBytes []byte
+	var publicKeyAlgorithm pkix.AlgorithmIdentifier
+	var err error
+
+	if publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(pub); err != nil {
+		return nil, err
+	}
+
+	pkix := pkixPublicKey{
+		Algo: publicKeyAlgorithm,
+		BitString: asn1.BitString{
+			Bytes:     publicKeyBytes,
+			BitLength: 8 * len(publicKeyBytes),
+		},
+	}
+
+	ret, _ := asn1.Marshal(pkix)
+	return ret, nil
+}
+
+// These structures reflect the ASN.1 structure of X.509 certificates.:
+
+type certificate struct {
+	Raw                asn1.RawContent
+	TBSCertificate     tbsCertificate
+	SignatureAlgorithm pkix.AlgorithmIdentifier
+	SignatureValue     asn1.BitString
+}
+
+type tbsCertificate struct {
+	Raw                asn1.RawContent
+	Version            int `asn1:"optional,explicit,default:0,tag:0"`
+	SerialNumber       *big.Int
+	SignatureAlgorithm pkix.AlgorithmIdentifier
+	Issuer             asn1.RawValue
+	Validity           validity
+	Subject            asn1.RawValue
+	PublicKey          publicKeyInfo
+	UniqueId           asn1.BitString   `asn1:"optional,tag:1"`
+	SubjectUniqueId    asn1.BitString   `asn1:"optional,tag:2"`
+	Extensions         []pkix.Extension `asn1:"optional,explicit,tag:3"`
+}
+
+type dsaAlgorithmParameters struct {
+	P, Q, G *big.Int
+}
+
+type dsaSignature struct {
+	R, S *big.Int
+}
+
+type ecdsaSignature dsaSignature
+
+type AugmentedECDSA struct {
+	Pub *ecdsa.PublicKey
+	Raw asn1.BitString
+}
+
+type validity struct {
+	NotBefore, NotAfter time.Time
+}
+
+type publicKeyInfo struct {
+	Raw       asn1.RawContent
+	Algorithm pkix.AlgorithmIdentifier
+	PublicKey asn1.BitString
+}
+
+// RFC 5280,  4.2.1.1
+type authKeyId struct {
+	Id []byte `asn1:"optional,tag:0"`
+}
+
+type SignatureAlgorithmOID asn1.ObjectIdentifier
+
+type SignatureAlgorithm int
+
+const (
+	UnknownSignatureAlgorithm SignatureAlgorithm = iota
+	MD2WithRSA
+	MD5WithRSA
+	SHA1WithRSA
+	SHA256WithRSA
+	SHA384WithRSA
+	SHA512WithRSA
+	DSAWithSHA1
+	DSAWithSHA256
+	ECDSAWithSHA1
+	ECDSAWithSHA256
+	ECDSAWithSHA384
+	ECDSAWithSHA512
+	SHA256WithRSAPSS
+	SHA384WithRSAPSS
+	SHA512WithRSAPSS
+	Ed25519Sig
+)
+
+func (algo SignatureAlgorithm) isRSAPSS() bool {
+	switch algo {
+	case SHA256WithRSAPSS, SHA384WithRSAPSS, SHA512WithRSAPSS:
+		return true
+	default:
+		return false
+	}
+}
+
+var algoName = [...]string{
+	MD2WithRSA:       "MD2-RSA",
+	MD5WithRSA:       "MD5-RSA",
+	SHA1WithRSA:      "SHA1-RSA",
+	SHA256WithRSA:    "SHA256-RSA",
+	SHA384WithRSA:    "SHA384-RSA",
+	SHA512WithRSA:    "SHA512-RSA",
+	SHA256WithRSAPSS: "SHA256-RSAPSS",
+	SHA384WithRSAPSS: "SHA384-RSAPSS",
+	SHA512WithRSAPSS: "SHA512-RSAPSS",
+	DSAWithSHA1:      "DSA-SHA1",
+	DSAWithSHA256:    "DSA-SHA256",
+	ECDSAWithSHA1:    "ECDSA-SHA1",
+	ECDSAWithSHA256:  "ECDSA-SHA256",
+	ECDSAWithSHA384:  "ECDSA-SHA384",
+	ECDSAWithSHA512:  "ECDSA-SHA512",
+	Ed25519Sig:       "Ed25519",
+}
+
+func (algo SignatureAlgorithm) String() string {
+	if 0 < algo && int(algo) < len(algoName) {
+		return algoName[algo]
+	}
+	return strconv.Itoa(int(algo))
+}
+
+var keyAlgorithmNames = []string{
+	"unknown_algorithm",
+	"RSA",
+	"DSA",
+	"ECDSA",
+	"Ed25519",
+	"X25519",
+}
+
+type PublicKeyAlgorithm int
+
+const (
+	UnknownPublicKeyAlgorithm PublicKeyAlgorithm = iota
+	RSA
+	DSA
+	ECDSA
+	Ed25519
+	X25519
+	total_key_algorithms
+)
+
+// curve25519 package does not expose key types
+type X25519PublicKey []byte
+
+// OIDs for signature algorithms
+//
+// pkcs-1 OBJECT IDENTIFIER ::= {
+//    iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 }
+//
+//
+// RFC 3279 2.2.1 RSA Signature Algorithms
+//
+// md2WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 2 }
+//
+// md5WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 4 }
+//
+// sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 }
+//
+// dsaWithSha1 OBJECT IDENTIFIER ::= {
+//    iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 3 }
+//
+// RFC 3279 2.2.3 ECDSA Signature Algorithm
+//
+// ecdsa-with-SHA1 OBJECT IDENTIFIER ::= {
+// 	  iso(1) member-body(2) us(840) ansi-x962(10045)
+//    signatures(4) ecdsa-with-SHA1(1)}
+//
+//
+// RFC 4055 5 PKCS #1 Version 1.5
+//
+// sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 }
+//
+// sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 }
+//
+// sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 }
+//
+//
+// RFC 5758 3.1 DSA Signature Algorithms
+//
+// dsaWithSha256 OBJECT IDENTIFIER ::= {
+//    joint-iso-ccitt(2) country(16) us(840) organization(1) gov(101)
+//    csor(3) algorithms(4) id-dsa-with-sha2(3) 2}
+//
+// RFC 5758 3.2 ECDSA Signature Algorithm
+//
+// ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+//    us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 2 }
+//
+// ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+//    us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 3 }
+//
+// ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+//    us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 4 }
+
+var (
+	oidSignatureMD2WithRSA      = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2}
+	oidSignatureMD5WithRSA      = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4}
+	oidSignatureSHA1WithRSA     = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5}
+	oidSignatureSHA256WithRSA   = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11}
+	oidSignatureSHA384WithRSA   = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12}
+	oidSignatureSHA512WithRSA   = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13}
+	oidSignatureRSAPSS          = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 10}
+	oidSignatureDSAWithSHA1     = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3}
+	oidSignatureDSAWithSHA256   = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 2}
+	oidSignatureECDSAWithSHA1   = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1}
+	oidSignatureECDSAWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2}
+	oidSignatureECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3}
+	oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4}
+
+	oidSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1}
+	oidSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2}
+	oidSHA512 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 3}
+
+	oidMGF1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 8}
+
+	// oidISOSignatureSHA1WithRSA means the same as oidSignatureSHA1WithRSA
+	// but it's specified by ISO. Microsoft's makecert.exe has been known
+	// to produce certificates with this OID.
+	oidISOSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 29}
+)
+
+// cryptoNoDigest means that the signature algorithm does not require a hash
+// digest. The distinction between cryptoNoDigest and crypto.Hash(0)
+// is purely superficial. crypto.Hash(0) is used in place of a null value
+// when hashing is not supported for the given algorithm (as in the case of
+// MD2WithRSA below).
+var cryptoNoDigest = crypto.Hash(0)
+
+var signatureAlgorithmDetails = []struct {
+	algo       SignatureAlgorithm
+	oid        asn1.ObjectIdentifier
+	pubKeyAlgo PublicKeyAlgorithm
+	hash       crypto.Hash
+}{
+	{MD2WithRSA, oidSignatureMD2WithRSA, RSA, crypto.Hash(0) /* no value for MD2 */},
+	{MD5WithRSA, oidSignatureMD5WithRSA, RSA, crypto.MD5},
+	{SHA1WithRSA, oidSignatureSHA1WithRSA, RSA, crypto.SHA1},
+	{SHA1WithRSA, oidISOSignatureSHA1WithRSA, RSA, crypto.SHA1},
+	{SHA256WithRSA, oidSignatureSHA256WithRSA, RSA, crypto.SHA256},
+	{SHA384WithRSA, oidSignatureSHA384WithRSA, RSA, crypto.SHA384},
+	{SHA512WithRSA, oidSignatureSHA512WithRSA, RSA, crypto.SHA512},
+	{SHA256WithRSAPSS, oidSignatureRSAPSS, RSA, crypto.SHA256},
+	{SHA384WithRSAPSS, oidSignatureRSAPSS, RSA, crypto.SHA384},
+	{SHA512WithRSAPSS, oidSignatureRSAPSS, RSA, crypto.SHA512},
+	{DSAWithSHA1, oidSignatureDSAWithSHA1, DSA, crypto.SHA1},
+	{DSAWithSHA256, oidSignatureDSAWithSHA256, DSA, crypto.SHA256},
+	{ECDSAWithSHA1, oidSignatureECDSAWithSHA1, ECDSA, crypto.SHA1},
+	{ECDSAWithSHA256, oidSignatureECDSAWithSHA256, ECDSA, crypto.SHA256},
+	{ECDSAWithSHA384, oidSignatureECDSAWithSHA384, ECDSA, crypto.SHA384},
+	{ECDSAWithSHA512, oidSignatureECDSAWithSHA512, ECDSA, crypto.SHA512},
+	{Ed25519Sig, oidKeyEd25519, Ed25519, cryptoNoDigest},
+}
+
+// pssParameters reflects the parameters in an AlgorithmIdentifier that
+// specifies RSA PSS. See https://tools.ietf.org/html/rfc3447#appendix-A.2.3
+type pssParameters struct {
+	// The following three fields are not marked as
+	// optional because the default values specify SHA-1,
+	// which is no longer suitable for use in signatures.
+	Hash         pkix.AlgorithmIdentifier `asn1:"explicit,tag:0"`
+	MGF          pkix.AlgorithmIdentifier `asn1:"explicit,tag:1"`
+	SaltLength   int                      `asn1:"explicit,tag:2"`
+	TrailerField int                      `asn1:"optional,explicit,tag:3,default:1"`
+}
+
+// rsaPSSParameters returns an asn1.RawValue suitable for use as the Parameters
+// in an AlgorithmIdentifier that specifies RSA PSS.
+func rsaPSSParameters(hashFunc crypto.Hash) asn1.RawValue {
+	var hashOID asn1.ObjectIdentifier
+
+	switch hashFunc {
+	case crypto.SHA256:
+		hashOID = oidSHA256
+	case crypto.SHA384:
+		hashOID = oidSHA384
+	case crypto.SHA512:
+		hashOID = oidSHA512
+	}
+
+	params := pssParameters{
+		Hash: pkix.AlgorithmIdentifier{
+			Algorithm:  hashOID,
+			Parameters: asn1.NullRawValue,
+		},
+		MGF: pkix.AlgorithmIdentifier{
+			Algorithm: oidMGF1,
+		},
+		SaltLength:   hashFunc.Size(),
+		TrailerField: 1,
+	}
+
+	mgf1Params := pkix.AlgorithmIdentifier{
+		Algorithm:  hashOID,
+		Parameters: asn1.NullRawValue,
+	}
+
+	var err error
+	params.MGF.Parameters.FullBytes, err = asn1.Marshal(mgf1Params)
+	if err != nil {
+		panic(err)
+	}
+
+	serialized, err := asn1.Marshal(params)
+	if err != nil {
+		panic(err)
+	}
+
+	return asn1.RawValue{FullBytes: serialized}
+}
+
+// GetSignatureAlgorithmFromAI converts asn1 AlgorithmIdentifier to SignatureAlgorithm int
+func GetSignatureAlgorithmFromAI(ai pkix.AlgorithmIdentifier) SignatureAlgorithm {
+	if !ai.Algorithm.Equal(oidSignatureRSAPSS) {
+		for _, details := range signatureAlgorithmDetails {
+			if ai.Algorithm.Equal(details.oid) {
+				return details.algo
+			}
+		}
+		return UnknownSignatureAlgorithm
+	}
+
+	// RSA PSS is special because it encodes important parameters
+	// in the Parameters.
+
+	var params pssParameters
+	if _, err := asn1.Unmarshal(ai.Parameters.FullBytes, &params); err != nil {
+		return UnknownSignatureAlgorithm
+	}
+
+	var mgf1HashFunc pkix.AlgorithmIdentifier
+	if _, err := asn1.Unmarshal(params.MGF.Parameters.FullBytes, &mgf1HashFunc); err != nil {
+		return UnknownSignatureAlgorithm
+	}
+
+	// PSS is greatly overburdened with options. This code forces
+	// them into three buckets by requiring that the MGF1 hash
+	// function always match the message hash function (as
+	// recommended in
+	// https://tools.ietf.org/html/rfc3447#section-8.1), that the
+	// salt length matches the hash length, and that the trailer
+	// field has the default value.
+	if !bytes.Equal(params.Hash.Parameters.FullBytes, asn1.NullBytes) ||
+		!params.MGF.Algorithm.Equal(oidMGF1) ||
+		!mgf1HashFunc.Algorithm.Equal(params.Hash.Algorithm) ||
+		!bytes.Equal(mgf1HashFunc.Parameters.FullBytes, asn1.NullBytes) ||
+		params.TrailerField != 1 {
+		return UnknownSignatureAlgorithm
+	}
+
+	switch {
+	case params.Hash.Algorithm.Equal(oidSHA256) && params.SaltLength == 32:
+		return SHA256WithRSAPSS
+	case params.Hash.Algorithm.Equal(oidSHA384) && params.SaltLength == 48:
+		return SHA384WithRSAPSS
+	case params.Hash.Algorithm.Equal(oidSHA512) && params.SaltLength == 64:
+		return SHA512WithRSAPSS
+	}
+
+	return UnknownSignatureAlgorithm
+}
+
+// RFC 3279, 2.3 Public Key Algorithms
+//
+// pkcs-1 OBJECT IDENTIFIER ::== { iso(1) member-body(2) us(840)
+//    rsadsi(113549) pkcs(1) 1 }
+//
+// rsaEncryption OBJECT IDENTIFIER ::== { pkcs1-1 1 }
+//
+// id-dsa OBJECT IDENTIFIER ::== { iso(1) member-body(2) us(840)
+//    x9-57(10040) x9cm(4) 1 }
+//
+// RFC 5480, 2.1.1 Unrestricted Algorithm Identifier and Parameters
+//
+// id-ecPublicKey OBJECT IDENTIFIER ::= {
+//       iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 }
+var (
+	oidPublicKeyRSA   = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
+	oidPublicKeyDSA   = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1}
+	oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}
+)
+
+func getPublicKeyAlgorithmFromOID(oid asn1.ObjectIdentifier) PublicKeyAlgorithm {
+	switch {
+	case oid.Equal(oidPublicKeyRSA):
+		return RSA
+	case oid.Equal(oidPublicKeyDSA):
+		return DSA
+	case oid.Equal(oidPublicKeyECDSA):
+		return ECDSA
+	case oid.Equal(oidKeyEd25519):
+		return Ed25519
+	case oid.Equal(oidKeyX25519):
+		return X25519
+	}
+	return UnknownPublicKeyAlgorithm
+}
+
+// RFC 5480, 2.1.1.1. Named Curve
+//
+// secp224r1 OBJECT IDENTIFIER ::= {
+//   iso(1) identified-organization(3) certicom(132) curve(0) 33 }
+//
+// secp256r1 OBJECT IDENTIFIER ::= {
+//   iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3)
+//   prime(1) 7 }
+//
+// secp384r1 OBJECT IDENTIFIER ::= {
+//   iso(1) identified-organization(3) certicom(132) curve(0) 34 }
+//
+// secp521r1 OBJECT IDENTIFIER ::= {
+//   iso(1) identified-organization(3) certicom(132) curve(0) 35 }
+//
+// NB: secp256r1 is equivalent to prime256v1
+var (
+	oidNamedCurveP224 = asn1.ObjectIdentifier{1, 3, 132, 0, 33}
+	oidNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7}
+	oidNamedCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34}
+	oidNamedCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35}
+)
+
+// https://datatracker.ietf.org/doc/draft-ietf-curdle-pkix/?include_text=1
+// id-X25519    OBJECT IDENTIFIER ::= { 1 3 101 110 }
+// id-Ed25519   OBJECT IDENTIFIER ::= { 1 3 101 112 }
+var (
+	oidKeyX25519  = asn1.ObjectIdentifier{1, 3, 101, 110}
+	oidKeyEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112}
+)
+
+func namedCurveFromOID(oid asn1.ObjectIdentifier) elliptic.Curve {
+	switch {
+	case oid.Equal(oidNamedCurveP224):
+		return elliptic.P224()
+	case oid.Equal(oidNamedCurveP256):
+		return elliptic.P256()
+	case oid.Equal(oidNamedCurveP384):
+		return elliptic.P384()
+	case oid.Equal(oidNamedCurveP521):
+		return elliptic.P521()
+	}
+	return nil
+}
+
+func oidFromNamedCurve(curve elliptic.Curve) (asn1.ObjectIdentifier, bool) {
+	switch curve {
+	case elliptic.P224():
+		return oidNamedCurveP224, true
+	case elliptic.P256():
+		return oidNamedCurveP256, true
+	case elliptic.P384():
+		return oidNamedCurveP384, true
+	case elliptic.P521():
+		return oidNamedCurveP521, true
+	}
+
+	return nil, false
+}
+
+// KeyUsage represents the set of actions that are valid for a given key. It's
+// a bitmap of the KeyUsage* constants.
+type KeyUsage int
+
+const (
+	KeyUsageDigitalSignature KeyUsage = 1 << iota
+	KeyUsageContentCommitment
+	KeyUsageKeyEncipherment
+	KeyUsageDataEncipherment
+	KeyUsageKeyAgreement
+	KeyUsageCertSign
+	KeyUsageCRLSign
+	KeyUsageEncipherOnly
+	KeyUsageDecipherOnly
+)
+
+// RFC 5280, 4.2.1.12  Extended Key Usage
+//
+// anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-ce-extKeyUsage 0 }
+//
+// id-kp OBJECT IDENTIFIER ::= { id-pkix 3 }
+//
+// id-kp-serverAuth             OBJECT IDENTIFIER ::= { id-kp 1 }
+// id-kp-clientAuth             OBJECT IDENTIFIER ::= { id-kp 2 }
+// id-kp-codeSigning            OBJECT IDENTIFIER ::= { id-kp 3 }
+// id-kp-emailProtection        OBJECT IDENTIFIER ::= { id-kp 4 }
+// id-kp-timeStamping           OBJECT IDENTIFIER ::= { id-kp 8 }
+// id-kp-OCSPSigning            OBJECT IDENTIFIER ::= { id-kp 9 }
+//var (
+//	oidExtKeyUsageAny                        = asn1.ObjectIdentifier{2, 5, 29, 37, 0}
+//	oidExtKeyUsageServerAuth                 = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 1}
+//	oidExtKeyUsageClientAuth                 = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 2}
+//	oidExtKeyUsageCodeSigning                = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 3}
+//	oidExtKeyUsageEmailProtection            = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 4}
+//	oidExtKeyUsageIPSECEndSystem             = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 5}
+//	oidExtKeyUsageIPSECTunnel                = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 6}
+//	oidExtKeyUsageIPSECUser                  = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 7}
+//	oidExtKeyUsageTimeStamping               = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 8}
+//	oidExtKeyUsageOCSPSigning                = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 9}
+//	oidExtKeyUsageMicrosoftServerGatedCrypto = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 3}
+//	oidExtKeyUsageNetscapeServerGatedCrypto  = asn1.ObjectIdentifier{2, 16, 840, 1, 113730, 4, 1}
+//)
+
+// ExtKeyUsage represents an extended set of actions that are valid for a given key.
+// Each of the ExtKeyUsage* constants define a unique action.
+type ExtKeyUsage int
+
+// TODO: slight differences in case in some names. Should be easy to align with stdlib.
+// leaving for now to not break compatibility
+
+// extKeyUsageOIDs contains the mapping between an ExtKeyUsage and its OID.
+var extKeyUsageOIDs = []struct {
+	extKeyUsage ExtKeyUsage
+	oid         asn1.ObjectIdentifier
+}{
+	{ExtKeyUsageAny, oidExtKeyUsageAny},
+	{ExtKeyUsageServerAuth, oidExtKeyUsageServerAuth},
+	{ExtKeyUsageClientAuth, oidExtKeyUsageClientAuth},
+	{ExtKeyUsageCodeSigning, oidExtKeyUsageCodeSigning},
+	{ExtKeyUsageEmailProtection, oidExtKeyUsageEmailProtection},
+	//{ExtKeyUsageIPSECEndSystem, oidExtKeyUsageIPSECEndSystem},
+	{ExtKeyUsageIpsecUser, oidExtKeyUsageIpsecEndSystem},
+	//{ExtKeyUsageIPSECTunnel, oidExtKeyUsageIPSECTunnel},
+	{ExtKeyUsageIpsecTunnel, oidExtKeyUsageIpsecTunnel},
+	//{ExtKeyUsageIPSECUser, oidExtKeyUsageIPSECUser},
+	{ExtKeyUsageIpsecUser, oidExtKeyUsageIpsecUser},
+	{ExtKeyUsageTimeStamping, oidExtKeyUsageTimeStamping},
+	//{ExtKeyUsageOCSPSigning, oidExtKeyUsageOCSPSigning},
+	{ExtKeyUsageOcspSigning, oidExtKeyUsageOcspSigning},
+	{ExtKeyUsageMicrosoftServerGatedCrypto, oidExtKeyUsageMicrosoftServerGatedCrypto},
+	{ExtKeyUsageNetscapeServerGatedCrypto, oidExtKeyUsageNetscapeServerGatedCrypto},
+}
+
+// TODO: slight differences in case in some names. Should be easy to align with stdlib.
+// leaving for now to not break compatibility
+
+// extKeyUsageOIDs contains the mapping between an ExtKeyUsage and its OID.
+var nativeExtKeyUsageOIDs = []struct {
+	extKeyUsage ExtKeyUsage
+	oid         asn1.ObjectIdentifier
+}{
+	{ExtKeyUsageAny, oidExtKeyUsageAny},
+	{ExtKeyUsageServerAuth, oidExtKeyUsageServerAuth},
+	{ExtKeyUsageClientAuth, oidExtKeyUsageClientAuth},
+	{ExtKeyUsageCodeSigning, oidExtKeyUsageCodeSigning},
+	{ExtKeyUsageEmailProtection, oidExtKeyUsageEmailProtection},
+	{ExtKeyUsageIpsecEndSystem, oidExtKeyUsageIpsecEndSystem},
+	{ExtKeyUsageIpsecTunnel, oidExtKeyUsageIpsecTunnel},
+	{ExtKeyUsageIpsecUser, oidExtKeyUsageIpsecUser},
+	{ExtKeyUsageTimeStamping, oidExtKeyUsageTimeStamping},
+	{ExtKeyUsageOcspSigning, oidExtKeyUsageOcspSigning},
+	{ExtKeyUsageMicrosoftServerGatedCrypto, oidExtKeyUsageMicrosoftServerGatedCrypto},
+	{ExtKeyUsageNetscapeServerGatedCrypto, oidExtKeyUsageNetscapeServerGatedCrypto},
+}
+
+func extKeyUsageFromOID(oid asn1.ObjectIdentifier) (eku ExtKeyUsage, ok bool) {
+	s := oid.String()
+	eku, ok = ekuConstants[s]
+	return
+}
+
+func oidFromExtKeyUsage(eku ExtKeyUsage) (oid asn1.ObjectIdentifier, ok bool) {
+	for _, pair := range nativeExtKeyUsageOIDs {
+		if eku == pair.extKeyUsage {
+			return pair.oid, true
+		}
+	}
+	return
+}
+
+// A Certificate represents an X.509 certificate.
+type Certificate struct {
+	Raw                     []byte // Complete ASN.1 DER content (certificate, signature algorithm and signature).
+	RawTBSCertificate       []byte // Certificate part of raw ASN.1 DER content.
+	RawSubjectPublicKeyInfo []byte // DER encoded SubjectPublicKeyInfo.
+	RawSubject              []byte // DER encoded Subject
+	RawIssuer               []byte // DER encoded Issuer
+
+	Signature          []byte
+	SignatureAlgorithm SignatureAlgorithm
+
+	SelfSigned bool
+
+	SignatureAlgorithmOID asn1.ObjectIdentifier
+
+	PublicKeyAlgorithm PublicKeyAlgorithm
+	PublicKey          interface{}
+
+	PublicKeyAlgorithmOID asn1.ObjectIdentifier
+
+	Version             int
+	SerialNumber        *big.Int
+	Issuer              pkix.Name
+	Subject             pkix.Name
+	NotBefore, NotAfter time.Time // Validity bounds.
+	ValidityPeriod      int
+	KeyUsage            KeyUsage
+
+	IssuerUniqueId  asn1.BitString
+	SubjectUniqueId asn1.BitString
+
+	// Extensions contains raw X.509 extensions. When parsing certificates,
+	// this can be used to extract non-critical extensions that are not
+	// parsed by this package. When marshaling certificates, the Extensions
+	// field is ignored, see ExtraExtensions.
+	Extensions []pkix.Extension
+
+	// ExtensionsMap contains raw x.509 extensions keyed by OID (in string
+	// representation). It allows fast membership testing of specific OIDs. Like
+	// the Extensions field this field is ignored when marshaling certificates. If
+	// multiple extensions with the same OID are present only the last
+	// pkix.Extension will be in this map. Consult the `Extensions` slice when it
+	// is required to process all extensions including duplicates.
+	ExtensionsMap map[string]pkix.Extension
+
+	// ExtraExtensions contains extensions to be copied, raw, into any
+	// marshaled certificates. Values override any extensions that would
+	// otherwise be produced based on the other fields. The ExtraExtensions
+	// field is not populated when parsing certificates, see Extensions.
+	ExtraExtensions []pkix.Extension
+
+	// UnhandledCriticalExtensions contains a list of extension IDs that
+	// were not (fully) processed when parsing. Verify will fail if this
+	// slice is non-empty, unless verification is delegated to an OS
+	// library which understands all the critical extensions.
+	//
+	// Users can access these extensions using Extensions and can remove
+	// elements from this slice if they believe that they have been
+	// handled.
+	UnhandledCriticalExtensions []asn1.ObjectIdentifier
+
+	ExtKeyUsage        []ExtKeyUsage           // Sequence of extended key usages.
+	UnknownExtKeyUsage []asn1.ObjectIdentifier // Encountered extended key usages unknown to this package.
+
+	BasicConstraintsValid bool // if true then the next two fields are valid.
+	IsCA                  bool
+
+	// MaxPathLen and MaxPathLenZero indicate the presence and
+	// value of the BasicConstraints' "pathLenConstraint".
+	//
+	// When parsing a certificate, a positive non-zero MaxPathLen
+	// means that the field was specified, -1 means it was unset,
+	// and MaxPathLenZero being true mean that the field was
+	// explicitly set to zero. The case of MaxPathLen==0 with MaxPathLenZero==false
+	// should be treated equivalent to -1 (unset).
+	//
+	// When generating a certificate, an unset pathLenConstraint
+	// can be requested with either MaxPathLen == -1 or using the
+	// zero value for both MaxPathLen and MaxPathLenZero.
+	MaxPathLen int
+	// MaxPathLenZero indicates that BasicConstraintsValid==true and
+	// MaxPathLen==0 should be interpreted as an actual Max path length
+	// of zero. Otherwise, that combination is interpreted as MaxPathLen
+	// not being set.
+	MaxPathLenZero bool
+
+	SubjectKeyId   []byte
+	AuthorityKeyId []byte
+
+	// RFC 5280, 4.2.2.1 (Authority Information Access)
+	OCSPServer            []string
+	IssuingCertificateURL []string
+
+	// Subject Alternate Name values
+	OtherNames     []pkix.OtherName
+	DNSNames       []string
+	EmailAddresses []string
+	DirectoryNames []pkix.Name
+	EDIPartyNames  []pkix.EDIPartyName
+	URIs           []string
+	IPAddresses    []net.IP
+	RegisteredIDs  []asn1.ObjectIdentifier
+
+	// Issuer Alternative Name values
+	IANOtherNames     []pkix.OtherName
+	IANDNSNames       []string
+	IANEmailAddresses []string
+	IANDirectoryNames []pkix.Name
+	IANEDIPartyNames  []pkix.EDIPartyName
+	IANURIs           []string
+	IANIPAddresses    []net.IP
+	IANRegisteredIDs  []asn1.ObjectIdentifier
+
+	// Certificate Policies values
+	QualifierId          [][]asn1.ObjectIdentifier
+	CPSuri               [][]string
+	ExplicitTexts        [][]asn1.RawValue
+	NoticeRefOrgnization [][]asn1.RawValue
+	NoticeRefNumbers     [][]NoticeNumber
+
+	ParsedExplicitTexts         [][]string
+	ParsedNoticeRefOrganization [][]string
+
+	// Name constraints
+	NameConstraintsCritical bool // if true then the name constraints are marked critical.
+	PermittedDNSNames       []GeneralSubtreeString
+	ExcludedDNSNames        []GeneralSubtreeString
+	PermittedEmailAddresses []GeneralSubtreeString
+	ExcludedEmailAddresses  []GeneralSubtreeString
+	PermittedURIs           []GeneralSubtreeString
+	ExcludedURIs            []GeneralSubtreeString
+	PermittedIPAddresses    []GeneralSubtreeIP
+	ExcludedIPAddresses     []GeneralSubtreeIP
+	PermittedDirectoryNames []GeneralSubtreeName
+	ExcludedDirectoryNames  []GeneralSubtreeName
+	PermittedEdiPartyNames  []GeneralSubtreeEdi
+	ExcludedEdiPartyNames   []GeneralSubtreeEdi
+	PermittedRegisteredIDs  []GeneralSubtreeOid
+	ExcludedRegisteredIDs   []GeneralSubtreeOid
+	PermittedX400Addresses  []GeneralSubtreeRaw
+	ExcludedX400Addresses   []GeneralSubtreeRaw
+
+	// CRL Distribution Points
+	CRLDistributionPoints []string
+
+	PolicyIdentifiers []asn1.ObjectIdentifier
+	ValidationLevel   CertValidationLevel
+
+	// Fingerprints
+	FingerprintMD5    CertificateFingerprint
+	FingerprintSHA1   CertificateFingerprint
+	FingerprintSHA256 CertificateFingerprint
+	FingerprintNoCT   CertificateFingerprint
+
+	// SPKI
+	SPKIFingerprint           CertificateFingerprint
+	SPKISubjectFingerprint    CertificateFingerprint
+	TBSCertificateFingerprint CertificateFingerprint
+
+	IsPrecert bool
+
+	// Internal
+	validSignature bool
+
+	// CT
+	SignedCertificateTimestampList []*ct.SignedCertificateTimestamp
+
+	// QWACS
+	CABFOrganizationIdentifier *CABFOrganizationIdentifier
+	QCStatements               *QCStatements
+
+	// Used to speed up the zlint checks. Populated by the GetParsedDNSNames method.
+	parsedDNSNames []ParsedDomainName
+	// Used to speed up the zlint checks. Populated by the GetParsedCommonName method
+	parsedCommonName *ParsedDomainName
+
+	// CAB Forum Tor Service Descriptor Hash Extensions (see EV Guidelines
+	// Appendix F)
+	TorServiceDescriptors []*TorServiceDescriptorHash
+}
+
+// ParsedDomainName is a structure holding a parsed domain name (CommonName or
+// DNS SAN) and a parsing error.
+type ParsedDomainName struct {
+	DomainString string
+	ParsedDomain *publicsuffix.DomainName
+	ParseError   error
+}
+
+// GetParsedDNSNames returns a list of parsed SAN DNS names. It is used to cache the parsing result and
+// speed up zlint linters. If invalidateCache is true, then the cache is repopulated with current list of string from
+// Certificate.DNSNames. This parameter should always be false, unless the Certificate.DNSNames have been modified
+// after calling GetParsedDNSNames the previous time.
+func (c *Certificate) GetParsedDNSNames(invalidateCache bool) []ParsedDomainName {
+	if c.parsedDNSNames != nil && !invalidateCache {
+		return c.parsedDNSNames
+	}
+	c.parsedDNSNames = make([]ParsedDomainName, len(c.DNSNames))
+
+	for i := range c.DNSNames {
+		var parsedDomain, parseError = publicsuffix.ParseFromListWithOptions(publicsuffix.DefaultList,
+			c.DNSNames[i],
+			&publicsuffix.FindOptions{IgnorePrivate: true, DefaultRule: publicsuffix.DefaultRule})
+
+		c.parsedDNSNames[i].DomainString = c.DNSNames[i]
+		c.parsedDNSNames[i].ParsedDomain = parsedDomain
+		c.parsedDNSNames[i].ParseError = parseError
+	}
+
+	return c.parsedDNSNames
+}
+
+// GetParsedCommonName returns parsed subject CommonName. It is used to cache the parsing result and
+// speed up zlint linters. If invalidateCache is true, then the cache is repopulated with current subject CommonName.
+// This parameter should always be false, unless the Certificate.Subject.CommonName have been modified
+// after calling GetParsedSubjectCommonName the previous time.
+func (c *Certificate) GetParsedSubjectCommonName(invalidateCache bool) ParsedDomainName {
+	if c.parsedCommonName != nil && !invalidateCache {
+		return *c.parsedCommonName
+	}
+
+	var parsedDomain, parseError = publicsuffix.ParseFromListWithOptions(publicsuffix.DefaultList,
+		c.Subject.CommonName,
+		&publicsuffix.FindOptions{IgnorePrivate: true, DefaultRule: publicsuffix.DefaultRule})
+
+	c.parsedCommonName = &ParsedDomainName{
+		DomainString: c.Subject.CommonName,
+		ParsedDomain: parsedDomain,
+		ParseError:   parseError,
+	}
+
+	return *c.parsedCommonName
+}
+
+// ErrUnsupportedAlgorithm results from attempting to perform an operation that
+// involves algorithms that are not currently implemented.
+var ErrUnsupportedAlgorithm = errors.New("x509: cannot verify signature: algorithm unimplemented")
+
+// An InsecureAlgorithmError
+type InsecureAlgorithmError SignatureAlgorithm
+
+func (e InsecureAlgorithmError) Error() string {
+	return fmt.Sprintf("x509: cannot verify signature: insecure algorithm %v", SignatureAlgorithm(e))
+}
+
+// ConstraintViolationError results when a requested usage is not permitted by
+// a certificate. For example: checking a signature when the public key isn't a
+// certificate signing key.
+type ConstraintViolationError struct{}
+
+func (ConstraintViolationError) Error() string {
+	return "x509: invalid signature: parent certificate cannot sign this kind of certificate"
+}
+
+func (c *Certificate) Equal(other *Certificate) bool {
+	return bytes.Equal(c.Raw, other.Raw)
+}
+
+func (c *Certificate) hasSANExtension() bool {
+	return oidInExtensions(oidExtensionSubjectAltName, c.Extensions)
+}
+
+// Entrust have a broken root certificate (CN=Entrust.net Certification
+// Authority (2048)) which isn't marked as a CA certificate and is thus invalid
+// according to PKIX.
+// We recognise this certificate by its SubjectPublicKeyInfo and exempt it
+// from the Basic Constraints requirement.
+// See http://www.entrust.net/knowledge-base/technote.cfm?tn=7869
+//
+// TODO(agl): remove this hack once their reissued root is sufficiently
+// widespread.
+var entrustBrokenSPKI = []byte{
+	0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09,
+	0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+	0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00,
+	0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01,
+	0x00, 0x97, 0xa3, 0x2d, 0x3c, 0x9e, 0xde, 0x05,
+	0xda, 0x13, 0xc2, 0x11, 0x8d, 0x9d, 0x8e, 0xe3,
+	0x7f, 0xc7, 0x4b, 0x7e, 0x5a, 0x9f, 0xb3, 0xff,
+	0x62, 0xab, 0x73, 0xc8, 0x28, 0x6b, 0xba, 0x10,
+	0x64, 0x82, 0x87, 0x13, 0xcd, 0x57, 0x18, 0xff,
+	0x28, 0xce, 0xc0, 0xe6, 0x0e, 0x06, 0x91, 0x50,
+	0x29, 0x83, 0xd1, 0xf2, 0xc3, 0x2a, 0xdb, 0xd8,
+	0xdb, 0x4e, 0x04, 0xcc, 0x00, 0xeb, 0x8b, 0xb6,
+	0x96, 0xdc, 0xbc, 0xaa, 0xfa, 0x52, 0x77, 0x04,
+	0xc1, 0xdb, 0x19, 0xe4, 0xae, 0x9c, 0xfd, 0x3c,
+	0x8b, 0x03, 0xef, 0x4d, 0xbc, 0x1a, 0x03, 0x65,
+	0xf9, 0xc1, 0xb1, 0x3f, 0x72, 0x86, 0xf2, 0x38,
+	0xaa, 0x19, 0xae, 0x10, 0x88, 0x78, 0x28, 0xda,
+	0x75, 0xc3, 0x3d, 0x02, 0x82, 0x02, 0x9c, 0xb9,
+	0xc1, 0x65, 0x77, 0x76, 0x24, 0x4c, 0x98, 0xf7,
+	0x6d, 0x31, 0x38, 0xfb, 0xdb, 0xfe, 0xdb, 0x37,
+	0x02, 0x76, 0xa1, 0x18, 0x97, 0xa6, 0xcc, 0xde,
+	0x20, 0x09, 0x49, 0x36, 0x24, 0x69, 0x42, 0xf6,
+	0xe4, 0x37, 0x62, 0xf1, 0x59, 0x6d, 0xa9, 0x3c,
+	0xed, 0x34, 0x9c, 0xa3, 0x8e, 0xdb, 0xdc, 0x3a,
+	0xd7, 0xf7, 0x0a, 0x6f, 0xef, 0x2e, 0xd8, 0xd5,
+	0x93, 0x5a, 0x7a, 0xed, 0x08, 0x49, 0x68, 0xe2,
+	0x41, 0xe3, 0x5a, 0x90, 0xc1, 0x86, 0x55, 0xfc,
+	0x51, 0x43, 0x9d, 0xe0, 0xb2, 0xc4, 0x67, 0xb4,
+	0xcb, 0x32, 0x31, 0x25, 0xf0, 0x54, 0x9f, 0x4b,
+	0xd1, 0x6f, 0xdb, 0xd4, 0xdd, 0xfc, 0xaf, 0x5e,
+	0x6c, 0x78, 0x90, 0x95, 0xde, 0xca, 0x3a, 0x48,
+	0xb9, 0x79, 0x3c, 0x9b, 0x19, 0xd6, 0x75, 0x05,
+	0xa0, 0xf9, 0x88, 0xd7, 0xc1, 0xe8, 0xa5, 0x09,
+	0xe4, 0x1a, 0x15, 0xdc, 0x87, 0x23, 0xaa, 0xb2,
+	0x75, 0x8c, 0x63, 0x25, 0x87, 0xd8, 0xf8, 0x3d,
+	0xa6, 0xc2, 0xcc, 0x66, 0xff, 0xa5, 0x66, 0x68,
+	0x55, 0x02, 0x03, 0x01, 0x00, 0x01,
+}
+
+// CheckSignatureFrom verifies that the signature on c is a valid signature
+// from parent.
+func (c *Certificate) CheckSignatureFrom(parent *Certificate) (err error) {
+	// RFC 5280, 4.2.1.9:
+	// "If the basic constraints extension is not present in a version 3
+	// certificate, or the extension is present but the cA boolean is not
+	// asserted, then the certified public key MUST NOT be used to verify
+	// certificate signatures."
+	// (except for Entrust, see comment above entrustBrokenSPKI)
+	if (parent.Version == 3 && !parent.BasicConstraintsValid ||
+		parent.BasicConstraintsValid && !parent.IsCA) &&
+		!bytes.Equal(c.RawSubjectPublicKeyInfo, entrustBrokenSPKI) {
+		return ConstraintViolationError{}
+	}
+
+	if parent.KeyUsage != 0 && parent.KeyUsage&KeyUsageCertSign == 0 {
+		return ConstraintViolationError{}
+	}
+
+	if parent.PublicKeyAlgorithm == UnknownPublicKeyAlgorithm {
+		return ErrUnsupportedAlgorithm
+	}
+
+	// TODO(agl): don't ignore the path length constraint.
+
+	if !bytes.Equal(parent.RawSubject, c.RawIssuer) {
+		return errors.New("Mis-match issuer/subject")
+	}
+
+	return parent.CheckSignature(c.SignatureAlgorithm, c.RawTBSCertificate, c.Signature)
+}
+
+func CheckSignatureFromKey(publicKey interface{}, algo SignatureAlgorithm, signed, signature []byte) (err error) {
+	var hashType crypto.Hash
+
+	switch algo {
+	// NOTE: exception to stdlib, allow MD5 algorithm
+	case MD5WithRSA:
+		hashType = crypto.MD5
+	case SHA1WithRSA, DSAWithSHA1, ECDSAWithSHA1:
+		hashType = crypto.SHA1
+	case SHA256WithRSA, SHA256WithRSAPSS, DSAWithSHA256, ECDSAWithSHA256:
+		hashType = crypto.SHA256
+	case SHA384WithRSA, SHA384WithRSAPSS, ECDSAWithSHA384:
+		hashType = crypto.SHA384
+	case SHA512WithRSA, SHA512WithRSAPSS, ECDSAWithSHA512:
+		hashType = crypto.SHA512
+	//case MD2WithRSA, MD5WithRSA:
+	case MD2WithRSA:
+		return InsecureAlgorithmError(algo)
+	case Ed25519Sig:
+		hashType = 0
+	default:
+		return ErrUnsupportedAlgorithm
+	}
+
+	if hashType != 0 && !hashType.Available() {
+		return ErrUnsupportedAlgorithm
+	}
+	digest := hash(hashType, signed)
+
+	switch pub := publicKey.(type) {
+	case *rsa.PublicKey:
+		if algo.isRSAPSS() {
+			return rsa.VerifyPSS(pub, hashType, digest, signature, &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash})
+		} else {
+			return rsa.VerifyPKCS1v15(pub, hashType, digest, signature)
+		}
+	case *dsa.PublicKey:
+		dsaSig := new(dsaSignature)
+		if rest, err := asn1.Unmarshal(signature, dsaSig); err != nil {
+			return err
+		} else if len(rest) != 0 {
+			return errors.New("x509: trailing data after DSA signature")
+		}
+		if dsaSig.R.Sign() <= 0 || dsaSig.S.Sign() <= 0 {
+			return errors.New("x509: DSA signature contained zero or negative values")
+		}
+		if !dsa.Verify(pub, digest, dsaSig.R, dsaSig.S) {
+			return errors.New("x509: DSA verification failure")
+		}
+		return
+	case *ecdsa.PublicKey:
+		ecdsaSig := new(ecdsaSignature)
+		if rest, err := asn1.Unmarshal(signature, ecdsaSig); err != nil {
+			return err
+		} else if len(rest) != 0 {
+			return errors.New("x509: trailing data after ECDSA signature")
+		}
+		if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
+			return errors.New("x509: ECDSA signature contained zero or negative values")
+		}
+		if !ecdsa.Verify(pub, digest, ecdsaSig.R, ecdsaSig.S) {
+			return errors.New("x509: ECDSA verification failure")
+		}
+		return
+	case *AugmentedECDSA:
+		ecdsaSig := new(ecdsaSignature)
+		if _, err := asn1.Unmarshal(signature, ecdsaSig); err != nil {
+			return err
+		}
+		if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
+			return errors.New("x509: ECDSA signature contained zero or negative values")
+		}
+		if !ecdsa.Verify(pub.Pub, digest, ecdsaSig.R, ecdsaSig.S) {
+			return errors.New("x509: ECDSA verification failure")
+		}
+		return
+	case ed25519.PublicKey:
+		if !ed25519.Verify(pub, digest, signature) {
+			return errors.New("x509: Ed25519 verification failure")
+		}
+		return
+	}
+	return ErrUnsupportedAlgorithm
+}
+
+// CheckSignature verifies that signature is a valid signature over signed from
+// c's public key.
+func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature []byte) (err error) {
+	return CheckSignatureFromKey(c.PublicKey, algo, signed, signature)
+}
+
+// CheckCRLSignature checks that the signature in crl is from c.
+func (c *Certificate) CheckCRLSignature(crl *pkix.CertificateList) error {
+	algo := GetSignatureAlgorithmFromAI(crl.SignatureAlgorithm)
+	return c.CheckSignature(algo, crl.TBSCertList.Raw, crl.SignatureValue.RightAlign())
+}
+
+// UnhandledCriticalExtension results when the certificate contains an
+// unimplemented X.509 extension marked as critical.
+type UnhandledCriticalExtension struct {
+	oid     asn1.ObjectIdentifier
+	message string
+}
+
+func (h UnhandledCriticalExtension) Error() string {
+	return fmt.Sprintf("x509: unhandled critical extension: %s | %s", h.oid, h.message)
+}
+
+// TimeInValidityPeriod returns true if NotBefore < t < NotAfter
+func (c *Certificate) TimeInValidityPeriod(t time.Time) bool {
+	return c.NotBefore.Before(t) && c.NotAfter.After(t)
+}
+
+// RFC 5280 4.2.1.4
+type policyInformation struct {
+	Policy     asn1.ObjectIdentifier
+	Qualifiers []policyQualifierInfo `asn1:"optional"`
+}
+
+type policyQualifierInfo struct {
+	PolicyQualifierId asn1.ObjectIdentifier
+	Qualifier         asn1.RawValue
+}
+
+type userNotice struct {
+	NoticeRef    noticeReference `asn1:"optional"`
+	ExplicitText asn1.RawValue   `asn1:"optional"`
+}
+
+type noticeReference struct {
+	Organization  asn1.RawValue
+	NoticeNumbers []int
+}
+
+type NoticeNumber []int
+
+type generalSubtree struct {
+	Value asn1.RawValue `asn1:"optional"`
+	Min   int           `asn1:"tag:0,default:0,optional"`
+	Max   int           `asn1:"tag:1,optional"`
+}
+
+type GeneralSubtreeString struct {
+	Data string
+	Max  int
+	Min  int
+}
+
+type GeneralSubtreeIP struct {
+	Data net.IPNet
+	Max  int
+	Min  int
+}
+
+type GeneralSubtreeName struct {
+	Data pkix.Name
+	Max  int
+	Min  int
+}
+
+type GeneralSubtreeEdi struct {
+	Data pkix.EDIPartyName
+	Max  int
+	Min  int
+}
+
+type GeneralSubtreeOid struct {
+	Data asn1.ObjectIdentifier
+	Max  int
+	Min  int
+}
+
+type GeneralSubtreeRaw struct {
+	Data asn1.RawValue
+	Max  int
+	Min  int
+}
+
+type basicConstraints struct {
+	IsCA       bool `asn1:"optional"`
+	MaxPathLen int  `asn1:"optional,default:-1"`
+}
+
+// RFC 5280, 4.2.1.10
+type nameConstraints struct {
+	Permitted []generalSubtree `asn1:"optional,tag:0"`
+	Excluded  []generalSubtree `asn1:"optional,tag:1"`
+}
+
+// RFC 5280, 4.2.2.1
+type authorityInfoAccess struct {
+	Method   asn1.ObjectIdentifier
+	Location asn1.RawValue
+}
+
+// RFC 5280, 4.2.1.14
+type distributionPoint struct {
+	DistributionPoint distributionPointName `asn1:"optional,tag:0"`
+	Reason            asn1.BitString        `asn1:"optional,tag:1"`
+	CRLIssuer         asn1.RawValue         `asn1:"optional,tag:2"`
+}
+
+type distributionPointName struct {
+	FullName     asn1.RawValue    `asn1:"optional,tag:0"`
+	RelativeName pkix.RDNSequence `asn1:"optional,tag:1"`
+}
+
+func maxValidationLevel(a, b CertValidationLevel) CertValidationLevel {
+	if a > b {
+		return a
+	}
+	return b
+}
+
+func hash(hashFunc crypto.Hash, raw []byte) []byte {
+	digest := raw
+	if hashFunc != 0 {
+		h := hashFunc.New()
+		h.Write(raw)
+		digest = h.Sum(nil)
+	}
+	return digest
+}
+
+func getMaxCertValidationLevel(oids []asn1.ObjectIdentifier) CertValidationLevel {
+	maxOID := UnknownValidationLevel
+	for _, oid := range oids {
+		if _, ok := ExtendedValidationOIDs[oid.String()]; ok {
+			return EV
+		} else if _, ok := OrganizationValidationOIDs[oid.String()]; ok {
+			maxOID = maxValidationLevel(maxOID, OV)
+		} else if _, ok := DomainValidationOIDs[oid.String()]; ok {
+			maxOID = maxValidationLevel(maxOID, DV)
+		}
+	}
+	return maxOID
+}
+
+func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{}, error) {
+	asn1Data := keyData.PublicKey.RightAlign()
+	switch algo {
+	case RSA:
+
+		// TODO: disabled since current behaviour does not expect it. Should be enabled though
+		// RSA public keys must have a NULL in the parameters
+		// (https://tools.ietf.org/html/rfc3279#section-2.3.1).
+		//if !bytes.Equal(keyData.Algorithm.Parameters.FullBytes, asn1.NullBytes) {
+		//	return nil, errors.New("x509: RSA key missing NULL parameters")
+		//}
+
+		p := new(pkcs1PublicKey)
+		rest, err := asn1.Unmarshal(asn1Data, p)
+		if err != nil {
+			return nil, err
+		}
+		if len(rest) != 0 {
+			return nil, errors.New("x509: trailing data after RSA public key")
+		}
+
+		if p.N.Sign() <= 0 {
+			return nil, errors.New("x509: RSA modulus is not a positive number")
+		}
+		if p.E <= 0 {
+			return nil, errors.New("x509: RSA public exponent is not a positive number")
+		}
+
+		pub := &rsa.PublicKey{
+			E: p.E,
+			N: p.N,
+		}
+		return pub, nil
+	case DSA:
+		var p *big.Int
+		rest, err := asn1.Unmarshal(asn1Data, &p)
+		if err != nil {
+			return nil, err
+		}
+		if len(rest) != 0 {
+			return nil, errors.New("x509: trailing data after DSA public key")
+		}
+		paramsData := keyData.Algorithm.Parameters.FullBytes
+		params := new(dsaAlgorithmParameters)
+		rest, err = asn1.Unmarshal(paramsData, params)
+		if err != nil {
+			return nil, err
+		}
+		if len(rest) != 0 {
+			return nil, errors.New("x509: trailing data after DSA parameters")
+		}
+		if p.Sign() <= 0 || params.P.Sign() <= 0 || params.Q.Sign() <= 0 || params.G.Sign() <= 0 {
+			return nil, errors.New("x509: zero or negative DSA parameter")
+		}
+		pub := &dsa.PublicKey{
+			Parameters: dsa.Parameters{
+				P: params.P,
+				Q: params.Q,
+				G: params.G,
+			},
+			Y: p,
+		}
+		return pub, nil
+	case ECDSA:
+		paramsData := keyData.Algorithm.Parameters.FullBytes
+		namedCurveOID := new(asn1.ObjectIdentifier)
+		rest, err := asn1.Unmarshal(paramsData, namedCurveOID)
+		if err != nil {
+			return nil, err
+		}
+		if len(rest) != 0 {
+			return nil, errors.New("x509: trailing data after ECDSA parameters")
+		}
+		namedCurve := namedCurveFromOID(*namedCurveOID)
+		if namedCurve == nil {
+			return nil, errors.New("x509: unsupported elliptic curve")
+		}
+		x, y := elliptic.Unmarshal(namedCurve, asn1Data)
+		if x == nil {
+			return nil, errors.New("x509: failed to unmarshal elliptic curve point")
+		}
+		key := &ecdsa.PublicKey{
+			Curve: namedCurve,
+			X:     x,
+			Y:     y,
+		}
+
+		pub := &AugmentedECDSA{
+			Pub: key,
+			Raw: keyData.PublicKey,
+		}
+		return pub, nil
+	case Ed25519:
+		p := ed25519.PublicKey(asn1Data)
+		if len(p) > ed25519.PublicKeySize {
+			return nil, errors.New("x509: trailing data after Ed25519 data")
+		}
+		return p, nil
+	case X25519:
+		p := X25519PublicKey(asn1Data)
+		if len(p) > 32 {
+			return nil, errors.New("x509: trailing data after X25519 public key")
+		}
+		return p, nil
+	default:
+		return nil, nil
+	}
+}
+
+func parseSANExtension(value []byte) (dnsNames, emailAddresses []string, ipAddresses []net.IP, err error) {
+	// RFC 5280, 4.2.1.6
+
+	// SubjectAltName ::= GeneralNames
+	//
+	// GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
+	//
+	// GeneralName ::= CHOICE {
+	//      otherName                       [0]     OtherName,
+	//      rfc822Name                      [1]     IA5String,
+	//      dNSName                         [2]     IA5String,
+	//      x400Address                     [3]     ORAddress,
+	//      directoryName                   [4]     Name,
+	//      ediPartyName                    [5]     EDIPartyName,
+	//      uniformResourceIdentifier       [6]     IA5String,
+	//      iPAddress                       [7]     OCTET STRING,
+	//      registeredID                    [8]     OBJECT IDENTIFIER }
+	var seq asn1.RawValue
+	var rest []byte
+	if rest, err = asn1.Unmarshal(value, &seq); err != nil {
+		return
+	} else if len(rest) != 0 {
+		err = errors.New("x509: trailing data after X.509 extension")
+		return
+	}
+	if !seq.IsCompound || seq.Tag != 16 || seq.Class != 0 {
+		err = asn1.StructuralError{Msg: "bad SAN sequence"}
+		return
+	}
+
+	rest = seq.Bytes
+	for len(rest) > 0 {
+		var v asn1.RawValue
+		rest, err = asn1.Unmarshal(rest, &v)
+		if err != nil {
+			return
+		}
+		switch v.Tag {
+		case 1:
+			emailAddresses = append(emailAddresses, string(v.Bytes))
+		case 2:
+			dnsNames = append(dnsNames, string(v.Bytes))
+		case 7:
+			switch len(v.Bytes) {
+			case net.IPv4len, net.IPv6len:
+				ipAddresses = append(ipAddresses, v.Bytes)
+			default:
+				err = errors.New("x509: certificate contained IP address of length " + strconv.Itoa(len(v.Bytes)))
+				return
+			}
+		}
+	}
+
+	return
+}
+
+func parseGeneralNames(value []byte) (otherNames []pkix.OtherName, dnsNames, emailAddresses, URIs []string, directoryNames []pkix.Name, ediPartyNames []pkix.EDIPartyName, ipAddresses []net.IP, registeredIDs []asn1.ObjectIdentifier, err error) {
+	// RFC 5280, 4.2.1.6
+
+	// SubjectAltName ::= GeneralNames
+	//
+	// GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
+	//
+	// GeneralName ::= CHOICE {
+	//      otherName                       [0]     OtherName,
+	//      rfc822Name                      [1]     IA5String,
+	//      dNSName                         [2]     IA5String,
+	//      x400Address                     [3]     ORAddress,
+	//      directoryName                   [4]     Name,
+	//      ediPartyName                    [5]     EDIPartyName,
+	//      uniformResourceIdentifier       [6]     IA5String,
+	//      iPAddress                       [7]     OCTET STRING,
+	//      registeredID                    [8]     OBJECT IDENTIFIER }
+	var seq asn1.RawValue
+	if _, err = asn1.Unmarshal(value, &seq); err != nil {
+		return
+	}
+	if !seq.IsCompound || seq.Tag != 16 || seq.Class != 0 {
+		err = asn1.StructuralError{Msg: "bad SAN sequence"}
+		return
+	}
+
+	rest := seq.Bytes
+	for len(rest) > 0 {
+		var v asn1.RawValue
+		rest, err = asn1.Unmarshal(rest, &v)
+		if err != nil {
+			return
+		}
+		switch v.Tag {
+		case 0:
+			var oName pkix.OtherName
+			_, err = asn1.UnmarshalWithParams(v.FullBytes, &oName, "tag:0")
+			if err != nil {
+				return
+			}
+			otherNames = append(otherNames, oName)
+		case 1:
+			emailAddresses = append(emailAddresses, string(v.Bytes))
+		case 2:
+			dnsNames = append(dnsNames, string(v.Bytes))
+		case 4:
+			var rdn pkix.RDNSequence
+			_, err = asn1.Unmarshal(v.Bytes, &rdn)
+			if err != nil {
+				return
+			}
+			var dir pkix.Name
+			dir.FillFromRDNSequence(&rdn)
+			directoryNames = append(directoryNames, dir)
+		case 5:
+			var ediName pkix.EDIPartyName
+			_, err = asn1.UnmarshalWithParams(v.FullBytes, &ediName, "tag:5")
+			if err != nil {
+				return
+			}
+			ediPartyNames = append(ediPartyNames, ediName)
+		case 6:
+			URIs = append(URIs, string(v.Bytes))
+		case 7:
+			switch len(v.Bytes) {
+			case net.IPv4len, net.IPv6len:
+				ipAddresses = append(ipAddresses, v.Bytes)
+			default:
+				err = errors.New("x509: certificate contained IP address of length " + strconv.Itoa(len(v.Bytes)))
+				return
+			}
+		case 8:
+			var id asn1.ObjectIdentifier
+			_, err = asn1.UnmarshalWithParams(v.FullBytes, &id, "tag:8")
+			if err != nil {
+				return
+			}
+			registeredIDs = append(registeredIDs, id)
+		}
+	}
+
+	return
+}
+
+//TODO
+func parseCertificate(in *certificate) (*Certificate, error) {
+	out := new(Certificate)
+	out.Raw = in.Raw
+	out.RawTBSCertificate = in.TBSCertificate.Raw
+	out.RawSubjectPublicKeyInfo = in.TBSCertificate.PublicKey.Raw
+	out.RawSubject = in.TBSCertificate.Subject.FullBytes
+	out.RawIssuer = in.TBSCertificate.Issuer.FullBytes
+
+	// Fingerprints
+	out.FingerprintMD5 = MD5Fingerprint(in.Raw)
+	out.FingerprintSHA1 = SHA1Fingerprint(in.Raw)
+	out.FingerprintSHA256 = SHA256Fingerprint(in.Raw)
+	out.SPKIFingerprint = SHA256Fingerprint(in.TBSCertificate.PublicKey.Raw)
+	out.TBSCertificateFingerprint = SHA256Fingerprint(in.TBSCertificate.Raw)
+
+	tbs := in.TBSCertificate
+	originalExtensions := in.TBSCertificate.Extensions
+
+	// Blow away the raw data since it also includes CT data
+	tbs.Raw = nil
+
+	// remove the CT extensions
+	extensions := make([]pkix.Extension, 0, len(originalExtensions))
+	for _, extension := range originalExtensions {
+		if extension.Id.Equal(oidExtensionCTPrecertificatePoison) {
+			continue
+		}
+		if extension.Id.Equal(oidExtensionSignedCertificateTimestampList) {
+			continue
+		}
+		extensions = append(extensions, extension)
+	}
+
+	tbs.Extensions = extensions
+
+	tbsbytes, err := asn1.Marshal(tbs)
+	if err != nil {
+		return nil, err
+	}
+	if tbsbytes == nil {
+		return nil, asn1.SyntaxError{Msg: "Trailing data"}
+	}
+	out.FingerprintNoCT = SHA256Fingerprint(tbsbytes[:])
+
+	// Hash both SPKI and Subject to create a fingerprint that we can use to describe a CA
+	hasher := sha256.New()
+	hasher.Write(in.TBSCertificate.PublicKey.Raw)
+	hasher.Write(in.TBSCertificate.Subject.FullBytes)
+	out.SPKISubjectFingerprint = hasher.Sum(nil)
+
+	out.Signature = in.SignatureValue.RightAlign()
+	out.SignatureAlgorithm =
+		GetSignatureAlgorithmFromAI(in.TBSCertificate.SignatureAlgorithm)
+
+	out.SignatureAlgorithmOID = in.TBSCertificate.SignatureAlgorithm.Algorithm
+
+	out.PublicKeyAlgorithm =
+		getPublicKeyAlgorithmFromOID(in.TBSCertificate.PublicKey.Algorithm.Algorithm)
+	out.PublicKey, err = parsePublicKey(out.PublicKeyAlgorithm, &in.TBSCertificate.PublicKey)
+	if err != nil {
+		return nil, err
+	}
+
+	out.PublicKeyAlgorithmOID = in.TBSCertificate.PublicKey.Algorithm.Algorithm
+	out.Version = in.TBSCertificate.Version + 1
+	out.SerialNumber = in.TBSCertificate.SerialNumber
+
+	var issuer, subject pkix.RDNSequence
+	if _, err := asn1.Unmarshal(in.TBSCertificate.Subject.FullBytes, &subject); err != nil {
+		return nil, err
+	}
+	if _, err := asn1.Unmarshal(in.TBSCertificate.Issuer.FullBytes, &issuer); err != nil {
+		return nil, err
+	}
+
+	out.Issuer.FillFromRDNSequence(&issuer)
+	out.Subject.FillFromRDNSequence(&subject)
+
+	// Check if self-signed
+	if bytes.Equal(out.RawSubject, out.RawIssuer) {
+		// Possibly self-signed, check the signature against itself.
+		if err := out.CheckSignature(out.SignatureAlgorithm, out.RawTBSCertificate, out.Signature); err == nil {
+			out.SelfSigned = true
+		}
+	}
+
+	out.NotBefore = in.TBSCertificate.Validity.NotBefore
+	out.NotAfter = in.TBSCertificate.Validity.NotAfter
+
+	out.ValidityPeriod = int(out.NotAfter.Sub(out.NotBefore).Seconds())
+
+	out.IssuerUniqueId = in.TBSCertificate.UniqueId
+	out.SubjectUniqueId = in.TBSCertificate.SubjectUniqueId
+
+	out.ExtensionsMap = make(map[string]pkix.Extension, len(in.TBSCertificate.Extensions))
+	for _, e := range in.TBSCertificate.Extensions {
+		out.Extensions = append(out.Extensions, e)
+		out.ExtensionsMap[e.Id.String()] = e
+
+		if len(e.Id) == 4 && e.Id[0] == 2 && e.Id[1] == 5 && e.Id[2] == 29 {
+			switch e.Id[3] {
+			case 15:
+				// RFC 5280, 4.2.1.3
+				var usageBits asn1.BitString
+				_, err := asn1.Unmarshal(e.Value, &usageBits)
+
+				if err == nil {
+					var usage int
+					for i := 0; i < 9; i++ {
+						if usageBits.At(i) != 0 {
+							usage |= 1 << uint(i)
+						}
+					}
+					out.KeyUsage = KeyUsage(usage)
+					continue
+				}
+			case 19:
+				// RFC 5280, 4.2.1.9
+				var constraints basicConstraints
+				_, err := asn1.Unmarshal(e.Value, &constraints)
+
+				if err == nil {
+					out.BasicConstraintsValid = true
+					out.IsCA = constraints.IsCA
+					out.MaxPathLen = constraints.MaxPathLen
+					out.MaxPathLenZero = out.MaxPathLen == 0
+					continue
+				}
+			case 17:
+				out.OtherNames, out.DNSNames, out.EmailAddresses, out.URIs, out.DirectoryNames, out.EDIPartyNames, out.IPAddresses, out.RegisteredIDs, err = parseGeneralNames(e.Value)
+				if err != nil {
+					return nil, err
+				}
+
+				if len(out.DNSNames) > 0 || len(out.EmailAddresses) > 0 || len(out.IPAddresses) > 0 {
+					continue
+				}
+				// If we didn't parse any of the names then we
+				// fall through to the critical check below.
+			case 18:
+				out.IANOtherNames, out.IANDNSNames, out.IANEmailAddresses, out.IANURIs, out.IANDirectoryNames, out.IANEDIPartyNames, out.IANIPAddresses, out.IANRegisteredIDs, err = parseGeneralNames(e.Value)
+				if err != nil {
+					return nil, err
+				}
+
+				if len(out.IANDNSNames) > 0 || len(out.IANEmailAddresses) > 0 || len(out.IANIPAddresses) > 0 {
+					continue
+				}
+			case 30:
+				// RFC 5280, 4.2.1.10
+
+				// NameConstraints ::= SEQUENCE {
+				//      permittedSubtrees       [0]     GeneralSubtrees OPTIONAL,
+				//      excludedSubtrees        [1]     GeneralSubtrees OPTIONAL }
+				//
+				// GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
+				//
+				// GeneralSubtree ::= SEQUENCE {
+				//      base                    GeneralName,
+				//      Min         [0]     BaseDistance DEFAULT 0,
+				//      Max         [1]     BaseDistance OPTIONAL }
+				//
+				// BaseDistance ::= INTEGER (0..MAX)
+
+				var constraints nameConstraints
+				_, err := asn1.Unmarshal(e.Value, &constraints)
+				if err != nil {
+					return nil, err
+				}
+
+				if e.Critical {
+					out.NameConstraintsCritical = true
+				}
+
+				for _, subtree := range constraints.Permitted {
+					switch subtree.Value.Tag {
+					case 1:
+						out.PermittedEmailAddresses = append(out.PermittedEmailAddresses, GeneralSubtreeString{Data: string(subtree.Value.Bytes), Max: subtree.Max, Min: subtree.Min})
+					case 2:
+						out.PermittedDNSNames = append(out.PermittedDNSNames, GeneralSubtreeString{Data: string(subtree.Value.Bytes), Max: subtree.Max, Min: subtree.Min})
+					case 3:
+						out.PermittedX400Addresses = append(out.PermittedX400Addresses, GeneralSubtreeRaw{Data: subtree.Value, Max: subtree.Max, Min: subtree.Min})
+					case 4:
+						var rawdn pkix.RDNSequence
+						if _, err := asn1.Unmarshal(subtree.Value.Bytes, &rawdn); err != nil {
+							return out, err
+						}
+						var dn pkix.Name
+						dn.FillFromRDNSequence(&rawdn)
+						out.PermittedDirectoryNames = append(out.PermittedDirectoryNames, GeneralSubtreeName{Data: dn, Max: subtree.Max, Min: subtree.Min})
+					case 5:
+						var ediName pkix.EDIPartyName
+						_, err = asn1.UnmarshalWithParams(subtree.Value.FullBytes, &ediName, "tag:5")
+						if err != nil {
+							return out, err
+						}
+						out.PermittedEdiPartyNames = append(out.PermittedEdiPartyNames, GeneralSubtreeEdi{Data: ediName, Max: subtree.Max, Min: subtree.Min})
+					case 6:
+						out.PermittedURIs = append(out.PermittedURIs, GeneralSubtreeString{Data: string(subtree.Value.Bytes), Max: subtree.Max, Min: subtree.Min})
+					case 7:
+						switch len(subtree.Value.Bytes) {
+						case net.IPv4len * 2:
+							ip := net.IPNet{IP: subtree.Value.Bytes[:net.IPv4len], Mask: subtree.Value.Bytes[net.IPv4len:]}
+							out.PermittedIPAddresses = append(out.PermittedIPAddresses, GeneralSubtreeIP{Data: ip, Max: subtree.Max, Min: subtree.Min})
+						case net.IPv6len * 2:
+							ip := net.IPNet{IP: subtree.Value.Bytes[:net.IPv6len], Mask: subtree.Value.Bytes[net.IPv6len:]}
+							out.PermittedIPAddresses = append(out.PermittedIPAddresses, GeneralSubtreeIP{Data: ip, Max: subtree.Max, Min: subtree.Min})
+						default:
+							return out, errors.New("x509: certificate name constraint contained IP address range of length " + strconv.Itoa(len(subtree.Value.Bytes)))
+						}
+					case 8:
+						var id asn1.ObjectIdentifier
+						_, err = asn1.UnmarshalWithParams(subtree.Value.FullBytes, &id, "tag:8")
+						if err != nil {
+							return out, err
+						}
+						out.PermittedRegisteredIDs = append(out.PermittedRegisteredIDs, GeneralSubtreeOid{Data: id, Max: subtree.Max, Min: subtree.Min})
+					}
+				}
+				for _, subtree := range constraints.Excluded {
+					switch subtree.Value.Tag {
+					case 1:
+						out.ExcludedEmailAddresses = append(out.ExcludedEmailAddresses, GeneralSubtreeString{Data: string(subtree.Value.Bytes), Max: subtree.Max, Min: subtree.Min})
+					case 2:
+						out.ExcludedDNSNames = append(out.ExcludedDNSNames, GeneralSubtreeString{Data: string(subtree.Value.Bytes), Max: subtree.Max, Min: subtree.Min})
+					case 3:
+						out.ExcludedX400Addresses = append(out.ExcludedX400Addresses, GeneralSubtreeRaw{Data: subtree.Value, Max: subtree.Max, Min: subtree.Min})
+					case 4:
+						var rawdn pkix.RDNSequence
+						if _, err := asn1.Unmarshal(subtree.Value.Bytes, &rawdn); err != nil {
+							return out, err
+						}
+						var dn pkix.Name
+						dn.FillFromRDNSequence(&rawdn)
+						out.ExcludedDirectoryNames = append(out.ExcludedDirectoryNames, GeneralSubtreeName{Data: dn, Max: subtree.Max, Min: subtree.Min})
+					case 5:
+						var ediName pkix.EDIPartyName
+						_, err = asn1.Unmarshal(subtree.Value.Bytes, &ediName)
+						if err != nil {
+							return out, err
+						}
+						out.ExcludedEdiPartyNames = append(out.ExcludedEdiPartyNames, GeneralSubtreeEdi{Data: ediName, Max: subtree.Max, Min: subtree.Min})
+					case 6:
+						out.ExcludedURIs = append(out.ExcludedURIs, GeneralSubtreeString{Data: string(subtree.Value.Bytes), Max: subtree.Max, Min: subtree.Min})
+					case 7:
+						switch len(subtree.Value.Bytes) {
+						case net.IPv4len * 2:
+							ip := net.IPNet{IP: subtree.Value.Bytes[:net.IPv4len], Mask: subtree.Value.Bytes[net.IPv4len:]}
+							out.ExcludedIPAddresses = append(out.ExcludedIPAddresses, GeneralSubtreeIP{Data: ip, Max: subtree.Max, Min: subtree.Min})
+						case net.IPv6len * 2:
+							ip := net.IPNet{IP: subtree.Value.Bytes[:net.IPv6len], Mask: subtree.Value.Bytes[net.IPv6len:]}
+							out.ExcludedIPAddresses = append(out.ExcludedIPAddresses, GeneralSubtreeIP{Data: ip, Max: subtree.Max, Min: subtree.Min})
+						default:
+							return out, errors.New("x509: certificate name constraint contained IP address range of length " + strconv.Itoa(len(subtree.Value.Bytes)))
+						}
+					case 8:
+						var id asn1.ObjectIdentifier
+						_, err = asn1.Unmarshal(subtree.Value.Bytes, &id)
+						if err != nil {
+							return out, err
+						}
+						out.ExcludedRegisteredIDs = append(out.ExcludedRegisteredIDs, GeneralSubtreeOid{Data: id, Max: subtree.Max, Min: subtree.Min})
+					}
+				}
+				continue
+
+			case 31:
+				// RFC 5280, 4.2.1.14
+
+				// CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
+				//
+				// DistributionPoint ::= SEQUENCE {
+				//     distributionPoint       [0]     DistributionPointName OPTIONAL,
+				//     reasons                 [1]     ReasonFlags OPTIONAL,
+				//     cRLIssuer               [2]     GeneralNames OPTIONAL }
+				//
+				// DistributionPointName ::= CHOICE {
+				//     fullName                [0]     GeneralNames,
+				//     nameRelativeToCRLIssuer [1]     RelativeDistinguishedName }
+
+				var cdp []distributionPoint
+				_, err := asn1.Unmarshal(e.Value, &cdp)
+				if err != nil {
+					return nil, err
+				}
+
+				for _, dp := range cdp {
+					// Per RFC 5280, 4.2.1.13, one of distributionPoint or cRLIssuer may be empty.
+					if len(dp.DistributionPoint.FullName.Bytes) == 0 {
+						continue
+					}
+
+					var n asn1.RawValue
+					dpName := dp.DistributionPoint.FullName.Bytes
+					// FullName is a GeneralNames, which is a SEQUENCE OF
+					// GeneralName, which in turn is a CHOICE.
+					// Per https://www.ietf.org/rfc/rfc5280.txt, multiple names
+					// for a single DistributionPoint give different pointers to
+					// the same CRL.
+					for len(dpName) > 0 {
+						dpName, err = asn1.Unmarshal(dpName, &n)
+						if err != nil {
+							return nil, err
+						}
+						if n.Tag == 6 {
+							out.CRLDistributionPoints = append(out.CRLDistributionPoints, string(n.Bytes))
+						}
+					}
+				}
+				continue
+
+			case 35:
+				// RFC 5280, 4.2.1.1
+				var a authKeyId
+				_, err = asn1.Unmarshal(e.Value, &a)
+				if err != nil {
+					return nil, err
+				}
+				out.AuthorityKeyId = a.Id
+				continue
+
+			case 37:
+				// RFC 5280, 4.2.1.12.  Extended Key Usage
+
+				// id-ce-extKeyUsage OBJECT IDENTIFIER ::= { id-ce 37 }
+				//
+				// ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
+				//
+				// KeyPurposeId ::= OBJECT IDENTIFIER
+
+				var keyUsage []asn1.ObjectIdentifier
+				_, err = asn1.Unmarshal(e.Value, &keyUsage)
+				if err != nil {
+					return nil, err
+				}
+
+				for _, u := range keyUsage {
+					if extKeyUsage, ok := extKeyUsageFromOID(u); ok {
+						out.ExtKeyUsage = append(out.ExtKeyUsage, extKeyUsage)
+					} else {
+						out.UnknownExtKeyUsage = append(out.UnknownExtKeyUsage, u)
+					}
+				}
+
+				continue
+
+			case 14:
+				// RFC 5280, 4.2.1.2
+				var keyid []byte
+				_, err = asn1.Unmarshal(e.Value, &keyid)
+				if err != nil {
+					return nil, err
+				}
+				out.SubjectKeyId = keyid
+				continue
+
+			case 32:
+				// RFC 5280 4.2.1.4: Certificate Policies
+				var policies []policyInformation
+				if _, err = asn1.Unmarshal(e.Value, &policies); err != nil {
+					return nil, err
+				}
+				out.PolicyIdentifiers = make([]asn1.ObjectIdentifier, len(policies))
+				out.QualifierId = make([][]asn1.ObjectIdentifier, len(policies))
+				out.ExplicitTexts = make([][]asn1.RawValue, len(policies))
+				out.NoticeRefOrgnization = make([][]asn1.RawValue, len(policies))
+				out.NoticeRefNumbers = make([][]NoticeNumber, len(policies))
+				out.ParsedExplicitTexts = make([][]string, len(policies))
+				out.ParsedNoticeRefOrganization = make([][]string, len(policies))
+				out.CPSuri = make([][]string, len(policies))
+
+				for i, policy := range policies {
+					out.PolicyIdentifiers[i] = policy.Policy
+					// parse optional Qualifier for zlint
+					for _, qualifier := range policy.Qualifiers {
+						out.QualifierId[i] = append(out.QualifierId[i], qualifier.PolicyQualifierId)
+						userNoticeOID := asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 2, 2}
+						cpsURIOID := asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 2, 1}
+						if qualifier.PolicyQualifierId.Equal(userNoticeOID) {
+							var un userNotice
+							if _, err = asn1.Unmarshal(qualifier.Qualifier.FullBytes, &un); err != nil {
+								return nil, err
+							}
+							if len(un.ExplicitText.Bytes) != 0 {
+								out.ExplicitTexts[i] = append(out.ExplicitTexts[i], un.ExplicitText)
+								out.ParsedExplicitTexts[i] = append(out.ParsedExplicitTexts[i], string(un.ExplicitText.Bytes))
+							}
+							if un.NoticeRef.Organization.Bytes != nil || un.NoticeRef.NoticeNumbers != nil {
+								out.NoticeRefOrgnization[i] = append(out.NoticeRefOrgnization[i], un.NoticeRef.Organization)
+								out.NoticeRefNumbers[i] = append(out.NoticeRefNumbers[i], un.NoticeRef.NoticeNumbers)
+								out.ParsedNoticeRefOrganization[i] = append(out.ParsedNoticeRefOrganization[i], string(un.NoticeRef.Organization.Bytes))
+							}
+						}
+						if qualifier.PolicyQualifierId.Equal(cpsURIOID) {
+							var cpsURIRaw asn1.RawValue
+							if _, err = asn1.Unmarshal(qualifier.Qualifier.FullBytes, &cpsURIRaw); err != nil {
+								return nil, err
+							}
+							out.CPSuri[i] = append(out.CPSuri[i], string(cpsURIRaw.Bytes))
+						}
+					}
+				}
+				if out.SelfSigned {
+					out.ValidationLevel = UnknownValidationLevel
+				} else {
+					// See http://unmitigatedrisk.com/?p=203
+					validationLevel := getMaxCertValidationLevel(out.PolicyIdentifiers)
+					if validationLevel == UnknownValidationLevel {
+						if (len(out.Subject.Organization) > 0 && out.Subject.Organization[0] == out.Subject.CommonName) || (len(out.Subject.OrganizationalUnit) > 0 && strings.Contains(out.Subject.OrganizationalUnit[0], "Domain Control Validated")) {
+							if len(out.Subject.Locality) == 0 && len(out.Subject.Province) == 0 && len(out.Subject.PostalCode) == 0 {
+								validationLevel = DV
+							}
+						} else if len(out.Subject.Organization) > 0 && out.Subject.Organization[0] == "Persona Not Validated" && strings.Contains(out.Issuer.CommonName, "StartCom") {
+							validationLevel = DV
+						}
+					}
+					out.ValidationLevel = validationLevel
+				}
+			}
+		} else if e.Id.Equal(oidExtensionAuthorityInfoAccess) {
+			// RFC 5280 4.2.2.1: Authority Information Access
+			var aia []authorityInfoAccess
+			if _, err = asn1.Unmarshal(e.Value, &aia); err != nil {
+				return nil, err
+			}
+
+			for _, v := range aia {
+				// GeneralName: uniformResourceIdentifier [6] IA5String
+				if v.Location.Tag != 6 {
+					continue
+				}
+				if v.Method.Equal(oidAuthorityInfoAccessOcsp) {
+					out.OCSPServer = append(out.OCSPServer, string(v.Location.Bytes))
+				} else if v.Method.Equal(oidAuthorityInfoAccessIssuers) {
+					out.IssuingCertificateURL = append(out.IssuingCertificateURL, string(v.Location.Bytes))
+				}
+			}
+		} else if e.Id.Equal(oidExtensionSignedCertificateTimestampList) {
+			err := parseSignedCertificateTimestampList(out, e)
+			if err != nil {
+				return nil, err
+			}
+		} else if e.Id.Equal(oidExtensionCTPrecertificatePoison) {
+			if e.Value[0] == 5 && e.Value[1] == 0 {
+				out.IsPrecert = true
+				continue
+			} else {
+				return nil, UnhandledCriticalExtension{e.Id, "Malformed precert poison"}
+			}
+		} else if e.Id.Equal(oidBRTorServiceDescriptor) {
+			descs, err := parseTorServiceDescriptorSyntax(e)
+			if err != nil {
+				return nil, err
+			}
+			out.TorServiceDescriptors = descs
+		} else if e.Id.Equal(oidExtCABFOrganizationID) {
+			cabf := CABFOrganizationIDASN{}
+			_, err := asn1.Unmarshal(e.Value, &cabf)
+			if err != nil {
+				return nil, err
+			}
+			out.CABFOrganizationIdentifier = &CABFOrganizationIdentifier{
+				Scheme:    cabf.RegistrationSchemeIdentifier,
+				Country:   cabf.RegistrationCountry,
+				Reference: cabf.RegistrationReference,
+				State:     cabf.RegistrationStateOrProvince,
+			}
+		} else if e.Id.Equal(oidExtQCStatements) {
+			rawStatements := QCStatementsASN{}
+			_, err := asn1.Unmarshal(e.Value, &rawStatements.QCStatements)
+			if err != nil {
+				return nil, err
+			}
+			qcStatements := QCStatements{}
+			if err := qcStatements.Parse(&rawStatements); err != nil {
+				return nil, err
+			}
+			out.QCStatements = &qcStatements
+		}
+
+		//if e.Critical {
+		//	return out, UnhandledCriticalExtension{e.Id}
+		//}
+	}
+
+	return out, nil
+}
+
+func parseSignedCertificateTimestampList(out *Certificate, ext pkix.Extension) error {
+	var scts []byte
+	if _, err := asn1.Unmarshal(ext.Value, &scts); err != nil {
+		return err
+	}
+	// ignore length of
+	if len(scts) < 2 {
+		return errors.New("malformed SCT extension: incomplete length field")
+	}
+	scts = scts[2:]
+	headerLength := 2
+	for {
+		switch len(scts) {
+		case 0:
+			return nil
+		case 1:
+			return errors.New("malformed SCT extension: trailing data")
+		default:
+			sctLength := int(scts[1]) + (int(scts[0]) << 8) + headerLength
+			if !(sctLength <= len(scts)) {
+				return errors.New("malformed SCT extension: incomplete SCT")
+			}
+			sct, err := ct.DeserializeSCT(bytes.NewReader(scts[headerLength:sctLength]))
+			if err != nil {
+				return fmt.Errorf("malformed SCT extension: SCT parse err: %v", err)
+			}
+			out.SignedCertificateTimestampList = append(out.SignedCertificateTimestampList, sct)
+			scts = scts[sctLength:]
+		}
+	}
+}
+
+// ParseCertificate parses a single certificate from the given ASN.1 DER data.
+func ParseCertificate(asn1Data []byte) (*Certificate, error) {
+	var cert certificate
+	rest, err := asn1.Unmarshal(asn1Data, &cert)
+	if err != nil {
+		return nil, err
+	}
+	if len(rest) > 0 {
+		return nil, asn1.SyntaxError{Msg: "trailing data"}
+	}
+
+	return parseCertificate(&cert)
+}
+
+// ParseCertificates parses one or more certificates from the given ASN.1 DER
+// data. The certificates must be concatenated with no intermediate padding.
+func ParseCertificates(asn1Data []byte) ([]*Certificate, error) {
+	var v []*certificate
+
+	for len(asn1Data) > 0 {
+		cert := new(certificate)
+		var err error
+		asn1Data, err = asn1.Unmarshal(asn1Data, cert)
+		if err != nil {
+			return nil, err
+		}
+		v = append(v, cert)
+	}
+
+	ret := make([]*Certificate, len(v))
+	for i, ci := range v {
+		cert, err := parseCertificate(ci)
+		if err != nil {
+			return nil, err
+		}
+		ret[i] = cert
+	}
+
+	return ret, nil
+}
+
+func ParseTBSCertificate(asn1Data []byte) (*Certificate, error) {
+	var tbsCert tbsCertificate
+	rest, err := asn1.Unmarshal(asn1Data, &tbsCert)
+	if err != nil {
+		//log.Print("Err unmarshalling asn1Data", asn1Data, rest)
+		return nil, err
+	}
+	if len(rest) > 0 {
+		return nil, asn1.SyntaxError{Msg: "trailing data"}
+	}
+	return parseCertificate(&certificate{
+		Raw:            tbsCert.Raw,
+		TBSCertificate: tbsCert})
+}
+
+// SubjectAndKey represents a (subjecty, subject public key info) tuple.
+type SubjectAndKey struct {
+	RawSubject              []byte
+	RawSubjectPublicKeyInfo []byte
+	Fingerprint             CertificateFingerprint
+	PublicKey               interface{}
+	PublicKeyAlgorithm      PublicKeyAlgorithm
+}
+
+// SubjectAndKey returns a SubjectAndKey for this certificate.
+func (c *Certificate) SubjectAndKey() *SubjectAndKey {
+	return &SubjectAndKey{
+		RawSubject:              c.RawSubject,
+		RawSubjectPublicKeyInfo: c.RawSubjectPublicKeyInfo,
+		Fingerprint:             c.SPKISubjectFingerprint,
+		PublicKey:               c.PublicKey,
+		PublicKeyAlgorithm:      c.PublicKeyAlgorithm,
+	}
+}
+
+func reverseBitsInAByte(in byte) byte {
+	b1 := in>>4 | in<<4
+	b2 := b1>>2&0x33 | b1<<2&0xcc
+	b3 := b2>>1&0x55 | b2<<1&0xaa
+	return b3
+}
+
+// asn1BitLength returns the bit-length of bitString by considering the
+// most-significant bit in a byte to be the "first" bit. This convention
+// matches ASN.1, but differs from almost everything else.
+func asn1BitLength(bitString []byte) int {
+	bitLen := len(bitString) * 8
+
+	for i := range bitString {
+		b := bitString[len(bitString)-i-1]
+
+		for bit := uint(0); bit < 8; bit++ {
+			if (b>>bit)&1 == 1 {
+				return bitLen
+			}
+			bitLen--
+		}
+	}
+
+	return 0
+}
+
+var (
+	oidExtensionSubjectKeyId                   = []int{2, 5, 29, 14}
+	oidExtensionKeyUsage                       = []int{2, 5, 29, 15}
+	oidExtensionExtendedKeyUsage               = []int{2, 5, 29, 37}
+	oidExtensionAuthorityKeyId                 = []int{2, 5, 29, 35}
+	oidExtensionBasicConstraints               = []int{2, 5, 29, 19}
+	oidExtensionSubjectAltName                 = []int{2, 5, 29, 17}
+	oidExtensionIssuerAltName                  = []int{2, 5, 29, 18}
+	oidExtensionCertificatePolicies            = []int{2, 5, 29, 32}
+	oidExtensionNameConstraints                = []int{2, 5, 29, 30}
+	oidExtensionCRLDistributionPoints          = []int{2, 5, 29, 31}
+	oidExtensionAuthorityInfoAccess            = []int{1, 3, 6, 1, 5, 5, 7, 1, 1}
+	oidExtensionSignedCertificateTimestampList = []int{1, 3, 6, 1, 4, 1, 11129, 2, 4, 2}
+)
+
+var (
+	oidAuthorityInfoAccessOcsp    = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 1}
+	oidAuthorityInfoAccessIssuers = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 2}
+)
+
+// oidNotInExtensions returns whether an extension with the given oid exists in
+// extensions.
+func oidInExtensions(oid asn1.ObjectIdentifier, extensions []pkix.Extension) bool {
+	for _, e := range extensions {
+		if e.Id.Equal(oid) {
+			return true
+		}
+	}
+	return false
+}
+
+// marshalSANs marshals a list of addresses into a the contents of an X.509
+// SubjectAlternativeName extension.
+func marshalSANs(dnsNames, emailAddresses []string, ipAddresses []net.IP) (derBytes []byte, err error) {
+	var rawValues []asn1.RawValue
+	for _, name := range dnsNames {
+		rawValues = append(rawValues, asn1.RawValue{Tag: 2, Class: 2, Bytes: []byte(name)})
+	}
+	for _, email := range emailAddresses {
+		rawValues = append(rawValues, asn1.RawValue{Tag: 1, Class: 2, Bytes: []byte(email)})
+	}
+	for _, rawIP := range ipAddresses {
+		// If possible, we always want to encode IPv4 addresses in 4 bytes.
+		ip := rawIP.To4()
+		if ip == nil {
+			ip = rawIP
+		}
+		rawValues = append(rawValues, asn1.RawValue{Tag: 7, Class: 2, Bytes: ip})
+	}
+	return asn1.Marshal(rawValues)
+}
+
+// NOTE ignoring authorityKeyID argument
+func buildExtensions(template *Certificate, _ []byte) (ret []pkix.Extension, err error) {
+	ret = make([]pkix.Extension, 10 /* Max number of elements. */)
+	n := 0
+
+	if template.KeyUsage != 0 &&
+		!oidInExtensions(oidExtensionKeyUsage, template.ExtraExtensions) {
+		ret[n].Id = oidExtensionKeyUsage
+		ret[n].Critical = true
+
+		var a [2]byte
+		a[0] = reverseBitsInAByte(byte(template.KeyUsage))
+		a[1] = reverseBitsInAByte(byte(template.KeyUsage >> 8))
+
+		l := 1
+		if a[1] != 0 {
+			l = 2
+		}
+
+		ret[n].Value, err = asn1.Marshal(asn1.BitString{Bytes: a[0:l], BitLength: l * 8})
+		if err != nil {
+			return
+		}
+		n++
+	}
+
+	if (len(template.ExtKeyUsage) > 0 || len(template.UnknownExtKeyUsage) > 0) &&
+		!oidInExtensions(oidExtensionExtendedKeyUsage, template.ExtraExtensions) {
+		ret[n].Id = oidExtensionExtendedKeyUsage
+
+		var oids []asn1.ObjectIdentifier
+		for _, u := range template.ExtKeyUsage {
+			if oid, ok := oidFromExtKeyUsage(u); ok {
+				oids = append(oids, oid)
+			} else {
+				panic("internal error")
+			}
+		}
+
+		oids = append(oids, template.UnknownExtKeyUsage...)
+
+		ret[n].Value, err = asn1.Marshal(oids)
+		if err != nil {
+			return
+		}
+		n++
+	}
+
+	if template.BasicConstraintsValid && !oidInExtensions(oidExtensionBasicConstraints, template.ExtraExtensions) {
+		// Leaving MaxPathLen as zero indicates that no Max path
+		// length is desired, unless MaxPathLenZero is set. A value of
+		// -1 causes encoding/asn1 to omit the value as desired.
+		maxPathLen := template.MaxPathLen
+		if maxPathLen == 0 && !template.MaxPathLenZero {
+			maxPathLen = -1
+		}
+		ret[n].Id = oidExtensionBasicConstraints
+		ret[n].Value, err = asn1.Marshal(basicConstraints{template.IsCA, maxPathLen})
+		ret[n].Critical = true
+		if err != nil {
+			return
+		}
+		n++
+	}
+
+	if len(template.SubjectKeyId) > 0 && !oidInExtensions(oidExtensionSubjectKeyId, template.ExtraExtensions) {
+		ret[n].Id = oidExtensionSubjectKeyId
+		ret[n].Value, err = asn1.Marshal(template.SubjectKeyId)
+		if err != nil {
+			return
+		}
+		n++
+	}
+
+	if len(template.AuthorityKeyId) > 0 && !oidInExtensions(oidExtensionAuthorityKeyId, template.ExtraExtensions) {
+		ret[n].Id = oidExtensionAuthorityKeyId
+		ret[n].Value, err = asn1.Marshal(authKeyId{template.AuthorityKeyId})
+		if err != nil {
+			return
+		}
+		n++
+	}
+
+	if (len(template.OCSPServer) > 0 || len(template.IssuingCertificateURL) > 0) &&
+		!oidInExtensions(oidExtensionAuthorityInfoAccess, template.ExtraExtensions) {
+		ret[n].Id = oidExtensionAuthorityInfoAccess
+		var aiaValues []authorityInfoAccess
+		for _, name := range template.OCSPServer {
+			aiaValues = append(aiaValues, authorityInfoAccess{
+				Method:   oidAuthorityInfoAccessOcsp,
+				Location: asn1.RawValue{Tag: 6, Class: 2, Bytes: []byte(name)},
+			})
+		}
+		for _, name := range template.IssuingCertificateURL {
+			aiaValues = append(aiaValues, authorityInfoAccess{
+				Method:   oidAuthorityInfoAccessIssuers,
+				Location: asn1.RawValue{Tag: 6, Class: 2, Bytes: []byte(name)},
+			})
+		}
+		ret[n].Value, err = asn1.Marshal(aiaValues)
+		if err != nil {
+			return
+		}
+		n++
+	}
+
+	if (len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0) &&
+		!oidInExtensions(oidExtensionSubjectAltName, template.ExtraExtensions) {
+		ret[n].Id = oidExtensionSubjectAltName
+		ret[n].Value, err = marshalSANs(template.DNSNames, template.EmailAddresses, template.IPAddresses)
+		if err != nil {
+			return
+		}
+		n++
+	}
+
+	if len(template.PolicyIdentifiers) > 0 &&
+		!oidInExtensions(oidExtensionCertificatePolicies, template.ExtraExtensions) {
+		ret[n].Id = oidExtensionCertificatePolicies
+		policies := make([]policyInformation, len(template.PolicyIdentifiers))
+		for i, policy := range template.PolicyIdentifiers {
+			policies[i].Policy = policy
+		}
+		ret[n].Value, err = asn1.Marshal(policies)
+		if err != nil {
+			return
+		}
+		n++
+	}
+
+	// TODO: this can be cleaned up in go1.10
+	if (len(template.PermittedEmailAddresses) > 0 || len(template.PermittedDNSNames) > 0 || len(template.PermittedDirectoryNames) > 0 ||
+		len(template.PermittedIPAddresses) > 0 || len(template.ExcludedEmailAddresses) > 0 || len(template.ExcludedDNSNames) > 0 ||
+		len(template.ExcludedDirectoryNames) > 0 || len(template.ExcludedIPAddresses) > 0) &&
+		!oidInExtensions(oidExtensionNameConstraints, template.ExtraExtensions) {
+		ret[n].Id = oidExtensionNameConstraints
+		if template.NameConstraintsCritical {
+			ret[n].Critical = true
+		}
+
+		var out nameConstraints
+
+		for _, permitted := range template.PermittedEmailAddresses {
+			out.Permitted = append(out.Permitted, generalSubtree{Value: asn1.RawValue{Tag: 1, Class: 2, Bytes: []byte(permitted.Data)}})
+		}
+		for _, excluded := range template.ExcludedEmailAddresses {
+			out.Excluded = append(out.Excluded, generalSubtree{Value: asn1.RawValue{Tag: 1, Class: 2, Bytes: []byte(excluded.Data)}})
+		}
+		for _, permitted := range template.PermittedDNSNames {
+			out.Permitted = append(out.Permitted, generalSubtree{Value: asn1.RawValue{Tag: 2, Class: 2, Bytes: []byte(permitted.Data)}})
+		}
+		for _, excluded := range template.ExcludedDNSNames {
+			out.Excluded = append(out.Excluded, generalSubtree{Value: asn1.RawValue{Tag: 2, Class: 2, Bytes: []byte(excluded.Data)}})
+		}
+		for _, permitted := range template.PermittedDirectoryNames {
+			var dn []byte
+			dn, err = asn1.Marshal(permitted.Data.ToRDNSequence())
+			if err != nil {
+				return
+			}
+			out.Permitted = append(out.Permitted, generalSubtree{Value: asn1.RawValue{Tag: 4, Class: 2, IsCompound: true, Bytes: dn}})
+		}
+		for _, excluded := range template.ExcludedDirectoryNames {
+			var dn []byte
+			dn, err = asn1.Marshal(excluded.Data.ToRDNSequence())
+			if err != nil {
+				return
+			}
+			out.Excluded = append(out.Excluded, generalSubtree{Value: asn1.RawValue{Tag: 4, Class: 2, IsCompound: true, Bytes: dn}})
+		}
+		for _, permitted := range template.PermittedIPAddresses {
+			ip := append(permitted.Data.IP, permitted.Data.Mask...)
+			out.Permitted = append(out.Permitted, generalSubtree{Value: asn1.RawValue{Tag: 7, Class: 2, Bytes: ip}})
+		}
+		for _, excluded := range template.ExcludedIPAddresses {
+			ip := append(excluded.Data.IP, excluded.Data.Mask...)
+			out.Excluded = append(out.Excluded, generalSubtree{Value: asn1.RawValue{Tag: 7, Class: 2, Bytes: ip}})
+		}
+		ret[n].Value, err = asn1.Marshal(out)
+		if err != nil {
+			return
+		}
+		n++
+	}
+
+	if len(template.CRLDistributionPoints) > 0 &&
+		!oidInExtensions(oidExtensionCRLDistributionPoints, template.ExtraExtensions) {
+		ret[n].Id = oidExtensionCRLDistributionPoints
+
+		var crlDp []distributionPoint
+		for _, name := range template.CRLDistributionPoints {
+			rawFullName, _ := asn1.Marshal(asn1.RawValue{Tag: 6, Class: 2, Bytes: []byte(name)})
+
+			dp := distributionPoint{
+				DistributionPoint: distributionPointName{
+					FullName: asn1.RawValue{Tag: 0, Class: 2, IsCompound: true, Bytes: rawFullName},
+				},
+			}
+			crlDp = append(crlDp, dp)
+		}
+
+		ret[n].Value, err = asn1.Marshal(crlDp)
+		if err != nil {
+			return
+		}
+		n++
+	}
+
+	// Adding another extension here? Remember to update the Max number
+	// of elements in the make() at the top of the function.
+
+	return append(ret[:n], template.ExtraExtensions...), nil
+}
+
+func subjectBytes(cert *Certificate) ([]byte, error) {
+	if len(cert.RawSubject) > 0 {
+		return cert.RawSubject, nil
+	}
+
+	return asn1.Marshal(cert.Subject.ToRDNSequence())
+}
+
+// signingParamsForPublicKey returns the parameters to use for signing with
+// priv. If requestedSigAlgo is not zero then it overrides the default
+// signature algorithm.
+func signingParamsForPublicKey(pub interface{}, requestedSigAlgo SignatureAlgorithm) (hashFunc crypto.Hash, sigAlgo pkix.AlgorithmIdentifier, err error) {
+	var pubType PublicKeyAlgorithm
+	shouldHash := true
+
+	switch pub := pub.(type) {
+	case *rsa.PublicKey:
+		pubType = RSA
+		hashFunc = crypto.SHA256
+		sigAlgo.Algorithm = oidSignatureSHA256WithRSA
+		sigAlgo.Parameters = asn1.NullRawValue
+
+	case *ecdsa.PublicKey:
+		pubType = ECDSA
+
+		switch pub.Curve {
+		case elliptic.P224(), elliptic.P256():
+			hashFunc = crypto.SHA256
+			sigAlgo.Algorithm = oidSignatureECDSAWithSHA256
+		case elliptic.P384():
+			hashFunc = crypto.SHA384
+			sigAlgo.Algorithm = oidSignatureECDSAWithSHA384
+		case elliptic.P521():
+			hashFunc = crypto.SHA512
+			sigAlgo.Algorithm = oidSignatureECDSAWithSHA512
+		default:
+			err = errors.New("x509: unknown elliptic curve")
+		}
+
+	case ed25519.PublicKey:
+		pubType = Ed25519
+		hashFunc = 0
+		shouldHash = false
+		sigAlgo.Algorithm = oidKeyEd25519
+
+	default:
+		err = errors.New("x509: only RSA, ECDSA, Ed25519, and X25519 keys supported")
+	}
+
+	if err != nil {
+		return
+	}
+
+	if requestedSigAlgo == 0 {
+		return
+	}
+
+	found := false
+	for _, details := range signatureAlgorithmDetails {
+		if details.algo == requestedSigAlgo {
+			if details.pubKeyAlgo != pubType {
+				err = errors.New("x509: requested SignatureAlgorithm does not match private key type")
+				return
+			}
+			sigAlgo.Algorithm, hashFunc = details.oid, details.hash
+			if hashFunc == 0 && shouldHash {
+				err = errors.New("x509: cannot sign with hash function requested")
+				return
+			}
+			if requestedSigAlgo.isRSAPSS() {
+				sigAlgo.Parameters = rsaPSSParameters(hashFunc)
+			}
+			found = true
+			break
+		}
+	}
+
+	if !found {
+		err = errors.New("x509: unknown SignatureAlgorithm")
+	}
+
+	return
+}
+
+// CreateCertificate creates a new certificate based on a template.
+// The following members of template are used: AuthorityKeyId,
+// BasicConstraintsValid, DNSNames, ExcludedDNSDomains, ExtKeyUsage,
+// IsCA, KeyUsage, MaxPathLen, MaxPathLenZero, NotAfter, NotBefore,
+// PermittedDNSDomains, PermittedDNSDomainsCritical, SerialNumber,
+// SignatureAlgorithm, Subject, SubjectKeyId, and UnknownExtKeyUsage.
+//
+// The certificate is signed by parent. If parent is equal to template then the
+// certificate is self-signed. The parameter pub is the public key of the
+// signee and priv is the private key of the signer.
+//
+// The returned slice is the certificate in DER encoding.
+//
+// All keys types that are implemented via crypto.Signer are supported (This
+// includes *rsa.PublicKey and *ecdsa.PublicKey.)
+//
+// The AuthorityKeyId will be taken from the SubjectKeyId of parent, if any,
+// unless the resulting certificate is self-signed. Otherwise the value from
+// template will be used.
+func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv interface{}) (cert []byte, err error) {
+	key, ok := priv.(crypto.Signer)
+	if !ok {
+		return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
+	}
+
+	if template.SerialNumber == nil {
+		return nil, errors.New("x509: no SerialNumber given")
+	}
+
+	hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm)
+	if err != nil {
+		return nil, err
+	}
+
+	publicKeyBytes, publicKeyAlgorithm, err := marshalPublicKey(pub)
+	if err != nil {
+		return nil, err
+	}
+
+	asn1Issuer, err := subjectBytes(parent)
+	if err != nil {
+		return
+	}
+
+	asn1Subject, err := subjectBytes(template)
+	if err != nil {
+		return
+	}
+
+	authorityKeyId := template.AuthorityKeyId
+	if !bytes.Equal(asn1Issuer, asn1Subject) && len(parent.SubjectKeyId) > 0 {
+		authorityKeyId = parent.SubjectKeyId
+	}
+
+	extensions, err := buildExtensions(template, authorityKeyId)
+	if err != nil {
+		return
+	}
+
+	encodedPublicKey := asn1.BitString{BitLength: len(publicKeyBytes) * 8, Bytes: publicKeyBytes}
+	c := tbsCertificate{
+		Version:            2,
+		SerialNumber:       template.SerialNumber,
+		SignatureAlgorithm: signatureAlgorithm,
+		Issuer:             asn1.RawValue{FullBytes: asn1Issuer},
+		Validity:           validity{template.NotBefore.UTC(), template.NotAfter.UTC()},
+		Subject:            asn1.RawValue{FullBytes: asn1Subject},
+		PublicKey:          publicKeyInfo{nil, publicKeyAlgorithm, encodedPublicKey},
+		Extensions:         extensions,
+	}
+
+	tbsCertContents, err := asn1.Marshal(c)
+	if err != nil {
+		return
+	}
+	c.Raw = tbsCertContents
+
+	digest := hash(hashFunc, c.Raw)
+
+	var signerOpts crypto.SignerOpts
+	signerOpts = hashFunc
+	if template.SignatureAlgorithm != 0 && template.SignatureAlgorithm.isRSAPSS() {
+		signerOpts = &rsa.PSSOptions{
+			SaltLength: rsa.PSSSaltLengthEqualsHash,
+			Hash:       hashFunc,
+		}
+	}
+
+	var signature []byte
+	signature, err = key.Sign(rand, digest, signerOpts)
+	if err != nil {
+		return
+	}
+
+	return asn1.Marshal(certificate{
+		nil,
+		c,
+		signatureAlgorithm,
+		asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
+	})
+}
+
+// pemCRLPrefix is the magic string that indicates that we have a PEM encoded
+// CRL.
+var pemCRLPrefix = []byte("-----BEGIN X509 CRL")
+
+// pemType is the type of a PEM encoded CRL.
+var pemType = "X509 CRL"
+
+// ParseCRL parses a CRL from the given bytes. It's often the case that PEM
+// encoded CRLs will appear where they should be DER encoded, so this function
+// will transparently handle PEM encoding as long as there isn't any leading
+// garbage.
+func ParseCRL(crlBytes []byte) (*pkix.CertificateList, error) {
+	if bytes.HasPrefix(crlBytes, pemCRLPrefix) {
+		block, _ := pem.Decode(crlBytes)
+		if block != nil && block.Type == pemType {
+			crlBytes = block.Bytes
+		}
+	}
+	return ParseDERCRL(crlBytes)
+}
+
+// ParseDERCRL parses a DER encoded CRL from the given bytes.
+func ParseDERCRL(derBytes []byte) (*pkix.CertificateList, error) {
+	certList := new(pkix.CertificateList)
+	if rest, err := asn1.Unmarshal(derBytes, certList); err != nil {
+		return nil, err
+	} else if len(rest) != 0 {
+		return nil, errors.New("x509: trailing data after CRL")
+	}
+	return certList, nil
+}
+
+// CreateCRL returns a DER encoded CRL, signed by this Certificate, that
+// contains the given list of revoked certificates.
+func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts []pkix.RevokedCertificate, now, expiry time.Time) (crlBytes []byte, err error) {
+	key, ok := priv.(crypto.Signer)
+	if !ok {
+		return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
+	}
+
+	hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), 0)
+	if err != nil {
+		return nil, err
+	}
+
+	// Force revocation times to UTC per RFC 5280.
+	revokedCertsUTC := make([]pkix.RevokedCertificate, len(revokedCerts))
+	for i, rc := range revokedCerts {
+		rc.RevocationTime = rc.RevocationTime.UTC()
+		revokedCertsUTC[i] = rc
+	}
+
+	tbsCertList := pkix.TBSCertificateList{
+		Version:             1,
+		Signature:           signatureAlgorithm,
+		Issuer:              c.Subject.ToRDNSequence(),
+		ThisUpdate:          now.UTC(),
+		NextUpdate:          expiry.UTC(),
+		RevokedCertificates: revokedCertsUTC,
+	}
+
+	// Authority Key Id
+	if len(c.SubjectKeyId) > 0 {
+		var aki pkix.Extension
+		aki.Id = oidExtensionAuthorityKeyId
+		aki.Value, err = asn1.Marshal(authKeyId{Id: c.SubjectKeyId})
+		if err != nil {
+			return
+		}
+		tbsCertList.Extensions = append(tbsCertList.Extensions, aki)
+	}
+
+	tbsCertListContents, err := asn1.Marshal(tbsCertList)
+	if err != nil {
+		return
+	}
+
+	digest := hash(hashFunc, tbsCertListContents)
+
+	var signature []byte
+	signature, err = key.Sign(rand, digest, hashFunc)
+	if err != nil {
+		return
+	}
+
+	return asn1.Marshal(pkix.CertificateList{
+		TBSCertList:        tbsCertList,
+		SignatureAlgorithm: signatureAlgorithm,
+		SignatureValue:     asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
+	})
+}
+
+// CertificateRequest represents a PKCS #10, certificate signature request.
+type CertificateRequest struct {
+	Raw                      []byte // Complete ASN.1 DER content (CSR, signature algorithm and signature).
+	RawTBSCertificateRequest []byte // Certificate request info part of raw ASN.1 DER content.
+	RawSubjectPublicKeyInfo  []byte // DER encoded SubjectPublicKeyInfo.
+	RawSubject               []byte // DER encoded Subject.
+
+	Version            int
+	Signature          []byte
+	SignatureAlgorithm SignatureAlgorithm
+
+	PublicKeyAlgorithm PublicKeyAlgorithm
+	PublicKey          interface{}
+
+	Subject pkix.Name
+
+	// Attributes is the dried husk of a bug and shouldn't be used.
+	Attributes []pkix.AttributeTypeAndValueSET
+
+	// Extensions contains raw X.509 extensions. When parsing CSRs, this
+	// can be used to extract extensions that are not parsed by this
+	// package.
+	Extensions []pkix.Extension
+
+	// ExtraExtensions contains extensions to be copied, raw, into any
+	// marshaled CSR. Values override any extensions that would otherwise
+	// be produced based on the other fields but are overridden by any
+	// extensions specified in Attributes.
+	//
+	// The ExtraExtensions field is not populated when parsing CSRs, see
+	// Extensions.
+	ExtraExtensions []pkix.Extension
+
+	// Subject Alternate Name values.
+	DNSNames       []string
+	EmailAddresses []string
+	IPAddresses    []net.IP
+}
+
+// These structures reflect the ASN.1 structure of X.509 certificate
+// signature requests (see RFC 2986):
+
+type tbsCertificateRequest struct {
+	Raw           asn1.RawContent
+	Version       int
+	Subject       asn1.RawValue
+	PublicKey     publicKeyInfo
+	RawAttributes []asn1.RawValue `asn1:"tag:0"`
+}
+
+type certificateRequest struct {
+	Raw                asn1.RawContent
+	TBSCSR             tbsCertificateRequest
+	SignatureAlgorithm pkix.AlgorithmIdentifier
+	SignatureValue     asn1.BitString
+}
+
+// oidExtensionRequest is a PKCS#9 OBJECT IDENTIFIER that indicates requested
+// extensions in a CSR.
+var oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14}
+
+// newRawAttributes converts AttributeTypeAndValueSETs from a template
+// CertificateRequest's Attributes into tbsCertificateRequest RawAttributes.
+func newRawAttributes(attributes []pkix.AttributeTypeAndValueSET) ([]asn1.RawValue, error) {
+	var rawAttributes []asn1.RawValue
+	b, err := asn1.Marshal(attributes)
+	if err != nil {
+		return nil, err
+	}
+	rest, err := asn1.Unmarshal(b, &rawAttributes)
+	if err != nil {
+		return nil, err
+	}
+	if len(rest) != 0 {
+		return nil, errors.New("x509: failed to unmarshal raw CSR Attributes")
+	}
+	return rawAttributes, nil
+}
+
+// parseRawAttributes Unmarshals RawAttributes intos AttributeTypeAndValueSETs.
+func parseRawAttributes(rawAttributes []asn1.RawValue) []pkix.AttributeTypeAndValueSET {
+	var attributes []pkix.AttributeTypeAndValueSET
+	for _, rawAttr := range rawAttributes {
+		var attr pkix.AttributeTypeAndValueSET
+		rest, err := asn1.Unmarshal(rawAttr.FullBytes, &attr)
+		// Ignore attributes that don't parse into pkix.AttributeTypeAndValueSET
+		// (i.e.: challengePassword or unstructuredName).
+		if err == nil && len(rest) == 0 {
+			attributes = append(attributes, attr)
+		}
+	}
+	return attributes
+}
+
+// parseCSRExtensions parses the attributes from a CSR and extracts any
+// requested extensions.
+func parseCSRExtensions(rawAttributes []asn1.RawValue) ([]pkix.Extension, error) {
+	// pkcs10Attribute reflects the Attribute structure from section 4.1 of
+	// https://tools.ietf.org/html/rfc2986.
+	type pkcs10Attribute struct {
+		Id     asn1.ObjectIdentifier
+		Values []asn1.RawValue `asn1:"set"`
+	}
+
+	var ret []pkix.Extension
+	for _, rawAttr := range rawAttributes {
+		var attr pkcs10Attribute
+		if rest, err := asn1.Unmarshal(rawAttr.FullBytes, &attr); err != nil || len(rest) != 0 || len(attr.Values) == 0 {
+			// Ignore attributes that don't parse.
+			continue
+		}
+
+		if !attr.Id.Equal(oidExtensionRequest) {
+			continue
+		}
+
+		var extensions []pkix.Extension
+		if _, err := asn1.Unmarshal(attr.Values[0].FullBytes, &extensions); err != nil {
+			return nil, err
+		}
+		ret = append(ret, extensions...)
+	}
+
+	return ret, nil
+}
+
+// CreateCertificateRequest creates a new certificate request based on a
+// template. The following members of template are used: Attributes, DNSNames,
+// EmailAddresses, ExtraExtensions, IPAddresses, SignatureAlgorithm, and
+// Subject. The private key is the private key of the signer.
+//
+// The returned slice is the certificate request in DER encoding.
+//
+// All keys types that are implemented via crypto.Signer are supported (This
+// includes *rsa.PublicKey and *ecdsa.PublicKey.)
+func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv interface{}) (csr []byte, err error) {
+	key, ok := priv.(crypto.Signer)
+	if !ok {
+		return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
+	}
+
+	var hashFunc crypto.Hash
+	var sigAlgo pkix.AlgorithmIdentifier
+	hashFunc, sigAlgo, err = signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm)
+	if err != nil {
+		return nil, err
+	}
+
+	var publicKeyBytes []byte
+	var publicKeyAlgorithm pkix.AlgorithmIdentifier
+	publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(key.Public())
+	if err != nil {
+		return nil, err
+	}
+
+	var extensions []pkix.Extension
+
+	if (len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0) &&
+		!oidInExtensions(oidExtensionSubjectAltName, template.ExtraExtensions) {
+		sanBytes, err := marshalSANs(template.DNSNames, template.EmailAddresses, template.IPAddresses)
+		if err != nil {
+			return nil, err
+		}
+
+		extensions = append(extensions, pkix.Extension{
+			Id:    oidExtensionSubjectAltName,
+			Value: sanBytes,
+		})
+	}
+
+	extensions = append(extensions, template.ExtraExtensions...)
+
+	var attributes []pkix.AttributeTypeAndValueSET
+	attributes = append(attributes, template.Attributes...)
+
+	if len(extensions) > 0 {
+		// specifiedExtensions contains all the extensions that we
+		// found specified via template.Attributes.
+		specifiedExtensions := make(map[string]bool)
+
+		for _, atvSet := range template.Attributes {
+			if !atvSet.Type.Equal(oidExtensionRequest) {
+				continue
+			}
+
+			for _, atvs := range atvSet.Value {
+				for _, atv := range atvs {
+					specifiedExtensions[atv.Type.String()] = true
+				}
+			}
+		}
+
+		atvs := make([]pkix.AttributeTypeAndValue, 0, len(extensions))
+		for _, e := range extensions {
+			if specifiedExtensions[e.Id.String()] {
+				// Attributes already contained a value for
+				// this extension and it takes priority.
+				continue
+			}
+
+			atvs = append(atvs, pkix.AttributeTypeAndValue{
+				// There is no place for the critical flag in a CSR.
+				Type:  e.Id,
+				Value: e.Value,
+			})
+		}
+
+		// Append the extensions to an existing attribute if possible.
+		appended := false
+		for _, atvSet := range attributes {
+			if !atvSet.Type.Equal(oidExtensionRequest) || len(atvSet.Value) == 0 {
+				continue
+			}
+
+			atvSet.Value[0] = append(atvSet.Value[0], atvs...)
+			appended = true
+			break
+		}
+
+		// Otherwise, add a new attribute for the extensions.
+		if !appended {
+			attributes = append(attributes, pkix.AttributeTypeAndValueSET{
+				Type: oidExtensionRequest,
+				Value: [][]pkix.AttributeTypeAndValue{
+					atvs,
+				},
+			})
+		}
+	}
+
+	asn1Subject := template.RawSubject
+	if len(asn1Subject) == 0 {
+		asn1Subject, err = asn1.Marshal(template.Subject.ToRDNSequence())
+		if err != nil {
+			return
+		}
+	}
+
+	rawAttributes, err := newRawAttributes(attributes)
+	if err != nil {
+		return
+	}
+
+	tbsCSR := tbsCertificateRequest{
+		Version: 0, // PKCS #10, RFC 2986
+		Subject: asn1.RawValue{FullBytes: asn1Subject},
+		PublicKey: publicKeyInfo{
+			Algorithm: publicKeyAlgorithm,
+			PublicKey: asn1.BitString{
+				Bytes:     publicKeyBytes,
+				BitLength: len(publicKeyBytes) * 8,
+			},
+		},
+		RawAttributes: rawAttributes,
+	}
+
+	tbsCSRContents, err := asn1.Marshal(tbsCSR)
+	if err != nil {
+		return
+	}
+	tbsCSR.Raw = tbsCSRContents
+
+	digest := hash(hashFunc, tbsCSRContents)
+
+	var signature []byte
+	signature, err = key.Sign(rand, digest, hashFunc)
+	if err != nil {
+		return
+	}
+
+	return asn1.Marshal(certificateRequest{
+		TBSCSR:             tbsCSR,
+		SignatureAlgorithm: sigAlgo,
+		SignatureValue: asn1.BitString{
+			Bytes:     signature,
+			BitLength: len(signature) * 8,
+		},
+	})
+}
+
+// ParseCertificateRequest parses a single certificate request from the
+// given ASN.1 DER data.
+func ParseCertificateRequest(asn1Data []byte) (*CertificateRequest, error) {
+	var csr certificateRequest
+
+	rest, err := asn1.Unmarshal(asn1Data, &csr)
+	if err != nil {
+		return nil, err
+	} else if len(rest) != 0 {
+		return nil, asn1.SyntaxError{Msg: "trailing data"}
+	}
+
+	return parseCertificateRequest(&csr)
+}
+
+func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error) {
+	out := &CertificateRequest{
+		Raw:                      in.Raw,
+		RawTBSCertificateRequest: in.TBSCSR.Raw,
+		RawSubjectPublicKeyInfo:  in.TBSCSR.PublicKey.Raw,
+		RawSubject:               in.TBSCSR.Subject.FullBytes,
+
+		Signature:          in.SignatureValue.RightAlign(),
+		SignatureAlgorithm: GetSignatureAlgorithmFromAI(in.SignatureAlgorithm),
+
+		PublicKeyAlgorithm: getPublicKeyAlgorithmFromOID(in.TBSCSR.PublicKey.Algorithm.Algorithm),
+
+		Version:    in.TBSCSR.Version,
+		Attributes: parseRawAttributes(in.TBSCSR.RawAttributes),
+	}
+
+	var err error
+	out.PublicKey, err = parsePublicKey(out.PublicKeyAlgorithm, &in.TBSCSR.PublicKey)
+	if err != nil {
+		return nil, err
+	}
+
+	var subject pkix.RDNSequence
+	if rest, err := asn1.Unmarshal(in.TBSCSR.Subject.FullBytes, &subject); err != nil {
+		return nil, err
+	} else if len(rest) != 0 {
+		return nil, errors.New("x509: trailing data after X.509 Subject")
+	}
+
+	out.Subject.FillFromRDNSequence(&subject)
+
+	if out.Extensions, err = parseCSRExtensions(in.TBSCSR.RawAttributes); err != nil {
+		return nil, err
+	}
+
+	for _, extension := range out.Extensions {
+		if extension.Id.Equal(oidExtensionSubjectAltName) {
+			out.DNSNames, out.EmailAddresses, out.IPAddresses, err = parseSANExtension(extension.Value)
+			if err != nil {
+				return nil, err
+			}
+		}
+	}
+
+	return out, nil
+}
+
+// CheckSignature reports whether the signature on c is valid.
+func (c *CertificateRequest) CheckSignature() error {
+	return CheckSignatureFromKey(c.PublicKey, c.SignatureAlgorithm, c.RawTBSCertificateRequest, c.Signature)
+}

+ 30 - 0
vendor/github.com/zmap/zlint/v3/.goreleaser.yml

@@ -0,0 +1,30 @@
+project_name: zlint
+before:
+  hooks:
+    - go mod tidy
+builds:
+  -
+    main: ./cmd/zlint/main.go
+    binary: zlint
+    env:
+      - CGO_ENABLED=0
+    goos:
+      - linux
+      - freebsd
+      - windows
+      - darwin
+    goarch:
+      - amd64
+archives:
+  -
+    wrap_in_directory: true
+    replacements:
+      darwin: Darwin
+      linux: Linux
+      windows: Windows
+      amd64: x86_64
+snapshot:
+  name_template: "{{ .Tag }}-next"
+release:
+  draft: true
+  prerelease: auto

+ 202 - 0
vendor/github.com/zmap/zlint/v3/LICENSE

@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   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.

+ 96 - 0
vendor/github.com/zmap/zlint/v3/lint/base.go

@@ -0,0 +1,96 @@
+package lint
+
+/*
+ * ZLint Copyright 2021 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.
+ */
+
+import (
+	"time"
+
+	"github.com/zmap/zcrypto/x509"
+	"github.com/zmap/zlint/v3/util"
+)
+
+// LintInterface is implemented by each Lint.
+type LintInterface interface {
+	// Initialize runs once per-lint. It is called during RegisterLint().
+	Initialize() error
+
+	// CheckApplies runs once per certificate. It returns true if the Lint should
+	// run on the given certificate. If CheckApplies returns false, the Lint
+	// result is automatically set to NA without calling CheckEffective() or
+	// Run().
+	CheckApplies(c *x509.Certificate) bool
+
+	// Execute() is the body of the lint. It is called for every certificate for
+	// which CheckApplies() returns true.
+	Execute(c *x509.Certificate) *LintResult
+}
+
+// A Lint struct represents a single lint, e.g.
+// "e_basic_constraints_not_critical". It contains an implementation of LintInterface.
+type Lint struct {
+
+	// Name is a lowercase underscore-separated string describing what a given
+	// Lint checks. If Name beings with "w", the lint MUST NOT return Error, only
+	// Warn. If Name beings with "e", the Lint MUST NOT return Warn, only Error.
+	Name string `json:"name,omitempty"`
+
+	// A human-readable description of what the Lint checks. Usually copied
+	// directly from the CA/B Baseline Requirements or RFC 5280.
+	Description string `json:"description,omitempty"`
+
+	// The source of the check, e.g. "BRs: 6.1.6" or "RFC 5280: 4.1.2.6".
+	Citation string `json:"citation,omitempty"`
+
+	// Programmatic source of the check, BRs, RFC5280, or ZLint
+	Source LintSource `json:"source"`
+
+	// Lints automatically returns NE for all certificates where CheckApplies() is
+	// true but with NotBefore < EffectiveDate. This check is bypassed if
+	// EffectiveDate is zero.
+	EffectiveDate time.Time `json:"-"`
+
+	// The implementation of the lint logic.
+	Lint LintInterface `json:"-"`
+}
+
+// CheckEffective returns true if c was issued on or after the EffectiveDate. If
+// EffectiveDate is zero, CheckEffective always returns true.
+func (l *Lint) CheckEffective(c *x509.Certificate) bool {
+	if l.EffectiveDate.IsZero() || !l.EffectiveDate.After(c.NotBefore) {
+		return true
+	}
+	return false
+}
+
+// Execute runs the lint against a certificate. For lints that are
+// sourced from the CA/B Forum Baseline Requirements, we first determine
+// if they are within the purview of the BRs. See LintInterface for details
+// about the other methods called. The ordering is as follows:
+//
+// CheckApplies()
+// CheckEffective()
+// Execute()
+func (l *Lint) Execute(cert *x509.Certificate) *LintResult {
+	if l.Source == CABFBaselineRequirements && !util.IsServerAuthCert(cert) {
+		return &LintResult{Status: NA}
+	}
+	if !l.Lint.CheckApplies(cert) {
+		return &LintResult{Status: NA}
+	} else if !l.CheckEffective(cert) {
+		return &LintResult{Status: NE}
+	}
+	res := l.Lint.Execute(cert)
+	return res
+}

+ 351 - 0
vendor/github.com/zmap/zlint/v3/lint/registration.go

@@ -0,0 +1,351 @@
+/*
+ * ZLint Copyright 2021 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.
+ */
+
+package lint
+
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io"
+	"regexp"
+	"sort"
+	"strings"
+	"sync"
+)
+
+// FilterOptions is a struct used by Registry.Filter to create a sub registry
+// containing only lints that meet the filter options specified.
+//
+// Source based exclusion/inclusion is evaluated before Lint name based
+// exclusion/inclusion. In both cases exclusion is processed before inclusion.
+//
+// Only one of NameFilter or IncludeNames/ExcludeNames can be provided at
+// a time.
+type FilterOptions struct {
+	// NameFilter is a regexp used to filter lints by their name. It is mutually
+	// exclusive with IncludeNames and ExcludeNames.
+	NameFilter *regexp.Regexp
+	// IncludeNames is a case sensitive list of lint names to include in the
+	// registry being filtered.
+	IncludeNames []string
+	// ExcludeNames is a case sensitive list of lint names to exclude from the
+	// registry being filtered.
+	ExcludeNames []string
+	// IncludeSource is a SourceList of LintSource's to be included in the
+	// registry being filtered.
+	IncludeSources SourceList
+	// ExcludeSources is a SourceList of LintSources's to be excluded in the
+	// registry being filtered.
+	ExcludeSources SourceList
+}
+
+// Empty returns true if the FilterOptions is empty and does not specify any
+// elements to filter by.
+func (opts FilterOptions) Empty() bool {
+	return opts.NameFilter == nil &&
+		len(opts.IncludeNames) == 0 &&
+		len(opts.ExcludeNames) == 0 &&
+		len(opts.IncludeSources) == 0 &&
+		len(opts.ExcludeSources) == 0
+}
+
+// Registry is an interface describing a collection of registered lints.
+// A Registry instance can be given to zlint.LintCertificateEx() to control what
+// lints are run for a given certificate.
+//
+// Typically users will interact with the global Registry returned by
+// GlobalRegistry(), or a filtered Registry created by applying FilterOptions to
+// the GlobalRegistry()'s Filter function.
+type Registry interface {
+	// Names returns a list of all of the lint names that have been registered
+	// in string sorted order.
+	Names() []string
+	// Sources returns a SourceList of registered LintSources. The list is not
+	// sorted but can be sorted by the caller with sort.Sort() if required.
+	Sources() SourceList
+	// ByName returns a pointer to the registered lint with the given name, or nil
+	// if there is no such lint registered in the registry.
+	ByName(name string) *Lint
+	// BySource returns a list of registered lints that have the same LintSource as
+	// provided (or nil if there were no such lints in the registry).
+	BySource(s LintSource) []*Lint
+	// Filter returns a new Registry containing only lints that match the
+	// FilterOptions criteria.
+	Filter(opts FilterOptions) (Registry, error)
+	// WriteJSON writes a description of each registered lint as
+	// a JSON object, one object per line, to the provided writer.
+	WriteJSON(w io.Writer)
+}
+
+// registryImpl implements the Registry interface to provide a global collection
+// of Lints that have been registered.
+type registryImpl struct {
+	sync.RWMutex
+	// lintsByName is a map of all registered lints by name.
+	lintsByName map[string]*Lint
+	// lintNames is a sorted list of all of the registered lint names. It is
+	// equivalent to collecting the keys from lintsByName into a slice and sorting
+	// them lexicographically.
+	lintNames []string
+	// lintsBySource is a map of all registered lints by source category. Lints
+	// are added to the lintsBySource map by RegisterLint.
+	lintsBySource map[LintSource][]*Lint
+}
+
+var (
+	// errNilLint is returned from registry.Register if the provided lint was nil.
+	errNilLint = errors.New("can not register a nil lint")
+	// errNilLintPtr is returned from registry.Register if the provided lint had
+	// a nil Lint field.
+	errNilLintPtr = errors.New("can not register a lint with a nil Lint pointer")
+	// errEmptyName is returned from registry.Register if the provided lint had an
+	// empty Name field.
+	errEmptyName = errors.New("can not register a lint with an empty Name")
+)
+
+// errDuplicateName is returned from registry.Register if the provided lint had
+// a Name field matching a lint that was previously registered.
+type errDuplicateName struct {
+	lintName string
+}
+
+func (e errDuplicateName) Error() string {
+	return fmt.Sprintf(
+		"can not register lint with name %q - it has already been registered",
+		e.lintName)
+}
+
+// errBadInit is returned from registry.Register if the provided lint's
+// Initialize function returned an error.
+type errBadInit struct {
+	lintName string
+	err      error
+}
+
+func (e errBadInit) Error() string {
+	return fmt.Sprintf(
+		"failed to register lint with name %q - failed to Initialize: %q",
+		e.lintName, e.err)
+}
+
+// register adds the provided lint to the Registry. If initialize is true then
+// the lint's Initialize() function will be called before registering the lint.
+//
+// An error is returned if the lint or lint's Lint pointer is nil, if the Lint
+// has an empty Name or if the Name was previously registered.
+func (r *registryImpl) register(l *Lint, initialize bool) error {
+	if l == nil {
+		return errNilLint
+	}
+	if l.Lint == nil {
+		return errNilLintPtr
+	}
+	if l.Name == "" {
+		return errEmptyName
+	}
+	if existing := r.ByName(l.Name); existing != nil {
+		return &errDuplicateName{l.Name}
+	}
+	if initialize {
+		if err := l.Lint.Initialize(); err != nil {
+			return &errBadInit{l.Name, err}
+		}
+	}
+	r.Lock()
+	defer r.Unlock()
+	r.lintNames = append(r.lintNames, l.Name)
+	r.lintsByName[l.Name] = l
+	r.lintsBySource[l.Source] = append(r.lintsBySource[l.Source], l)
+	sort.Strings(r.lintNames)
+	return nil
+}
+
+// ByName returns the Lint previously registered under the given name with
+// Register, or nil if no matching lint name has been registered.
+func (r *registryImpl) ByName(name string) *Lint {
+	r.RLock()
+	defer r.RUnlock()
+	return r.lintsByName[name]
+}
+
+// Names returns a list of all of the lint names that have been registered
+// in string sorted order.
+func (r *registryImpl) Names() []string {
+	r.RLock()
+	defer r.RUnlock()
+	return r.lintNames
+}
+
+// BySource returns a list of registered lints that have the same LintSource as
+// provided (or nil if there were no such lints).
+func (r *registryImpl) BySource(s LintSource) []*Lint {
+	r.RLock()
+	defer r.RUnlock()
+	return r.lintsBySource[s]
+}
+
+// Sources returns a SourceList of registered LintSources. The list is not
+// sorted but can be sorted by the caller with sort.Sort() if required.
+func (r *registryImpl) Sources() SourceList {
+	r.RLock()
+	defer r.RUnlock()
+	var results SourceList
+	for k := range r.lintsBySource {
+		results = append(results, k)
+	}
+	return results
+}
+
+// lintNamesToMap converts a list of lit names into a bool hashmap useful for
+// filtering. If any of the lint names are not known by the registry an error is
+// returned.
+func (r *registryImpl) lintNamesToMap(names []string) (map[string]bool, error) {
+	if len(names) == 0 {
+		return nil, nil
+	}
+
+	namesMap := make(map[string]bool, len(names))
+	for _, n := range names {
+		n = strings.TrimSpace(n)
+		if l := r.ByName(n); l == nil {
+			return nil, fmt.Errorf("unknown lint name %q", n)
+		}
+		namesMap[n] = true
+	}
+	return namesMap, nil
+}
+
+func sourceListToMap(sources SourceList) map[LintSource]bool {
+	if len(sources) == 0 {
+		return nil
+	}
+	sourceMap := make(map[LintSource]bool, len(sources))
+	for _, s := range sources {
+		sourceMap[s] = true
+	}
+	return sourceMap
+}
+
+// Filter creates a new Registry with only the lints that meet the FilterOptions
+// criteria included.
+//
+// FilterOptions are applied in the following order of precedence:
+//   ExcludeSources > IncludeSources > NameFilter > ExcludeNames > IncludeNames
+func (r *registryImpl) Filter(opts FilterOptions) (Registry, error) {
+	// If there's no filtering to be done, return the existing Registry.
+	if opts.Empty() {
+		return r, nil
+	}
+
+	filteredRegistry := NewRegistry()
+
+	sourceExcludes := sourceListToMap(opts.ExcludeSources)
+	sourceIncludes := sourceListToMap(opts.IncludeSources)
+
+	nameExcludes, err := r.lintNamesToMap(opts.ExcludeNames)
+	if err != nil {
+		return nil, err
+	}
+	nameIncludes, err := r.lintNamesToMap(opts.IncludeNames)
+	if err != nil {
+		return nil, err
+	}
+
+	if opts.NameFilter != nil && (len(nameExcludes) != 0 || len(nameIncludes) != 0) {
+		return nil, errors.New(
+			"FilterOptions.NameFilter cannot be used at the same time as " +
+				"FilterOptions.ExcludeNames or FilterOptions.IncludeNames")
+	}
+
+	for _, name := range r.Names() {
+		l := r.ByName(name)
+
+		if sourceExcludes != nil && sourceExcludes[l.Source] {
+			continue
+		}
+		if sourceIncludes != nil && !sourceIncludes[l.Source] {
+			continue
+		}
+		if opts.NameFilter != nil && !opts.NameFilter.MatchString(name) {
+			continue
+		}
+		if nameExcludes != nil && nameExcludes[name] {
+			continue
+		}
+		if nameIncludes != nil && !nameIncludes[name] {
+			continue
+		}
+
+		// when adding lints to a filtered registry we do not want Initialize() to
+		// be called a second time, so provide false as the initialize argument.
+		if err := filteredRegistry.register(l, false); err != nil {
+			return nil, err
+		}
+	}
+
+	return filteredRegistry, nil
+}
+
+// WriteJSON writes a description of each registered lint as
+// a JSON object, one object per line, to the provided writer.
+func (r *registryImpl) WriteJSON(w io.Writer) {
+	enc := json.NewEncoder(w)
+	enc.SetEscapeHTML(false)
+	for _, name := range r.Names() {
+		_ = enc.Encode(r.ByName(name))
+	}
+}
+
+// NewRegistry constructs a Registry implementation that can be used to register
+// lints.
+func NewRegistry() *registryImpl {
+	return &registryImpl{
+		lintsByName:   make(map[string]*Lint),
+		lintsBySource: make(map[LintSource][]*Lint),
+	}
+}
+
+// globalRegistry is the Registry used by all loaded lints that call
+// RegisterLint().
+var globalRegistry *registryImpl = NewRegistry()
+
+// RegisterLint must be called once for each lint to be executed. Normally,
+// RegisterLint is called from the Go init() function of a lint implementation.
+//
+// RegsterLint will call l.Lint's Initialize() function as part of the
+// registration process.
+//
+// IMPORTANT: RegisterLint will panic if given a nil lint, or a lint with a nil
+// Lint pointer, or if the lint's Initialize function errors, or if the lint
+// name matches a previously registered lint's name. These conditions all
+// indicate a bug that should be addressed by a developer.
+func RegisterLint(l *Lint) {
+	// RegisterLint always sets initialize to true. It's assumed this is called by
+	// the package init() functions and therefore must be doing the first
+	// initialization of a lint.
+	if err := globalRegistry.register(l, true); err != nil {
+		panic(fmt.Sprintf("RegisterLint error: %v\n", err.Error()))
+	}
+}
+
+// GlobalRegistry is the Registry used by RegisterLint and contains all of the
+// lints that are loaded.
+//
+// If you want to run only a subset of the globally registered lints use
+// GloablRegistry().Filter with FilterOptions to create a filtered
+// Registry.
+func GlobalRegistry() Registry {
+	return globalRegistry
+}

+ 106 - 0
vendor/github.com/zmap/zlint/v3/lint/result.go

@@ -0,0 +1,106 @@
+package lint
+
+/*
+ * ZLint Copyright 2021 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.
+ */
+
+import (
+	"encoding/json"
+	"fmt"
+	"strings"
+)
+
+// LintStatus is an enum returned by lints inside of a LintResult.
+type LintStatus int
+
+// Known LintStatus values
+const (
+	// Unused / unset LintStatus
+	Reserved LintStatus = 0
+
+	// Not Applicable
+	NA LintStatus = 1
+
+	// Not Effective
+	NE LintStatus = 2
+
+	Pass   LintStatus = 3
+	Notice LintStatus = 4
+	Warn   LintStatus = 5
+	Error  LintStatus = 6
+	Fatal  LintStatus = 7
+)
+
+var (
+	// StatusLabelToLintStatus is used to work backwards from
+	// a LintStatus.String() to the LintStatus. This is used by
+	// LintStatus.Unmarshal.
+	StatusLabelToLintStatus = map[string]LintStatus{
+		Reserved.String(): Reserved,
+		NA.String():       NA,
+		NE.String():       NE,
+		Pass.String():     Pass,
+		Notice.String():   Notice,
+		Warn.String():     Warn,
+		Error.String():    Error,
+		Fatal.String():    Fatal,
+	}
+)
+
+// LintResult contains a LintStatus, and an optional human-readable description.
+// The output of a lint is a LintResult.
+type LintResult struct {
+	Status  LintStatus `json:"result"`
+	Details string     `json:"details,omitempty"`
+}
+
+// MarshalJSON implements the json.Marshaler interface.
+func (e LintStatus) MarshalJSON() ([]byte, error) {
+	s := e.String()
+	return json.Marshal(s)
+}
+
+// UnmarshalJSON implements the json.Unmarshaler interface.
+func (e *LintStatus) UnmarshalJSON(data []byte) error {
+	key := strings.ReplaceAll(string(data), `"`, "")
+	if status, ok := StatusLabelToLintStatus[key]; ok {
+		*e = status
+	} else {
+		return fmt.Errorf("bad LintStatus JSON value: %s", string(data))
+	}
+	return nil
+}
+
+// String returns the canonical representation of a LintStatus as a string.
+func (e LintStatus) String() string {
+	switch e {
+	case Reserved:
+		return "reserved"
+	case NA:
+		return "NA"
+	case NE:
+		return "NE"
+	case Pass:
+		return "pass"
+	case Notice:
+		return "info"
+	case Warn:
+		return "warn"
+	case Error:
+		return "error"
+	case Fatal:
+		return "fatal"
+	default:
+		return ""
+	}
+}

+ 129 - 0
vendor/github.com/zmap/zlint/v3/lint/source.go

@@ -0,0 +1,129 @@
+package lint
+
+import (
+	"encoding/json"
+	"fmt"
+	"strings"
+)
+
+/*
+ * ZLint Copyright 2021 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.
+ */
+
+// LintSource is a type representing a known lint source that lints cite
+// requirements from.
+type LintSource string
+
+const (
+	UnknownLintSource        LintSource = "Unknown"
+	RFC5280                  LintSource = "RFC5280"
+	RFC5480                  LintSource = "RFC5480"
+	RFC5891                  LintSource = "RFC5891"
+	CABFBaselineRequirements LintSource = "CABF_BR"
+	CABFEVGuidelines         LintSource = "CABF_EV"
+	MozillaRootStorePolicy   LintSource = "Mozilla"
+	AppleRootStorePolicy     LintSource = "Apple"
+	Community                LintSource = "Community"
+	EtsiEsi                  LintSource = "ETSI_ESI"
+)
+
+// UnmarshalJSON implements the json.Unmarshaler interface. It ensures that the
+// unmarshaled value is a known LintSource.
+func (s *LintSource) UnmarshalJSON(data []byte) error {
+	var throwAway string
+	if err := json.Unmarshal(data, &throwAway); err != nil {
+		return err
+	}
+
+	switch LintSource(throwAway) {
+	case RFC5280, RFC5480, RFC5891, CABFBaselineRequirements, CABFEVGuidelines, MozillaRootStorePolicy, AppleRootStorePolicy, Community, EtsiEsi:
+		*s = LintSource(throwAway)
+		return nil
+	default:
+		*s = UnknownLintSource
+		return fmt.Errorf("unknown LintSource value %q", throwAway)
+	}
+}
+
+// FromString sets the LintSource value based on the source string provided
+// (case sensitive). If the src string does not match any of the known
+// LintSource's then s is set to the UnknownLintSource.
+func (s *LintSource) FromString(src string) {
+	// Start with the unknown lint source
+	*s = UnknownLintSource
+	// Trim space and try to match a known value
+	src = strings.TrimSpace(src)
+	switch LintSource(src) {
+	case RFC5280:
+		*s = RFC5280
+	case RFC5480:
+		*s = RFC5480
+	case RFC5891:
+		*s = RFC5891
+	case CABFBaselineRequirements:
+		*s = CABFBaselineRequirements
+	case CABFEVGuidelines:
+		*s = CABFEVGuidelines
+	case MozillaRootStorePolicy:
+		*s = MozillaRootStorePolicy
+	case AppleRootStorePolicy:
+		*s = AppleRootStorePolicy
+	case Community:
+		*s = Community
+	case EtsiEsi:
+		*s = EtsiEsi
+	}
+}
+
+// SourceList is a slice of LintSources that can be sorted.
+type SourceList []LintSource
+
+// Len returns the length of the list.
+func (l SourceList) Len() int {
+	return len(l)
+}
+
+// Swap swaps the LintSource at index i and j in the list.
+func (l SourceList) Swap(i, j int) {
+	l[i], l[j] = l[j], l[i]
+}
+
+// Less compares the LintSources at index i and j lexicographically.
+func (l SourceList) Less(i, j int) bool {
+	return l[i] < l[j]
+}
+
+// FromString populates a SourceList (replacing any existing content) with the
+// comma separated list of sources provided in raw. If any of the comma
+// separated values are not known LintSource's an error is returned.
+func (l *SourceList) FromString(raw string) error {
+	// Start with an empty list
+	*l = SourceList{}
+
+	values := strings.Split(raw, ",")
+	for _, val := range values {
+		val = strings.TrimSpace(val)
+		if val == "" {
+			continue
+		}
+		// Populate the LintSource with the trimmed value.
+		var src LintSource
+		src.FromString(val)
+		// If the LintSource is UnknownLintSource then return an error.
+		if src == UnknownLintSource {
+			return fmt.Errorf("unknown lint source in list: %q", val)
+		}
+		*l = append(*l, src)
+	}
+	return nil
+}

+ 157 - 0
vendor/github.com/zmap/zlint/v3/lints/apple/lint_ct_sct_policy_count_unsatisfied.go

@@ -0,0 +1,157 @@
+/*
+ * ZLint Copyright 2021 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.
+ */
+
+package apple
+
+import (
+	"fmt"
+	"time"
+
+	"github.com/zmap/zcrypto/x509"
+	"github.com/zmap/zcrypto/x509/ct"
+	"github.com/zmap/zlint/v3/lint"
+	"github.com/zmap/zlint/v3/util"
+)
+
+type sctPolicyCount struct{}
+
+func init() {
+	lint.RegisterLint(&lint.Lint{
+		Name:          "w_ct_sct_policy_count_unsatisfied",
+		Description:   "Check if certificate has enough embedded SCTs to meet Apple CT Policy",
+		Citation:      "https://support.apple.com/en-us/HT205280",
+		Source:        lint.AppleRootStorePolicy,
+		EffectiveDate: util.AppleCTPolicyDate,
+		Lint:          &sctPolicyCount{},
+	})
+}
+
+// Initialize for a sctPolicyCount instance does nothing.
+func (l *sctPolicyCount) Initialize() error {
+	return nil
+}
+
+// CheckApplies returns true for any subscriber certificates that are not
+// precertificates (e.g. that do not have the CT poison extension defined in RFC
+// 6962.
+func (l *sctPolicyCount) CheckApplies(c *x509.Certificate) bool {
+	return util.IsSubscriberCert(c) && !util.IsExtInCert(c, util.CtPoisonOID)
+}
+
+// Execute checks if the provided certificate has embedded SCTs from
+// a sufficient number of unique CT logs to meet Apple's CT log policy[0],
+// effective Oct 15th, 2018.
+//
+// The number of required SCTs from different logs is calculated based on the
+// Certificate's lifetime. If the number of required SCTs are not embedded in
+// the certificate a Notice level lint.LintResult is returned.
+//
+// | Certificate lifetime | # of SCTs from separate logs |
+// -------------------------------------------------------
+// | Less than 15 months  | 2                            |
+// | 15 to 27 months      | 3                            |
+// | 27 to 39 months      | 4                            |
+// | More than 39 months  | 5                            |
+// -------------------------------------------------------
+//
+// Important note 1: We can't know whether additional SCTs were presented
+// alongside the certificate via OCSP stapling. This linter assumes only
+// embedded SCTs are used and ignores the portion of the Apple policy related to
+// SCTs delivered via OCSP. This is one limitation that restricts the linter's
+// findings to Notice level. See more background discussion in Issue 226[1].
+//
+// Important note 2: The linter doesn't maintain a list of Apple's trusted
+// logs. The SCTs embedded in the certificate may not be from log's Apple
+// actually trusts. Similarly the embedded SCT signatures are not validated
+// in any way.
+//
+// [0]: https://support.apple.com/en-us/HT205280
+// [1]: https://github.com/zmap/zlint/issues/226
+func (l *sctPolicyCount) Execute(c *x509.Certificate) *lint.LintResult {
+	// Determine the required number of SCTs from separate logs
+	expected := appleCTPolicyExpectedSCTs(c)
+
+	// If there are no SCTs then the job is easy. We can return a Notice
+	// lint.LintResult immediately.
+	if len(c.SignedCertificateTimestampList) == 0 && expected > 0 {
+		return &lint.LintResult{
+			Status: lint.Notice,
+			Details: fmt.Sprintf(
+				"Certificate had 0 embedded SCTs. Browser policy may require %d for this certificate.",
+				expected),
+		}
+	}
+
+	// Build a map from LogID to SCT so that we can count embedded SCTs by unique
+	// log.
+	sctsByLogID := make(map[ct.SHA256Hash]*ct.SignedCertificateTimestamp)
+	for _, sct := range c.SignedCertificateTimestampList {
+		sctsByLogID[sct.LogID] = sct
+	}
+
+	// If the number of embedded SCTs from separate logs meets expected return
+	// a lint.Pass result.
+	if len(sctsByLogID) >= expected {
+		return &lint.LintResult{Status: lint.Pass}
+	}
+
+	// Otherwise return a Notice result - there weren't enough SCTs embedded in
+	// the certificate. More must be provided by OCSP stapling if the certificate
+	// is to meet Apple's CT policy.
+	return &lint.LintResult{
+		Status: lint.Notice,
+		Details: fmt.Sprintf(
+			"Certificate had %d embedded SCTs from distinct log IDs. "+
+				"Browser policy may require %d for this certificate.",
+			len(sctsByLogID), expected),
+	}
+}
+
+// appleCTPolicyExpectedSCTs returns a count of the number of SCTs expected to
+// be embedded in the given certificate based on its lifetime.
+//
+// For this function the relevant portion of Apple's policy is the table
+// "Number of embedded SCTs based on certificate lifetime" (Also reproduced in
+// the `Execute` godoc comment).
+func appleCTPolicyExpectedSCTs(cert *x509.Certificate) int {
+	// Lifetime is relative to the certificate's NotBefore date.
+	start := cert.NotBefore
+
+	// Thresholds is an ordered array of lifetime periods and their expected # of
+	// SCTs. A lifetime period is defined by the cutoff date relative to the
+	// start of the certificate's lifetime.
+	thresholds := []struct {
+		CutoffDate time.Time
+		Expected   int
+	}{
+		// Start date ... 15 months
+		{CutoffDate: start.AddDate(0, 15, 0), Expected: 2},
+		// Start date ... 27 months
+		{CutoffDate: start.AddDate(0, 27, 0), Expected: 3},
+		// Start date ... 39 months
+		{CutoffDate: start.AddDate(0, 39, 0), Expected: 4},
+	}
+
+	// If the certificate's lifetime falls into any of the cutoff date ranges then
+	// we expect that range's expected # of SCTs for this certificate. This loop
+	// assumes the `thresholds` list is sorted in ascending order.
+	for _, threshold := range thresholds {
+		if cert.NotAfter.Before(threshold.CutoffDate) {
+			return threshold.Expected
+		}
+	}
+
+	// The certificate had a validity > 39 months.
+	return 5
+}

+ 61 - 0
vendor/github.com/zmap/zlint/v3/lints/apple/lint_e_server_cert_valid_time_longer_than_398_days.go

@@ -0,0 +1,61 @@
+/*
+ * ZLint Copyright 2021 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.
+ */
+
+package apple
+
+import (
+	"time"
+
+	"github.com/zmap/zcrypto/x509"
+	"github.com/zmap/zlint/v3/lint"
+	"github.com/zmap/zlint/v3/util"
+)
+
+type serverCertValidityTooLong struct{}
+
+func init() {
+	lint.RegisterLint(&lint.Lint{
+		Name: "e_tls_server_cert_valid_time_longer_than_398_days",
+		Description: "TLS server certificates issued on or after September 1, 2020 " +
+			"00:00 GMT/UTC must not have a validity period greater than 398 days",
+		Citation:      "https://support.apple.com/en-us/HT211025",
+		Source:        lint.AppleRootStorePolicy,
+		EffectiveDate: util.AppleReducedLifetimeDate,
+		Lint:          &serverCertValidityTooLong{},
+	})
+}
+
+func (l *serverCertValidityTooLong) Initialize() error {
+	return nil
+}
+
+func (l *serverCertValidityTooLong) CheckApplies(c *x509.Certificate) bool {
+	return util.IsServerAuthCert(c) && !c.IsCA
+}
+
+func (l *serverCertValidityTooLong) Execute(c *x509.Certificate) *lint.LintResult {
+	// "TLS server certificates issued on or after September 1, 2020 00:00 GMT/UTC
+	// must not have a validity period greater than 398 days."
+	maxValidity := 398 * appleDayLength
+
+	// RFC 5280, section 4.1.2.5: "The validity period for a certificate is the period
+	// of time from notBefore through notAfter, inclusive."
+	certValidity := c.NotAfter.Add(1 * time.Second).Sub(c.NotBefore)
+
+	if certValidity > maxValidity {
+		return &lint.LintResult{Status: lint.Error}
+	}
+
+	return &lint.LintResult{Status: lint.Pass}
+}

+ 67 - 0
vendor/github.com/zmap/zlint/v3/lints/apple/lint_w_server_cert_valid_time_longer_than_397_days.go

@@ -0,0 +1,67 @@
+/*
+ * ZLint Copyright 2021 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.
+ */
+
+package apple
+
+import (
+	"time"
+
+	"github.com/zmap/zcrypto/x509"
+	"github.com/zmap/zlint/v3/lint"
+	"github.com/zmap/zlint/v3/util"
+)
+
+type serverCertValidityAlmostTooLong struct{}
+
+func init() {
+	lint.RegisterLint(&lint.Lint{
+		Name: "w_tls_server_cert_valid_time_longer_than_397_days",
+		Description: "TLS server certificates issued on or after September 1, 2020 " +
+			"00:00 GMT/UTC should not have a validity period greater than 397 days",
+		Citation:      "https://support.apple.com/en-us/HT211025",
+		Source:        lint.AppleRootStorePolicy,
+		EffectiveDate: util.AppleReducedLifetimeDate,
+		Lint:          &serverCertValidityAlmostTooLong{},
+	})
+}
+
+func (l *serverCertValidityAlmostTooLong) Initialize() error {
+	return nil
+}
+
+func (l *serverCertValidityAlmostTooLong) CheckApplies(c *x509.Certificate) bool {
+	return util.IsServerAuthCert(c) && !c.IsCA
+}
+
+func (l *serverCertValidityAlmostTooLong) Execute(c *x509.Certificate) *lint.LintResult {
+	// "We recommend that certificates be issued with a maximum validity of 397 days."
+	warnValidity := 397 * appleDayLength
+
+	// RFC 5280, section 4.1.2.5: "The validity period for a certificate is the period
+	// of time from notBefore through notAfter, inclusive."
+	certValidity := c.NotAfter.Add(1 * time.Second).Sub(c.NotBefore)
+
+	if certValidity > warnValidity {
+		return &lint.LintResult{
+			// RFC 2119 has SHOULD and RECOMMENDED as equal. Since Apple recommends
+			// 397 days we treat this as a lint.Warn result as a violation of
+			// a SHOULD.
+			Status: lint.Warn,
+			Details: "Apple recommends that certificates be issued with a maximum " +
+				"validity of 397 days.",
+		}
+	}
+
+	return &lint.LintResult{Status: lint.Pass}
+}

+ 13 - 0
vendor/github.com/zmap/zlint/v3/lints/apple/time.go

@@ -0,0 +1,13 @@
+package apple
+
+import "time"
+
+// In the context of a root policy update on trusted certificate lifetimes[0]
+// Apple provided an unambiguous definition for the length of a day:
+//   "398 days is measured with a day being equal to 86,400 seconds. Any time
+//   greater than this indicates an additional day of validity."
+//
+// We provide that value as a constant here for lints to use.
+//
+// [0]: https://support.apple.com/en-us/HT211025
+var appleDayLength = 86400 * time.Second

+ 50 - 0
vendor/github.com/zmap/zlint/v3/lints/cabf_br/lint_ca_common_name_missing.go

@@ -0,0 +1,50 @@
+package cabf_br
+
+/*
+ * ZLint Copyright 2021 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.
+ */
+
+import (
+	"github.com/zmap/zcrypto/x509"
+	"github.com/zmap/zlint/v3/lint"
+	"github.com/zmap/zlint/v3/util"
+)
+
+type caCommonNameMissing struct{}
+
+func init() {
+	lint.RegisterLint(&lint.Lint{
+		Name:          "e_ca_common_name_missing",
+		Description:   "CA Certificates common name MUST be included.",
+		Citation:      "BRs: 7.1.4.3.1",
+		Source:        lint.CABFBaselineRequirements,
+		EffectiveDate: util.CABV148Date,
+		Lint:          &caCommonNameMissing{},
+	})
+}
+
+func (l *caCommonNameMissing) Initialize() error {
+	return nil
+}
+
+func (l *caCommonNameMissing) CheckApplies(c *x509.Certificate) bool {
+	return util.IsCACert(c)
+}
+
+func (l *caCommonNameMissing) Execute(c *x509.Certificate) *lint.LintResult {
+	if c.Subject.CommonName == "" {
+		return &lint.LintResult{Status: lint.Error}
+	} else {
+		return &lint.LintResult{Status: lint.Pass}
+	}
+}

+ 63 - 0
vendor/github.com/zmap/zlint/v3/lints/cabf_br/lint_ca_country_name_invalid.go

@@ -0,0 +1,63 @@
+package cabf_br
+
+/*
+ * ZLint Copyright 2021 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.
+ */
+
+import (
+	"github.com/zmap/zcrypto/x509"
+	"github.com/zmap/zlint/v3/lint"
+	"github.com/zmap/zlint/v3/util"
+)
+
+type caCountryNameInvalid struct{}
+
+/************************************************
+BRs: 7.1.2.1e
+The	Certificate	Subject	MUST contain the following:
+‐	countryName	(OID 2.5.4.6).
+This field MUST	contain	the	two‐letter	ISO	3166‐1 country code	for	the country
+in which the CA’s place	of business	is located.
+************************************************/
+
+func init() {
+	lint.RegisterLint(&lint.Lint{
+		Name:          "e_ca_country_name_invalid",
+		Description:   "Root and Subordinate CA certificates MUST have a two-letter country code specified in ISO 3166-1",
+		Citation:      "BRs: 7.1.2.1",
+		Source:        lint.CABFBaselineRequirements,
+		EffectiveDate: util.CABEffectiveDate,
+		Lint:          &caCountryNameInvalid{},
+	})
+}
+
+func (l *caCountryNameInvalid) Initialize() error {
+	return nil
+}
+
+func (l *caCountryNameInvalid) CheckApplies(c *x509.Certificate) bool {
+	return c.IsCA
+}
+
+func (l *caCountryNameInvalid) Execute(c *x509.Certificate) *lint.LintResult {
+	if c.Subject.Country != nil {
+		for _, j := range c.Subject.Country {
+			if !util.IsISOCountryCode(j) {
+				return &lint.LintResult{Status: lint.Error}
+			}
+		}
+		return &lint.LintResult{Status: lint.Pass}
+	} else {
+		return &lint.LintResult{Status: lint.NA}
+	}
+}

+ 58 - 0
vendor/github.com/zmap/zlint/v3/lints/cabf_br/lint_ca_country_name_missing.go

@@ -0,0 +1,58 @@
+package cabf_br
+
+/*
+ * ZLint Copyright 2021 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.
+ */
+
+import (
+	"github.com/zmap/zcrypto/x509"
+	"github.com/zmap/zlint/v3/lint"
+	"github.com/zmap/zlint/v3/util"
+)
+
+type caCountryNameMissing struct{}
+
+/************************************************
+BRs: 7.1.2.1e
+The	Certificate	Subject	MUST contain the following:
+‐	countryName	(OID 2.5.4.6).
+This field MUST	contain	the	two‐letter	ISO	3166‐1 country code	for	the country
+in which the CA’s place	of business	is located.
+************************************************/
+
+func init() {
+	lint.RegisterLint(&lint.Lint{
+		Name:          "e_ca_country_name_missing",
+		Description:   "Root and Subordinate CA certificates MUST have a countryName present in subject information",
+		Citation:      "BRs: 7.1.2.1",
+		Source:        lint.CABFBaselineRequirements,
+		EffectiveDate: util.CABEffectiveDate,
+		Lint:          &caCountryNameMissing{},
+	})
+}
+
+func (l *caCountryNameMissing) Initialize() error {
+	return nil
+}
+
+func (l *caCountryNameMissing) CheckApplies(c *x509.Certificate) bool {
+	return c.IsCA
+}
+
+func (l *caCountryNameMissing) Execute(c *x509.Certificate) *lint.LintResult {
+	if c.Subject.Country != nil && c.Subject.Country[0] != "" {
+		return &lint.LintResult{Status: lint.Pass}
+	} else {
+		return &lint.LintResult{Status: lint.Error}
+	}
+}

+ 57 - 0
vendor/github.com/zmap/zlint/v3/lints/cabf_br/lint_ca_crl_sign_not_set.go

@@ -0,0 +1,57 @@
+package cabf_br
+
+/*
+ * ZLint Copyright 2021 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.
+ */
+
+import (
+	"github.com/zmap/zcrypto/x509"
+	"github.com/zmap/zlint/v3/lint"
+	"github.com/zmap/zlint/v3/util"
+)
+
+type caCRLSignNotSet struct{}
+
+/************************************************
+BRs: 7.1.2.1b
+This extension MUST be present and MUST be marked critical. Bit positions for
+keyCertSign and cRLSign MUST be set. If the Root CA Private Key is used for
+signing OCSP responses, then the digitalSignature bit MUST be set.
+************************************************/
+
+func init() {
+	lint.RegisterLint(&lint.Lint{
+		Name:          "e_ca_crl_sign_not_set",
+		Description:   "Root and Subordinate CA certificate keyUsage extension's crlSign bit MUST be set",
+		Citation:      "BRs: 7.1.2.1",
+		Source:        lint.CABFBaselineRequirements,
+		EffectiveDate: util.CABEffectiveDate,
+		Lint:          &caCRLSignNotSet{},
+	})
+}
+
+func (l *caCRLSignNotSet) Initialize() error {
+	return nil
+}
+
+func (l *caCRLSignNotSet) CheckApplies(c *x509.Certificate) bool {
+	return c.IsCA && util.IsExtInCert(c, util.KeyUsageOID)
+}
+
+func (l *caCRLSignNotSet) Execute(c *x509.Certificate) *lint.LintResult {
+	if c.KeyUsage&x509.KeyUsageCRLSign != 0 {
+		return &lint.LintResult{Status: lint.Pass}
+	} else {
+		return &lint.LintResult{Status: lint.Error}
+	}
+}

+ 60 - 0
vendor/github.com/zmap/zlint/v3/lints/cabf_br/lint_ca_digital_signature_not_set.go

@@ -0,0 +1,60 @@
+package cabf_br
+
+/*
+ * ZLint Copyright 2021 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.
+ */
+
+import (
+	"github.com/zmap/zcrypto/x509"
+	"github.com/zmap/zlint/v3/lint"
+	"github.com/zmap/zlint/v3/util"
+)
+
+type caDigSignNotSet struct{}
+
+/************************************************
+BRs: 7.1.2.1b: Root CA Certificate keyUsage
+This extension MUST be present and MUST be marked critical. Bit positions for keyCertSign and cRLSign MUST be set.
+If the Root CA Private Key is used for signing OCSP responses, then the digitalSignature bit MUST be set.
+
+BRs: 7.1.2.2e: Subordinate CA Certificate keyUsage
+This extension MUST be present and MUST be marked critical. Bit positions for keyCertSign and cRLSign MUST be set.
+If the Root CA Private Key is used for signing OCSP responses, then the digitalSignature bit MUST be set.
+************************************************/
+
+func init() {
+	lint.RegisterLint(&lint.Lint{
+		Name:          "n_ca_digital_signature_not_set",
+		Description:   "Root and Subordinate CA Certificates that wish to use their private key for signing OCSP responses will not be able to without their digital signature set",
+		Citation:      "BRs: 7.1.2.1",
+		Source:        lint.CABFBaselineRequirements,
+		EffectiveDate: util.CABEffectiveDate,
+		Lint:          &caDigSignNotSet{},
+	})
+}
+
+func (l *caDigSignNotSet) Initialize() error {
+	return nil
+}
+
+func (l *caDigSignNotSet) CheckApplies(c *x509.Certificate) bool {
+	return c.IsCA && util.IsExtInCert(c, util.KeyUsageOID)
+}
+
+func (l *caDigSignNotSet) Execute(c *x509.Certificate) *lint.LintResult {
+	if c.KeyUsage&x509.KeyUsageDigitalSignature != 0 {
+		return &lint.LintResult{Status: lint.Pass}
+	} else {
+		return &lint.LintResult{Status: lint.Notice}
+	}
+}

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels