Jelajahi Sumber

Merge pull request #46184 from thaJeztah/bump_swarmkit

vendor: github.com/moby/swarmkit/v2 v2.0.0-20230808164555-1983e41a9fff
Bjorn Neergaard 1 tahun lalu
induk
melakukan
fc5702b284
100 mengubah file dengan 22716 tambahan dan 316 penghapusan
  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 {
 		if i%2 != 0 {
 			cert, _, key, err = initca.New(&csr.CertificateRequest{
 			cert, _, key, err = initca.New(&csr.CertificateRequest{
 				CN:         "newRoot",
 				CN:         "newRoot",
-				KeyRequest: csr.NewBasicKeyRequest(),
+				KeyRequest: csr.NewKeyRequest(),
 				CA:         &csr.CAConfig{Expiry: ca.RootCAExpiration},
 				CA:         &csr.CAConfig{Expiry: ca.RootCAExpiration},
 			})
 			})
 			assert.NilError(c, err)
 			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/aws-sdk-go-v2/service/cloudwatchlogs v1.15.17
 	github.com/aws/smithy-go v1.13.5
 	github.com/aws/smithy-go v1.13.5
 	github.com/bsphere/le_go v0.0.0-20200109081728-fc06dab2caa8
 	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/container-orchestrated-devices/container-device-interface v0.6.0
 	github.com/containerd/cgroups/v3 v3.0.2
 	github.com/containerd/cgroups/v3 v3.0.2
 	github.com/containerd/containerd v1.6.22
 	github.com/containerd/containerd v1.6.22
@@ -65,7 +65,7 @@ require (
 	github.com/moby/locker v1.0.1
 	github.com/moby/locker v1.0.1
 	github.com/moby/patternmatcher v0.5.0
 	github.com/moby/patternmatcher v0.5.0
 	github.com/moby/pubsub v1.0.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/mount v0.3.3
 	github.com/moby/sys/mountinfo v0.6.2
 	github.com/moby/sys/mountinfo v0.6.2
 	github.com/moby/sys/sequential v0.5.0
 	github.com/moby/sys/sequential v0.5.0
@@ -158,6 +158,7 @@ require (
 	github.com/hashicorp/golang-lru v0.5.4 // indirect
 	github.com/hashicorp/golang-lru v0.5.4 // indirect
 	github.com/in-toto/in-toto-golang v0.5.0 // indirect
 	github.com/in-toto/in-toto-golang v0.5.0 // indirect
 	github.com/inconshreveable/mousetrap v1.1.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/matttproud/golang_protobuf_extensions v1.0.4 // indirect
 	github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
 	github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
 	github.com/mitchellh/reflectwalk v1.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/fsutil v0.0.0-20230629203738-36ef4d8c0dbb // indirect
 	github.com/tonistiigi/go-actions-cache v0.0.0-20220404170428-0bdeb6e1eac7 // 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/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/client/pkg/v3 v3.5.6 // indirect
 	go.etcd.io/etcd/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
 	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/atomic v1.9.0 // indirect
 	go.uber.org/multierr v1.8.0 // indirect
 	go.uber.org/multierr v1.8.0 // indirect
 	go.uber.org/zap v1.21.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/oauth2 v0.6.0 // indirect
 	golang.org/x/tools v0.6.0 // indirect
 	golang.org/x/tools v0.6.0 // indirect
 	google.golang.org/api v0.110.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/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/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 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-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-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
 github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
 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 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/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.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/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/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
 github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
 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.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
 github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
 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.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/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo=
 github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
 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=
 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/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 h1:jkp/imWsmJz2f6LyFsk7EkVeN2HxR/HTTOY8kHrsxfA=
 github.com/moby/pubsub v1.0.0/go.mod h1:bXSO+3h5MNXXCaEG+6/NlAIk7MMZbySZlnB+cUQhKKc=
 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.0/go.mod h1:FVQFLDRWwyBjDTBNQXDlWnSFREqOo3OKX9aqhmeoo74=
 github.com/moby/sys/mount v0.1.1/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=
 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/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-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/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.0.0-20200520151820-abd8a0e76976/go.mod h1:x8F1gnqOkIEiO4rqoeEEEqQbo7HjGMTvyoq3gej4iT0=
 github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
 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=
 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.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.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 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.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
 github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
 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 h1:Cn05BRLm+iRP/DZxyVSsfVyrzgjDbwHwkVt38qvXnNI=
 github.com/vishvananda/netns v0.0.2/go.mod h1:yitZXdAVI+yPFSb4QUe+VW3vOVl4PZPNcBgbPxAtJxw=
 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/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-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
 github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=
 github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=
 github.com/xanzy/go-gitlab v0.31.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug=
 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/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/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/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.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
 go.etcd.io/bbolt v1.3.3/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=
 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-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-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-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-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-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.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-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-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/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-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-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-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-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-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210112080510-489259a85091/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 (
 import (
 	"encoding/json"
 	"encoding/json"
-	"io/ioutil"
+	"io"
 	"net/http"
 	"net/http"
 
 
 	"github.com/cloudflare/cfssl/errors"
 	"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) {
 func readRequestBlob(r *http.Request) (map[string]string, error) {
 	var blob map[string]string
 	var blob map[string]string
 
 
-	body, err := ioutil.ReadAll(r.Body)
+	body, err := io.ReadAll(r.Body)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -176,7 +176,7 @@ type Response struct {
 	Messages []ResponseMessage `json:"messages"`
 	Messages []ResponseMessage `json:"messages"`
 }
 }
 
 
-// NewSuccessResponse is a shortcut for creating new successul API
+// NewSuccessResponse is a shortcut for creating new successful API
 // responses.
 // responses.
 func NewSuccessResponse(result interface{}) Response {
 func NewSuccessResponse(result interface{}) Response {
 	return Response{
 	return Response{

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

@@ -10,7 +10,6 @@ import (
 	"crypto/sha256"
 	"crypto/sha256"
 	"encoding/hex"
 	"encoding/hex"
 	"fmt"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"os"
 	"strings"
 	"strings"
 )
 )
@@ -52,11 +51,11 @@ func New(key string, ad []byte) (*Standard, error) {
 		case "env":
 		case "env":
 			key = os.Getenv(splitKey[1])
 			key = os.Getenv(splitKey[1])
 		case "file":
 		case "file":
-			data, err := ioutil.ReadFile(splitKey[1])
+			data, err := os.ReadFile(splitKey[1])
 			if err != nil {
 			if err != nil {
 				return nil, err
 				return nil, err
 			}
 			}
-			key = string(data)
+			key = strings.TrimSpace(string(data))
 		default:
 		default:
 			return nil, fmt.Errorf("unknown key prefix: %s", splitKey[0])
 			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
 ### Use goose to start and terminate a MySQL DB
 To start a MySQL using goose:
 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
 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
 Note: the administration of MySQL DB is not included. We assume
 the databases being connected to are already created and access control
 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
 ### Use goose to start and terminate a PostgreSQL DB
 To start a PostgreSQL using goose:
 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
 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
 Note: the administration of PostgreSQL DB is not included. We assume
 the databases being connected to are already created and access control
 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
 ### Use goose to start and terminate a SQLite DB
 To start a SQLite DB using goose:
 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
 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
 ## CFSSL Configuration
 
 

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

@@ -1,7 +1,11 @@
 package certdb
 package certdb
 
 
 import (
 import (
+	"database/sql"
+	"encoding/json"
 	"time"
 	"time"
+
+	"github.com/jmoiron/sqlx/types"
 )
 )
 
 
 // CertificateRecord encodes a certificate and its metadata
 // CertificateRecord encodes a certificate and its metadata
@@ -15,6 +19,46 @@ type CertificateRecord struct {
 	Expiry    time.Time `db:"expiry"`
 	Expiry    time.Time `db:"expiry"`
 	RevokedAt time.Time `db:"revoked_at"`
 	RevokedAt time.Time `db:"revoked_at"`
 	PEM       string    `db:"pem"`
 	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
 // OCSPRecord encodes a OCSP response body and its metadata
@@ -32,7 +76,9 @@ type Accessor interface {
 	GetCertificate(serial, aki string) ([]CertificateRecord, error)
 	GetCertificate(serial, aki string) ([]CertificateRecord, error)
 	GetUnexpiredCertificates() ([]CertificateRecord, error)
 	GetUnexpiredCertificates() ([]CertificateRecord, error)
 	GetRevokedAndUnexpiredCertificates() ([]CertificateRecord, error)
 	GetRevokedAndUnexpiredCertificates() ([]CertificateRecord, error)
+	GetUnexpiredCertificatesByLabel(labels []string) (crs []CertificateRecord, err error)
 	GetRevokedAndUnexpiredCertificatesByLabel(label string) ([]CertificateRecord, error)
 	GetRevokedAndUnexpiredCertificatesByLabel(label string) ([]CertificateRecord, error)
+	GetRevokedAndUnexpiredCertificatesByLabelSelectColumns(label string) ([]CertificateRecord, error)
 	RevokeCertificate(serial, aki string, reasonCode int) error
 	RevokeCertificate(serial, aki string, reasonCode int) error
 	InsertOCSP(rr OCSPRecord) error
 	InsertOCSP(rr OCSPRecord) error
 	GetOCSP(serial, aki string) ([]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"
 	"encoding/json"
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
-	"io/ioutil"
+	"os"
 	"regexp"
 	"regexp"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
@@ -19,6 +19,9 @@ import (
 	"github.com/cloudflare/cfssl/helpers"
 	"github.com/cloudflare/cfssl/helpers"
 	"github.com/cloudflare/cfssl/log"
 	"github.com/cloudflare/cfssl/log"
 	ocspConfig "github.com/cloudflare/cfssl/ocsp/config"
 	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
 // A CSRWhitelist stores booleans for fields in the CSR. If a CSRWhitelist is
@@ -32,7 +35,7 @@ import (
 // mechanism.
 // mechanism.
 type CSRWhitelist struct {
 type CSRWhitelist struct {
 	Subject, PublicKeyAlgorithm, PublicKey, SignatureAlgorithm bool
 	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
 // 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"`
 	ExpiryString        string       `json:"expiry"`
 	BackdateString      string       `json:"backdate"`
 	BackdateString      string       `json:"backdate"`
 	AuthKeyName         string       `json:"auth_key"`
 	AuthKeyName         string       `json:"auth_key"`
+	CopyExtensions      bool         `json:"copy_extensions"`
+	PrevAuthKeyName     string       `json:"prev_auth_key"` // to support key rotation
 	RemoteName          string       `json:"remote"`
 	RemoteName          string       `json:"remote"`
 	NotBefore           time.Time    `json:"not_before"`
 	NotBefore           time.Time    `json:"not_before"`
 	NotAfter            time.Time    `json:"not_after"`
 	NotAfter            time.Time    `json:"not_after"`
@@ -89,11 +94,26 @@ type SigningProfile struct {
 	CTLogServers        []string     `json:"ct_log_servers"`
 	CTLogServers        []string     `json:"ct_log_servers"`
 	AllowedExtensions   []OID        `json:"allowed_extensions"`
 	AllowedExtensions   []OID        `json:"allowed_extensions"`
 	CertStore           string       `json:"cert_store"`
 	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
 	Policies                    []CertificatePolicy
 	Expiry                      time.Duration
 	Expiry                      time.Duration
 	Backdate                    time.Duration
 	Backdate                    time.Duration
 	Provider                    auth.Provider
 	Provider                    auth.Provider
+	PrevProvider                auth.Provider // to suppport key rotation
 	RemoteProvider              auth.Provider
 	RemoteProvider              auth.Provider
 	RemoteServer                string
 	RemoteServer                string
 	RemoteCAs                   *x509.CertPool
 	RemoteCAs                   *x509.CertPool
@@ -102,6 +122,11 @@ type SigningProfile struct {
 	NameWhitelist               *regexp.Regexp
 	NameWhitelist               *regexp.Regexp
 	ExtensionWhitelist          map[string]bool
 	ExtensionWhitelist          map[string]bool
 	ClientProvidesSerialNumbers 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.
 // UnmarshalJSON unmarshals a JSON string into an OID.
@@ -229,7 +254,7 @@ func (p *SigningProfile) populate(cfg *Config) error {
 
 
 	if p.AuthKeyName != "" {
 	if p.AuthKeyName != "" {
 		log.Debug("match auth key in profile to auth_keys section")
 		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" {
 			if key.Type == "standard" {
 				p.Provider, err = auth.New(key.Key, nil)
 				p.Provider, err = auth.New(key.Key, nil)
 				if err != 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 != "" {
 	if p.AuthRemote.AuthKeyName != "" {
 		log.Debug("match auth remote key in profile to auth_keys section")
 		log.Debug("match auth remote key in profile to auth_keys section")
 		if key, ok := cfg.AuthKeys[p.AuthRemote.AuthKeyName]; ok == true {
 		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
 		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
 	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.
 // valid local default profile has defined at least a default expiration.
 // A valid remote profile (default or not) has remote signer initialized.
 // A valid remote profile (default or not) has remote signer initialized.
 // In addition, a remote profile must has a valid auth provider if auth
 // 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 {
 func (p *SigningProfile) validProfile(isDefault bool) bool {
 	if p == nil {
 	if p == nil {
 		return false
 		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")
 	log.Debugf("profile is valid")
 	return true
 	return true
 }
 }
@@ -613,7 +699,7 @@ func LoadFile(path string) (*Config, error) {
 		return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("invalid path"))
 		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 {
 	if err != nil {
 		return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("could not read configuration file"))
 		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.
 // 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
 // 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,
 // 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
 // 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
 // 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:
 // 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,
 // There are 6 possible ContentTypes, data, signedData, envelopedData,
 // signedAndEnvelopedData, digestedData, and encryptedData.  Here signedData, Data, and encrypted
 // signedAndEnvelopedData, digestedData, and encryptedData.  Here signedData, Data, and encrypted
@@ -22,15 +22,14 @@
 // formats.
 // formats.
 // The ContentType signedData has the form:
 // 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
 // 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
 // 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/asn1"
 	"encoding/pem"
 	"encoding/pem"
 	"errors"
 	"errors"
+	"fmt"
 	"net"
 	"net"
 	"net/mail"
 	"net/mail"
+	"net/url"
+	"strconv"
 	"strings"
 	"strings"
 
 
 	cferr "github.com/cloudflare/cfssl/errors"
 	cferr "github.com/cloudflare/cfssl/errors"
@@ -29,46 +32,40 @@ const (
 
 
 // A Name contains the SubjectInfo fields.
 // A Name contains the SubjectInfo fields.
 type Name struct {
 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"`
 	A string `json:"algo" yaml:"algo"`
 	S int    `json:"size" yaml:"size"`
 	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.
 // Algo returns the requested key algorithm represented as a string.
-func (kr *BasicKeyRequest) Algo() string {
+func (kr *KeyRequest) Algo() string {
 	return kr.A
 	return kr.A
 }
 }
 
 
 // Size returns the requested key size.
 // Size returns the requested key size.
-func (kr *BasicKeyRequest) Size() int {
+func (kr *KeyRequest) Size() int {
 	return kr.S
 	return kr.S
 }
 }
 
 
 // Generate generates a key as specified in the request. Currently,
 // Generate generates a key as specified in the request. Currently,
 // only ECDSA and RSA are supported.
 // 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())
 	log.Debugf("generate key from request: algo=%s, size=%d", kr.Algo(), kr.Size())
 	switch kr.Algo() {
 	switch kr.Algo() {
 	case "rsa":
 	case "rsa":
@@ -99,7 +96,7 @@ func (kr *BasicKeyRequest) Generate() (crypto.PrivateKey, error) {
 
 
 // SigAlgo returns an appropriate X.509 signature algorithm given the
 // SigAlgo returns an appropriate X.509 signature algorithm given the
 // key request's type and size.
 // key request's type and size.
-func (kr *BasicKeyRequest) SigAlgo() x509.SignatureAlgorithm {
+func (kr *KeyRequest) SigAlgo() x509.SignatureAlgorithm {
 	switch kr.Algo() {
 	switch kr.Algo() {
 	case "rsa":
 	case "rsa":
 		switch {
 		switch {
@@ -139,19 +136,22 @@ type CAConfig struct {
 // A CertificateRequest encapsulates the API interface to the
 // A CertificateRequest encapsulates the API interface to the
 // certificate request functionality.
 // certificate request functionality.
 type CertificateRequest struct {
 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
 // New returns a new, empty CertificateRequest with a
-// BasicKeyRequest.
+// KeyRequest.
 func New() *CertificateRequest {
 func New() *CertificateRequest {
 	return &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.
 // 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
 	var name pkix.Name
 	name.CommonName = cr.CN
 	name.CommonName = cr.CN
 
 
@@ -173,9 +190,19 @@ func (cr *CertificateRequest) Name() pkix.Name {
 		appendIf(n.L, &name.Locality)
 		appendIf(n.L, &name.Locality)
 		appendIf(n.O, &name.Organization)
 		appendIf(n.O, &name.Organization)
 		appendIf(n.OU, &name.OrganizationalUnit)
 		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
 	name.SerialNumber = cr.SerialNumber
-	return name
+	return name, nil
 }
 }
 
 
 // BasicConstraints CSR information RFC 5280, 4.2.1.9
 // 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) {
 func ParseRequest(req *CertificateRequest) (csr, key []byte, err error) {
 	log.Info("received CSR")
 	log.Info("received CSR")
 	if req.KeyRequest == nil {
 	if req.KeyRequest == nil {
-		req.KeyRequest = NewBasicKeyRequest()
+		req.KeyRequest = NewKeyRequest()
 	}
 	}
 
 
 	log.Infof("generating key: %s-%d", req.KeyRequest.Algo(), req.KeyRequest.Size())
 	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 {
 	for _, email := range cert.EmailAddresses {
 		hosts = append(hosts, email)
 		hosts = append(hosts, email)
 	}
 	}
+	for _, uri := range cert.URIs {
+		hosts = append(hosts, uri.String())
+	}
 
 
 	return hosts
 	return hosts
 }
 }
 
 
 // getNames returns an array of Names from the certificate
 // 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 {
 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 := func(v1 int, vn ...int) (max int) {
 		max = v1
 		max = v1
 		for i := 0; i < len(vn); i++ {
 		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)
 		return nil, cferr.New(cferr.PrivateKeyError, cferr.Unavailable)
 	}
 	}
 
 
+	subj, err := req.Name()
+	if err != nil {
+		return nil, err
+	}
+
 	var tpl = x509.CertificateRequest{
 	var tpl = x509.CertificateRequest{
-		Subject:            req.Name(),
+		Subject:            subj,
 		SignatureAlgorithm: sigAlgo,
 		SignatureAlgorithm: sigAlgo,
 	}
 	}
 
 
@@ -379,11 +414,15 @@ func Generate(priv crypto.Signer, req *CertificateRequest) (csr []byte, err erro
 			tpl.IPAddresses = append(tpl.IPAddresses, ip)
 			tpl.IPAddresses = append(tpl.IPAddresses, ip)
 		} else if email, err := mail.ParseAddress(req.Hosts[i]); err == nil && email != nil {
 		} else if email, err := mail.ParseAddress(req.Hosts[i]); err == nil && email != nil {
 			tpl.EmailAddresses = append(tpl.EmailAddresses, email.Address)
 			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 {
 		} else {
 			tpl.DNSNames = append(tpl.DNSNames, req.Hosts[i])
 			tpl.DNSNames = append(tpl.DNSNames, req.Hosts[i])
 		}
 		}
 	}
 	}
 
 
+	tpl.ExtraExtensions = []pkix.Extension{}
+
 	if req.CA != nil {
 	if req.CA != nil {
 		err = appendCAInfoToCSR(req.CA, &tpl)
 		err = appendCAInfoToCSR(req.CA, &tpl)
 		if err != nil {
 		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)
 	csr, err = x509.CreateCertificateRequest(rand.Reader, &tpl, priv)
 	if err != nil {
 	if err != nil {
 		log.Errorf("failed to generate a CSR: %v", err)
 		log.Errorf("failed to generate a CSR: %v", err)
@@ -420,13 +471,19 @@ func appendCAInfoToCSR(reqConf *CAConfig, csr *x509.CertificateRequest) error {
 		return err
 		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
 	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"}
 Example: {"code":1002, "message": "Failed to decode certificate"}
 
 
 The index of codes are listed below:
 The index of codes are listed below:
+
 	1XXX: CertificateError
 	1XXX: CertificateError
 	    1000: Unknown
 	    1000: Unknown
 	    1001: ReadFailed
 	    1001: ReadFailed

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

@@ -5,14 +5,15 @@ package derhelpers
 import (
 import (
 	"crypto"
 	"crypto"
 	"crypto/ecdsa"
 	"crypto/ecdsa"
+	"crypto/ed25519"
 	"crypto/rsa"
 	"crypto/rsa"
 	"crypto/x509"
 	"crypto/x509"
 
 
 	cferr "github.com/cloudflare/cfssl/errors"
 	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) {
 func ParsePrivateKeyDER(keyDER []byte) (key crypto.Signer, err error) {
 	generalKey, err := x509.ParsePKCS8PrivateKey(keyDER)
 	generalKey, err := x509.ParsePKCS8PrivateKey(keyDER)
 	if err != nil {
 	if err != nil {
@@ -20,12 +21,15 @@ func ParsePrivateKeyDER(keyDER []byte) (key crypto.Signer, err error) {
 		if err != nil {
 		if err != nil {
 			generalKey, err = x509.ParseECPrivateKey(keyDER)
 			generalKey, err = x509.ParseECPrivateKey(keyDER)
 			if err != nil {
 			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
 		return generalKey.(*rsa.PrivateKey), nil
 	case *ecdsa.PrivateKey:
 	case *ecdsa.PrivateKey:
 		return generalKey.(*ecdsa.PrivateKey), nil
 		return generalKey.(*ecdsa.PrivateKey), nil
+	case ed25519.PrivateKey:
+		return generalKey.(ed25519.PrivateKey), nil
 	}
 	}
 
 
 	// should never reach here
 	// 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"
 	"encoding/pem"
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"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"
 	"strings"
 	"time"
 	"time"
 
 
@@ -30,6 +23,11 @@ import (
 	cferr "github.com/cloudflare/cfssl/errors"
 	cferr "github.com/cloudflare/cfssl/errors"
 	"github.com/cloudflare/cfssl/helpers/derhelpers"
 	"github.com/cloudflare/cfssl/helpers/derhelpers"
 	"github.com/cloudflare/cfssl/log"
 	"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"
 	"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.
 // OneDay is a time.Duration representing a day's worth of seconds.
 const OneDay = 24 * time.Hour
 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
 // InclusiveDate returns the time.Time representation of a date - 1
 // nanosecond. This allows time.After to be used inclusively.
 // nanosecond. This allows time.After to be used inclusively.
 func InclusiveDate(year int, month time.Month, day int) time.Time {
 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
 // EncodeCertificatesPEM encodes a number of x509 certificates to PEM
 func EncodeCertificatesPEM(certs []*x509.Certificate) []byte {
 func EncodeCertificatesPEM(certs []*x509.Certificate) []byte {
 	var buffer bytes.Buffer
 	var buffer bytes.Buffer
@@ -322,7 +343,7 @@ func LoadPEMCertPool(certsFile string) (*x509.CertPool, error) {
 	if certsFile == "" {
 	if certsFile == "" {
 		return nil, nil
 		return nil, nil
 	}
 	}
-	pemCerts, err := ioutil.ReadFile(certsFile)
+	pemCerts, err := os.ReadFile(certsFile)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		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.
 // GetKeyDERFromPEM parses a PEM-encoded private key and returns DER-format key bytes.
 func GetKeyDERFromPEM(in []byte, password []byte) ([]byte, error) {
 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 keyDER != nil {
 		if procType, ok := keyDER.Headers["Proc-Type"]; ok {
 		if procType, ok := keyDER.Headers["Proc-Type"]; ok {
 			if strings.Contains(procType, "ENCRYPTED") {
 			if strings.Contains(procType, "ENCRYPTED") {
@@ -460,7 +489,7 @@ func LoadClientCertificate(certFile string, keyFile string) (*tls.Certificate, e
 	if certFile != "" && keyFile != "" {
 	if certFile != "" && keyFile != "" {
 		cert, err := tls.LoadX509KeyPair(certFile, keyFile)
 		cert, err := tls.LoadX509KeyPair(certFile, keyFile)
 		if err != nil {
 		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
 			return nil, err
 		}
 		}
 		log.Debug("Client certificate loaded ")
 		log.Debug("Client certificate loaded ")
@@ -560,13 +589,13 @@ func SCTListFromOCSPResponse(response *ocsp.Response) ([]ct.SignedCertificateTim
 func ReadBytes(valFile string) ([]byte, error) {
 func ReadBytes(valFile string) ([]byte, error) {
 	switch splitVal := strings.SplitN(valFile, ":", 2); len(splitVal) {
 	switch splitVal := strings.SplitN(valFile, ":", 2); len(splitVal) {
 	case 1:
 	case 1:
-		return ioutil.ReadFile(valFile)
+		return os.ReadFile(valFile)
 	case 2:
 	case 2:
 		switch splitVal[0] {
 		switch splitVal[0] {
 		case "env":
 		case "env":
 			return []byte(os.Getenv(splitVal[1])), nil
 			return []byte(os.Getenv(splitVal[1])), nil
 		case "file":
 		case "file":
-			return ioutil.ReadFile(splitVal[1])
+			return os.ReadFile(splitVal[1])
 		default:
 		default:
 			return nil, fmt.Errorf("unknown prefix: %s", splitVal[0])
 			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}
 	g := &csr.Generator{Validator: validator}
 	csrPEM, key, err = g.ProcessRequest(req)
 	csrPEM, key, err = g.ProcessRequest(req)
 	if err != nil {
 	if err != nil {

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

@@ -3,20 +3,27 @@ package local
 
 
 import (
 import (
 	"bytes"
 	"bytes"
+	"context"
 	"crypto"
 	"crypto"
+	"crypto/ecdsa"
+	"crypto/elliptic"
 	"crypto/rand"
 	"crypto/rand"
 	"crypto/x509"
 	"crypto/x509"
 	"crypto/x509/pkix"
 	"crypto/x509/pkix"
+	"database/sql"
 	"encoding/asn1"
 	"encoding/asn1"
 	"encoding/hex"
 	"encoding/hex"
 	"encoding/pem"
 	"encoding/pem"
 	"errors"
 	"errors"
+	"fmt"
 	"io"
 	"io"
 	"math/big"
 	"math/big"
 	"net"
 	"net"
 	"net/http"
 	"net/http"
 	"net/mail"
 	"net/mail"
+	"net/url"
 	"os"
 	"os"
+	"time"
 
 
 	"github.com/cloudflare/cfssl/certdb"
 	"github.com/cloudflare/cfssl/certdb"
 	"github.com/cloudflare/cfssl/config"
 	"github.com/cloudflare/cfssl/config"
@@ -25,17 +32,23 @@ import (
 	"github.com/cloudflare/cfssl/info"
 	"github.com/cloudflare/cfssl/info"
 	"github.com/cloudflare/cfssl/log"
 	"github.com/cloudflare/cfssl/log"
 	"github.com/cloudflare/cfssl/signer"
 	"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/client"
 	"github.com/google/certificate-transparency-go/jsonclient"
 	"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
 // Signer contains a signer that uses the standard library to
 // support both ECDSA and RSA CA keys.
 // support both ECDSA and RSA CA keys.
 type Signer struct {
 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
 	policy     *config.Signing
 	sigAlgo    x509.SignatureAlgorithm
 	sigAlgo    x509.SignatureAlgorithm
 	dbAccessor certdb.Accessor
 	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)
 		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{
 	return &Signer{
-		ca:      cert,
-		priv:    priv,
-		sigAlgo: sigAlgo,
-		policy:  policy,
+		ca:       cert,
+		priv:     priv,
+		lintPriv: lintPriv,
+		sigAlgo:  sigAlgo,
+		policy:   policy,
 	}, nil
 	}, nil
 }
 }
 
 
@@ -89,14 +121,75 @@ func NewSignerFromFile(caFile, caKeyFile string, policy *config.Signing) (*Signe
 
 
 	priv, err := helpers.ParsePrivateKeyPEMWithPassword(cakey, password)
 	priv, err := helpers.ParsePrivateKeyPEMWithPassword(cakey, password)
 	if err != nil {
 	if err != nil {
-		log.Debug("Malformed private key %v", err)
+		log.Debugf("Malformed private key %v", err)
 		return nil, err
 		return nil, err
 	}
 	}
 
 
 	return NewSigner(priv, parsedCa, signer.DefaultSigAlgo(priv), policy)
 	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
 	var initRoot bool
 	if s.ca == nil {
 	if s.ca == nil {
 		if !template.IsCA {
 		if !template.IsCA {
@@ -105,10 +198,15 @@ func (s *Signer) sign(template *x509.Certificate) (cert []byte, err error) {
 		}
 		}
 		template.DNSNames = nil
 		template.DNSNames = nil
 		template.EmailAddresses = nil
 		template.EmailAddresses = nil
+		template.URIs = nil
 		s.ca = template
 		s.ca = template
 		initRoot = true
 		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)
 	derBytes, err := x509.CreateCertificate(rand.Reader, template, s.ca, template.PublicKey, s.priv)
 	if err != nil {
 	if err != nil {
 		return nil, cferr.Wrap(cferr.CertificateError, cferr.Unknown, err)
 		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
 	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.
 // content of hosts, if it is not nil.
 func OverrideHosts(template *x509.Certificate, hosts []string) {
 func OverrideHosts(template *x509.Certificate, hosts []string) {
 	if hosts != nil {
 	if hosts != nil {
 		template.IPAddresses = []net.IP{}
 		template.IPAddresses = []net.IP{}
 		template.EmailAddresses = []string{}
 		template.EmailAddresses = []string{}
 		template.DNSNames = []string{}
 		template.DNSNames = []string{}
+		template.URIs = []*url.URL{}
 	}
 	}
 
 
 	for i := range hosts {
 	for i := range hosts {
@@ -173,6 +272,8 @@ func OverrideHosts(template *x509.Certificate, hosts []string) {
 			template.IPAddresses = append(template.IPAddresses, ip)
 			template.IPAddresses = append(template.IPAddresses, ip)
 		} else if email, err := mail.ParseAddress(hosts[i]); err == nil && email != nil {
 		} else if email, err := mail.ParseAddress(hosts[i]); err == nil && email != nil {
 			template.EmailAddresses = append(template.EmailAddresses, email.Address)
 			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 {
 		} else {
 			template.DNSNames = append(template.DNSNames, hosts[i])
 			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"))
 			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 {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -232,6 +333,9 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
 		if profile.CSRWhitelist.EmailAddresses {
 		if profile.CSRWhitelist.EmailAddresses {
 			safeTemplate.EmailAddresses = csrTemplate.EmailAddresses
 			safeTemplate.EmailAddresses = csrTemplate.EmailAddresses
 		}
 		}
+		if profile.CSRWhitelist.URIs {
+			safeTemplate.URIs = csrTemplate.URIs
+		}
 	}
 	}
 
 
 	if req.CRLOverride != "" {
 	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)
 				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 {
 	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 poisonExtension = pkix.Extension{Id: signer.CTPoisonOID, Critical: true, Value: []byte{0x05, 0x00}}
 		var poisonedPreCert = certTBS
 		var poisonedPreCert = certTBS
 		poisonedPreCert.ExtraExtensions = append(safeTemplate.ExtraExtensions, poisonExtension)
 		poisonedPreCert.ExtraExtensions = append(safeTemplate.ExtraExtensions, poisonExtension)
-		cert, err = s.sign(&poisonedPreCert)
+		cert, err = s.sign(&poisonedPreCert, profile.LintErrLevel, profile.LintRegistry)
 		if err != nil {
 		if err != nil {
 			return
 			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}
 		var SCTListExtension = pkix.Extension{Id: signer.SCTListOID, Critical: false, Value: serializedSCTList}
 		certTBS.ExtraExtensions = append(certTBS.ExtraExtensions, SCTListExtension)
 		certTBS.ExtraExtensions = append(certTBS.ExtraExtensions, SCTListExtension)
 	}
 	}
+
 	var signedCert []byte
 	var signedCert []byte
-	signedCert, err = s.sign(&certTBS)
+	signedCert, err = s.sign(&certTBS, profile.LintErrLevel, profile.LintRegistry)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -397,19 +507,29 @@ func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
 	parsedCert, _ := helpers.ParseCertificatePEM(signedCert)
 	parsedCert, _ := helpers.ParseCertificatePEM(signedCert)
 
 
 	if s.dbAccessor != nil {
 	if s.dbAccessor != nil {
+		now := time.Now()
 		var certRecord = certdb.CertificateRecord{
 		var certRecord = certdb.CertificateRecord{
 			Serial: certTBS.SerialNumber.String(),
 			Serial: certTBS.SerialNumber.String(),
 			// this relies on the specific behavior of x509.CreateCertificate
 			// this relies on the specific behavior of x509.CreateCertificate
 			// which sets the AuthorityKeyId from the signer's SubjectKeyId
 			// 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
 			return nil, err
 		}
 		}
 		log.Debug("saved certificate with serial number ", certTBS.SerialNumber)
 		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
 // 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
 // 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
 // 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) {
 func (s *Signer) SignFromPrecert(precert *x509.Certificate, scts []ct.SignedCertificateTimestamp) ([]byte, error) {
 	// Verify certificate was signed by s.ca
 	// Verify certificate was signed by s.ca
 	if err := precert.CheckSignatureFrom(s.ca); err != nil {
 	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
 	// 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.
 	// use memory that may be altered by us or the caller at a later stage.
 	tbsCert := x509.Certificate{
 	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,
 		IsCA:                        precert.IsCA,
 		MaxPathLen:                  precert.MaxPathLen,
 		MaxPathLen:                  precert.MaxPathLen,
 		MaxPathLenZero:              precert.MaxPathLenZero,
 		MaxPathLenZero:              precert.MaxPathLenZero,
@@ -493,8 +615,10 @@ func (s *Signer) SignFromPrecert(precert *x509.Certificate, scts []ct.SignedCert
 	// Insert the SCT list extension
 	// Insert the SCT list extension
 	tbsCert.ExtraExtensions = append(tbsCert.ExtraExtensions, sctExt)
 	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.
 // 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/config"
 	"github.com/cloudflare/cfssl/csr"
 	"github.com/cloudflare/cfssl/csr"
 	cferr "github.com/cloudflare/cfssl/errors"
 	cferr "github.com/cloudflare/cfssl/errors"
+	"github.com/cloudflare/cfssl/helpers"
 	"github.com/cloudflare/cfssl/info"
 	"github.com/cloudflare/cfssl/info"
 )
 )
 
 
@@ -45,7 +46,7 @@ type Extension struct {
 // Extensions provided in the signRequest are copied into the certificate, as
 // Extensions provided in the signRequest are copied into the certificate, as
 // long as they are in the ExtensionWhitelist for the signer's policy.
 // long as they are in the ExtensionWhitelist for the signer's policy.
 // Extensions requested in the CSR are ignored, except for those processed by
 // Extensions requested in the CSR are ignored, except for those processed by
-// ParseCertificateRequest (mainly subjectAltName).
+// ParseCertificateRequest (mainly subjectAltName) and DelegationUsage.
 type SignRequest struct {
 type SignRequest struct {
 	Hosts       []string    `json:"hosts"`
 	Hosts       []string    `json:"hosts"`
 	Request     string      `json:"certificate_request"`
 	Request     string      `json:"certificate_request"`
@@ -70,6 +71,9 @@ type SignRequest struct {
 	// be passed to SignFromPrecert with the SCTs in order to create a
 	// be passed to SignFromPrecert with the SCTs in order to create a
 	// valid certificate.
 	// valid certificate.
 	ReturnPrecert bool
 	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.
 // 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
 // ParseCertificateRequest takes an incoming certificate request and
 // builds a certificate template from it.
 // 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)
 	csrv, err := x509.ParseCertificateRequest(csrBytes)
 	if err != nil {
 	if err != nil {
 		err = cferr.Wrap(cferr.CSRError, cferr.ParseFailed, err)
 		err = cferr.Wrap(cferr.CSRError, cferr.ParseFailed, err)
 		return
 		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()
 	err = csrv.CheckSignature()
 	if err != nil {
 	if err != nil {
 		err = cferr.Wrap(cferr.CSRError, cferr.KeyMismatch, err)
 		err = cferr.Wrap(cferr.CSRError, cferr.KeyMismatch, err)
@@ -185,13 +212,16 @@ func ParseCertificateRequest(s Signer, csrBytes []byte) (template *x509.Certific
 	}
 	}
 
 
 	template = &x509.Certificate{
 	template = &x509.Certificate{
-		Subject:            csrv.Subject,
+		Subject:            subject,
 		PublicKeyAlgorithm: csrv.PublicKeyAlgorithm,
 		PublicKeyAlgorithm: csrv.PublicKeyAlgorithm,
 		PublicKey:          csrv.PublicKey,
 		PublicKey:          csrv.PublicKey,
 		SignatureAlgorithm: s.SigAlgo(),
 		SignatureAlgorithm: s.SigAlgo(),
 		DNSNames:           csrv.DNSNames,
 		DNSNames:           csrv.DNSNames,
 		IPAddresses:        csrv.IPAddresses,
 		IPAddresses:        csrv.IPAddresses,
 		EmailAddresses:     csrv.EmailAddresses,
 		EmailAddresses:     csrv.EmailAddresses,
+		URIs:               csrv.URIs,
+		Extensions:         csrv.Extensions,
+		ExtraExtensions:    []pkix.Extension{},
 	}
 	}
 
 
 	for _, val := range csrv.Extensions {
 	for _, val := range csrv.Extensions {
@@ -211,6 +241,13 @@ func ParseCertificateRequest(s Signer, csrBytes []byte) (template *x509.Certific
 			template.IsCA = constraints.IsCA
 			template.IsCA = constraints.IsCA
 			template.MaxPathLen = constraints.MaxPathLen
 			template.MaxPathLen = constraints.MaxPathLen
 			template.MaxPathLenZero = template.MaxPathLen == 0
 			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.DNSNames = nil
 		template.EmailAddresses = nil
 		template.EmailAddresses = nil
+		template.URIs = nil
 	}
 	}
 	template.SubjectKeyId = ski
 	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"
 	"sync"
 	"time"
 	"time"
 
 
-	"github.com/sirupsen/logrus"
-
 	"github.com/docker/docker/pkg/plugingetter"
 	"github.com/docker/docker/pkg/plugingetter"
 
 
 	"github.com/moby/swarmkit/v2/agent/csi/plugin"
 	"github.com/moby/swarmkit/v2/agent/csi/plugin"
@@ -65,7 +63,7 @@ func (r *volumes) retryVolumes() {
 	for {
 	for {
 		vid, attempt := r.pendingVolumes.Wait()
 		vid, attempt := r.pendingVolumes.Wait()
 
 
-		dctx := log.WithFields(ctx, logrus.Fields{
+		dctx := log.WithFields(ctx, log.Fields{
 			"volume.id": vid,
 			"volume.id": vid,
 			"attempt":   fmt.Sprintf("%d", attempt),
 			"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/log"
 	"github.com/moby/swarmkit/v2/protobuf/ptypes"
 	"github.com/moby/swarmkit/v2/protobuf/ptypes"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
-	"github.com/sirupsen/logrus"
 )
 )
 
 
 // Controller controls execution of a task.
 // 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) {
 func logStateChange(ctx context.Context, desired, previous, next api.TaskState) {
 	if previous != next {
 	if previous != next {
-		fields := logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"state.transition": fmt.Sprintf("%v->%v", previous, next),
 			"state.transition": fmt.Sprintf("%v->%v", previous, next),
 			"state.desired":    desired,
 			"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/api"
 	"github.com/moby/swarmkit/v2/connectionbroker"
 	"github.com/moby/swarmkit/v2/connectionbroker"
 	"github.com/moby/swarmkit/v2/log"
 	"github.com/moby/swarmkit/v2/log"
-	"github.com/sirupsen/logrus"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 	"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
 	heartbeat := time.NewTimer(1) // send out a heartbeat right away
 	defer heartbeat.Stop()
 	defer heartbeat.Stop()
 
 
-	fields := logrus.Fields{
+	fields := log.Fields{
 		"sessionID": s.sessionID,
 		"sessionID": s.sessionID,
 		"method":    "(*session).heartbeat",
 		"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 {
 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)
 	client := api.NewLogBrokerClient(s.conn.ClientConn)
 	subscriptions, err := client.ListenSubscriptions(ctx, &api.ListenSubscriptionsRequest{})
 	subscriptions, err := client.ListenSubscriptions(ctx, &api.ListenSubscriptionsRequest{})
@@ -257,7 +256,7 @@ func (s *session) logSubscriptions(ctx context.Context) error {
 		resp, err := subscriptions.Recv()
 		resp, err := subscriptions.Recv()
 		st, _ := status.FromError(err)
 		st, _ := status.FromError(err)
 		if st.Code() == codes.Unimplemented {
 		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
 			// Don't return, because returning would bounce the session
 			select {
 			select {
 			case <-s.closed:
 			case <-s.closed:
@@ -281,8 +280,8 @@ func (s *session) logSubscriptions(ctx context.Context) error {
 }
 }
 
 
 func (s *session) watch(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 (
 	var (
 		resp            *api.AssignmentsMessage
 		resp            *api.AssignmentsMessage
 		assignmentWatch api.Dispatcher_AssignmentsClient
 		assignmentWatch api.Dispatcher_AssignmentsClient
@@ -313,7 +312,7 @@ func (s *session) watch(ctx context.Context) error {
 				}
 				}
 				tasksFallback = true
 				tasksFallback = true
 				assignmentWatch = nil
 				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/api"
 	"github.com/moby/swarmkit/v2/log"
 	"github.com/moby/swarmkit/v2/log"
 	"github.com/moby/swarmkit/v2/watch"
 	"github.com/moby/swarmkit/v2/watch"
-	"github.com/sirupsen/logrus"
 	bolt "go.etcd.io/bbolt"
 	bolt "go.etcd.io/bbolt"
 )
 )
 
 
@@ -135,7 +134,7 @@ func (w *worker) Assign(ctx context.Context, assignments []*api.AssignmentChange
 		return ErrClosed
 		return ErrClosed
 	}
 	}
 
 
-	log.G(ctx).WithFields(logrus.Fields{
+	log.G(ctx).WithFields(log.Fields{
 		"len(assignments)": len(assignments),
 		"len(assignments)": len(assignments),
 	}).Debug("(*worker).Assign")
 	}).Debug("(*worker).Assign")
 
 
@@ -174,7 +173,7 @@ func (w *worker) Update(ctx context.Context, assignments []*api.AssignmentChange
 		return ErrClosed
 		return ErrClosed
 	}
 	}
 
 
-	log.G(ctx).WithFields(logrus.Fields{
+	log.G(ctx).WithFields(log.Fields{
 		"len(assignments)": len(assignments),
 		"len(assignments)": len(assignments),
 	}).Debug("(*worker).Update")
 	}).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(updatedTasks)": len(updatedTasks),
 		"len(removedTasks)": len(removedTasks),
 		"len(removedTasks)": len(removedTasks),
 	}).Debug("(*worker).reconcileTaskState")
 	}).Debug("(*worker).reconcileTaskState")
@@ -227,10 +226,10 @@ func reconcileTaskState(ctx context.Context, w *worker, assignments []*api.Assig
 	assigned := map[string]struct{}{}
 	assigned := map[string]struct{}{}
 
 
 	for _, task := range updatedTasks {
 	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 {
 		if err := PutTask(tx, task); err != nil {
 			return err
 			return err
 		}
 		}
@@ -359,7 +358,7 @@ func reconcileSecrets(ctx context.Context, w *worker, assignments []*api.Assignm
 
 
 	secrets := secretsProvider.Secrets()
 	secrets := secretsProvider.Secrets()
 
 
-	log.G(ctx).WithFields(logrus.Fields{
+	log.G(ctx).WithFields(log.Fields{
 		"len(updatedSecrets)": len(updatedSecrets),
 		"len(updatedSecrets)": len(updatedSecrets),
 		"len(removedSecrets)": len(removedSecrets),
 		"len(removedSecrets)": len(removedSecrets),
 	}).Debug("(*worker).reconcileSecrets")
 	}).Debug("(*worker).reconcileSecrets")
@@ -402,7 +401,7 @@ func reconcileConfigs(ctx context.Context, w *worker, assignments []*api.Assignm
 
 
 	configs := configsProvider.Configs()
 	configs := configsProvider.Configs()
 
 
-	log.G(ctx).WithFields(logrus.Fields{
+	log.G(ctx).WithFields(log.Fields{
 		"len(updatedConfigs)": len(updatedConfigs),
 		"len(updatedConfigs)": len(updatedConfigs),
 		"len(removedConfigs)": len(removedConfigs),
 		"len(removedConfigs)": len(removedConfigs),
 	}).Debug("(*worker).reconcileConfigs")
 	}).Debug("(*worker).reconcileConfigs")
@@ -448,7 +447,7 @@ func reconcileVolumes(ctx context.Context, w *worker, assignments []*api.Assignm
 
 
 	volumes := volumesProvider.Volumes()
 	volumes := volumesProvider.Volumes()
 
 
-	log.G(ctx).WithFields(logrus.Fields{
+	log.G(ctx).WithFields(log.Fields{
 		"len(updatedVolumes)": len(updatedVolumes),
 		"len(updatedVolumes)": len(updatedVolumes),
 		"len(removedVolumes)": len(removedVolumes),
 		"len(removedVolumes)": len(removedVolumes),
 	}).Debug("(*worker).reconcileVolumes")
 	}).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) {
 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,
 		"task.id":    task.ID,
 		"service.id": task.ServiceID,
 		"service.id": task.ServiceID,
 	}))
 	}))

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

@@ -6,8 +6,6 @@ import (
 	"crypto/x509/pkix"
 	"crypto/x509/pkix"
 	"strings"
 	"strings"
 
 
-	"github.com/sirupsen/logrus"
-
 	"github.com/moby/swarmkit/v2/api"
 	"github.com/moby/swarmkit/v2/api"
 	"github.com/moby/swarmkit/v2/log"
 	"github.com/moby/swarmkit/v2/log"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/codes"
@@ -43,7 +41,7 @@ func LogTLSState(ctx context.Context, tlsState *tls.ConnectionState) {
 		verifiedChain = append(verifiedChain, strings.Join(subjects, ","))
 		verifiedChain = append(verifiedChain, strings.Join(subjects, ","))
 	}
 	}
 
 
-	log.G(ctx).WithFields(logrus.Fields{
+	log.G(ctx).WithFields(log.Fields{
 		"peer.peerCert": peerCerts,
 		"peer.peerCert": peerCerts,
 		// "peer.verifiedChain": verifiedChain},
 		// "peer.verifiedChain": verifiedChain},
 	}).Debugf("")
 	}).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
 	// Create a simple CSR for the CA using the default CA validator and policy
 	req := cfcsr.CertificateRequest{
 	req := cfcsr.CertificateRequest{
 		CN:         rootCN,
 		CN:         rootCN,
-		KeyRequest: &cfcsr.BasicKeyRequest{A: RootKeyAlgo, S: RootKeySize},
+		KeyRequest: &cfcsr.KeyRequest{A: RootKeyAlgo, S: RootKeySize},
 		CA:         &cfcsr.CAConfig{Expiry: RootCAExpiration},
 		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
 // GenerateNewCSR returns a newly generated key and CSR signed with said key
 func GenerateNewCSR() ([]byte, []byte, error) {
 func GenerateNewCSR() ([]byte, []byte, error) {
 	req := &cfcsr.CertificateRequest{
 	req := &cfcsr.CertificateRequest{
-		KeyRequest: cfcsr.NewBasicKeyRequest(),
+		KeyRequest: cfcsr.NewKeyRequest(),
 	}
 	}
 
 
 	csr, key, err := cfcsr.ParseRequest(req)
 	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/moby/swarmkit/v2/watch"
 	"github.com/opencontainers/go-digest"
 	"github.com/opencontainers/go-digest"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
-	"github.com/sirupsen/logrus"
 	"google.golang.org/grpc/credentials"
 	"google.golang.org/grpc/credentials"
 )
 )
 
 
@@ -463,7 +462,7 @@ func LoadSecurityConfig(ctx context.Context, rootCA RootCA, krw *KeyReadWriter,
 		PublicKey: issuer.RawSubjectPublicKeyInfo,
 		PublicKey: issuer.RawSubjectPublicKeyInfo,
 	})
 	})
 	if err == nil {
 	if err == nil {
-		log.G(ctx).WithFields(logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"node.id":   secConfig.ClientTLSCreds.NodeID(),
 			"node.id":   secConfig.ClientTLSCreds.NodeID(),
 			"node.role": secConfig.ClientTLSCreds.Role(),
 			"node.role": secConfig.ClientTLSCreds.Role(),
 		}).Debug("loaded node credentials")
 		}).Debug("loaded node credentials")
@@ -524,12 +523,12 @@ func (rootCA RootCA) CreateSecurityConfig(ctx context.Context, krw *KeyReadWrite
 			return nil, nil, err
 			return nil, nil, err
 		}
 		}
 	case nil:
 	case nil:
-		log.G(ctx).WithFields(logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"node.id":   cn,
 			"node.id":   cn,
 			"node.role": proposedRole,
 			"node.role": proposedRole,
 		}).Debug("issued new TLS certificate")
 		}).Debug("issued new TLS certificate")
 	default:
 	default:
-		log.G(ctx).WithFields(logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"node.id":   cn,
 			"node.id":   cn,
 			"node.role": proposedRole,
 			"node.role": proposedRole,
 		}).WithError(err).Errorf("failed to issue and save new certificate")
 		}).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)
 	secConfig, cleanup, err := NewSecurityConfig(&rootCA, krw, tlsKeyPair, issuerInfo)
 	if err == nil {
 	if err == nil {
-		log.G(ctx).WithFields(logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"node.id":   secConfig.ClientTLSCreds.NodeID(),
 			"node.id":   secConfig.ClientTLSCreds.NodeID(),
 			"node.role": secConfig.ClientTLSCreds.Role(),
 			"node.role": secConfig.ClientTLSCreds.Role(),
 		}).Debugf("new node credentials generated: %s", krw.Target())
 		}).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()
 	defer s.renewalMu.Unlock()
 
 
 	ctx = log.WithModule(ctx, "tls")
 	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.id":   s.ClientTLSCreds.NodeID(),
 		"node.role": s.ClientTLSCreds.Role(),
 		"node.role": s.ClientTLSCreds.Role(),
 	})
 	})
@@ -602,7 +601,7 @@ func RenewTLSConfigNow(ctx context.Context, s *SecurityConfig, connBroker *conne
 		}
 		}
 	}
 	}
 	if err != nil {
 	if err != nil {
-		log.WithError(err).Errorf("failed to renew the certificate")
+		logger.WithError(err).Errorf("failed to renew the certificate")
 		return err
 		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/cloudflare/cfssl/signer"
 	"github.com/moby/swarmkit/v2/log"
 	"github.com/moby/swarmkit/v2/log"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
-	"github.com/sirupsen/logrus"
 	"golang.org/x/net/context/ctxhttp"
 	"golang.org/x/net/context/ctxhttp"
 )
 )
 
 
@@ -203,7 +202,7 @@ func makeExternalSignRequest(ctx context.Context, client *http.Client, url strin
 
 
 	var apiResponse api.Response
 	var apiResponse api.Response
 	if err := json.Unmarshal(body, &apiResponse); err != nil {
 	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")}
 		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/connectionbroker"
 	"github.com/moby/swarmkit/v2/log"
 	"github.com/moby/swarmkit/v2/log"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
-	"github.com/sirupsen/logrus"
 )
 )
 
 
 // RenewTLSExponentialBackoff sets the exponential backoff when trying to renew TLS certificates that have expired
 // 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)
 		defer close(updates)
 		for {
 		for {
 			ctx = log.WithModule(ctx, "tls")
 			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.id":   t.s.ClientTLSCreds.NodeID(),
 				"node.role": t.s.ClientTLSCreds.Role(),
 				"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())
 			validFrom, validUntil, err := readCertValidity(t.s.KeyReader())
 			if err != nil {
 			if err != nil {
 				// We failed to read the expiration, let's stick with the starting default
 				// 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 {
 				select {
 				case updates <- CertificateUpdate{Err: errors.New("failed to read certificate expiration")}:
 				case updates <- CertificateUpdate{Err: errors.New("failed to read certificate expiration")}:
 				case <-ctx.Done():
 				case <-ctx.Done():
-					log.Info("shutting down certificate renewal routine")
+					logger.Info("shutting down certificate renewal routine")
 					return
 					return
 				}
 				}
 			} else {
 			} else {
 				// If we have an expired certificate, try to renew immediately: the hope that this is a temporary clock skew, or
 				// 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.
 				// we can issue our own TLS certs.
 				if validUntil.Before(time.Now()) {
 				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 immediately(ish) with exponential backoff
 					retry = expBackoff.Proceed(nil)
 					retry = expBackoff.Proceed(nil)
 				} else if forceRetry {
 				} 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),
 				"time": time.Now().Add(retry),
 			}).Debugf("next certificate renewal scheduled for %v from now", retry)
 			}).Debugf("next certificate renewal scheduled for %v from now", retry)
 
 
 			select {
 			select {
 			case <-time.After(retry):
 			case <-time.After(retry):
-				log.Info("renewing certificate")
+				logger.Info("renewing certificate")
 			case <-t.renew:
 			case <-t.renew:
 				forceRetry = true
 				forceRetry = true
-				log.Info("forced certificate renewal")
+				logger.Info("forced certificate renewal")
 
 
 				// Pause briefly before attempting the renewal,
 				// Pause briefly before attempting the renewal,
 				// to give the CA a chance to reconcile the
 				// to give the CA a chance to reconcile the
@@ -127,11 +126,11 @@ func (t *TLSRenewer) Start(ctx context.Context) <-chan CertificateUpdate {
 				select {
 				select {
 				case <-time.After(500 * time.Millisecond):
 				case <-time.After(500 * time.Millisecond):
 				case <-ctx.Done():
 				case <-ctx.Done():
-					log.Info("shutting down certificate renewal routine")
+					logger.Info("shutting down certificate renewal routine")
 					return
 					return
 				}
 				}
 			case <-ctx.Done():
 			case <-ctx.Done():
-				log.Info("shutting down certificate renewal routine")
+				logger.Info("shutting down certificate renewal routine")
 				return
 				return
 			}
 			}
 
 
@@ -158,7 +157,7 @@ func (t *TLSRenewer) Start(ctx context.Context) <-chan CertificateUpdate {
 			select {
 			select {
 			case updates <- certUpdate:
 			case updates <- certUpdate:
 			case <-ctx.Done():
 			case <-ctx.Done():
-				log.Info("shutting down certificate renewal routine")
+				logger.Info("shutting down certificate renewal routine")
 				return
 				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/log"
 	"github.com/moby/swarmkit/v2/manager/state/store"
 	"github.com/moby/swarmkit/v2/manager/state/store"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
-	"github.com/sirupsen/logrus"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 	"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())
 		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,
 		"node.id": node.ID,
 		"status":  node.Certificate.Status,
 		"status":  node.Certificate.Status,
 		"method":  "NodeCertificateStatus",
 		"method":  "NodeCertificateStatus",
@@ -196,7 +195,7 @@ func (s *Server) NodeCertificateStatus(ctx context.Context, request *api.NodeCer
 		}, nil
 		}, nil
 	}
 	}
 
 
-	log.G(ctx).WithFields(logrus.Fields{
+	log.G(ctx).WithFields(log.Fields{
 		"node.id": node.ID,
 		"node.id": node.ID,
 		"status":  node.Certificate.Status,
 		"status":  node.Certificate.Status,
 		"method":  "NodeCertificateStatus",
 		"method":  "NodeCertificateStatus",
@@ -326,7 +325,7 @@ func (s *Server) IssueNodeCertificate(ctx context.Context, request *api.IssueNod
 			return store.CreateNode(tx, node)
 			return store.CreateNode(tx, node)
 		})
 		})
 		if err == nil {
 		if err == nil {
-			log.G(ctx).WithFields(logrus.Fields{
+			log.G(ctx).WithFields(log.Fields{
 				"node.id":   nodeID,
 				"node.id":   nodeID,
 				"node.role": role,
 				"node.role": role,
 				"method":    "IssueNodeCertificate",
 				"method":    "IssueNodeCertificate",
@@ -339,7 +338,7 @@ func (s *Server) IssueNodeCertificate(ctx context.Context, request *api.IssueNod
 		if i == maxRetries {
 		if i == maxRetries {
 			return nil, err
 			return nil, err
 		}
 		}
-		log.G(ctx).WithFields(logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"node.id":   nodeID,
 			"node.id":   nodeID,
 			"node.role": role,
 			"node.role": role,
 			"method":    "IssueNodeCertificate",
 			"method":    "IssueNodeCertificate",
@@ -363,7 +362,7 @@ func (s *Server) issueRenewCertificate(ctx context.Context, nodeID string, csr [
 		// Attempt to retrieve the node with nodeID
 		// Attempt to retrieve the node with nodeID
 		node = store.GetNode(tx, nodeID)
 		node = store.GetNode(tx, nodeID)
 		if node == nil {
 		if node == nil {
-			log.G(ctx).WithFields(logrus.Fields{
+			log.G(ctx).WithFields(log.Fields{
 				"node.id": nodeID,
 				"node.id": nodeID,
 				"method":  "issueRenewCertificate",
 				"method":  "issueRenewCertificate",
 			}).Warnf("node does not exist")
 			}).Warnf("node does not exist")
@@ -388,7 +387,7 @@ func (s *Server) issueRenewCertificate(ctx context.Context, nodeID string, csr [
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	log.G(ctx).WithFields(logrus.Fields{
+	log.G(ctx).WithFields(log.Fields{
 		"cert.cn":   cert.CN,
 		"cert.cn":   cert.CN,
 		"cert.role": cert.Role,
 		"cert.role": cert.Role,
 		"method":    "issueRenewCertificate",
 		"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
 // 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.
 // 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) {
 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",
 		"method": "GetRootCACertificate",
 	})
 	})
 
 
@@ -477,7 +476,7 @@ func (s *Server) Run(ctx context.Context) error {
 	s.mu.Unlock()
 	s.mu.Unlock()
 
 
 	if err != nil {
 	if err != nil {
-		log.G(ctx).WithFields(logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"method": "(*Server).Run",
 			"method": "(*Server).Run",
 		}).WithError(err).Errorf("snapshot store view failed")
 		}).WithError(err).Errorf("snapshot store view failed")
 		return err
 		return err
@@ -489,7 +488,7 @@ func (s *Server) Run(ctx context.Context) error {
 	if err := s.reconcileNodeCertificates(ctx, nodes); err != nil {
 	if err := s.reconcileNodeCertificates(ctx, nodes); err != nil {
 		// We don't return here because that means the Run loop would
 		// We don't return here because that means the Run loop would
 		// never run. Log an error instead.
 		// never run. Log an error instead.
-		log.G(ctx).WithFields(logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"method": "(*Server).Run",
 			"method": "(*Server).Run",
 		}).WithError(err).Errorf("error attempting to reconcile certificates")
 		}).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
 	firstSeenCluster := s.lastSeenClusterRootCA == nil && s.lastSeenExternalCAs == nil
 	rootCAChanged := len(rCA.CACert) != 0 && !equality.RootCAEqualStable(s.lastSeenClusterRootCA, rCA)
 	rootCAChanged := len(rCA.CACert) != 0 && !equality.RootCAEqualStable(s.lastSeenClusterRootCA, rCA)
 	externalCAChanged := !equality.ExternalCAsEqualStable(s.lastSeenExternalCAs, cluster.Spec.CAConfig.ExternalCAs)
 	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,
 		"cluster.id": cluster.ID,
 		"method":     "(*Server).UpdateRootCA",
 		"method":     "(*Server).UpdateRootCA",
 	}))
 	}))
@@ -773,7 +772,7 @@ func (s *Server) signNodeCert(ctx context.Context, node *api.Node) error {
 	// Convert the role from proto format
 	// Convert the role from proto format
 	role, err := ParseRole(node.Certificate.Role)
 	role, err := ParseRole(node.Certificate.Role)
 	if err != nil {
 	if err != nil {
-		log.G(ctx).WithFields(logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"node.id": node.ID,
 			"node.id": node.ID,
 			"method":  "(*Server).signNodeCert",
 			"method":  "(*Server).signNodeCert",
 		}).WithError(err).Errorf("failed to parse role")
 		}).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 {
 	if err != nil {
-		log.G(ctx).WithFields(logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"node.id": node.ID,
 			"node.id": node.ID,
 			"method":  "(*Server).signNodeCert",
 			"method":  "(*Server).signNodeCert",
 		}).WithError(err).Errorf("failed to sign CSR")
 		}).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)
 			return store.UpdateNode(tx, node)
 		})
 		})
 		if err != nil {
 		if err != nil {
-			log.G(ctx).WithFields(logrus.Fields{
+			log.G(ctx).WithFields(log.Fields{
 				"node.id": nodeID,
 				"node.id": nodeID,
 				"method":  "(*Server).signNodeCert",
 				"method":  "(*Server).signNodeCert",
 			}).WithError(err).Errorf("transaction failed when setting state to FAILED")
 			}).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
 			return err
 		})
 		})
 		if err == nil {
 		if err == nil {
-			log.G(ctx).WithFields(logrus.Fields{
+			log.G(ctx).WithFields(log.Fields{
 				"node.id":   node.ID,
 				"node.id":   node.ID,
 				"node.role": node.Certificate.Role,
 				"node.role": node.Certificate.Role,
 				"method":    "(*Server).signNodeCert",
 				"method":    "(*Server).signNodeCert",
@@ -870,7 +869,7 @@ func (s *Server) signNodeCert(ctx context.Context, node *api.Node) error {
 			continue
 			continue
 		}
 		}
 
 
-		log.G(ctx).WithFields(logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"node.id": nodeID,
 			"node.id": nodeID,
 			"method":  "(*Server).signNodeCert",
 			"method":  "(*Server).signNodeCert",
 		}).WithError(err).Errorf("transaction failed")
 		}).WithError(err).Errorf("transaction failed")

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

@@ -23,6 +23,9 @@ type (
 	moduleKey struct{}
 	moduleKey struct{}
 )
 )
 
 
+// Fields type to pass to "WithFields".
+type Fields = map[string]any
+
 // WithLogger returns a new context with the provided logger. Use in
 // WithLogger returns a new context with the provided logger. Use in
 // combination with logger.WithField(s) for great effect.
 // combination with logger.WithField(s) for great effect.
 func WithLogger(ctx context.Context, logger *logrus.Entry) context.Context {
 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.
 // 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{})
 	logger := ctx.Value(loggerKey{})
 
 
 	if logger == nil {
 	if logger == nil {
@@ -41,7 +44,7 @@ func WithFields(ctx context.Context, fields logrus.Fields) context.Context {
 
 
 // WithField is convenience wrapper around WithFields.
 // WithField is convenience wrapper around WithFields.
 func WithField(ctx context.Context, key, value string) context.Context {
 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
 // 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
 package cnmallocator
 
 
 import (
 import (
+	"context"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
 
 
@@ -8,7 +9,7 @@ import (
 	builtinIpam "github.com/docker/docker/libnetwork/ipams/builtin"
 	builtinIpam "github.com/docker/docker/libnetwork/ipams/builtin"
 	nullIpam "github.com/docker/docker/libnetwork/ipams/null"
 	nullIpam "github.com/docker/docker/libnetwork/ipams/null"
 	"github.com/docker/docker/libnetwork/ipamutils"
 	"github.com/docker/docker/libnetwork/ipamutils"
-	"github.com/sirupsen/logrus"
+	"github.com/moby/swarmkit/v2/log"
 )
 )
 
 
 func initIPAMDrivers(r ipamapi.Registerer, netConfig *NetworkConfig) error {
 func initIPAMDrivers(r ipamapi.Registerer, netConfig *NetworkConfig) error {
@@ -35,7 +36,7 @@ func initIPAMDrivers(r ipamapi.Registerer, netConfig *NetworkConfig) error {
 		return err
 		return err
 	}
 	}
 	if addressPool != nil {
 	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){
 	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/log"
 	"github.com/moby/swarmkit/v2/manager/allocator/networkallocator"
 	"github.com/moby/swarmkit/v2/manager/allocator/networkallocator"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
-	"github.com/sirupsen/logrus"
 )
 )
 
 
 const (
 const (
@@ -261,7 +260,7 @@ vipLoop:
 		}
 		}
 		for _, nAttach := range specNetworks {
 		for _, nAttach := range specNetworks {
 			if nAttach.Target == eAttach.NetworkID {
 			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 {
 				if err = na.allocateVIP(eAttach); err != nil {
 					return err
 					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/identity"
 	"github.com/moby/swarmkit/v2/log"
 	"github.com/moby/swarmkit/v2/log"
 	"github.com/moby/swarmkit/v2/manager/state/store"
 	"github.com/moby/swarmkit/v2/manager/state/store"
-	"github.com/sirupsen/logrus"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 	"google.golang.org/grpc/status"
 )
 )
@@ -80,7 +79,7 @@ func (s *Server) UpdateConfig(ctx context.Context, request *api.UpdateConfigRequ
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	log.G(ctx).WithFields(logrus.Fields{
+	log.G(ctx).WithFields(log.Fields{
 		"config.ID":   request.ConfigID,
 		"config.ID":   request.ConfigID,
 		"config.Name": request.Spec.Annotations.Name,
 		"config.Name": request.Spec.Annotations.Name,
 		"method":      "UpdateConfig",
 		"method":      "UpdateConfig",
@@ -166,7 +165,7 @@ func (s *Server) CreateConfig(ctx context.Context, request *api.CreateConfigRequ
 	case store.ErrNameConflict:
 	case store.ErrNameConflict:
 		return nil, status.Errorf(codes.AlreadyExists, "config %s already exists", request.Spec.Annotations.Name)
 		return nil, status.Errorf(codes.AlreadyExists, "config %s already exists", request.Spec.Annotations.Name)
 	case nil:
 	case nil:
-		log.G(ctx).WithFields(logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"config.Name": request.Spec.Annotations.Name,
 			"config.Name": request.Spec.Annotations.Name,
 			"method":      "CreateConfig",
 			"method":      "CreateConfig",
 		}).Debugf("config created")
 		}).Debugf("config created")
@@ -222,7 +221,7 @@ func (s *Server) RemoveConfig(ctx context.Context, request *api.RemoveConfigRequ
 	case store.ErrNotExist:
 	case store.ErrNotExist:
 		return nil, status.Errorf(codes.NotFound, "config %s not found", request.ConfigID)
 		return nil, status.Errorf(codes.NotFound, "config %s not found", request.ConfigID)
 	case nil:
 	case nil:
-		log.G(ctx).WithFields(logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"config.ID": request.ConfigID,
 			"config.ID": request.ConfigID,
 			"method":    "RemoveConfig",
 			"method":    "RemoveConfig",
 		}).Debugf("config removed")
 		}).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/identity"
 	"github.com/moby/swarmkit/v2/log"
 	"github.com/moby/swarmkit/v2/log"
 	"github.com/moby/swarmkit/v2/manager/state/store"
 	"github.com/moby/swarmkit/v2/manager/state/store"
-	"github.com/sirupsen/logrus"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 	"google.golang.org/grpc/status"
 )
 )
@@ -37,7 +36,7 @@ func (s *Server) CreateExtension(ctx context.Context, request *api.CreateExtensi
 	case store.ErrNameConflict:
 	case store.ErrNameConflict:
 		return nil, status.Errorf(codes.AlreadyExists, "extension %s already exists", request.Annotations.Name)
 		return nil, status.Errorf(codes.AlreadyExists, "extension %s already exists", request.Annotations.Name)
 	case nil:
 	case nil:
-		log.G(ctx).WithFields(logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"extension.Name": request.Annotations.Name,
 			"extension.Name": request.Annotations.Name,
 			"method":         "CreateExtension",
 			"method":         "CreateExtension",
 		}).Debugf("extension created")
 		}).Debugf("extension created")
@@ -121,7 +120,7 @@ func (s *Server) RemoveExtension(ctx context.Context, request *api.RemoveExtensi
 	case store.ErrNotExist:
 	case store.ErrNotExist:
 		return nil, status.Errorf(codes.NotFound, "extension %s not found", request.ExtensionID)
 		return nil, status.Errorf(codes.NotFound, "extension %s not found", request.ExtensionID)
 	case nil:
 	case nil:
-		log.G(ctx).WithFields(logrus.Fields{
+		log.G(ctx).WithFields(log.Fields{
 			"extension.ID": request.ExtensionID,
 			"extension.ID": request.ExtensionID,
 			"method":       "RemoveExtension",
 			"method":       "RemoveExtension",
 		}).Debugf("extension removed")
 		}).Debugf("extension removed")

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

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

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

@@ -7,10 +7,8 @@ import (
 	"sync"
 	"sync"
 	"time"
 	"time"
 
 
-	"github.com/docker/go-events"
-	"github.com/sirupsen/logrus"
-
 	"github.com/docker/docker/pkg/plugingetter"
 	"github.com/docker/docker/pkg/plugingetter"
+	"github.com/docker/go-events"
 
 
 	"github.com/moby/swarmkit/v2/api"
 	"github.com/moby/swarmkit/v2/api"
 	"github.com/moby/swarmkit/v2/log"
 	"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.
 // processVolumes encapuslates the logic for processing pending Volumes.
 func (vm *Manager) processVolume(ctx context.Context, id string, attempt uint) {
 func (vm *Manager) processVolume(ctx context.Context, id string, attempt uint) {
 	// set up log fields for a derrived context to pass to handleVolume.
 	// 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,
 		"volume.id": id,
 		"attempt":   attempt,
 		"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/equality"
 	"github.com/moby/swarmkit/v2/api/validation"
 	"github.com/moby/swarmkit/v2/api/validation"
 	"github.com/moby/swarmkit/v2/identity"
 	"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/drivers"
 	"github.com/moby/swarmkit/v2/manager/state/store"
 	"github.com/moby/swarmkit/v2/manager/state/store"
 	"github.com/sirupsen/logrus"
 	"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)
 	secret, doNotReuse, err := a.secret(readTx, t, mapKey.id)
 	if err != nil {
 	if err != nil {
-		a.log.WithFields(logrus.Fields{
+		a.log.WithFields(log.Fields{
 			"resource.type": "secret",
 			"resource.type": "secret",
 			"secret.id":     mapKey.id,
 			"secret.id":     mapKey.id,
 			"error":         err,
 			"error":         err,
@@ -89,7 +90,7 @@ func assignConfig(a *assignmentSet, readTx store.ReadTx, mapKey typeAndID) {
 	a.tasksUsingDependency[mapKey] = make(map[string]struct{})
 	a.tasksUsingDependency[mapKey] = make(map[string]struct{})
 	config := store.GetConfig(readTx, mapKey.id)
 	config := store.GetConfig(readTx, mapKey.id)
 	if config == nil {
 	if config == nil {
-		a.log.WithFields(logrus.Fields{
+		a.log.WithFields(log.Fields{
 			"resource.type": "config",
 			"resource.type": "config",
 			"config.id":     mapKey.id,
 			"config.id":     mapKey.id,
 		}).Debug("config not found")
 		}).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/remotes"
 	"github.com/moby/swarmkit/v2/watch"
 	"github.com/moby/swarmkit/v2/watch"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
-	"github.com/sirupsen/logrus"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 	"google.golang.org/grpc/status"
 )
 )
@@ -619,7 +618,7 @@ func (d *Dispatcher) UpdateTaskStatus(ctx context.Context, r *api.UpdateTaskStat
 		return nil, err
 		return nil, err
 	}
 	}
 	nodeID := nodeInfo.NodeID
 	nodeID := nodeInfo.NodeID
-	fields := logrus.Fields{
+	fields := log.Fields{
 		"node.id":      nodeID,
 		"node.id":      nodeID,
 		"node.session": r.SessionID,
 		"node.session": r.SessionID,
 		"method":       "(*Dispatcher).UpdateTaskStatus",
 		"method":       "(*Dispatcher).UpdateTaskStatus",
@@ -695,7 +694,7 @@ func (d *Dispatcher) UpdateVolumeStatus(ctx context.Context, r *api.UpdateVolume
 	}
 	}
 
 
 	nodeID := nodeInfo.NodeID
 	nodeID := nodeInfo.NodeID
-	fields := logrus.Fields{
+	fields := log.Fields{
 		"node.id":      nodeID,
 		"node.id":      nodeID,
 		"node.session": r.SessionID,
 		"node.session": r.SessionID,
 		"method":       "(*Dispatcher).UpdateVolumeStatus",
 		"method":       "(*Dispatcher).UpdateVolumeStatus",
@@ -703,19 +702,19 @@ func (d *Dispatcher) UpdateVolumeStatus(ctx context.Context, r *api.UpdateVolume
 	if nodeInfo.ForwardedBy != nil {
 	if nodeInfo.ForwardedBy != nil {
 		fields["forwarder.id"] = nodeInfo.ForwardedBy.NodeID
 		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 {
 	if _, err := d.nodes.GetWithSession(nodeID, r.SessionID); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
 	d.unpublishedVolumesLock.Lock()
 	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.
 			// 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()
 	d.unpublishedVolumesLock.Unlock()
@@ -756,14 +755,14 @@ func (d *Dispatcher) processUpdates(ctx context.Context) {
 		return
 		return
 	}
 	}
 
 
-	log := log.G(ctx).WithFields(logrus.Fields{
+	logr := log.G(ctx).WithFields(log.Fields{
 		"method": "(*Dispatcher).processUpdates",
 		"method": "(*Dispatcher).processUpdates",
 	})
 	})
 
 
 	err := d.store.Batch(func(batch *store.Batch) error {
 	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 {
 			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)
 				task := store.GetTask(tx, taskID)
 				if task == nil {
 				if task == nil {
 					// Task may have been deleted
 					// Task may have been deleted
@@ -771,14 +770,14 @@ func (d *Dispatcher) processUpdates(ctx context.Context) {
 					return nil
 					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")
 					logger.Debug("task status identical, ignoring")
 					return nil
 					return nil
 				}
 				}
 
 
-				if task.Status.State > status.State {
+				if task.Status.State > taskStatus.State {
 					logger.Debug("task status invalid transition")
 					logger.Debug("task status invalid transition")
 					return nil
 					return nil
 				}
 				}
@@ -789,12 +788,12 @@ func (d *Dispatcher) processUpdates(ctx context.Context) {
 				// the network delay between the worker and the leader.
 				// 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
 				// 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.
 				// 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)
 					schedulingDelayTimer.UpdateSince(start)
 				}
 				}
 
 
-				task.Status = *status
+				task.Status = *taskStatus
 				task.Status.AppliedBy = d.securityConfig.ClientTLSCreds.NodeID()
 				task.Status.AppliedBy = d.securityConfig.ClientTLSCreds.NodeID()
 				task.Status.AppliedAt = ptypes.MustTimestampProto(time.Now())
 				task.Status.AppliedAt = ptypes.MustTimestampProto(time.Now())
 				logger.Debugf("state for task %v updated to %v", task.GetID(), task.Status.State)
 				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
 				return nil
 			})
 			})
 			if err != 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 {
 		for nodeID, nodeUpdate := range nodeUpdates {
 			err := batch.Update(func(tx store.Tx) error {
 			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)
 				node := store.GetNode(tx, nodeID)
 				if node == nil {
 				if node == nil {
 					logger.Error("node unavailable")
 					logger.Error("node unavailable")
@@ -838,13 +837,13 @@ func (d *Dispatcher) processUpdates(ctx context.Context) {
 				return nil
 				return nil
 			})
 			})
 			if err != 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 {
 		for volumeID, nodes := range unpublishedVolumes {
 			err := batch.Update(func(tx store.Tx) error {
 			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)
 				volume := store.GetVolume(tx, volumeID)
 				if volume == nil {
 				if volume == nil {
 					logger.Error("volume unavailable")
 					logger.Error("volume unavailable")
@@ -869,14 +868,14 @@ func (d *Dispatcher) processUpdates(ctx context.Context) {
 			})
 			})
 
 
 			if err != nil {
 			if err != nil {
-				log.WithError(err).Error("dispatcher volume update transaction failed")
+				logr.WithError(err).Error("dispatcher volume update transaction failed")
 			}
 			}
 		}
 		}
 
 
 		return nil
 		return nil
 	})
 	})
 	if err != nil {
 	if err != nil {
-		log.WithError(err).Error("dispatcher batch failed")
+		logr.WithError(err).Error("dispatcher batch failed")
 	}
 	}
 
 
 	d.processUpdatesCond.Broadcast()
 	d.processUpdatesCond.Broadcast()
@@ -900,7 +899,7 @@ func (d *Dispatcher) Tasks(r *api.TasksRequest, stream api.Dispatcher_TasksServe
 	}
 	}
 	nodeID := nodeInfo.NodeID
 	nodeID := nodeInfo.NodeID
 
 
-	fields := logrus.Fields{
+	fields := log.Fields{
 		"node.id":      nodeID,
 		"node.id":      nodeID,
 		"node.session": r.SessionID,
 		"node.session": r.SessionID,
 		"method":       "(*Dispatcher).Tasks",
 		"method":       "(*Dispatcher).Tasks",
@@ -1026,7 +1025,7 @@ func (d *Dispatcher) Assignments(r *api.AssignmentsRequest, stream api.Dispatche
 	}
 	}
 	nodeID := nodeInfo.NodeID
 	nodeID := nodeInfo.NodeID
 
 
-	fields := logrus.Fields{
+	fields := log.Fields{
 		"node.id":      nodeID,
 		"node.id":      nodeID,
 		"node.session": r.SessionID,
 		"node.session": r.SessionID,
 		"method":       "(*Dispatcher).Assignments",
 		"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.id":      nodeID,
 		"node.session": sessionID,
 		"node.session": sessionID,
 		"method":       "(*Dispatcher).Session",
 		"method":       "(*Dispatcher).Session",
@@ -1402,7 +1401,7 @@ func (d *Dispatcher) Session(r *api.SessionRequest, stream api.Dispatcher_Sessio
 	if nodeInfo.ForwardedBy != nil {
 	if nodeInfo.ForwardedBy != nil {
 		fields["forwarder.id"] = nodeInfo.ForwardedBy.NodeID
 		fields["forwarder.id"] = nodeInfo.ForwardedBy.NodeID
 	}
 	}
-	log := log.G(ctx).WithFields(fields)
+	logger := log.G(ctx).WithFields(fields)
 
 
 	var nodeObj *api.Node
 	var nodeObj *api.Node
 	nodeUpdates, cancel, err := store.ViewAndWatch(d.store, func(readTx store.ReadTx) error {
 	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 {
 	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 {
 	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 is a helper forcibly shutdown connection
 	disconnectNode := func() error {
 	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 {
 		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.
 		// still return an abort if the transport closure was ineffective.
 		return status.Errorf(codes.Aborted, "node must disconnect")
 		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/log"
 	"github.com/moby/swarmkit/v2/manager/state/store"
 	"github.com/moby/swarmkit/v2/manager/state/store"
 	"github.com/moby/swarmkit/v2/watch"
 	"github.com/moby/swarmkit/v2/watch"
-	"github.com/sirupsen/logrus"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 	"google.golang.org/grpc/status"
 )
 )
@@ -239,13 +238,13 @@ func (lb *LogBroker) SubscribeLogs(request *api.SubscribeLogsRequest, stream api
 	subscription.Run(pctx)
 	subscription.Run(pctx)
 	defer subscription.Stop()
 	defer subscription.Stop()
 
 
-	log := log.G(ctx).WithFields(
-		logrus.Fields{
+	logger := log.G(ctx).WithFields(
+		log.Fields{
 			"method":          "(*LogBroker).SubscribeLogs",
 			"method":          "(*LogBroker).SubscribeLogs",
 			"subscription.id": subscription.message.ID,
 			"subscription.id": subscription.message.ID,
 		},
 		},
 	)
 	)
-	log.Debug("subscribed")
+	logger.Debug("subscribed")
 
 
 	publishCh, publishCancel := lb.subscribe(subscription.message.ID)
 	publishCh, publishCancel := lb.subscribe(subscription.message.ID)
 	defer publishCancel()
 	defer publishCancel()
@@ -319,8 +318,8 @@ func (lb *LogBroker) ListenSubscriptions(request *api.ListenSubscriptionsRequest
 	lb.nodeConnected(remote.NodeID)
 	lb.nodeConnected(remote.NodeID)
 	defer lb.nodeDisconnected(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",
 			"method": "(*LogBroker).ListenSubscriptions",
 			"node":   remote.NodeID,
 			"node":   remote.NodeID,
 		},
 		},
@@ -328,7 +327,7 @@ func (lb *LogBroker) ListenSubscriptions(request *api.ListenSubscriptionsRequest
 	subscriptions, subscriptionCh, subscriptionCancel := lb.watchSubscriptions(remote.NodeID)
 	subscriptions, subscriptionCh, subscriptionCancel := lb.watchSubscriptions(remote.NodeID)
 	defer subscriptionCancel()
 	defer subscriptionCancel()
 
 
-	log.Debug("node registered")
+	logger.Debug("node registered")
 
 
 	activeSubscriptions := make(map[string]*subscription)
 	activeSubscriptions := make(map[string]*subscription)
 
 
@@ -343,7 +342,7 @@ func (lb *LogBroker) ListenSubscriptions(request *api.ListenSubscriptionsRequest
 		}
 		}
 
 
 		if err := stream.Send(subscription.message); err != nil {
 		if err := stream.Send(subscription.message); err != nil {
-			log.Error(err)
+			logger.Error(err)
 			return err
 			return err
 		}
 		}
 		activeSubscriptions[subscription.message.ID] = subscription
 		activeSubscriptions[subscription.message.ID] = subscription
@@ -365,7 +364,7 @@ func (lb *LogBroker) ListenSubscriptions(request *api.ListenSubscriptionsRequest
 				activeSubscriptions[subscription.message.ID] = subscription
 				activeSubscriptions[subscription.message.ID] = subscription
 			}
 			}
 			if err := stream.Send(subscription.message); err != nil {
 			if err := stream.Send(subscription.message); err != nil {
-				log.Error(err)
+				logger.Error(err)
 				return err
 				return err
 			}
 			}
 		case <-stream.Context().Done():
 		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/remotes"
 	"github.com/moby/swarmkit/v2/xnet"
 	"github.com/moby/swarmkit/v2/xnet"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
-	"github.com/sirupsen/logrus"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/credentials"
 	"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 {
 func (m *Manager) updateKEK(ctx context.Context, cluster *api.Cluster) error {
 	securityConfig := m.config.SecurityConfig
 	securityConfig := m.config.SecurityConfig
 	nodeID := m.config.SecurityConfig.ClientTLSCreds.NodeID()
 	nodeID := m.config.SecurityConfig.ClientTLSCreds.NodeID()
-	logger := log.G(ctx).WithFields(logrus.Fields{
+	logger := log.G(ctx).WithFields(log.Fields{
 		"node.id":   nodeID,
 		"node.id":   nodeID,
 		"node.role": ca.ManagerRole,
 		"node.role": ca.ManagerRole,
 	})
 	})
@@ -899,11 +898,10 @@ func (m *Manager) serveListener(ctx context.Context, lCh <-chan net.Listener) {
 	case <-ctx.Done():
 	case <-ctx.Done():
 		return
 		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 {
 	if _, ok := l.(*net.TCPListener); !ok {
 		log.G(ctx).Info("Listening for local connections")
 		log.G(ctx).Info("Listening for local connections")
 		// we need to disallow double closes because UnixListener.Close
 		// 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) {
 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 {
 	if len(schedulingDecisions) == 0 {
 		return
 		return
 	}
 	}
@@ -619,9 +631,7 @@ func (s *Scheduler) applySchedulingDecisions(ctx context.Context, schedulingDeci
 		}
 		}
 		// finally, every time we make new scheduling decisions, take the
 		// finally, every time we make new scheduling decisions, take the
 		// opportunity to release volumes.
 		// opportunity to release volumes.
-		return batch.Update(func(tx store.Tx) error {
-			return s.volumes.freeVolumes(tx)
-		})
+		return nil
 	})
 	})
 
 
 	if err != 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
 // TODO(dperny): this is messy and has a lot of overhead. it should be reworked
 // to something more streamlined.
 // 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 {
 	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
 	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
 		return nil, err
 	}
 	}
 
 
-	fields := logrus.Fields{
+	fields := log.Fields{
 		"node.id": nodeInfo.NodeID,
 		"node.id": nodeInfo.NodeID,
 		"method":  "(*Node).Join",
 		"method":  "(*Node).Join",
 		"raft_id": fmt.Sprintf("%x", n.Config.ID),
 		"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 {
 	if nodeInfo.ForwardedBy != nil {
 		fields["forwarder.id"] = nodeInfo.ForwardedBy.NodeID
 		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
 	// can't stop the raft node while an async RPC is in progress
 	n.stopMu.RLock()
 	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 {
 			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
 				return nil, err
 			}
 			}
 
 
-			log.Info("updated node address")
+			logger.Info("updated node address")
 			return n.joinResponse(m.RaftID), nil
 			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)
 	err = n.addMember(ctx, remoteAddr, raftID, nodeInfo.NodeID)
 	if err != nil {
 	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
 		return nil, err
 	}
 	}
 
 
-	log.Debug("node joined")
+	logger.Debug("node joined")
 
 
 	return n.joinResponse(raftID), nil
 	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
 	// spawn updating info in raft in background to unblock transport
 	go func() {
 	go func() {
 		if err := n.updateNodeBlocking(ctx, id, addr); err != nil {
 		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)
 	ctx, cancel := n.WithContext(ctx)
 	defer cancel()
 	defer cancel()
 
 
-	fields := logrus.Fields{
+	fields := log.Fields{
 		"node.id": nodeInfo.NodeID,
 		"node.id": nodeInfo.NodeID,
 		"method":  "(*Node).Leave",
 		"method":  "(*Node).Leave",
 		"raft_id": fmt.Sprintf("%x", n.Config.ID),
 		"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
 // ProcessRaftMessage. Usually nothing will be logged, so it is useful to avoid
 // formatting strings and allocating a logger when it won't be used.
 // formatting strings and allocating a logger when it won't be used.
 func (n *Node) processRaftMessageLogger(ctx context.Context, msg *api.ProcessRaftMessageRequest) *logrus.Entry {
 func (n *Node) processRaftMessageLogger(ctx context.Context, msg *api.ProcessRaftMessageRequest) *logrus.Entry {
-	fields := logrus.Fields{
+	fields := log.Fields{
 		"method": "(*Node).ProcessRaftMessage",
 		"method": "(*Node).ProcessRaftMessage",
 	}
 	}
 
 
@@ -1474,7 +1474,7 @@ func (n *Node) ResolveAddress(ctx context.Context, msg *api.ResolveAddressReques
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	fields := logrus.Fields{
+	fields := log.Fields{
 		"node.id": nodeInfo.NodeID,
 		"node.id": nodeInfo.NodeID,
 		"method":  "(*Node).ResolveAddress",
 		"method":  "(*Node).ResolveAddress",
 		"raft_id": fmt.Sprintf("%x", n.Config.ID),
 		"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")
 		log.G(ctx).WithError(err).Error("failed to configure VXLAN UDP port")
 		return
 		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) {
 func (n *Node) run(ctx context.Context) (err error) {
@@ -444,7 +444,7 @@ func (n *Node) run(ctx context.Context) (err error) {
 	go func() {
 	go func() {
 		for certUpdate := range updates {
 		for certUpdate := range updates {
 			if certUpdate.Err != nil {
 			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
 				continue
 			}
 			}
 			// Set the new role, and notify our waiting role changing logic
 			// 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
 		// Attempt to load certificate from disk
 		securityConfig, cancel, err = ca.LoadSecurityConfig(ctx, rootCA, krw, n.config.ForceNewCluster)
 		securityConfig, cancel, err = ca.LoadSecurityConfig(ctx, rootCA, krw, n.config.ForceNewCluster)
 		if err == nil {
 		if err == nil {
-			log.G(ctx).WithFields(logrus.Fields{
+			log.G(ctx).WithFields(log.Fields{
 				"node.id": securityConfig.ClientTLSCreds.NodeID(),
 				"node.id": securityConfig.ClientTLSCreds.NodeID(),
 			}).Debugf("loaded TLS certificate")
 			}).Debugf("loaded TLS certificate")
 		} else {
 		} else {

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

@@ -6,7 +6,7 @@ import (
 	"sync"
 	"sync"
 
 
 	"github.com/docker/go-events"
 	"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
 // 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,
 			// Eventually, go-events should not use logrus at all,
 			// and should bubble up conditions like this through
 			// and should bubble up conditions like this through
 			// error values.
 			// error values.
-			logrus.WithFields(logrus.Fields{
+			log.L.WithFields(log.Fields{
 				"event": event,
 				"event": event,
 				"sink":  eq.dst,
 				"sink":  eq.dst,
 			}).WithError(err).Debug("eventqueue: dropped event")
 			}).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}
+	}
+}

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini